Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions site/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,15 @@
success+error axis onto sky-blue (success) + vermilion/orange
(destructive). Warning shifts to fuchsia so it does not collide
with destructive states on the orange axis.
- dark-tritan / light-tritan: keep the red/green success+error
axis intact and move warning from amber to fuchsia because
amber and sky-blue blur together under tritanopia.
- dark-tritan / light-tritan: keep destructive states on the
red/orange axis and shift `success` (and the green-tinted
diff/git surfaces) onto sky-blue. This matches GitHub
Primer's tritanopia preset, where diff additions render in
blue rather than green so the success+destructive pair stays
consistent with the protan-deuter palette and with other
tritan-aware tools. Warning still moves from amber to
fuchsia because amber and sky-blue blur together under
tritanopia.
Comment thread
DanielleMaywood marked this conversation as resolved.
*/
.light-protan-deuter {
--content-success: 199 89% 48%;
Expand Down Expand Up @@ -252,24 +258,41 @@
--surface-git-deleted: 17 75% 15%;
}
.light-tritan {
--content-success: 199 89% 48%;
--content-warning: 322 81% 43%;
--surface-green: 201 94% 86%;
--surface-orange: 289 100% 98%;
--border-success: 199 89% 48%;
--border-green: 201 94% 86%;
--border-warning: 322 81% 60%;
--highlight-green: 201 94% 36%;
--highlight-orange: 322 81% 43%;
--highlight-magenta: 322, 81%, 43%;
--syntax-boolean: 322 81% 43%;
--syntax-number: 199 89% 38%;
--git-added: 199 89% 48%;
--git-modified: 322 81% 43%;
--git-added-bright: 199 89% 48%;
--surface-git-added: 204 94% 94%;
}
.dark-tritan {
--content-success: 199 82% 67%;
--content-warning: 322 81% 67%;
--surface-green: 201 80% 14%;
--surface-orange: 322 70% 15%;
--surface-magenta: 322 70% 15%;
--border-success: 199 82% 67%;
--border-green: 201 94% 86%;
--border-magenta: 322 81% 72%;
--border-warning: 322 81% 67%;
--highlight-green: 201 94% 86%;
--highlight-orange: 322 81% 67%;
--highlight-magenta: 322 81% 72%;
--syntax-boolean: 322 81% 67%;
--git-added: 199 82% 67%;
--git-modified: 322 81% 72%;
--git-added-bright: 199 89% 48%;
--surface-git-added: 201 80% 14%;
}
}

Expand Down
48 changes: 47 additions & 1 deletion site/src/theme/colorblind.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import themes, {
baseModeFor,
CONCRETE_THEMES,
isConcreteThemeName,
legacyAutoToSync,
resolveThemeName,
} from ".";

Expand Down Expand Up @@ -71,8 +72,10 @@ describe("isConcreteThemeName", () => {
}
});

it("rejects the auto preference (embeds require a concrete theme)", () => {
it("rejects legacy auto-family preferences", () => {
expect(isConcreteThemeName("auto")).toBe(false);
expect(isConcreteThemeName("auto-protan-deuter")).toBe(false);
expect(isConcreteThemeName("auto-tritan")).toBe(false);
});

it("rejects non-string and empty values", () => {
Expand All @@ -84,6 +87,34 @@ describe("isConcreteThemeName", () => {
});
});

describe("legacyAutoToSync", () => {
it("maps each legacy auto value to its sync pair", () => {
expect(legacyAutoToSync("auto")).toEqual({
mode: "sync",
light: "light",
dark: "dark",
});
expect(legacyAutoToSync("auto-protan-deuter")).toEqual({
mode: "sync",
light: "light-protan-deuter",
dark: "dark-protan-deuter",
});
expect(legacyAutoToSync("auto-tritan")).toEqual({
mode: "sync",
light: "light-tritan",
dark: "dark-tritan",
});
});

it("returns null for concrete theme names and unrelated values", () => {
expect(legacyAutoToSync("dark")).toBeNull();
expect(legacyAutoToSync("dark-tritan")).toBeNull();
expect(legacyAutoToSync("")).toBeNull();
expect(legacyAutoToSync(undefined)).toBeNull();
expect(legacyAutoToSync("garbage")).toBeNull();
});
});

describe("baseModeFor", () => {
it("maps every concrete theme to its base mode", () => {
for (const name of CONCRETE_THEMES) {
Expand Down Expand Up @@ -120,4 +151,19 @@ describe("colorblind role palettes", () => {
themes.dark.roles.danger,
);
});

it("shifts tritan success off the base green role onto sky-blue", () => {
expect(themes["light-tritan"].roles.success).not.toEqual(
themes.light.roles.success,
);
expect(themes["dark-tritan"].roles.success).not.toEqual(
themes.dark.roles.success,
);
expect(themes["light-tritan"].roles.success).toEqual(
themes["light-protan-deuter"].roles.success,
);
expect(themes["dark-tritan"].roles.success).toEqual(
themes["dark-protan-deuter"].roles.success,
);
});
});
33 changes: 14 additions & 19 deletions site/src/theme/darkTritan/roles.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import type { Roles } from "../roles";
import colors from "../tailwindColors";

// Tritanopia reduces blue/yellow discrimination, so the standard amber
// warning can blur into the sky-blue active/notice accents. Under
// tritanopia, red vs green remains intact, so we keep `success` on green,
// `error` on red, and `danger` on the base orange. Only `warning` shifts
// to a magenta/pink that stays distinct from blue and red states.
const roles: Roles = {
danger: {
background: colors.orange[950],
Expand Down Expand Up @@ -80,31 +75,31 @@ const roles: Roles = {
},
},
success: {
background: colors.green[950],
outline: colors.green[500],
text: colors.green[50],
background: colors.sky[950],
outline: colors.sky[500],
text: colors.sky[50],
fill: {
solid: colors.green[600],
outline: colors.green[600],
solid: colors.sky[600],
outline: colors.sky[600],
text: colors.white,
},
disabled: {
background: colors.green[950],
outline: colors.green[800],
text: colors.green[200],
background: colors.sky[950],
outline: colors.sky[800],
text: colors.sky[200],
fill: {
solid: colors.green[800],
outline: colors.green[800],
solid: colors.sky[800],
outline: colors.sky[800],
text: colors.white,
},
},
hover: {
background: colors.green[900],
outline: colors.green[500],
background: colors.sky[900],
outline: colors.sky[500],
text: colors.white,
fill: {
solid: colors.green[500],
outline: colors.green[500],
solid: colors.sky[500],
outline: colors.sky[500],
text: colors.white,
},
},
Expand Down
29 changes: 29 additions & 0 deletions site/src/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,35 @@ export const isConcreteThemeName = (
return typeof value === "string" && concreteThemeSet.has(value);
};

type LegacyAutoSync = {
mode: "sync";
light: ConcreteThemeName;
dark: ConcreteThemeName;
};

const LEGACY_AUTO_SYNC: Record<string, LegacyAutoSync> = {
auto: { mode: "sync", light: "light", dark: "dark" },
"auto-protan-deuter": {
mode: "sync",
light: "light-protan-deuter",
dark: "dark-protan-deuter",
},
"auto-tritan": {
mode: "sync",
light: "light-tritan",
dark: "dark-tritan",
},
};

export const legacyAutoToSync = (
preference: string | undefined,
): LegacyAutoSync | null => {
if (!preference) {
return null;
}
return LEGACY_AUTO_SYNC[preference] ?? null;
};

export const resolveThemeName = (
preference: string | undefined,
osScheme: "dark" | "light",
Expand Down
32 changes: 14 additions & 18 deletions site/src/theme/lightTritan/roles.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import type { Roles } from "../roles";
import colors from "../tailwindColors";

// Tritanopia reduces blue/yellow discrimination. Red vs green remains
// intact, so we keep `success` on green, `error` on red, and `danger`
// on the base orange. Only `warning` shifts to a magenta/fuchsia that
// stays distinct from the blue accents and red destructive states.
const roles: Roles = {
danger: {
background: colors.orange[50],
Expand Down Expand Up @@ -79,31 +75,31 @@ const roles: Roles = {
},
},
success: {
background: colors.green[50],
outline: colors.green[500],
text: colors.green[950],
background: colors.sky[100],
outline: colors.sky[500],
text: colors.sky[950],
fill: {
solid: colors.green[600],
outline: colors.green[600],
solid: colors.sky[600],
outline: colors.sky[600],
text: colors.white,
},
disabled: {
background: colors.green[50],
outline: colors.green[800],
text: colors.green[800],
background: colors.sky[50],
outline: colors.sky[800],
text: colors.sky[800],
fill: {
solid: colors.green[800],
outline: colors.green[800],
solid: colors.sky[800],
outline: colors.sky[800],
text: colors.white,
},
},
hover: {
background: colors.green[100],
outline: colors.green[500],
background: colors.sky[200],
outline: colors.sky[500],
text: colors.black,
fill: {
solid: colors.green[500],
outline: colors.green[500],
solid: colors.sky[500],
outline: colors.sky[500],
text: colors.white,
},
},
Expand Down
Loading