feat: dark/light theming system + design tokens (OMC design system port)
- Restructure design tokens into :root/.dark raw vars mapped via @theme inline - Add light/dark/system theming: useTheme hook + FOUC guard + ThemeToggle - Keep iamcavalli palette (primary #1A463C, accent #DEF168) and Geist fonts - Derive brand-consistent dark palette (verde-nero bg, lightened primary) - Add scrollbar utilities (.no-scrollbar/.thin-scrollbar) - Install tailwindcss-animate, register via @plugin (Tailwind v4) - Mount ThemeToggle in admin sidebar footer Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+164
-40
@@ -1,64 +1,154 @@
|
||||
@import "tailwindcss";
|
||||
@plugin "tailwindcss-animate";
|
||||
@source not "../../.01_projects/**";
|
||||
@source not "../../.claude/**";
|
||||
@source not "../../scripts/**";
|
||||
@source not "../../.planning/**";
|
||||
|
||||
/* Class-based dark mode (Tailwind v4). The FOUC guard in layout.tsx toggles
|
||||
`.dark` on <html> before paint; the useTheme hook keeps it in sync. */
|
||||
@custom-variant dark (&:where(.dark, .dark *));
|
||||
|
||||
/* =========================================================
|
||||
Design tokens — iamcavalli brand palette (Tailwind v4 @theme)
|
||||
Design tokens — iamcavalli brand palette
|
||||
Raw values live in :root (light) / .dark (dark) so the whole
|
||||
app themes off a single class toggle; @theme inline below maps
|
||||
them to Tailwind color utilities (bg-background, text-primary…).
|
||||
========================================================= */
|
||||
:root {
|
||||
/* Base */
|
||||
--background: #ffffff;
|
||||
--foreground: #1a1a1a;
|
||||
|
||||
/* Brand primary — verde scuro iamcavalli */
|
||||
--primary: #1A463C;
|
||||
--primary-foreground: #ffffff;
|
||||
|
||||
/* Brand accent — giallo lime */
|
||||
--accent: #DEF168;
|
||||
--accent-foreground: #1A463C;
|
||||
|
||||
/* Secondary — grigio neutro */
|
||||
--secondary: #f4f4f5;
|
||||
--secondary-foreground: #1a1a1a;
|
||||
|
||||
/* Muted — per testi e sfondi secondari */
|
||||
--muted: #f9f9f9;
|
||||
--muted-foreground: #71717a;
|
||||
|
||||
/* Destructive */
|
||||
--destructive: #ef4444;
|
||||
--destructive-foreground: #ffffff;
|
||||
|
||||
/* Card */
|
||||
--card: #ffffff;
|
||||
--card-foreground: #1a1a1a;
|
||||
|
||||
/* Popover */
|
||||
--popover: #ffffff;
|
||||
--popover-foreground: #1a1a1a;
|
||||
|
||||
/* Border / Input / Ring */
|
||||
--border: #e5e7eb;
|
||||
--input: #e5e7eb;
|
||||
--ring: #1A463C;
|
||||
|
||||
/* Semantic — stato task/pagamenti */
|
||||
--success: #16a34a;
|
||||
--warning: #ca8a04;
|
||||
--info: #2563eb;
|
||||
|
||||
/* Legacy — usati inline nei componenti esistenti */
|
||||
--tertiary: #999999;
|
||||
--bg-subtle: #f9f9f9;
|
||||
--border-light: #e5e5e5;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
/* Base — verde-nero, coerente col brand */
|
||||
--background: #0e1512;
|
||||
--foreground: #f2f4f3;
|
||||
|
||||
/* Brand primary — verde schiarito per contrasto su fondo scuro */
|
||||
--primary: #3FA88C;
|
||||
--primary-foreground: #06110d;
|
||||
|
||||
/* Brand accent — lime invariato, testo verde scuro */
|
||||
--accent: #DEF168;
|
||||
--accent-foreground: #14231d;
|
||||
|
||||
--secondary: #1b2420;
|
||||
--secondary-foreground: #f2f4f3;
|
||||
|
||||
--muted: #171f1b;
|
||||
--muted-foreground: #9aa39e;
|
||||
|
||||
--destructive: #f87171;
|
||||
--destructive-foreground: #1a0a0a;
|
||||
|
||||
--card: #131a16;
|
||||
--card-foreground: #f2f4f3;
|
||||
|
||||
--popover: #131a16;
|
||||
--popover-foreground: #f2f4f3;
|
||||
|
||||
--border: #26302b;
|
||||
--input: #26302b;
|
||||
--ring: #3FA88C;
|
||||
|
||||
--success: #22c55e;
|
||||
--warning: #eab308;
|
||||
--info: #3b82f6;
|
||||
|
||||
--tertiary: #8a938d;
|
||||
--bg-subtle: #171f1b;
|
||||
--border-light: #26302b;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
/* Font */
|
||||
--font-sans: var(--font-geist-sans), system-ui, -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", Roboto, "Helvetica Neue", sans-serif;
|
||||
--font-mono: var(--font-geist-mono);
|
||||
|
||||
/* Base */
|
||||
--color-background: #ffffff;
|
||||
--color-foreground: #1a1a1a;
|
||||
/* Colors — mapped from the raw tokens above */
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
|
||||
/* Brand primary — verde scuro iamcavalli */
|
||||
--color-primary: #1A463C;
|
||||
--color-primary-foreground: #ffffff;
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
|
||||
/* Brand accent — giallo lime */
|
||||
--color-accent: #DEF168;
|
||||
--color-accent-foreground: #1A463C;
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
|
||||
/* Secondary — grigio neutro */
|
||||
--color-secondary: #f4f4f5;
|
||||
--color-secondary-foreground: #1a1a1a;
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
|
||||
/* Muted — per testi e sfondi secondari */
|
||||
--color-muted: #f9f9f9;
|
||||
--color-muted-foreground: #71717a;
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
|
||||
/* Destructive */
|
||||
--color-destructive: #ef4444;
|
||||
--color-destructive-foreground: #ffffff;
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
|
||||
/* Card */
|
||||
--color-card: #ffffff;
|
||||
--color-card-foreground: #1a1a1a;
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
|
||||
/* Popover */
|
||||
--color-popover: #ffffff;
|
||||
--color-popover-foreground: #1a1a1a;
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
|
||||
/* Border / Input / Ring */
|
||||
--color-border: #e5e7eb;
|
||||
--color-input: #e5e7eb;
|
||||
--color-ring: #1A463C;
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
|
||||
/* Semantic — stato task/pagamenti */
|
||||
--color-success: #16a34a;
|
||||
--color-warning: #ca8a04;
|
||||
--color-info: #2563eb;
|
||||
--color-success: var(--success);
|
||||
--color-warning: var(--warning);
|
||||
--color-info: var(--info);
|
||||
|
||||
/* Legacy — usati inline nei componenti esistenti */
|
||||
--color-tertiary: #999999;
|
||||
--color-bg-subtle: #f9f9f9;
|
||||
--color-border-light: #e5e5e5;
|
||||
--color-tertiary: var(--tertiary);
|
||||
--color-bg-subtle: var(--bg-subtle);
|
||||
--color-border-light: var(--border-light);
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
@@ -75,10 +165,44 @@ html {
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #ffffff;
|
||||
color: #171717;
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: var(--font-sans);
|
||||
line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
Scrollbar utilities (ported from OMC design system)
|
||||
========================================================= */
|
||||
@layer utilities {
|
||||
/* Hide the native scrollbar without breaking scroll. */
|
||||
.no-scrollbar {
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Very thin, muted scrollbar — discoverable but low-noise. */
|
||||
.thin-scrollbar {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--border) transparent;
|
||||
}
|
||||
.thin-scrollbar::-webkit-scrollbar {
|
||||
height: 3px;
|
||||
width: 3px;
|
||||
}
|
||||
.thin-scrollbar::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
.thin-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: var(--border);
|
||||
border-radius: 9999px;
|
||||
}
|
||||
.thin-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--muted-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -32,7 +32,12 @@ export default function RootLayout({
|
||||
lang="it"
|
||||
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
|
||||
>
|
||||
<body className="min-h-full flex flex-col bg-white text-zinc-900">
|
||||
<body className="min-h-full flex flex-col bg-background text-foreground">
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `(function(){try{var k='iamcavalli:theme';var p=localStorage.getItem(k);var d=p==='dark'||((p==null||p==='system')&&window.matchMedia('(prefers-color-scheme: dark)').matches);document.documentElement.classList.toggle('dark',d);}catch(e){}})();`,
|
||||
}}
|
||||
/>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user