feat: simplify theme system to single Warm Sage brand palette

Consolidate from 11 themes to one cohesive Warm Sage palette across
landing page, auth layout, dashboard components, kanban columns,
demo banner, theme picker, and CSS variables.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-03-03 18:26:40 -06:00
parent 264107e3bf
commit 44993ae601
17 changed files with 187 additions and 1381 deletions
+20 -291
View File
@@ -19,305 +19,34 @@ export interface ThemeDefinition {
}
/**
* All 11 themes matching the KMM/iOS theme system.
* Hex values are taken directly from ThemeColors.kt.
* Single "Warm Sage" theme — the Casera brand palette.
*/
export const themes: ThemeDefinition[] = [
{
id: "default",
name: "Default",
description: "Warm orange with teal accents",
name: "Warm Sage",
description: "Calming sage with warm clay accents",
light: {
primary: "#E07A3A",
secondary: "#0D7C66",
accent: "#D4A574",
error: "#DC2626",
bgPrimary: "#FFFFFF",
bgSecondary: "#F7F7F7",
textPrimary: "#1C1917",
textSecondary: "#78716C",
primary: "#6B8F71",
secondary: "#C4856A",
accent: "#C4856A",
error: "#C75B4A",
bgPrimary: "#FAFAF7",
bgSecondary: "#F2EFE9",
textPrimary: "#2D3436",
textSecondary: "#8A8F87",
textOnPrimary: "#FFFFFF",
},
dark: {
primary: "#F0A070",
secondary: "#4FC9AF",
accent: "#DDB892",
error: "#EF4444",
bgPrimary: "#0A0A0A",
bgSecondary: "#161616",
textPrimary: "#FAFAFA",
textSecondary: "#A1A1A1",
textOnPrimary: "#0A0A0A",
},
},
{
id: "teal",
name: "Teal",
description: "Blue-green with warm accents",
light: {
primary: "#069FC3",
secondary: "#0054A4",
accent: "#EFC707",
error: "#DD1C1A",
bgPrimary: "#FFF0D0",
bgSecondary: "#FFFFFF",
textPrimary: "#111111",
textSecondary: "#444444",
textOnPrimary: "#FFFFFF",
},
dark: {
primary: "#60CCE2",
secondary: "#60A5D8",
accent: "#EFC707",
error: "#FF5244",
bgPrimary: "#091829",
bgSecondary: "#1A2E3E",
textPrimary: "#F5F5F5",
textSecondary: "#C6C6C6",
textOnPrimary: "#FFFFFF",
},
},
{
id: "ocean",
name: "Ocean",
description: "Deep blues and coral tones",
light: {
primary: "#006B8F",
secondary: "#008A8A",
accent: "#FF7E50",
error: "#DD1C1A",
bgPrimary: "#E4EBF1",
bgSecondary: "#BCCAD5",
textPrimary: "#111111",
textSecondary: "#444444",
textOnPrimary: "#FFFFFF",
},
dark: {
primary: "#49B5D1",
secondary: "#60D1C6",
accent: "#FF7E50",
error: "#FF5244",
bgPrimary: "#161B22",
bgSecondary: "#313A4B",
textPrimary: "#F5F5F5",
textSecondary: "#C6C6C6",
textOnPrimary: "#FFFFFF",
},
},
{
id: "forest",
name: "Forest",
description: "Earth greens and golden hues",
light: {
primary: "#2C5015",
secondary: "#6B8E22",
accent: "#FFD600",
error: "#DD1C1A",
bgPrimary: "#EBEEE2",
bgSecondary: "#C1C8AD",
textPrimary: "#111111",
textSecondary: "#444444",
textOnPrimary: "#FFFFFF",
},
dark: {
primary: "#93C66B",
secondary: "#AFD182",
accent: "#FFD600",
error: "#FF5244",
bgPrimary: "#181E17",
bgSecondary: "#384436",
textPrimary: "#F5F5F5",
textSecondary: "#C6C6C6",
textOnPrimary: "#FFFFFF",
},
},
{
id: "sunset",
name: "Sunset",
description: "Warm oranges and reds",
light: {
primary: "#FF4500",
secondary: "#FF6246",
accent: "#FFD600",
error: "#DD1C1A",
bgPrimary: "#F7F0E8",
bgSecondary: "#DCD0BA",
textPrimary: "#111111",
textSecondary: "#444444",
textOnPrimary: "#FFFFFF",
},
dark: {
primary: "#FF9E60",
secondary: "#FFAD7C",
accent: "#FFD600",
error: "#FF5244",
bgPrimary: "#201813",
bgSecondary: "#433329",
textPrimary: "#F5F5F5",
textSecondary: "#C6C6C6",
textOnPrimary: "#FFFFFF",
},
},
{
id: "monochrome",
name: "Monochrome",
description: "Elegant grayscale",
light: {
primary: "#333333",
secondary: "#666666",
accent: "#999999",
error: "#DD1C1A",
bgPrimary: "#F0F0F0",
bgSecondary: "#D4D4D4",
textPrimary: "#111111",
textSecondary: "#444444",
textOnPrimary: "#FFFFFF",
},
dark: {
primary: "#E5E5E5",
secondary: "#BFBFBF",
accent: "#D1D1D1",
error: "#FF5244",
bgPrimary: "#161616",
bgSecondary: "#3B3B3B",
textPrimary: "#F5F5F5",
textSecondary: "#C6C6C6",
textOnPrimary: "#FFFFFF",
},
},
{
id: "lavender",
name: "Lavender",
description: "Soft purple with pink accents",
light: {
primary: "#6B418A",
secondary: "#8A60AF",
accent: "#E24982",
error: "#DD1C1A",
bgPrimary: "#F1EFF5",
bgSecondary: "#D9D1DF",
textPrimary: "#111111",
textSecondary: "#444444",
textOnPrimary: "#FFFFFF",
},
dark: {
primary: "#D1AFE2",
secondary: "#DDBFEA",
accent: "#FF9EC6",
error: "#FF5244",
bgPrimary: "#17131E",
bgSecondary: "#393042",
textPrimary: "#F5F5F5",
textSecondary: "#C6C6C6",
textOnPrimary: "#FFFFFF",
},
},
{
id: "crimson",
name: "Crimson",
description: "Bold red with warm highlights",
light: {
primary: "#B51E28",
secondary: "#992D38",
accent: "#E26000",
error: "#DD1C1A",
bgPrimary: "#F6EDEB",
bgSecondary: "#DECFCC",
textPrimary: "#111111",
textSecondary: "#444444",
textOnPrimary: "#FFFFFF",
},
dark: {
primary: "#FF827C",
secondary: "#F99993",
accent: "#FFB56B",
error: "#FF5244",
bgPrimary: "#1B1215",
bgSecondary: "#412E39",
textPrimary: "#F5F5F5",
textSecondary: "#C6C6C6",
textOnPrimary: "#FFFFFF",
},
},
{
id: "midnight",
name: "Midnight",
description: "Deep navy with sky blue",
light: {
primary: "#1E4993",
secondary: "#2D60AF",
accent: "#4993E2",
error: "#DD1C1A",
bgPrimary: "#EDF0F7",
bgSecondary: "#CCD5E2",
textPrimary: "#111111",
textSecondary: "#444444",
textOnPrimary: "#FFFFFF",
},
dark: {
primary: "#82B5EA",
secondary: "#93C6F2",
accent: "#9ED8FF",
error: "#FF5244",
bgPrimary: "#12161F",
bgSecondary: "#2F3848",
textPrimary: "#F5F5F5",
textSecondary: "#C6C6C6",
textOnPrimary: "#FFFFFF",
},
},
{
id: "desert",
name: "Desert",
description: "Warm terracotta and sand tones",
light: {
primary: "#AF6049",
secondary: "#9E7C60",
accent: "#D1932D",
error: "#DD1C1A",
bgPrimary: "#F6F0EA",
bgSecondary: "#E5D8C6",
textPrimary: "#111111",
textSecondary: "#444444",
textOnPrimary: "#FFFFFF",
},
dark: {
primary: "#F2B593",
secondary: "#EAD1AF",
accent: "#FFD86B",
error: "#FF5244",
bgPrimary: "#1F1C16",
bgSecondary: "#494138",
textPrimary: "#F5F5F5",
textSecondary: "#C6C6C6",
textOnPrimary: "#FFFFFF",
},
},
{
id: "mint",
name: "Mint",
description: "Fresh green with turquoise",
light: {
primary: "#38AF93",
secondary: "#60C6AF",
accent: "#2D9EAF",
error: "#DD1C1A",
bgPrimary: "#EDF6F0",
bgSecondary: "#D1E2D8",
textPrimary: "#111111",
textSecondary: "#444444",
textOnPrimary: "#FFFFFF",
},
dark: {
primary: "#93F2D8",
secondary: "#BFF9EA",
accent: "#6BEAF2",
error: "#FF5244",
bgPrimary: "#161F1F",
bgSecondary: "#384949",
textPrimary: "#F5F5F5",
textSecondary: "#C6C6C6",
textOnPrimary: "#FFFFFF",
primary: "#8FB896",
secondary: "#D4A08A",
accent: "#D4A08A",
error: "#E07A6B",
bgPrimary: "#1A1D1A",
bgSecondary: "#2A2E2A",
textPrimary: "#E8E5DF",
textSecondary: "#9A9E97",
textOnPrimary: "#1A1D1A",
},
},
];
-23
View File
@@ -4,14 +4,8 @@ import { useEffect } from "react";
import { useThemeStore } from "@/stores/theme";
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const themeId = useThemeStore((s) => s.themeId);
const mode = useThemeStore((s) => s.mode);
// Sync data-theme attribute
useEffect(() => {
document.documentElement.setAttribute("data-theme", themeId);
}, [themeId]);
// Sync dark class based on mode + system preference
useEffect(() => {
const applyDarkClass = (isDark: boolean) => {
@@ -41,22 +35,5 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
return () => mql.removeEventListener("change", handler);
}, [mode]);
// On mount, migrate any stale persisted state to light mode
useEffect(() => {
const stored = localStorage.getItem("casera-theme");
if (stored) {
try {
const parsed = JSON.parse(stored);
if (parsed?.state?.mode === "system") {
parsed.state.mode = "light";
localStorage.setItem("casera-theme", JSON.stringify(parsed));
useThemeStore.getState().setMode("light");
}
} catch {
// ignore
}
}
}, []);
return <>{children}</>;
}
+2 -6
View File
@@ -9,7 +9,7 @@ import { themes, getThemeById, type ThemeDefinition } from "./theme-config";
* (accounting for system preference), and setters.
*/
export function useTheme() {
const { themeId, mode, setTheme, setMode } = useThemeStore();
const { mode, setMode } = useThemeStore();
const [effectiveMode, setEffectiveMode] = useState<"light" | "dark">("light");
@@ -28,11 +28,9 @@ export function useTheme() {
return () => mql.removeEventListener("change", handler);
}, [mode]);
const currentTheme: ThemeDefinition = getThemeById(themeId);
const currentTheme: ThemeDefinition = getThemeById("default");
return {
/** Current theme ID string */
themeId,
/** Current mode setting (light | dark | system) */
mode,
/** Resolved mode after considering system preference */
@@ -41,8 +39,6 @@ export function useTheme() {
currentTheme,
/** All available theme definitions */
themes,
/** Set the active theme by ID */
setTheme,
/** Set the color mode */
setMode,
};