|
1 | 1 | // Canonical color legend for environment categories. Mapped by handle or alias |
2 | 2 | // so admin pages, status boards, and service rows all paint the same swatch |
3 | 3 | // for the same environment. |
| 4 | +// |
| 5 | +// The palette is canon in daniel-miller/infra/README.md ("Environment |
| 6 | +// colors"); cmds-app/platform/web/src/lib/environments.ts carries the same |
| 7 | +// values. Keep this file in step with those, not ahead of them. |
| 8 | +// |
| 9 | +// The ramp says how far a mistake travels, not whether a thing is healthy. |
| 10 | +// Green left it on 2026-08-12 because admins read it as a traffic light: green |
| 11 | +// means "passing" and "healthy" everywhere else in the app, and the green/red |
| 12 | +// pair it made with live gave a red-green color blind operator no signal. |
| 13 | +// Violet work, blue test, amber stage, then live with no hue. Amber sits at |
| 14 | +// the loud end because stage is the one that looks like production without |
| 15 | +// being it. |
4 | 16 |
|
5 | 17 | export const ENVIRONMENT_COLORS = { |
6 | | - local: "#4A90D9", |
7 | | - development: "#2ECC71", |
8 | | - sandbox: "#F5A623", |
9 | | - production: "#E74C3C", |
10 | | - other: "#5D6472", |
| 18 | + work: "rgb(150, 122, 214)", |
| 19 | + test: "rgb(74, 144, 217)", |
| 20 | + stage: "rgb(245, 166, 35)", |
| 21 | + // Theme-aware token rather than a literal: a near-black swatch disappears |
| 22 | + // against a dark card. See --color-env-live in styles/globals.css. Red left |
| 23 | + // here on 2026-08-12 - it read as "stop", and it competed with the danger |
| 24 | + // color marking destructive actions on the same screen. |
| 25 | + live: "var(--color-env-live)", |
| 26 | + // Cold, echo, and demo share one gray. Unmapped handles land here too: a |
| 27 | + // token nobody has categorized should look unremarkable rather than borrow a |
| 28 | + // lifecycle color. |
| 29 | + special: "rgb(93, 100, 114)", |
11 | 30 | } as const; |
12 | 31 |
|
13 | 32 | export type EnvironmentCategory = keyof typeof ENVIRONMENT_COLORS; |
14 | 33 |
|
15 | | -const LOCAL_TAGS = new Set(["local", "work"]); |
16 | | -const DEVELOPMENT_TAGS = new Set(["development", "dev", "test", "qa", "uat"]); |
| 34 | +const WORK_TAGS = new Set(["work", "local"]); |
| 35 | +const TEST_TAGS = new Set(["test", "dev", "development", "qa", "uat"]); |
17 | 36 | // "demo" is deliberately absent: since the 2026-07-31 roster rename it names |
18 | | -// the demonstration environment (gray "other"), not the pre-production gate. |
19 | | -const SANDBOX_TAGS = new Set(["sandbox", "stage", "staging"]); |
20 | | -const PRODUCTION_TAGS = new Set(["production", "prod", "live"]); |
| 37 | +// the demonstration environment (gray "special"), not the pre-production gate. |
| 38 | +const STAGE_TAGS = new Set(["stage", "sandbox", "staging"]); |
| 39 | +const LIVE_TAGS = new Set(["live", "prod", "production"]); |
21 | 40 |
|
22 | 41 | export function categorizeEnvironment( |
23 | 42 | handle: string, |
24 | 43 | aliases: readonly string[] = [], |
25 | 44 | ): EnvironmentCategory { |
26 | 45 | const tags = [handle, ...aliases].map((t) => t.toLowerCase()); |
27 | 46 | for (const t of tags) { |
28 | | - if (LOCAL_TAGS.has(t)) return "local"; |
29 | | - if (DEVELOPMENT_TAGS.has(t)) return "development"; |
30 | | - if (SANDBOX_TAGS.has(t)) return "sandbox"; |
31 | | - if (PRODUCTION_TAGS.has(t)) return "production"; |
| 47 | + if (WORK_TAGS.has(t)) return "work"; |
| 48 | + if (TEST_TAGS.has(t)) return "test"; |
| 49 | + if (STAGE_TAGS.has(t)) return "stage"; |
| 50 | + if (LIVE_TAGS.has(t)) return "live"; |
32 | 51 | } |
33 | | - return "other"; |
| 52 | + return "special"; |
34 | 53 | } |
35 | 54 |
|
36 | 55 | export function environmentColor(handle: string, aliases: readonly string[] = []): string { |
|
0 commit comments