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
16 changes: 7 additions & 9 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,13 @@ Colors are referenced through CSS custom properties, never hardcoded hex values.

### Themes

Five premium themes, each with light and dark variants:

| Theme | Vibe |
| --------------------- | ------------------------------------- |
| **Iridescent Void** | Futuristic, expensive, slightly alien |
| **Carbon** | Stark, modern, performance-focused |
| **Vapor** | Refined, fluid, purposeful |
| **Cotton Candy** | Sweet, dreamy, pink and blue |
| **Cathedral Circuit** | Sacred machine, techno-gothic |
Three premium themes, each with light and dark variants:

| Theme | Vibe |
| ------------------- | ------------------------------------- |
| **Iridescent Void** | Futuristic, expensive, slightly alien |
| **Carbon** | Stark, modern, performance-focused |
| **Cotton Candy** | Sweet, dreamy, pink and blue |

All themes define the same set of CSS custom properties. Components must use semantic
tokens (`bg-accent`, `text-muted-foreground`) — never theme-specific values.
Expand Down
16 changes: 1 addition & 15 deletions apps/web/src/hooks/useTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,7 @@ import { useCallback, useEffect, useSyncExternalStore } from "react";
import { initCustomTheme } from "../lib/customTheme";

type Theme = "light" | "dark" | "system";
type ColorTheme =
| "default"
| "iridescent-void"
| "solar-witch"
| "carbon"
| "vapor"
| "cathedral-circuit"
| "cotton-candy"
| "custom";
type ColorTheme = "default" | "iridescent-void" | "carbon" | "cotton-candy" | "custom";

type FontFamily = "dm-sans" | "inter" | "plus-jakarta-sans";

Expand All @@ -24,10 +16,7 @@ type ThemeSnapshot = {
export const COLOR_THEMES: { id: ColorTheme; label: string }[] = [
{ id: "default", label: "Default" },
{ id: "iridescent-void", label: "Iridescent Void" },
{ id: "solar-witch", label: "Solar Witch" },
{ id: "carbon", label: "Carbon" },
{ id: "vapor", label: "Vapor" },
{ id: "cathedral-circuit", label: "Cathedral Circuit" },
{ id: "cotton-candy", label: "Cotton Candy" },
{ id: "custom", label: "Custom" },
];
Expand Down Expand Up @@ -73,10 +62,7 @@ function getStoredColorTheme(): ColorTheme {
if (
raw === "default" ||
raw === "iridescent-void" ||
raw === "solar-witch" ||
raw === "carbon" ||
raw === "vapor" ||
raw === "cathedral-circuit" ||
raw === "cotton-candy" ||
raw === "custom"
) {
Expand Down
26 changes: 1 addition & 25 deletions apps/web/src/selection-styles.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,18 +136,6 @@ const themes: ThemeDef[] = [
background: hexToRgb("#000000"),
foreground: hexToRgb("#e8e4f0"),
},
{
name: "Solar Witch Light",
primary: oklchToRgb(0.62, 0.18, 55),
background: hexToRgb("#faf5ee"),
foreground: hexToRgb("#2d2118"),
},
{
name: "Solar Witch Dark",
primary: oklchToRgb(0.72, 0.17, 60),
background: hexToRgb("#120e0a"),
foreground: hexToRgb("#f0e6d6"),
},
{
name: "Cursor Dark Light",
primary: oklchToRgb(0.55, 0.18, 260),
Expand All @@ -160,18 +148,6 @@ const themes: ThemeDef[] = [
background: hexToRgb("#181818"),
foreground: hexToRgb("#cccccc"),
},
{
name: "Cathedral Circuit Light",
primary: oklchToRgb(0.48, 0.2, 260),
background: hexToRgb("#f2f0ed"),
foreground: hexToRgb("#1c1a18"),
},
{
name: "Cathedral Circuit Dark",
primary: oklchToRgb(0.62, 0.2, 260),
background: hexToRgb("#121214"),
foreground: hexToRgb("#dcd8d2"),
},
];

// ═══════════════════════════════════════════════════════════════════════════
Expand Down Expand Up @@ -420,7 +396,7 @@ describe("WCAG selection contrast ratios", () => {

it("selection is perceivable (selection bg vs page bg ≥ 1.9:1)", () => {
const ratio = contrastRatio(selBgLum, bgLum);
// Warm-on-warm themes (e.g. Solar Witch amber on cream) have
// Warm-on-warm themes can have
// inherently lower perceived contrast at the default 55%
// opacity. The forced-colors and prefers-contrast: more media
// queries provide fallbacks for those users. We enforce a
Expand Down
208 changes: 0 additions & 208 deletions apps/web/src/themes.css
Original file line number Diff line number Diff line change
Expand Up @@ -63,94 +63,6 @@
--warning-foreground: #f1a10d;
}

/* ─── Solar Witch ─── mystical, radiant, high-contrast sunset magic ─── */

:root.theme-solar-witch {
color-scheme: light;
--background: #fff7ed;
--foreground: #3b0764;
--card: #ffedd5;
--card-foreground: #3b0764;
--popover: #fff7ed;
--popover-foreground: #3b0764;
--primary: oklch(0.68 0.23 35);
--primary-foreground: #ffffff;
--secondary: rgba(251, 146, 60, 0.12);
--secondary-foreground: #7c2d12;
--muted: rgba(245, 158, 11, 0.12);
--muted-foreground: #9a3412;
--accent: rgba(236, 72, 153, 0.12);
--accent-foreground: #831843;
--destructive: #dc2626;
--destructive-foreground: #b91c1c;
--border: rgba(234, 88, 12, 0.18);
--input: rgba(234, 88, 12, 0.14);
--ring: oklch(0.68 0.23 35);
--info: #7c3aed;
--info-foreground: #6d28d9;
--success: #16a34a;
--success-foreground: #15803d;
--warning: #f59e0b;
--warning-foreground: #b45309;
}

:root.theme-solar-witch.dark {
color-scheme: dark;
--background: #140b1f;
--foreground: #f8e8ff;
--card: #1f102b;
--card-foreground: #f8e8ff;
--popover: #1f102b;
--popover-foreground: #f8e8ff;
--primary: oklch(0.74 0.21 55);
--primary-foreground: #1a1022;
--secondary: rgba(251, 146, 60, 0.12);
--secondary-foreground: #ffd7a3;
--muted: rgba(236, 72, 153, 0.1);
--muted-foreground: #d8b4fe;
--accent: rgba(168, 85, 247, 0.14);
--accent-foreground: #f3e8ff;
--destructive: #fb7185;
--destructive-foreground: #fda4af;
--border: rgba(251, 146, 60, 0.14);
--input: rgba(251, 146, 60, 0.18);
--ring: oklch(0.74 0.21 55);
--info: #a78bfa;
--info-foreground: #c4b5fd;
--success: #4ade80;
--success-foreground: #86efac;
--warning: #fbbf24;
--warning-foreground: #fcd34d;
}
:root.theme-solar-witch.dark {
color-scheme: dark;
--background: #140b1f;
--foreground: #f8e8ff;
--card: #1f102b;
--card-foreground: #f8e8ff;
--popover: #1f102b;
--popover-foreground: #f8e8ff;
--primary: oklch(0.74 0.21 55);
--primary-foreground: #1a1022;
--secondary: rgba(251, 146, 60, 0.12);
--secondary-foreground: #ffd7a3;
--muted: rgba(236, 72, 153, 0.1);
--muted-foreground: #d8b4fe;
--accent: rgba(168, 85, 247, 0.14);
--accent-foreground: #f3e8ff;
--destructive: #fb7185;
--destructive-foreground: #fda4af;
--border: rgba(251, 146, 60, 0.14);
--input: rgba(251, 146, 60, 0.18);
--ring: oklch(0.74 0.21 55);
--info: #a78bfa;
--info-foreground: #c4b5fd;
--success: #4ade80;
--success-foreground: #86efac;
--warning: #fbbf24;
--warning-foreground: #fcd34d;
}

/* ─── Carbon ─── stark, modern, performance-focused (Vercel-inspired) ─── */

:root.theme-carbon {
Expand Down Expand Up @@ -211,66 +123,6 @@
--warning-foreground: #f7b955;
}

/* ─── Vapor ─── refined, fluid, purposeful (Linear-inspired) ─── */

:root.theme-vapor {
color-scheme: light;
--background: #f9f8fc;
--foreground: #1c1c25;
--card: #f1eff8;
--card-foreground: #1c1c25;
--popover: #f1eff8;
--popover-foreground: #1c1c25;
--primary: oklch(0.53 0.17 277);
--primary-foreground: #ffffff;
--secondary: rgba(94, 106, 210, 0.06);
--secondary-foreground: #1c1c25;
--muted: rgba(94, 106, 210, 0.06);
--muted-foreground: #6e6d80;
--accent: rgba(94, 106, 210, 0.08);
--accent-foreground: #1c1c25;
--destructive: #e5484d;
--destructive-foreground: #cd2b31;
--border: rgba(94, 106, 210, 0.1);
--input: rgba(94, 106, 210, 0.12);
--ring: oklch(0.53 0.17 277);
--info: #5e6ad2;
--info-foreground: #4c58b8;
--success: #45be82;
--success-foreground: #2d9a63;
--warning: #e5a836;
--warning-foreground: #ad7a18;
}

:root.theme-vapor.dark {
color-scheme: dark;
--background: #111119;
--foreground: #e2e0ea;
--card: #191924;
--card-foreground: #e2e0ea;
--popover: #191924;
--popover-foreground: #e2e0ea;
--primary: oklch(0.65 0.18 277);
--primary-foreground: #ffffff;
--secondary: rgba(140, 150, 230, 0.06);
--secondary-foreground: #e2e0ea;
--muted: rgba(140, 150, 230, 0.06);
--muted-foreground: #8a889e;
--accent: rgba(140, 150, 230, 0.08);
--accent-foreground: #e2e0ea;
--destructive: #ff6369;
--destructive-foreground: #ff9592;
--border: rgba(140, 150, 230, 0.08);
--input: rgba(140, 150, 230, 0.1);
--ring: oklch(0.65 0.18 277);
--info: #8b92e8;
--info-foreground: #a8aef0;
--success: #50d07a;
--success-foreground: #5ee090;
--warning: #f5c542;
--warning-foreground: #e8b830;
}

/* ─── Cotton Candy ─── sweet, dreamy pink & blue ─── */

:root.theme-cotton-candy {
Expand Down Expand Up @@ -330,63 +182,3 @@
--warning: #f5bfcc;
--warning-foreground: #f8cdd8;
}

/* ─── Cathedral Circuit ─── sacred machine, techno-gothic ─── */

:root.theme-cathedral-circuit {
color-scheme: light;
--background: #f2f0ed;
--foreground: #1c1a18;
--card: #ebe8e4;
--card-foreground: #1c1a18;
--popover: #ebe8e4;
--popover-foreground: #1c1a18;
--primary: oklch(0.48 0.2 260);
--primary-foreground: #ffffff;
--secondary: rgba(60, 60, 90, 0.06);
--secondary-foreground: #1c1a18;
--muted: rgba(60, 60, 90, 0.06);
--muted-foreground: #6e6a64;
--accent: rgba(60, 60, 90, 0.08);
--accent-foreground: #1c1a18;
--destructive: #dc3545;
--destructive-foreground: #b62a37;
--border: rgba(60, 60, 90, 0.1);
--input: rgba(60, 60, 90, 0.12);
--ring: oklch(0.48 0.2 260);
--info: #3b6bcc;
--info-foreground: #2d5ab3;
--success: #3d9a5f;
--success-foreground: #2d7a4a;
--warning: #d4920a;
--warning-foreground: #a87308;
}

:root.theme-cathedral-circuit.dark {
color-scheme: dark;
--background: #121214;
--foreground: #dcd8d2;
--card: #1a1a1e;
--card-foreground: #dcd8d2;
--popover: #1a1a1e;
--popover-foreground: #dcd8d2;
--primary: oklch(0.62 0.2 260);
--primary-foreground: #ffffff;
--secondary: rgba(160, 160, 220, 0.06);
--secondary-foreground: #dcd8d2;
--muted: rgba(160, 160, 220, 0.06);
--muted-foreground: #8a8680;
--accent: rgba(160, 160, 220, 0.08);
--accent-foreground: #dcd8d2;
--destructive: #ff6b72;
--destructive-foreground: #ff9499;
--border: rgba(160, 160, 220, 0.08);
--input: rgba(160, 160, 220, 0.1);
--ring: oklch(0.62 0.2 260);
--info: #6e9fff;
--info-foreground: #92b5ff;
--success: #50d07a;
--success-foreground: #5ee090;
--warning: #f5c542;
--warning-foreground: #e8b830;
}
Loading
Loading