feat(gui-v2): port WorkspaceSwitcher to TypeScript
Ports crewli-starter WorkspaceSwitcher into the Crewli SPA as production TypeScript: PrimeVue Popover replaces the manual click-outside listener, data is derived from useAuthStore/useOrganisationStore (no new store), gradient pairs are deterministic via a new pure util with full Vitest coverage. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
39
apps/app/src/utils/v2/gradient.ts
Normal file
39
apps/app/src/utils/v2/gradient.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* computeOrgGradient — deterministic gradient pair for an organisation.
|
||||
*
|
||||
* Maps an org `id` string to one of 8 teal-adjacent colour pairs via a
|
||||
* simple djb2-style character-code hash. Same id always returns the
|
||||
* same pair; no external dependencies.
|
||||
*
|
||||
* Palette rationale: teal / cyan / emerald / sea-green family to stay
|
||||
* on-brand with Crewli's teal primary. Each tuple is [from, to] for a
|
||||
* 135° linear gradient (darker "to" keeps depth on the logo square).
|
||||
*/
|
||||
|
||||
/** Exported so tests can assert membership without hard-coding values. */
|
||||
export const GRADIENT_PALETTE: [string, string][] = [
|
||||
['#0d9488', '#0f766e'], // teal-600 → teal-700
|
||||
['#0891b2', '#0e7490'], // cyan-600 → cyan-700
|
||||
['#059669', '#047857'], // emerald-600 → emerald-700
|
||||
['#10b981', '#059669'], // emerald-500 → emerald-600
|
||||
['#0284c7', '#0369a1'], // sky-600 → sky-700
|
||||
['#14b8a6', '#0d9488'], // teal-500 → teal-600
|
||||
['#06b6d4', '#0891b2'], // cyan-500 → cyan-600
|
||||
['#34d399', '#10b981'], // emerald-400 → emerald-500
|
||||
]
|
||||
|
||||
/**
|
||||
* Returns a `[fromHex, toHex]` colour pair deterministically derived
|
||||
* from `id`. Handles empty string (hash stays 0; maps to palette[0]).
|
||||
*/
|
||||
export function computeOrgGradient(id: string): [string, string] {
|
||||
// djb2-style hash: accumulate across char codes
|
||||
let hash = 5381
|
||||
for (let i = 0; i < id.length; i++) {
|
||||
// Equivalent to hash * 33 ^ charCode, kept 32-bit safe via >>> 0
|
||||
hash = ((hash << 5) + hash + id.charCodeAt(i)) >>> 0
|
||||
}
|
||||
const index = hash % GRADIENT_PALETTE.length
|
||||
|
||||
return GRADIENT_PALETTE[index]
|
||||
}
|
||||
Reference in New Issue
Block a user