Two new extra-detailed themes: Cybperpunk and Blueprint
This commit is contained in:
parent
5e23a984e1
commit
be6926c027
594
app/globals.css
594
app/globals.css
|
|
@ -5,9 +5,9 @@
|
||||||
@import "@uiw/react-markdown-preview/markdown.css";
|
@import "@uiw/react-markdown-preview/markdown.css";
|
||||||
|
|
||||||
/* "dark:" must be true for every dark-surfaced theme, not just .dark --
|
/* "dark:" must be true for every dark-surfaced theme, not just .dark --
|
||||||
the dark looks (Dark, Ocean, Pine, Plum, Midnight, Ember, Rosewood) all
|
the dark looks (Dark, Ocean, Pine, Plum, Midnight, Ember, Rosewood,
|
||||||
turn on dark utilities. */
|
Cyberpunk) all turn on dark utilities. */
|
||||||
@custom-variant dark (&:is(.dark *, .ocean *, .theme-pine *, .theme-plum *, .theme-midnight *, .theme-ember *, .theme-rosewood *));
|
@custom-variant dark (&:is(.dark *, .ocean *, .theme-pine *, .theme-plum *, .theme-midnight *, .theme-ember *, .theme-rosewood *, .theme-cyberpunk *));
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--color-background: var(--background);
|
--color-background: var(--background);
|
||||||
|
|
@ -59,7 +59,7 @@
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
Themes
|
Themes
|
||||||
The app ships fourteen looks, chosen via the theme picker:
|
The app ships sixteen looks, chosen via the theme picker:
|
||||||
Light:
|
Light:
|
||||||
default -- calm, cool neutral light theme (the safe, focused one)
|
default -- calm, cool neutral light theme (the safe, focused one)
|
||||||
sunset -- warm paper + persimmon accent, a cozier light theme
|
sunset -- warm paper + persimmon accent, a cozier light theme
|
||||||
|
|
@ -68,6 +68,9 @@
|
||||||
rose -- soft pink paper with a raspberry accent ("Ros\xe9")
|
rose -- soft pink paper with a raspberry accent ("Ros\xe9")
|
||||||
lavender -- lilac paper with a violet accent
|
lavender -- lilac paper with a violet accent
|
||||||
slate -- cool grey-blue paper with a steel-blue accent
|
slate -- cool grey-blue paper with a steel-blue accent
|
||||||
|
blueprint -- EXTRA: deep cobalt drafting-paper background with
|
||||||
|
white paper cards + cobalt-ink lettering, grid +
|
||||||
|
registration marks, sharp corners, hand-drawn headings
|
||||||
Dark:
|
Dark:
|
||||||
dark -- deep charcoal with an indigo accent
|
dark -- deep charcoal with an indigo accent
|
||||||
ocean -- deep blue-green night theme with a seafoam accent
|
ocean -- deep blue-green night theme with a seafoam accent
|
||||||
|
|
@ -76,8 +79,12 @@
|
||||||
midnight -- near-black navy with an ice-periwinkle accent
|
midnight -- near-black navy with an ice-periwinkle accent
|
||||||
ember -- warm hearth charcoal with a glowing amber accent
|
ember -- warm hearth charcoal with a glowing amber accent
|
||||||
rosewood -- deep wine with a rose accent
|
rosewood -- deep wine with a rose accent
|
||||||
|
cyberpunk -- EXTRA: near-black violet, neon magenta + cyan,
|
||||||
|
scanlines, glitch, glow, VT323 pixel face
|
||||||
Each is a complete token set; components only ever use tokens, so adding
|
Each is a complete token set; components only ever use tokens, so adding
|
||||||
another theme later is just another block like these.
|
another theme later is just another block like these. The two EXTRA
|
||||||
|
themes additionally carry their own fonts, backgrounds, and animations,
|
||||||
|
all scoped in the "extras" section below.
|
||||||
--------------------------------------------------------------------------- */
|
--------------------------------------------------------------------------- */
|
||||||
|
|
||||||
:root,
|
:root,
|
||||||
|
|
@ -169,12 +176,12 @@
|
||||||
--popover-foreground: oklch(0.27 0.032 52);
|
--popover-foreground: oklch(0.27 0.032 52);
|
||||||
/* Persimmon -- warm enough to feel like part of the paper, saturated
|
/* Persimmon -- warm enough to feel like part of the paper, saturated
|
||||||
enough to stay unmistakably "the accent". */
|
enough to stay unmistakably "the accent". */
|
||||||
--primary: oklch(0.58 0.19 42);
|
--primary: oklch(0.565 0.19 42);
|
||||||
--primary-foreground: oklch(0.98 0.01 60);
|
--primary-foreground: oklch(0.98 0.01 60);
|
||||||
--secondary: oklch(0.945 0.02 72);
|
--secondary: oklch(0.945 0.02 72);
|
||||||
--secondary-foreground: oklch(0.32 0.05 50);
|
--secondary-foreground: oklch(0.32 0.05 50);
|
||||||
--muted: oklch(0.938 0.02 72);
|
--muted: oklch(0.938 0.02 72);
|
||||||
--muted-foreground: oklch(0.54 0.045 58);
|
--muted-foreground: oklch(0.52 0.045 58);
|
||||||
--accent: oklch(0.928 0.035 62);
|
--accent: oklch(0.928 0.035 62);
|
||||||
--accent-foreground: oklch(0.36 0.11 44);
|
--accent-foreground: oklch(0.36 0.11 44);
|
||||||
--destructive: oklch(0.57 0.21 25);
|
--destructive: oklch(0.57 0.21 25);
|
||||||
|
|
@ -191,7 +198,7 @@
|
||||||
--radius: 0.9rem;
|
--radius: 0.9rem;
|
||||||
--sidebar: oklch(0.958 0.013 75);
|
--sidebar: oklch(0.958 0.013 75);
|
||||||
--sidebar-foreground: oklch(0.27 0.032 52);
|
--sidebar-foreground: oklch(0.27 0.032 52);
|
||||||
--sidebar-primary: oklch(0.58 0.19 42);
|
--sidebar-primary: oklch(0.565 0.19 42);
|
||||||
--sidebar-primary-foreground: oklch(0.98 0.01 60);
|
--sidebar-primary-foreground: oklch(0.98 0.01 60);
|
||||||
--sidebar-accent: oklch(0.928 0.035 62);
|
--sidebar-accent: oklch(0.928 0.035 62);
|
||||||
--sidebar-accent-foreground: oklch(0.36 0.11 44);
|
--sidebar-accent-foreground: oklch(0.36 0.11 44);
|
||||||
|
|
@ -250,12 +257,12 @@
|
||||||
--popover: oklch(0.992 0.005 145);
|
--popover: oklch(0.992 0.005 145);
|
||||||
--popover-foreground: oklch(0.26 0.03 150);
|
--popover-foreground: oklch(0.26 0.03 150);
|
||||||
/* Emerald -- leafy enough to feel grown, saturated enough to lead. */
|
/* Emerald -- leafy enough to feel grown, saturated enough to lead. */
|
||||||
--primary: oklch(0.55 0.16 155);
|
--primary: oklch(0.52 0.16 155);
|
||||||
--primary-foreground: oklch(0.98 0.01 145);
|
--primary-foreground: oklch(0.98 0.01 145);
|
||||||
--secondary: oklch(0.945 0.018 145);
|
--secondary: oklch(0.945 0.018 145);
|
||||||
--secondary-foreground: oklch(0.31 0.05 150);
|
--secondary-foreground: oklch(0.31 0.05 150);
|
||||||
--muted: oklch(0.938 0.016 145);
|
--muted: oklch(0.938 0.016 145);
|
||||||
--muted-foreground: oklch(0.53 0.04 150);
|
--muted-foreground: oklch(0.515 0.04 150);
|
||||||
--accent: oklch(0.925 0.03 150);
|
--accent: oklch(0.925 0.03 150);
|
||||||
--accent-foreground: oklch(0.35 0.1 155);
|
--accent-foreground: oklch(0.35 0.1 155);
|
||||||
--destructive: oklch(0.57 0.21 25);
|
--destructive: oklch(0.57 0.21 25);
|
||||||
|
|
@ -271,7 +278,7 @@
|
||||||
--radius: 0.8rem;
|
--radius: 0.8rem;
|
||||||
--sidebar: oklch(0.965 0.01 145);
|
--sidebar: oklch(0.965 0.01 145);
|
||||||
--sidebar-foreground: oklch(0.26 0.03 150);
|
--sidebar-foreground: oklch(0.26 0.03 150);
|
||||||
--sidebar-primary: oklch(0.55 0.16 155);
|
--sidebar-primary: oklch(0.52 0.16 155);
|
||||||
--sidebar-primary-foreground: oklch(0.98 0.01 145);
|
--sidebar-primary-foreground: oklch(0.98 0.01 145);
|
||||||
--sidebar-accent: oklch(0.925 0.03 150);
|
--sidebar-accent: oklch(0.925 0.03 150);
|
||||||
--sidebar-accent-foreground: oklch(0.35 0.1 155);
|
--sidebar-accent-foreground: oklch(0.35 0.1 155);
|
||||||
|
|
@ -290,12 +297,12 @@
|
||||||
--popover: oklch(0.99 0.014 95);
|
--popover: oklch(0.99 0.014 95);
|
||||||
--popover-foreground: oklch(0.28 0.04 80);
|
--popover-foreground: oklch(0.28 0.04 80);
|
||||||
/* Honey-amber -- glowing but gentle, like light through glass. */
|
/* Honey-amber -- glowing but gentle, like light through glass. */
|
||||||
--primary: oklch(0.6 0.16 70);
|
--primary: oklch(0.555 0.16 70);
|
||||||
--primary-foreground: oklch(0.98 0.015 90);
|
--primary-foreground: oklch(0.98 0.015 90);
|
||||||
--secondary: oklch(0.948 0.03 92);
|
--secondary: oklch(0.948 0.03 92);
|
||||||
--secondary-foreground: oklch(0.33 0.06 78);
|
--secondary-foreground: oklch(0.33 0.06 78);
|
||||||
--muted: oklch(0.94 0.028 92);
|
--muted: oklch(0.94 0.028 92);
|
||||||
--muted-foreground: oklch(0.55 0.05 82);
|
--muted-foreground: oklch(0.52 0.05 82);
|
||||||
--accent: oklch(0.93 0.04 88);
|
--accent: oklch(0.93 0.04 88);
|
||||||
--accent-foreground: oklch(0.37 0.11 75);
|
--accent-foreground: oklch(0.37 0.11 75);
|
||||||
--destructive: oklch(0.57 0.21 25);
|
--destructive: oklch(0.57 0.21 25);
|
||||||
|
|
@ -312,7 +319,7 @@
|
||||||
--radius: 0.85rem;
|
--radius: 0.85rem;
|
||||||
--sidebar: oklch(0.962 0.02 95);
|
--sidebar: oklch(0.962 0.02 95);
|
||||||
--sidebar-foreground: oklch(0.28 0.04 80);
|
--sidebar-foreground: oklch(0.28 0.04 80);
|
||||||
--sidebar-primary: oklch(0.6 0.16 70);
|
--sidebar-primary: oklch(0.555 0.16 70);
|
||||||
--sidebar-primary-foreground: oklch(0.98 0.015 90);
|
--sidebar-primary-foreground: oklch(0.98 0.015 90);
|
||||||
--sidebar-accent: oklch(0.93 0.04 88);
|
--sidebar-accent: oklch(0.93 0.04 88);
|
||||||
--sidebar-accent-foreground: oklch(0.37 0.11 75);
|
--sidebar-accent-foreground: oklch(0.37 0.11 75);
|
||||||
|
|
@ -337,7 +344,7 @@
|
||||||
--secondary: oklch(0.948 0.02 15);
|
--secondary: oklch(0.948 0.02 15);
|
||||||
--secondary-foreground: oklch(0.32 0.06 12);
|
--secondary-foreground: oklch(0.32 0.06 12);
|
||||||
--muted: oklch(0.94 0.018 15);
|
--muted: oklch(0.94 0.018 15);
|
||||||
--muted-foreground: oklch(0.54 0.045 12);
|
--muted-foreground: oklch(0.525 0.045 12);
|
||||||
--accent: oklch(0.93 0.032 14);
|
--accent: oklch(0.93 0.032 14);
|
||||||
--accent-foreground: oklch(0.36 0.11 12);
|
--accent-foreground: oklch(0.36 0.11 12);
|
||||||
/* A deeper red than the rest of the pink, so errors still read as errors. */
|
/* A deeper red than the rest of the pink, so errors still read as errors. */
|
||||||
|
|
@ -379,7 +386,7 @@
|
||||||
--secondary: oklch(0.948 0.018 300);
|
--secondary: oklch(0.948 0.018 300);
|
||||||
--secondary-foreground: oklch(0.32 0.06 305);
|
--secondary-foreground: oklch(0.32 0.06 305);
|
||||||
--muted: oklch(0.94 0.016 300);
|
--muted: oklch(0.94 0.016 300);
|
||||||
--muted-foreground: oklch(0.54 0.045 305);
|
--muted-foreground: oklch(0.525 0.045 305);
|
||||||
--accent: oklch(0.93 0.03 302);
|
--accent: oklch(0.93 0.03 302);
|
||||||
--accent-foreground: oklch(0.36 0.11 305);
|
--accent-foreground: oklch(0.36 0.11 305);
|
||||||
--destructive: oklch(0.57 0.21 25);
|
--destructive: oklch(0.57 0.21 25);
|
||||||
|
|
@ -645,6 +652,561 @@
|
||||||
--sidebar-ring: oklch(0.72 0.11 20);
|
--sidebar-ring: oklch(0.72 0.11 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Blueprint -- a deep cobalt drafting board with white drafting paper on
|
||||||
|
top: the sheet is the white card, the ink is cobalt blue. It's a *light*
|
||||||
|
surface (the working paper is white with dark blue ink), but the page
|
||||||
|
backdrop stays deep cobalt like a blueprint under glass. The board chrome
|
||||||
|
(titles, lane labels, buttons) that sits directly on the cobalt uses the
|
||||||
|
near-white `--foreground`; the paper carries the cobalt `--card-foreground`
|
||||||
|
ink (see the extras section, which also re-inks the group-card title and
|
||||||
|
the board chrome's muted text). Sharp corners, a bright azure highlighter
|
||||||
|
for focus, and a hand-drawn architectural face. */
|
||||||
|
.theme-blueprint {
|
||||||
|
color-scheme: light;
|
||||||
|
/* The board: deep drafting cobalt. */
|
||||||
|
--background: oklch(0.42 0.13 255);
|
||||||
|
/* Board chrome ink -- sits on the cobalt, so it's near-white. */
|
||||||
|
--foreground: oklch(0.97 0.01 225);
|
||||||
|
/* The paper: warm near-white drafting sheet. */
|
||||||
|
--card: oklch(0.976 0.006 250);
|
||||||
|
/* Drafting ink: the cobalt pen that writes on the paper. */
|
||||||
|
--card-foreground: oklch(0.43 0.13 255);
|
||||||
|
--popover: oklch(0.976 0.006 250);
|
||||||
|
--popover-foreground: oklch(0.43 0.13 255);
|
||||||
|
/* The action color: a strong cobalt pen stroke. */
|
||||||
|
--primary: oklch(0.47 0.16 255);
|
||||||
|
--primary-foreground: oklch(0.99 0 0);
|
||||||
|
--secondary: oklch(0.915 0.03 250);
|
||||||
|
--secondary-foreground: oklch(0.4 0.13 255);
|
||||||
|
--muted: oklch(0.93 0.022 250);
|
||||||
|
/* Drafting ink at a muted weight (secondary text on the paper). */
|
||||||
|
--muted-foreground: oklch(0.47 0.12 255);
|
||||||
|
--accent: oklch(0.895 0.045 250);
|
||||||
|
--accent-foreground: oklch(0.38 0.13 255);
|
||||||
|
--destructive: oklch(0.58 0.2 25);
|
||||||
|
--destructive-foreground: oklch(0.99 0 0);
|
||||||
|
--border: oklch(0.74 0.06 250);
|
||||||
|
--input: oklch(0.74 0.06 250);
|
||||||
|
/* Bright azure highlighter for focus + registration marks. */
|
||||||
|
--ring: oklch(0.72 0.16 215);
|
||||||
|
--lane: oklch(1 0 0 / 8%);
|
||||||
|
--chart-1: oklch(0.58 0.14 250);
|
||||||
|
--chart-2: oklch(0.66 0.14 200);
|
||||||
|
--chart-3: oklch(0.6 0.13 180);
|
||||||
|
--chart-4: oklch(0.58 0.13 120);
|
||||||
|
--chart-5: oklch(0.6 0.14 60);
|
||||||
|
/* Sharp, technical corners. */
|
||||||
|
--radius: 0.15rem;
|
||||||
|
--sidebar: oklch(0.45 0.125 255);
|
||||||
|
--sidebar-foreground: oklch(0.96 0.01 225);
|
||||||
|
--sidebar-primary: oklch(0.97 0.01 225);
|
||||||
|
--sidebar-primary-foreground: oklch(0.4 0.13 255);
|
||||||
|
--sidebar-accent: oklch(0.5 0.11 255);
|
||||||
|
--sidebar-accent-foreground: oklch(0.97 0.01 225);
|
||||||
|
--sidebar-border: oklch(1 0 0 / 30%);
|
||||||
|
--sidebar-ring: oklch(0.72 0.16 215);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cyberpunk -- near-black violet night + neon magenta with an electric-cyan
|
||||||
|
secondary: the loud one. Dark-surfaced; see the extras section for the
|
||||||
|
scanlines, glitch, glow, and VT323 pixel face. */
|
||||||
|
.theme-cyberpunk {
|
||||||
|
color-scheme: dark;
|
||||||
|
--background: oklch(0.16 0.03 290);
|
||||||
|
--foreground: oklch(0.9 0.03 210);
|
||||||
|
--card: oklch(0.2 0.035 290);
|
||||||
|
--card-foreground: oklch(0.9 0.03 210);
|
||||||
|
--popover: oklch(0.21 0.04 290);
|
||||||
|
--popover-foreground: oklch(0.9 0.03 210);
|
||||||
|
/* Neon magenta -- the city at night, at full saturation. */
|
||||||
|
--primary: oklch(0.72 0.24 350);
|
||||||
|
--primary-foreground: oklch(0.16 0.03 300);
|
||||||
|
--secondary: oklch(0.24 0.045 290);
|
||||||
|
--secondary-foreground: oklch(0.88 0.06 200);
|
||||||
|
--muted: oklch(0.23 0.04 290);
|
||||||
|
--muted-foreground: oklch(0.7 0.03 220);
|
||||||
|
--accent: oklch(0.28 0.06 295);
|
||||||
|
--accent-foreground: oklch(0.92 0.06 350);
|
||||||
|
--destructive: oklch(0.68 0.23 30);
|
||||||
|
--border: oklch(0.9 0.06 210 / 22%);
|
||||||
|
--input: oklch(0.9 0.06 210 / 16%);
|
||||||
|
/* Electric-cyan focus. */
|
||||||
|
--ring: oklch(0.85 0.14 195);
|
||||||
|
--lane: oklch(1 0 0 / 6%);
|
||||||
|
--chart-1: oklch(0.85 0.15 195);
|
||||||
|
--chart-2: oklch(0.75 0.18 280);
|
||||||
|
--chart-3: oklch(0.68 0.22 350);
|
||||||
|
--chart-4: oklch(0.78 0.14 230);
|
||||||
|
--chart-5: oklch(0.9 0.03 200);
|
||||||
|
/* Angular chrome. */
|
||||||
|
--radius: 0.2rem;
|
||||||
|
--sidebar: oklch(0.185 0.035 290);
|
||||||
|
--sidebar-foreground: oklch(0.9 0.03 210);
|
||||||
|
--sidebar-primary: oklch(0.72 0.24 350);
|
||||||
|
--sidebar-primary-foreground: oklch(0.16 0.03 300);
|
||||||
|
--sidebar-accent: oklch(0.28 0.06 295);
|
||||||
|
--sidebar-accent-foreground: oklch(0.92 0.06 350);
|
||||||
|
--sidebar-border: oklch(0.9 0.06 210 / 22%);
|
||||||
|
--sidebar-ring: oklch(0.85 0.14 195);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
EXTRA THEMES -- beyond tokens, Blueprint and Cyberpunk carry their own
|
||||||
|
fonts, backgrounds, and animations. Everything here is scoped under the
|
||||||
|
theme's own class on <html>, so no other theme is touched. The reduced-
|
||||||
|
motion guard in @layer base still kills the animations for users who
|
||||||
|
ask for it (the static styling remains).
|
||||||
|
--------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* ------------------------------ Blueprint -------------------------------- */
|
||||||
|
|
||||||
|
/* Engineering grid on the drafting paper: fine 16px squares with a bolder
|
||||||
|
96px major line, fixed to the viewport like a drawing under glass. */
|
||||||
|
html.theme-blueprint body {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgb(255 255 255 / 0.14) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgb(255 255 255 / 0.14) 1px, transparent 1px),
|
||||||
|
linear-gradient(rgb(255 255 255 / 0.06) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgb(255 255 255 / 0.06) 1px, transparent 1px);
|
||||||
|
background-size:
|
||||||
|
96px 96px,
|
||||||
|
96px 96px,
|
||||||
|
16px 16px,
|
||||||
|
16px 16px;
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The drafting face carries the whole sheet: a hand-drawn architectural face
|
||||||
|
(Architects Daughter) for headings AND for the body/to-do text -- everything
|
||||||
|
reads as lettered by hand, not just the title blocks. We retarget the
|
||||||
|
theme's sans variable so every `font-sans` surface (to-dos, buttons, nav,
|
||||||
|
note editor) picks it up. */
|
||||||
|
html.theme-blueprint {
|
||||||
|
--font-sans: var(--font-blueprint), "Segoe Print", "Bradley Hand", cursive;
|
||||||
|
--font-heading: var(--font-blueprint), "Segoe Print", "Bradley Hand", cursive;
|
||||||
|
}
|
||||||
|
/* The base body sets a tight negative letter-spacing tuned for Inter -- a
|
||||||
|
handwriting face crowds under it, so relax it back to natural spacing. */
|
||||||
|
html.theme-blueprint body,
|
||||||
|
html.theme-blueprint h1,
|
||||||
|
html.theme-blueprint h2,
|
||||||
|
html.theme-blueprint h3,
|
||||||
|
html.theme-blueprint h4 {
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Headings: keep the natural hand-drawn weight -- faux-bolding a single-weight
|
||||||
|
handwriting face blurs its strokes, so hold the title blocks at 400. */
|
||||||
|
html.theme-blueprint .font-heading {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sharp, technical corners across the UI (rounded-full stays round --
|
||||||
|
progress rings, check marks, dots keep their circles). */
|
||||||
|
html.theme-blueprint .rounded-2xl {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
html.theme-blueprint .rounded-xl {
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
html.theme-blueprint .rounded-lg {
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Group cards: dashed stroke, like a layer outline on a drawing, plus a deep
|
||||||
|
cobalt offset shadow for a sheet-of-paper lift off the board. */
|
||||||
|
html.theme-blueprint .border-\[3px\] {
|
||||||
|
border-style: dashed;
|
||||||
|
box-shadow: 5px 5px 0 0 rgb(14 24 64 / 0.32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Standard cards and dialogs get a double drafting frame: a thin cobalt inner
|
||||||
|
line plus a deep offset, like a mounted sheet. */
|
||||||
|
html.theme-blueprint [data-slot="card"],
|
||||||
|
html.theme-blueprint [data-slot="dialog-content"] {
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 1px rgb(40 60 160 / 0.28),
|
||||||
|
5px 5px 0 0 rgb(14 24 64 / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* You're at a drafting table -- crosshair everywhere (inputs keep the
|
||||||
|
text cursor via UA defaults). */
|
||||||
|
html.theme-blueprint {
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Registration marks: corner brackets snap onto buttons on hover/focus,
|
||||||
|
like aligning a plotter. */
|
||||||
|
html.theme-blueprint [data-slot="button"] {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
html.theme-blueprint [data-slot="button"]::before,
|
||||||
|
html.theme-blueprint [data-slot="button"]::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border: 1px solid var(--ring);
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition:
|
||||||
|
opacity 150ms ease,
|
||||||
|
transform 150ms ease;
|
||||||
|
}
|
||||||
|
html.theme-blueprint [data-slot="button"]::before {
|
||||||
|
top: -4px;
|
||||||
|
left: -4px;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
transform: translate(3px, 3px);
|
||||||
|
}
|
||||||
|
html.theme-blueprint [data-slot="button"]::after {
|
||||||
|
bottom: -4px;
|
||||||
|
right: -4px;
|
||||||
|
border-left: 0;
|
||||||
|
border-top: 0;
|
||||||
|
transform: translate(-3px, -3px);
|
||||||
|
}
|
||||||
|
html.theme-blueprint [data-slot="button"]:hover::before,
|
||||||
|
html.theme-blueprint [data-slot="button"]:hover::after,
|
||||||
|
html.theme-blueprint [data-slot="button"]:focus-visible::before,
|
||||||
|
html.theme-blueprint [data-slot="button"]:focus-visible::after {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Completed to-dos: a slightly heavier, pen-weight strikethrough across the
|
||||||
|
words. Native line-through spans only the glyphs (not the whole flex row),
|
||||||
|
so it reads as pen crossing out the text rather than a line across the card. */
|
||||||
|
html.theme-blueprint .line-through {
|
||||||
|
text-decoration: line-through;
|
||||||
|
text-decoration-thickness: 1.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To-do checkbox: a small technical box -- squarer corner, crisp stroke, and
|
||||||
|
registration ticks that snap in on hover/focus like a plotter aligning to a
|
||||||
|
point. (The box is the base-ui checkbox button; its stroke/fill already come
|
||||||
|
from the group's own accent color.) */
|
||||||
|
html.theme-blueprint [data-todo-checkbox] {
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
html.theme-blueprint [data-todo-checkbox]:hover {
|
||||||
|
box-shadow: 0 0 0 3px rgb(40 60 160 / 0.18);
|
||||||
|
}
|
||||||
|
html.theme-blueprint [data-todo-checkbox]::before,
|
||||||
|
html.theme-blueprint [data-todo-checkbox]::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border: 1px solid var(--ring);
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 150ms ease;
|
||||||
|
}
|
||||||
|
html.theme-blueprint [data-todo-checkbox]::before {
|
||||||
|
top: -5px;
|
||||||
|
left: -5px;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
html.theme-blueprint [data-todo-checkbox]::after {
|
||||||
|
bottom: -5px;
|
||||||
|
right: -5px;
|
||||||
|
border-left: 0;
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
html.theme-blueprint [data-todo-checkbox]:hover::before,
|
||||||
|
html.theme-blueprint [data-todo-checkbox]:hover::after,
|
||||||
|
html.theme-blueprint [data-todo-checkbox]:focus-visible::before,
|
||||||
|
html.theme-blueprint [data-todo-checkbox]:focus-visible::after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The group card's title inherits the board's near-white foreground, which
|
||||||
|
would wash out on the white paper -- re-ink the whole card with the cobalt
|
||||||
|
drafting ink (the open to-do rows already carry their own accent color, and
|
||||||
|
the muted bits below read correctly on the paper). */
|
||||||
|
html.theme-blueprint [data-group-card] {
|
||||||
|
color: var(--card-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Board chrome that sits on the cobalt (the lane label, the open-to-do counts,
|
||||||
|
the add-lane button, the empty state, and the two sidebar columns) uses the
|
||||||
|
muted ink -- re-ink it light so it reads against the deep board, not the
|
||||||
|
paper. (Group cards and dialogs/popovers are the white paper and keep the
|
||||||
|
cobalt ink.) */
|
||||||
|
html.theme-blueprint [data-board-chrome] .text-muted-foreground,
|
||||||
|
html.theme-blueprint [data-board-chrome].text-muted-foreground,
|
||||||
|
html.theme-blueprint .bg-sidebar .text-muted-foreground,
|
||||||
|
html.theme-blueprint .bg-sidebar.text-muted-foreground {
|
||||||
|
color: var(--sidebar-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------ Cyberpunk -------------------------------- */
|
||||||
|
|
||||||
|
/* The pixel face runs the whole deck: VT323 for headings AND for the
|
||||||
|
body/to-do text, so everything reads like a CRT terminal, not just the
|
||||||
|
headers. We retarget the theme's sans variable so every `font-sans`
|
||||||
|
surface (to-dos, buttons, nav, note editor) picks it up. */
|
||||||
|
html.theme-cyberpunk {
|
||||||
|
--font-sans: var(--font-cyberpunk), ui-monospace, monospace;
|
||||||
|
--font-heading: var(--font-cyberpunk), ui-monospace, monospace;
|
||||||
|
}
|
||||||
|
/* Headings keep the pixel face + a touch of tracking for the terminal feel. */
|
||||||
|
html.theme-cyberpunk .font-heading {
|
||||||
|
font-family: var(--font-cyberpunk), monospace;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Angular chrome (rounded-full stays round). */
|
||||||
|
html.theme-cyberpunk .rounded-2xl {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
html.theme-cyberpunk .rounded-xl {
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
html.theme-cyberpunk .rounded-lg {
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Faint tron grid under everything. */
|
||||||
|
html.theme-cyberpunk body {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgb(34 255 238 / 0.04) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgb(34 255 238 / 0.04) 1px, transparent 1px);
|
||||||
|
background-size: 28px 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CRT scanlines + vignette over the whole app -- fixed and click-through,
|
||||||
|
so it sits over dialogs and toasts too, the way a monitor sits over
|
||||||
|
everything. */
|
||||||
|
html.theme-cyberpunk body::before {
|
||||||
|
content: "";
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 999;
|
||||||
|
pointer-events: none;
|
||||||
|
background:
|
||||||
|
radial-gradient(120% 90% at 50% 45%, transparent 55%, rgb(0 0 0 / 0.35) 100%),
|
||||||
|
repeating-linear-gradient(
|
||||||
|
0deg,
|
||||||
|
rgb(0 0 0 / 0.12) 0px,
|
||||||
|
rgb(0 0 0 / 0.12) 1px,
|
||||||
|
transparent 1px,
|
||||||
|
transparent 3px
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A slow scan band drifting down the screen, like a CRT refresh. */
|
||||||
|
html.theme-cyberpunk body::after {
|
||||||
|
content: "";
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 15%;
|
||||||
|
z-index: 999;
|
||||||
|
pointer-events: none;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
transparent,
|
||||||
|
rgb(34 255 238 / 0.05) 45%,
|
||||||
|
rgb(255 43 214 / 0.04) 55%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
animation: cp-scan 9s linear infinite;
|
||||||
|
}
|
||||||
|
@keyframes cp-scan {
|
||||||
|
from {
|
||||||
|
transform: translateY(-120%);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateY(720%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Neon focus glow on top of the standard ring. */
|
||||||
|
html.theme-cyberpunk :focus-visible {
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 3px color-mix(in oklch, var(--ring) 45%, transparent),
|
||||||
|
0 0 16px rgb(34 255 238 / 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Energized surfaces: anything filled with the primary color blooms. */
|
||||||
|
html.theme-cyberpunk .bg-primary {
|
||||||
|
box-shadow: 0 0 14px rgb(255 43 214 / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Glitch: a brief boot flicker whenever the theme (re)applies, and an
|
||||||
|
RGB-split jitter when a heading is hovered. */
|
||||||
|
html.theme-cyberpunk .font-heading {
|
||||||
|
animation: cp-boot 700ms steps(12, jump-none) 1;
|
||||||
|
}
|
||||||
|
@keyframes cp-boot {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
8% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
14% {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
22% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
opacity: 0.55;
|
||||||
|
}
|
||||||
|
42%,
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html.theme-cyberpunk .font-heading:hover {
|
||||||
|
text-shadow:
|
||||||
|
2px 0 rgb(255 43 214 / 0.85),
|
||||||
|
-2px 0 rgb(34 255 238 / 0.85);
|
||||||
|
animation: cp-glitch 260ms steps(3, jump-none) 1;
|
||||||
|
}
|
||||||
|
@keyframes cp-glitch {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: translate(0, 0) skewX(0deg);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: translate(-2px, 1px) skewX(-6deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translate(3px, -1px) skewX(3deg);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: translate(-1px, 0) skewX(-2deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Corruption: completed to-dos glitch out before they fade/drop away. */
|
||||||
|
html.theme-cyberpunk .line-through {
|
||||||
|
animation: cp-corrupt 450ms steps(6, jump-none) 1;
|
||||||
|
}
|
||||||
|
@keyframes cp-corrupt {
|
||||||
|
0% {
|
||||||
|
transform: translate(0, 0);
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
15% {
|
||||||
|
transform: translate(-3px, 1px) skewX(-8deg);
|
||||||
|
text-shadow:
|
||||||
|
3px 0 rgb(255 43 214 / 0.9),
|
||||||
|
-3px 0 rgb(34 255 238 / 0.9);
|
||||||
|
}
|
||||||
|
35% {
|
||||||
|
transform: translate(4px, -1px) skewX(5deg);
|
||||||
|
text-shadow:
|
||||||
|
-4px 0 rgb(34 255 238 / 0.9),
|
||||||
|
4px 0 rgb(255 43 214 / 0.9);
|
||||||
|
}
|
||||||
|
55% {
|
||||||
|
transform: translate(-2px, 1px);
|
||||||
|
text-shadow:
|
||||||
|
2px 0 rgb(255 43 214 / 0.8),
|
||||||
|
-2px 0 rgb(34 255 238 / 0.8);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: translate(2px, -1px) skewX(-3deg);
|
||||||
|
text-shadow:
|
||||||
|
-2px 0 rgb(255 43 214 / 0.7),
|
||||||
|
2px 0 rgb(34 255 238 / 0.7);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate(0, 0);
|
||||||
|
text-shadow: none;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To-do checkbox: a neon terminal box -- faint scanline texture on the empty
|
||||||
|
box, a glow that builds on hover, and a full bloom the moment it's checked.
|
||||||
|
(The check's own stroke/fill already come from the group's accent color.) */
|
||||||
|
html.theme-cyberpunk [data-todo-checkbox] {
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
html.theme-cyberpunk [data-todo-checkbox]:not([aria-checked="true"]) {
|
||||||
|
background-image: repeating-linear-gradient(
|
||||||
|
0deg,
|
||||||
|
rgb(34 255 238 / 0.07) 0px,
|
||||||
|
rgb(34 255 238 / 0.07) 1px,
|
||||||
|
transparent 1px,
|
||||||
|
transparent 3px
|
||||||
|
);
|
||||||
|
}
|
||||||
|
html.theme-cyberpunk [data-todo-checkbox]:hover {
|
||||||
|
box-shadow: 0 0 10px rgb(34 255 238 / 0.5);
|
||||||
|
}
|
||||||
|
html.theme-cyberpunk [data-todo-checkbox][aria-checked="true"] {
|
||||||
|
box-shadow: 0 0 12px rgb(34 255 238 / 0.6);
|
||||||
|
}
|
||||||
|
html.theme-cyberpunk [data-todo-checkbox] svg {
|
||||||
|
filter: drop-shadow(0 0 3px rgb(34 255 238 / 0.85));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The whole card glitches every so often -- a brief RGB-split, a skew, and a
|
||||||
|
sliced clip, then it settles back. Most of the cycle is calm; the burst is a
|
||||||
|
handful of held frames (steps, so it jitters rather than eases). Cards are
|
||||||
|
phase-offset so a boardful of them don't all tear on the same beat. */
|
||||||
|
html.theme-cyberpunk [data-group-card] {
|
||||||
|
animation: cp-card-glitch 7s steps(1, end) infinite;
|
||||||
|
will-change: transform, filter;
|
||||||
|
}
|
||||||
|
html.theme-cyberpunk [data-group-card]:nth-child(2n) {
|
||||||
|
animation-delay: -3.5s;
|
||||||
|
}
|
||||||
|
html.theme-cyberpunk [data-group-card]:nth-child(3n) {
|
||||||
|
animation-delay: -1.7s;
|
||||||
|
}
|
||||||
|
@keyframes cp-card-glitch {
|
||||||
|
0%,
|
||||||
|
86%,
|
||||||
|
93%,
|
||||||
|
100% {
|
||||||
|
/* rest: no properties set -> the card keeps its natural transform,
|
||||||
|
filter, clip and shadow (incl. hover lift) between bursts */
|
||||||
|
}
|
||||||
|
87% {
|
||||||
|
transform: translate(-2px, 1px) skewX(-3deg);
|
||||||
|
filter: saturate(1.6) hue-rotate(-16deg);
|
||||||
|
box-shadow:
|
||||||
|
3px 0 rgb(255 43 214 / 0.55),
|
||||||
|
-3px 0 rgb(34 255 238 / 0.55);
|
||||||
|
}
|
||||||
|
88% {
|
||||||
|
transform: translate(3px, -1px);
|
||||||
|
clip-path: inset(0 0 14% 0);
|
||||||
|
filter: saturate(1.8);
|
||||||
|
}
|
||||||
|
89% {
|
||||||
|
transform: translate(-1px, 1px) skewX(2deg);
|
||||||
|
clip-path: inset(12% 0 0 0);
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
transform: translate(2px, -1px);
|
||||||
|
clip-path: inset(6% 0 18% 0);
|
||||||
|
box-shadow:
|
||||||
|
-4px 0 rgb(255 43 214 / 0.5),
|
||||||
|
4px 0 rgb(34 255 238 / 0.5);
|
||||||
|
}
|
||||||
|
91% {
|
||||||
|
transform: translate(-2px, 0) skewX(-2deg);
|
||||||
|
filter: hue-rotate(14deg);
|
||||||
|
}
|
||||||
|
92% {
|
||||||
|
transform: translate(1px, 1px);
|
||||||
|
filter: saturate(1.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
* {
|
* {
|
||||||
@apply border-border outline-ring/50;
|
@apply border-border outline-ring/50;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import type { Metadata, Viewport } from "next";
|
import type { Metadata, Viewport } from "next";
|
||||||
import { Figtree, Inter, JetBrains_Mono } from "next/font/google";
|
import { Architects_Daughter, Figtree, Inter, JetBrains_Mono, VT323 } from "next/font/google";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
import { ThemeProvider } from "@/components/theme/theme-provider";
|
import { ThemeProvider } from "@/components/theme/theme-provider";
|
||||||
|
|
@ -27,6 +27,21 @@ const jetbrainsMono = JetBrains_Mono({
|
||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** Blueprint theme's drafting face (see app/globals.css) -- a hand-drawn
|
||||||
|
* architectural face, lettered like a drawing's title block. */
|
||||||
|
const architectsDaughter = Architects_Daughter({
|
||||||
|
variable: "--font-blueprint",
|
||||||
|
subsets: ["latin"],
|
||||||
|
weight: "400",
|
||||||
|
});
|
||||||
|
|
||||||
|
/** Cyberpunk theme's pixel-terminal face (see app/globals.css). */
|
||||||
|
const vt323 = VT323({
|
||||||
|
variable: "--font-cyberpunk",
|
||||||
|
subsets: ["latin"],
|
||||||
|
weight: "400",
|
||||||
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Organize",
|
title: "Organize",
|
||||||
description: "An extended to-do list and notes organizer.",
|
description: "An extended to-do list and notes organizer.",
|
||||||
|
|
@ -53,19 +68,21 @@ export default function RootLayout({ children }: LayoutProps<"/">) {
|
||||||
return (
|
return (
|
||||||
<html
|
<html
|
||||||
lang="en"
|
lang="en"
|
||||||
className={`${inter.variable} ${figtree.variable} ${jetbrainsMono.variable} h-full antialiased`}
|
className={`${inter.variable} ${figtree.variable} ${jetbrainsMono.variable} ${architectsDaughter.variable} ${vt323.variable} h-full antialiased`}
|
||||||
suppressHydrationWarning
|
suppressHydrationWarning
|
||||||
>
|
>
|
||||||
<body className="min-h-full flex flex-col">
|
<body className="min-h-full flex flex-col">
|
||||||
{/* Fourteen looks: seven light (Default, Sunset, Meadow, Honey,
|
{/* Sixteen looks: eight light (Default, Sunset, Meadow, Honey, Rosé,
|
||||||
Rosé, Lavender, Slate) and seven dark (Dark, Ocean, Pine, Plum,
|
Lavender, Slate, Blueprint) and eight dark (Dark, Ocean, Pine,
|
||||||
Midnight, Ember, Rosewood) -- complete token sets in
|
Plum, Midnight, Ember, Rosewood, Cyberpunk) -- complete token
|
||||||
app/globals.css. "system" resolves to Default/Dark by OS
|
sets in app/globals.css; Blueprint and Cyberpunk additionally
|
||||||
preference. No-FOUC theme restore: runs before first paint,
|
carry their own fonts, backgrounds, and animations.
|
||||||
applies the stored preference to <html> (class + color-scheme). */}
|
"system" resolves to Default/Dark by OS preference.
|
||||||
|
No-FOUC theme restore: runs before first paint, applies the
|
||||||
|
stored preference to <html> (class + color-scheme). */}
|
||||||
<script
|
<script
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: `!(function(){try{var r=document.documentElement,c=['theme-default','theme-sunset','theme-meadow','theme-honey','theme-rose','theme-lavender','theme-slate','dark','ocean','theme-pine','theme-plum','theme-midnight','theme-ember','theme-rosewood','light'];for(var i=0;i<c.length;i++){r.classList.remove(c[i]);}var v=null;try{v=localStorage.getItem('theme');}catch(e){}var m={default:'theme-default',sunset:'theme-sunset',meadow:'theme-meadow',honey:'theme-honey',rose:'theme-rose',lavender:'theme-lavender',slate:'theme-slate',dark:'dark',ocean:'ocean',pine:'theme-pine',plum:'theme-plum',midnight:'theme-midnight',ember:'theme-ember',rosewood:'theme-rosewood'};var d=['dark','ocean','pine','plum','midnight','ember','rosewood'];if(v==='system'||!v){v=window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'default';}if(m[v]){r.classList.add(m[v]);r.style.colorScheme=d.indexOf(v)>=0?'dark':'light';}}catch(e){}})();`,
|
__html: `!(function(){try{var r=document.documentElement,c=['theme-default','theme-sunset','theme-meadow','theme-honey','theme-rose','theme-lavender','theme-slate','theme-blueprint','dark','ocean','theme-pine','theme-plum','theme-midnight','theme-ember','theme-rosewood','theme-cyberpunk','light'];for(var i=0;i<c.length;i++){r.classList.remove(c[i]);}var v=null;try{v=localStorage.getItem('theme');}catch(e){}var m={default:'theme-default',sunset:'theme-sunset',meadow:'theme-meadow',honey:'theme-honey',rose:'theme-rose',lavender:'theme-lavender',slate:'theme-slate',blueprint:'theme-blueprint',dark:'dark',ocean:'ocean',pine:'theme-pine',plum:'theme-plum',midnight:'theme-midnight',ember:'theme-ember',rosewood:'theme-rosewood',cyberpunk:'theme-cyberpunk'};var d=['dark','ocean','pine','plum','midnight','ember','rosewood','cyberpunk'];if(v==='system'||!v){v=window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'default';}if(m[v]){r.classList.add(m[v]);r.style.colorScheme=d.indexOf(v)>=0?'dark':'light';}}catch(e){}})();`,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ThemeProvider defaultTheme="system">
|
<ThemeProvider defaultTheme="system">
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ export function AddCategoryLane() {
|
||||||
<DialogTrigger
|
<DialogTrigger
|
||||||
render={
|
render={
|
||||||
<button
|
<button
|
||||||
|
data-board-chrome=""
|
||||||
className="flex h-full min-h-32 w-72 shrink-0 flex-col items-center justify-center gap-2 rounded-2xl border-2 border-dashed border-border/80 text-muted-foreground transition-colors hover:border-primary/60 hover:bg-primary/5 hover:text-primary"
|
className="flex h-full min-h-32 w-72 shrink-0 flex-col items-center justify-center gap-2 rounded-2xl border-2 border-dashed border-border/80 text-muted-foreground transition-colors hover:border-primary/60 hover:bg-primary/5 hover:text-primary"
|
||||||
aria-label="Add category"
|
aria-label="Add category"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,10 @@ export function CategoryLane({ category }: { category: CategoryDTO }) {
|
||||||
isDragging && "opacity-50"
|
isDragging && "opacity-50"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-1.5 px-3 pt-3 pb-2">
|
<div
|
||||||
|
data-board-chrome=""
|
||||||
|
className="flex items-center gap-1.5 px-3 pt-3 pb-2"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
ref={setActivatorNodeRef}
|
ref={setActivatorNodeRef}
|
||||||
{...attributes}
|
{...attributes}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@ import { LayoutDashboard } from "lucide-react";
|
||||||
|
|
||||||
export function EmptyState() {
|
export function EmptyState() {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-1 flex-col items-center justify-center gap-3 rounded-2xl border border-dashed border-border/80 p-10 text-center">
|
<div
|
||||||
|
data-board-chrome=""
|
||||||
|
className="flex flex-1 flex-col items-center justify-center gap-3 rounded-2xl border border-dashed border-border/80 p-10 text-center"
|
||||||
|
>
|
||||||
<div className="flex size-14 items-center justify-center rounded-2xl bg-primary/10 text-primary">
|
<div className="flex size-14 items-center justify-center rounded-2xl bg-primary/10 text-primary">
|
||||||
<LayoutDashboard className="size-7" />
|
<LayoutDashboard className="size-7" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,7 @@ export function GroupCard({ group }: { group: GroupDTO }) {
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
ref={setNodeRef}
|
ref={setNodeRef}
|
||||||
|
data-group-card=""
|
||||||
style={{
|
style={{
|
||||||
transform: CSS.Transform.toString(transform),
|
transform: CSS.Transform.toString(transform),
|
||||||
transition,
|
transition,
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,10 @@ function Board({ title }: { title: string }) {
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
>
|
>
|
||||||
<div className="flex h-full flex-col gap-4 p-4">
|
<div className="flex h-full flex-col gap-4 p-4">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-x-3 gap-y-2 px-1">
|
<div
|
||||||
|
data-board-chrome=""
|
||||||
|
className="flex flex-wrap items-center justify-between gap-x-3 gap-y-2 px-1"
|
||||||
|
>
|
||||||
<div className="flex min-w-0 items-center gap-3">
|
<div className="flex min-w-0 items-center gap-3">
|
||||||
<span className="hidden size-10 shrink-0 items-center justify-center rounded-xl bg-primary/10 text-primary sm:flex">
|
<span className="hidden size-10 shrink-0 items-center justify-center rounded-xl bg-primary/10 text-primary sm:flex">
|
||||||
<LayoutDashboard className="size-5" />
|
<LayoutDashboard className="size-5" />
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ export function TodoCheckbox({
|
||||||
<CheckboxPrimitive.Root
|
<CheckboxPrimitive.Root
|
||||||
checked={checked}
|
checked={checked}
|
||||||
onCheckedChange={onCheckedChange}
|
onCheckedChange={onCheckedChange}
|
||||||
|
data-todo-checkbox=""
|
||||||
aria-label={ariaLabel}
|
aria-label={ariaLabel}
|
||||||
style={{
|
style={{
|
||||||
borderColor: accentColor,
|
borderColor: accentColor,
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ export const THEMES = [
|
||||||
"rose",
|
"rose",
|
||||||
"lavender",
|
"lavender",
|
||||||
"slate",
|
"slate",
|
||||||
|
"blueprint",
|
||||||
"dark",
|
"dark",
|
||||||
"ocean",
|
"ocean",
|
||||||
"pine",
|
"pine",
|
||||||
|
|
@ -44,6 +45,7 @@ export const THEMES = [
|
||||||
"midnight",
|
"midnight",
|
||||||
"ember",
|
"ember",
|
||||||
"rosewood",
|
"rosewood",
|
||||||
|
"cyberpunk",
|
||||||
] as const;
|
] as const;
|
||||||
export type ThemeName = (typeof THEMES)[number];
|
export type ThemeName = (typeof THEMES)[number];
|
||||||
export type RawTheme = ThemeName | "system";
|
export type RawTheme = ThemeName | "system";
|
||||||
|
|
@ -57,6 +59,7 @@ const THEME_CLASSES: Record<ThemeName, string> = {
|
||||||
rose: "theme-rose",
|
rose: "theme-rose",
|
||||||
lavender: "theme-lavender",
|
lavender: "theme-lavender",
|
||||||
slate: "theme-slate",
|
slate: "theme-slate",
|
||||||
|
blueprint: "theme-blueprint",
|
||||||
dark: "dark",
|
dark: "dark",
|
||||||
ocean: "ocean",
|
ocean: "ocean",
|
||||||
pine: "theme-pine",
|
pine: "theme-pine",
|
||||||
|
|
@ -64,6 +67,7 @@ const THEME_CLASSES: Record<ThemeName, string> = {
|
||||||
midnight: "theme-midnight",
|
midnight: "theme-midnight",
|
||||||
ember: "theme-ember",
|
ember: "theme-ember",
|
||||||
rosewood: "theme-rosewood",
|
rosewood: "theme-rosewood",
|
||||||
|
cyberpunk: "theme-cyberpunk",
|
||||||
};
|
};
|
||||||
const ALL_CLASSES = Object.values(THEME_CLASSES);
|
const ALL_CLASSES = Object.values(THEME_CLASSES);
|
||||||
/* Themes whose *surfaces* are dark (see app/globals.css). The single source
|
/* Themes whose *surfaces* are dark (see app/globals.css). The single source
|
||||||
|
|
@ -77,6 +81,7 @@ export const DARK_SURFACES: ThemeName[] = [
|
||||||
"midnight",
|
"midnight",
|
||||||
"ember",
|
"ember",
|
||||||
"rosewood",
|
"rosewood",
|
||||||
|
"cyberpunk",
|
||||||
];
|
];
|
||||||
|
|
||||||
interface ThemeContextValue {
|
interface ThemeContextValue {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ import {
|
||||||
Star,
|
Star,
|
||||||
Flame,
|
Flame,
|
||||||
Wine,
|
Wine,
|
||||||
|
DraftingCompass,
|
||||||
|
CircuitBoard,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
import { useTheme } from "@/components/theme/theme-provider";
|
import { useTheme } from "@/components/theme/theme-provider";
|
||||||
|
|
@ -49,6 +51,7 @@ const LIGHT_OPTIONS: ThemeOption[] = [
|
||||||
{ value: "rose", label: "Rosé", icon: Rose, swatch: "#e11d48" },
|
{ value: "rose", label: "Rosé", icon: Rose, swatch: "#e11d48" },
|
||||||
{ value: "lavender", label: "Lavender", icon: Flower2, swatch: "#7c3aed" },
|
{ value: "lavender", label: "Lavender", icon: Flower2, swatch: "#7c3aed" },
|
||||||
{ value: "slate", label: "Slate", icon: Mountain, swatch: "#4a6d9c" },
|
{ value: "slate", label: "Slate", icon: Mountain, swatch: "#4a6d9c" },
|
||||||
|
{ value: "blueprint", label: "Blueprint", icon: DraftingCompass, swatch: "#2b4bc4" },
|
||||||
];
|
];
|
||||||
const DARK_OPTIONS: ThemeOption[] = [
|
const DARK_OPTIONS: ThemeOption[] = [
|
||||||
{ value: "dark", label: "Dark", icon: Moon, swatch: "#7c83f2" },
|
{ value: "dark", label: "Dark", icon: Moon, swatch: "#7c83f2" },
|
||||||
|
|
@ -58,6 +61,7 @@ const DARK_OPTIONS: ThemeOption[] = [
|
||||||
{ value: "midnight", label: "Midnight", icon: Star, swatch: "#93c5fd" },
|
{ value: "midnight", label: "Midnight", icon: Star, swatch: "#93c5fd" },
|
||||||
{ value: "ember", label: "Ember", icon: Flame, swatch: "#fbbf24" },
|
{ value: "ember", label: "Ember", icon: Flame, swatch: "#fbbf24" },
|
||||||
{ value: "rosewood", label: "Rosewood", icon: Wine, swatch: "#fb7185" },
|
{ value: "rosewood", label: "Rosewood", icon: Wine, swatch: "#fb7185" },
|
||||||
|
{ value: "cyberpunk", label: "Cyberpunk", icon: CircuitBoard, swatch: "#ff2bd6" },
|
||||||
];
|
];
|
||||||
const ALL_OPTIONS = [...LIGHT_OPTIONS, ...DARK_OPTIONS];
|
const ALL_OPTIONS = [...LIGHT_OPTIONS, ...DARK_OPTIONS];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ function useMounted(): boolean {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True when the active theme has dark surfaces (Dark, Ocean, Pine, Plum,
|
* True when the active theme has dark surfaces (Dark, Ocean, Pine, Plum,
|
||||||
* Midnight, Ember, Rosewood).
|
* Midnight, Ember, Rosewood, Cyberpunk).
|
||||||
*
|
*
|
||||||
* Reactive to UI theme switches: the value is derived from the provider's
|
* Reactive to UI theme switches: the value is derived from the provider's
|
||||||
* theme state (the single source of truth), so the moment `setTheme` fires,
|
* theme state (the single source of truth), so the moment `setTheme` fires,
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,11 @@ export function getBrighterColor(hex: string, variant: "light" | "dark"): string
|
||||||
if (cached) return cached;
|
if (cached) return cached;
|
||||||
|
|
||||||
const [hue, saturation, lightness] = rgbToHsl(...hexToRgb(hex));
|
const [hue, saturation, lightness] = rgbToHsl(...hexToRgb(hex));
|
||||||
const delta = variant === "dark" ? 8 : -8;
|
// Light surfaces: the to-do ink runs DEEPER than the group's stroke (not
|
||||||
|
// lighter) so it clears WCAG AA (>=4.5:1) against the near-white pastel
|
||||||
|
// card fills -- a flat -8 only reached ~3.3:1 for the warm hues. Dark
|
||||||
|
// surfaces do the opposite: brighter ink over the dark tint.
|
||||||
|
const delta = variant === "dark" ? 8 : -16;
|
||||||
const result = hslToHex(
|
const result = hslToHex(
|
||||||
hue,
|
hue,
|
||||||
saturation,
|
saturation,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue