From faf78df71c7ccb84814cecb47906676272b51b04 Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Wed, 1 Jul 2026 17:26:01 +0530
Subject: [PATCH 01/16] feat(dashboard): add themes
---
.../src/components/theme-provider.tsx | 41 +-
.../dashboard/src/components/theme-toggle.tsx | 49 ++-
apps/dashboard/src/styles.css | 370 +++++++++++++++++-
3 files changed, 444 insertions(+), 16 deletions(-)
diff --git a/apps/dashboard/src/components/theme-provider.tsx b/apps/dashboard/src/components/theme-provider.tsx
index e18440d7..dccf1438 100644
--- a/apps/dashboard/src/components/theme-provider.tsx
+++ b/apps/dashboard/src/components/theme-provider.tsx
@@ -1,6 +1,27 @@
import { createContext, useContext, useEffect, useState } from "react";
-type Theme = "dark" | "light" | "system";
+export type Theme =
+ | "dark"
+ | "light"
+ | "system"
+ | "crimson-moon"
+ | "sepia"
+ | "midnight-blurple"
+ | "forest"
+ | "dusk"
+ | "citrus-sherbet";
+
+// Custom palettes derive their tokens from the shared `.theme-dark` /
+// `.theme-light` markers, added alongside the palette class in the effect below.
+const DARK_THEMES = [
+ "crimson-moon",
+ "sepia",
+ "midnight-blurple",
+ "forest",
+ "dusk",
+] as const;
+const LIGHT_THEMES = ["citrus-sherbet"] as const;
+const CUSTOM_THEMES: readonly string[] = [...DARK_THEMES, ...LIGHT_THEMES];
type ThemeProviderProps = {
children: React.ReactNode;
@@ -33,7 +54,13 @@ export function ThemeProvider({
useEffect(() => {
const root = window.document.documentElement;
- root.classList.remove("light", "dark");
+ root.classList.remove(
+ "light",
+ "dark",
+ "theme-dark",
+ "theme-light",
+ ...CUSTOM_THEMES,
+ );
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
@@ -45,6 +72,16 @@ export function ThemeProvider({
return;
}
+ if ((DARK_THEMES as readonly string[]).includes(theme)) {
+ root.classList.add(theme, "theme-dark");
+ return;
+ }
+
+ if ((LIGHT_THEMES as readonly string[]).includes(theme)) {
+ root.classList.add(theme, "theme-light");
+ return;
+ }
+
root.classList.add(theme);
}, [theme]);
diff --git a/apps/dashboard/src/components/theme-toggle.tsx b/apps/dashboard/src/components/theme-toggle.tsx
index 316b5c21..5a7b7768 100644
--- a/apps/dashboard/src/components/theme-toggle.tsx
+++ b/apps/dashboard/src/components/theme-toggle.tsx
@@ -1,37 +1,60 @@
-import { Moon, Sun } from "lucide-react";
-import { useTheme } from "@/components/theme-provider";
+import { Palette } from "lucide-react";
+import { type Theme, useTheme } from "@/components/theme-provider";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
+ DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
+import { cn } from "@/lib/utils";
+
+const BASE_THEMES: { key: Theme; label: string }[] = [
+ { key: "light", label: "Light" },
+ { key: "dark", label: "Dark" },
+ { key: "system", label: "System" },
+];
+
+const NITRO_THEMES: { key: Theme; label: string }[] = [
+ { key: "crimson-moon", label: "Crimson Moon" },
+ { key: "sepia", label: "Sepia" },
+ { key: "midnight-blurple", label: "Midnight Blurple" },
+ { key: "forest", label: "Forest" },
+ { key: "dusk", label: "Dusk" },
+ { key: "citrus-sherbet", label: "Citrus Sherbet" },
+];
export function ModeToggle() {
const { setTheme } = useTheme();
+ const renderItem = ({ key, label }: { key: Theme; label: string }) => (
+ setTheme(key)}>
+
+ {label}
+
+ );
+
return (
-
-
+
Toggle theme
}
/>
- setTheme("light")}>
- Light
-
- setTheme("dark")}>
- Dark
-
- setTheme("system")}>
- System
-
+ {BASE_THEMES.map(renderItem)}
+
+ {NITRO_THEMES.map(renderItem)}
);
diff --git a/apps/dashboard/src/styles.css b/apps/dashboard/src/styles.css
index 349e876b..6f43b95a 100644
--- a/apps/dashboard/src/styles.css
+++ b/apps/dashboard/src/styles.css
@@ -6,7 +6,10 @@
@import "@fontsource-variable/geist";
-@custom-variant dark (&:is(.dark *));
+/* The custom DARK themes carry a `.theme-dark` marker, so every `dark:` utility
+ the shadcn components already ship activates under them too. `.theme-light`
+ (Citrus Sherbet) is intentionally excluded. `:root` and `.dark` are unchanged. */
+@custom-variant dark (&:is(.dark *, .theme-dark *));
:root {
--background: oklch(1 0 0);
@@ -79,6 +82,204 @@
--sidebar-ring: oklch(0.553 0.013 58.071);
}
+/* =========================================================================
+ Discord Nitro–inspired theme engine.
+
+ Each palette declares only three tints (+ a gradient and a shadow hue) at the
+ bottom of this file; every shadcn token below is DERIVED from them via OKLCH
+ ramps + color-mix(in oklab). The shadcn variables stay the public API —
+ nothing hardcodes a per-token color, so adding a theme is a ~6-line block.
+
+ `.theme-dark` = dark surface + light foreground (Crimson Moon, Sepia,
+ Midnight Blurple, Forest, Dusk). `.theme-light` = the mirror, for a light
+ surface + dark foreground (Citrus Sherbet). The ThemeProvider adds the
+ matching marker class alongside the palette name. `:root` and `.dark` (the
+ original stone light/dark themes) are never touched.
+ ========================================================================= */
+
+/* ---- shared derivation for the DARK palettes ---- */
+.theme-dark {
+ color-scheme: dark;
+
+ /* surfaces: surface tint on an elevation ramp (mixed toward white) */
+ --background: color-mix(in oklab, var(--theme-surface-tint) 95%, white); /* +5% canvas */
+ --card: color-mix(in oklab, var(--theme-surface-tint) 92%, white); /* +8% one step up */
+ --popover: color-mix(in oklab, var(--theme-surface-tint) 86%, white); /* +14% elevated */
+ --sidebar: color-mix(in oklab, var(--theme-surface-tint) 97%, black); /* darker than bg */
+ --muted: color-mix(in oklab, var(--theme-surface-tint) 89%, white); /* +11% fills */
+ --accent: color-mix(in oklab, var(--theme-surface-tint) 87%, white); /* +13% hover fills */
+ --secondary: color-mix(in oklab, var(--theme-surface-tint) 89%, white);
+ --input: color-mix(in oklab, var(--theme-surface-tint) 86%, white);
+ --sidebar-accent: color-mix(in oklab, var(--theme-surface-tint) 87%, white);
+
+ /* primary: bright surface (buttons), deep-tint text */
+ --primary: color-mix(in oklab, var(--theme-foreground-tint) 88%, var(--theme-surface-tint));
+ --primary-foreground: color-mix(in oklab, var(--theme-surface-tint) 90%, black);
+ --sidebar-primary: var(--primary);
+ --sidebar-primary-foreground: var(--primary-foreground);
+
+ /* text: foreground tint toward pure white (subtle tint, never loud) */
+ --foreground: color-mix(in oklab, var(--theme-foreground-tint) 55%, white);
+ --card-foreground: var(--foreground);
+ --popover-foreground: var(--foreground);
+ --sidebar-foreground: color-mix(in oklab, var(--theme-foreground-tint) 60%, white);
+ --muted-foreground: color-mix(in oklab, var(--theme-foreground-tint) 92%, transparent);
+ --secondary-foreground: color-mix(in oklab, var(--theme-foreground-tint) 70%, white);
+ --accent-foreground: color-mix(in oklab, var(--theme-foreground-tint) 70%, white);
+ --sidebar-accent-foreground: var(--accent-foreground);
+
+ /* borders at low alpha; ring is a tinted glow derived from the foreground */
+ --border: color-mix(in oklab, var(--theme-foreground-tint) 7%, transparent);
+ --sidebar-border: color-mix(in oklab, var(--theme-foreground-tint) 6%, transparent);
+ --ring: color-mix(in oklab, var(--theme-foreground-tint) 60%, transparent);
+ --sidebar-ring: var(--ring);
+
+ /* destructive stays a true red across every theme */
+ --destructive: oklch(0.6 0.22 25);
+ --destructive-foreground: color-mix(in oklab, var(--theme-foreground-tint) 40%, white);
+
+ /* charts: a monochrome ramp from the foreground tint down to the surface */
+ --chart-1: var(--theme-foreground-tint);
+ --chart-2: color-mix(in oklab, var(--theme-foreground-tint) 78%, var(--theme-surface-tint));
+ --chart-3: color-mix(in oklab, var(--theme-foreground-tint) 58%, var(--theme-surface-tint));
+ --chart-4: color-mix(in oklab, var(--theme-foreground-tint) 40%, var(--theme-surface-tint));
+ --chart-5: color-mix(in oklab, var(--theme-foreground-tint) 25%, var(--theme-surface-tint));
+}
+
+/* ---- shared derivation for the LIGHT palettes (light surface, dark fg) ---- */
+.theme-light {
+ color-scheme: light;
+
+ /* surfaces: cards/popovers climb toward white; fills recede toward the fg tint */
+ --background: color-mix(in oklab, var(--theme-surface-tint) 90%, white);
+ --card: color-mix(in oklab, var(--theme-surface-tint) 55%, white);
+ --popover: color-mix(in oklab, var(--theme-surface-tint) 45%, white);
+ --sidebar: color-mix(in oklab, var(--theme-foreground-tint) 4%, var(--theme-surface-tint));
+ --muted: color-mix(in oklab, var(--theme-foreground-tint) 6%, var(--theme-surface-tint));
+ --accent: color-mix(in oklab, var(--theme-foreground-tint) 9%, var(--theme-surface-tint));
+ --secondary: color-mix(in oklab, var(--theme-foreground-tint) 6%, var(--theme-surface-tint));
+ --input: color-mix(in oklab, var(--theme-surface-tint) 62%, white);
+ --sidebar-accent: color-mix(in oklab, var(--theme-foreground-tint) 9%, var(--theme-surface-tint));
+
+ /* primary: dark warm surface (buttons), light text */
+ --primary: color-mix(in oklab, var(--theme-foreground-tint) 90%, var(--theme-surface-tint));
+ --primary-foreground: color-mix(in oklab, var(--theme-surface-tint) 92%, white);
+ --sidebar-primary: var(--primary);
+ --sidebar-primary-foreground: var(--primary-foreground);
+
+ /* text: foreground tint toward black (raise contrast on light surfaces) */
+ --foreground: color-mix(in oklab, var(--theme-foreground-tint) 92%, black);
+ --card-foreground: var(--foreground);
+ --popover-foreground: var(--foreground);
+ --sidebar-foreground: color-mix(in oklab, var(--theme-foreground-tint) 88%, black);
+ --muted-foreground: color-mix(in oklab, var(--theme-foreground-tint) 60%, transparent);
+ --secondary-foreground: color-mix(in oklab, var(--theme-foreground-tint) 85%, black);
+ --accent-foreground: color-mix(in oklab, var(--theme-foreground-tint) 85%, black);
+ --sidebar-accent-foreground: var(--accent-foreground);
+
+ --border: color-mix(in oklab, var(--theme-foreground-tint) 14%, transparent);
+ --sidebar-border: color-mix(in oklab, var(--theme-foreground-tint) 12%, transparent);
+ --ring: color-mix(in oklab, var(--theme-foreground-tint) 45%, transparent);
+ --sidebar-ring: var(--ring);
+
+ --destructive: oklch(0.58 0.22 27);
+ --destructive-foreground: oklch(0.985 0 0);
+
+ --chart-1: var(--theme-foreground-tint);
+ --chart-2: color-mix(in oklab, var(--theme-foreground-tint) 78%, var(--theme-surface-tint));
+ --chart-3: color-mix(in oklab, var(--theme-foreground-tint) 58%, var(--theme-surface-tint));
+ --chart-4: color-mix(in oklab, var(--theme-foreground-tint) 40%, var(--theme-surface-tint));
+ --chart-5: color-mix(in oklab, var(--theme-foreground-tint) 25%, var(--theme-surface-tint));
+}
+
+/* ---- layered premium shadows (shared): inset highlight + soft ambient +
+ a subtle colored glow tinted by each palette's --theme-shadow-color.
+ Applied per data-slot below (Tailwind v4 inlines shadow-* utilities at
+ build time, so we set box-shadow directly rather than override tokens). ---- */
+.theme-dark,
+.theme-light {
+ --cm-shadow-sm:
+ inset 0 1px 0 0 hsl(0 0% 100% / 0.05),
+ 0 1px 2px 0 hsl(var(--theme-shadow-color) / 0.4),
+ 0 2px 6px -1px hsl(var(--theme-shadow-color) / 0.3);
+ --cm-shadow-lg:
+ inset 0 1px 0 0 hsl(0 0% 100% / 0.06),
+ 0 4px 8px -2px hsl(var(--theme-shadow-color) / 0.42),
+ 0 12px 28px -6px hsl(var(--theme-shadow-color) / 0.4),
+ 0 0 40px -8px hsl(var(--theme-shadow-color) / 0.25);
+ --cm-shadow-xl:
+ inset 0 1px 0 0 hsl(0 0% 100% / 0.07),
+ 0 8px 16px -4px hsl(var(--theme-shadow-color) / 0.45),
+ 0 20px 48px -10px hsl(var(--theme-shadow-color) / 0.45),
+ 0 0 64px -12px hsl(var(--theme-shadow-color) / 0.28);
+}
+
+/* =========================================================================
+ Palettes — each declares only its three tints, a full-page gradient (dim
+ wash + color layer, already fixed/cover), and a shadow hue (bare HSL
+ channels consumed by the shadow recipes above).
+ ========================================================================= */
+
+/* Crimson Moon */
+.crimson-moon {
+ --theme-surface-tint: rgb(26 0 0);
+ --theme-foreground-tint: rgb(255 229 229);
+ --theme-gradient:
+ linear-gradient(rgb(0 0 0 / 0.82), rgb(0 0 0 / 0.82)) fixed 0 0 / cover,
+ linear-gradient(64.92deg, #950909 16.17%, #000000 72%) fixed 0 0 / cover;
+ --theme-shadow-color: 0 72% 12%;
+}
+
+/* Sepia */
+.sepia {
+ --theme-surface-tint: rgb(26 15 0);
+ --theme-foreground-tint: rgb(255 243 229);
+ --theme-gradient:
+ linear-gradient(rgb(0 0 0 / 0.9), rgb(0 0 0 / 0.9)) fixed 0 0 / cover,
+ linear-gradient(69.98deg, #857664 14.14%, #5b4421 60.35%) fixed 0 0 / cover;
+ --theme-shadow-color: 28 70% 10%;
+}
+
+/* Midnight Blurple */
+.midnight-blurple {
+ --theme-surface-tint: rgb(8 0 26);
+ --theme-foreground-tint: rgb(162 153 255);
+ --theme-gradient:
+ linear-gradient(rgb(0 0 0 / 0.9), rgb(0 0 0 / 0.9)) fixed 0 0 / cover,
+ linear-gradient(48.17deg, #5348ca 11.21%, #140730 61.92%) fixed 0 0 / cover;
+ --theme-shadow-color: 250 65% 14%;
+}
+
+/* Forest */
+.forest {
+ --theme-surface-tint: rgb(0 26 2);
+ --theme-foreground-tint: rgb(255 248 229);
+ --theme-gradient:
+ linear-gradient(rgb(0 0 0 / 0.9), rgb(0 0 0 / 0.9)) fixed 0 0 / cover,
+ linear-gradient(162.27deg, #142215 11.2%, #2d4d39 29.93%, #454c32 48.64%, #5a7c58 67.85%, #a98e4b 83.54%) fixed 0 0 / cover;
+ --theme-shadow-color: 130 60% 8%;
+}
+
+/* Dusk */
+.dusk {
+ --theme-surface-tint: rgb(22 0 26);
+ --theme-foreground-tint: rgb(153 182 255);
+ --theme-gradient:
+ linear-gradient(rgb(0 0 0 / 0.9), rgb(0 0 0 / 0.9)) fixed 0 0 / cover,
+ linear-gradient(180deg, #665069 12.84%, #91a3d1 85.99%) fixed 0 0 / cover;
+ --theme-shadow-color: 285 45% 14%;
+}
+
+/* Citrus Sherbet (light) */
+.citrus-sherbet {
+ --theme-surface-tint: rgb(255 238 204);
+ --theme-foreground-tint: rgb(77 23 0);
+ --theme-gradient:
+ linear-gradient(rgb(255 255 255 / 0.85), rgb(255 255 255 / 0.85)) fixed 0 0 / cover,
+ linear-gradient(180deg, #f3b336 31.1%, #ee8558 67.09%) fixed 0 0 / cover;
+ --theme-shadow-color: 28 55% 45%;
+}
+
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
@@ -134,3 +335,170 @@
@apply font-sans;
}
}
+
+/* =========================================================================
+ Custom themes — scoped atmosphere, motion, and per-component polish.
+ Keyed off the .theme-dark / .theme-light markers so every palette shares
+ them; unlayered so they win over `@layer base`. `:root`/`.dark` (the
+ original stone themes) are never matched.
+ ========================================================================= */
+
+/* Atmospheric page background: the palette's full gradient value (dim wash +
+ color layer, already fixed/cover) reads as depth behind the panels. */
+:is(.theme-dark, .theme-light) body {
+ background: var(--theme-gradient);
+}
+
+/* Text selection tinted from the foreground tint. */
+:is(.theme-dark, .theme-light) ::selection {
+ background: color-mix(in oklab, var(--theme-foreground-tint) 22%, transparent);
+ color: var(--foreground);
+}
+
+/* Thin, rounded, low-contrast scrollbars. */
+:is(.theme-dark, .theme-light) * {
+ scrollbar-width: thin;
+ scrollbar-color: color-mix(in oklab, var(--theme-foreground-tint) 14%, transparent) transparent;
+}
+:is(.theme-dark, .theme-light) *::-webkit-scrollbar {
+ width: 10px;
+ height: 10px;
+}
+:is(.theme-dark, .theme-light) *::-webkit-scrollbar-track {
+ background: transparent;
+}
+:is(.theme-dark, .theme-light) *::-webkit-scrollbar-thumb {
+ background: color-mix(in oklab, var(--theme-foreground-tint) 12%, transparent);
+ border-radius: 9999px;
+ border: 2px solid transparent;
+ background-clip: padding-box;
+}
+:is(.theme-dark, .theme-light) *::-webkit-scrollbar-thumb:hover {
+ background: color-mix(in oklab, var(--theme-foreground-tint) 22%, transparent);
+ background-clip: padding-box;
+}
+
+/* Premium hover timing (150–180ms) on the surfaces users actually touch. */
+:is(.theme-dark, .theme-light)
+ :is(
+ a,
+ [data-slot="button"],
+ [data-slot="table-row"],
+ [data-slot="sidebar-menu-button"],
+ [data-slot="input"],
+ [data-slot="textarea"],
+ [data-slot="card"]
+ ) {
+ transition-property: color, background-color, border-color, box-shadow, transform, opacity;
+ transition-duration: 165ms;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+}
+@media (prefers-reduced-motion: reduce) {
+ :is(.theme-dark, .theme-light) * {
+ transition-duration: 0ms !important;
+ }
+}
+
+/* Layered shadows on the shadow-bearing slots (sm cards, lg menus, xl modals). */
+:is(.theme-dark, .theme-light) [data-slot="card"] {
+ box-shadow: var(--cm-shadow-sm);
+}
+:is(.theme-dark, .theme-light)
+ :is(
+ [data-slot="popover-content"],
+ [data-slot="dropdown-menu-content"],
+ [data-slot="select-content"],
+ [data-slot="tooltip-content"]
+ ) {
+ box-shadow: var(--cm-shadow-lg);
+}
+:is(.theme-dark, .theme-light)
+ :is(
+ [data-slot="dialog-content"],
+ [data-slot="alert-dialog-content"],
+ [data-slot="sheet-content"],
+ [data-slot="drawer-content"]
+ ) {
+ box-shadow: var(--cm-shadow-xl);
+}
+
+/* Primary button: subtle vertical gradient, premium shadow, hover lift.
+ `.bg-primary` targets shadcn's default button variant without touching the
+ component. */
+:is(.theme-dark, .theme-light) [data-slot="button"].bg-primary {
+ background-image: linear-gradient(
+ 180deg,
+ color-mix(in oklab, var(--primary) 94%, white) 0%,
+ var(--primary) 55%,
+ color-mix(in oklab, var(--primary) 92%, black) 100%
+ );
+ box-shadow: var(--cm-shadow-sm);
+}
+:is(.theme-dark, .theme-light) [data-slot="button"].bg-primary:hover {
+ transform: translateY(-1px);
+ box-shadow: var(--cm-shadow-lg);
+}
+:is(.theme-dark, .theme-light) [data-slot="button"].bg-primary:active {
+ transform: translateY(0);
+}
+
+/* Tables: tinted hover + selected rows. */
+:is(.theme-dark, .theme-light) [data-slot="table-row"]:hover {
+ background: color-mix(in oklab, var(--theme-foreground-tint) 4%, transparent);
+}
+:is(.theme-dark, .theme-light) [data-slot="table-row"][data-state="selected"] {
+ background: color-mix(in oklab, var(--theme-foreground-tint) 7%, transparent);
+}
+
+/* Inputs: tinted fill, restrained blur, themed focus glow. */
+:is(.theme-dark, .theme-light)
+ :is([data-slot="input"], [data-slot="textarea"]) {
+ background: color-mix(in oklab, var(--input) 88%, transparent);
+ backdrop-filter: blur(6px);
+ -webkit-backdrop-filter: blur(6px);
+}
+:is(.theme-dark, .theme-light)
+ :is([data-slot="input"], [data-slot="textarea"]):focus-visible {
+ box-shadow:
+ 0 0 0 3px color-mix(in oklab, var(--ring) 28%, transparent),
+ 0 0 18px -4px color-mix(in oklab, var(--ring) 40%, transparent);
+}
+
+/* Sidebar menu: gentle tinted hover, no loud background. */
+:is(.theme-dark, .theme-light) [data-slot="sidebar-menu-button"]:hover {
+ background: color-mix(in oklab, var(--theme-foreground-tint) 5%, transparent);
+}
+
+/* =========================================================================
+ Theme swatches — the little gradient discs shown next to each theme name in
+ the picker. These are the color layer only (no dim wash) so they stay vivid,
+ and they are unscoped/global so every swatch renders regardless of the
+ active theme. Geometry (size / shape / ring) comes from Tailwind on the span.
+ ========================================================================= */
+.theme-swatch-light {
+ background: #ffffff;
+}
+.theme-swatch-dark {
+ background: #1c1917;
+}
+.theme-swatch-system {
+ background: linear-gradient(135deg, #fafafa 0 50%, #1c1917 50% 100%);
+}
+.theme-swatch-crimson-moon {
+ background: linear-gradient(64.92deg, #950909, #000000);
+}
+.theme-swatch-sepia {
+ background: linear-gradient(69.98deg, #857664, #5b4421);
+}
+.theme-swatch-midnight-blurple {
+ background: linear-gradient(48.17deg, #5348ca, #140730);
+}
+.theme-swatch-forest {
+ background: linear-gradient(162.27deg, #142215, #2d4d39, #454c32, #5a7c58, #a98e4b);
+}
+.theme-swatch-dusk {
+ background: linear-gradient(180deg, #665069, #91a3d1);
+}
+.theme-swatch-citrus-sherbet {
+ background: linear-gradient(180deg, #f3b336, #ee8558);
+}
From 05ec914ba0d0cf0129fa7bfb7d441cae5c91fedb Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Wed, 1 Jul 2026 17:27:18 +0530
Subject: [PATCH 02/16] style: formatting
---
apps/dashboard/src/styles.css | 254 ++++++++++++++++++++++++++++------
1 file changed, 212 insertions(+), 42 deletions(-)
diff --git a/apps/dashboard/src/styles.css b/apps/dashboard/src/styles.css
index 6f43b95a..1c4986cb 100644
--- a/apps/dashboard/src/styles.css
+++ b/apps/dashboard/src/styles.css
@@ -102,19 +102,51 @@
color-scheme: dark;
/* surfaces: surface tint on an elevation ramp (mixed toward white) */
- --background: color-mix(in oklab, var(--theme-surface-tint) 95%, white); /* +5% canvas */
- --card: color-mix(in oklab, var(--theme-surface-tint) 92%, white); /* +8% one step up */
- --popover: color-mix(in oklab, var(--theme-surface-tint) 86%, white); /* +14% elevated */
- --sidebar: color-mix(in oklab, var(--theme-surface-tint) 97%, black); /* darker than bg */
- --muted: color-mix(in oklab, var(--theme-surface-tint) 89%, white); /* +11% fills */
- --accent: color-mix(in oklab, var(--theme-surface-tint) 87%, white); /* +13% hover fills */
+ --background: color-mix(
+ in oklab,
+ var(--theme-surface-tint) 95%,
+ white
+ ); /* +5% canvas */
+ --card: color-mix(
+ in oklab,
+ var(--theme-surface-tint) 92%,
+ white
+ ); /* +8% one step up */
+ --popover: color-mix(
+ in oklab,
+ var(--theme-surface-tint) 86%,
+ white
+ ); /* +14% elevated */
+ --sidebar: color-mix(
+ in oklab,
+ var(--theme-surface-tint) 97%,
+ black
+ ); /* darker than bg */
+ --muted: color-mix(
+ in oklab,
+ var(--theme-surface-tint) 89%,
+ white
+ ); /* +11% fills */
+ --accent: color-mix(
+ in oklab,
+ var(--theme-surface-tint) 87%,
+ white
+ ); /* +13% hover fills */
--secondary: color-mix(in oklab, var(--theme-surface-tint) 89%, white);
--input: color-mix(in oklab, var(--theme-surface-tint) 86%, white);
--sidebar-accent: color-mix(in oklab, var(--theme-surface-tint) 87%, white);
/* primary: bright surface (buttons), deep-tint text */
- --primary: color-mix(in oklab, var(--theme-foreground-tint) 88%, var(--theme-surface-tint));
- --primary-foreground: color-mix(in oklab, var(--theme-surface-tint) 90%, black);
+ --primary: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 88%,
+ var(--theme-surface-tint)
+ );
+ --primary-foreground: color-mix(
+ in oklab,
+ var(--theme-surface-tint) 90%,
+ black
+ );
--sidebar-primary: var(--primary);
--sidebar-primary-foreground: var(--primary-foreground);
@@ -122,28 +154,68 @@
--foreground: color-mix(in oklab, var(--theme-foreground-tint) 55%, white);
--card-foreground: var(--foreground);
--popover-foreground: var(--foreground);
- --sidebar-foreground: color-mix(in oklab, var(--theme-foreground-tint) 60%, white);
- --muted-foreground: color-mix(in oklab, var(--theme-foreground-tint) 92%, transparent);
- --secondary-foreground: color-mix(in oklab, var(--theme-foreground-tint) 70%, white);
- --accent-foreground: color-mix(in oklab, var(--theme-foreground-tint) 70%, white);
+ --sidebar-foreground: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 60%,
+ white
+ );
+ --muted-foreground: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 92%,
+ transparent
+ );
+ --secondary-foreground: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 70%,
+ white
+ );
+ --accent-foreground: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 70%,
+ white
+ );
--sidebar-accent-foreground: var(--accent-foreground);
/* borders at low alpha; ring is a tinted glow derived from the foreground */
--border: color-mix(in oklab, var(--theme-foreground-tint) 7%, transparent);
- --sidebar-border: color-mix(in oklab, var(--theme-foreground-tint) 6%, transparent);
+ --sidebar-border: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 6%,
+ transparent
+ );
--ring: color-mix(in oklab, var(--theme-foreground-tint) 60%, transparent);
--sidebar-ring: var(--ring);
/* destructive stays a true red across every theme */
--destructive: oklch(0.6 0.22 25);
- --destructive-foreground: color-mix(in oklab, var(--theme-foreground-tint) 40%, white);
+ --destructive-foreground: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 40%,
+ white
+ );
/* charts: a monochrome ramp from the foreground tint down to the surface */
--chart-1: var(--theme-foreground-tint);
- --chart-2: color-mix(in oklab, var(--theme-foreground-tint) 78%, var(--theme-surface-tint));
- --chart-3: color-mix(in oklab, var(--theme-foreground-tint) 58%, var(--theme-surface-tint));
- --chart-4: color-mix(in oklab, var(--theme-foreground-tint) 40%, var(--theme-surface-tint));
- --chart-5: color-mix(in oklab, var(--theme-foreground-tint) 25%, var(--theme-surface-tint));
+ --chart-2: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 78%,
+ var(--theme-surface-tint)
+ );
+ --chart-3: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 58%,
+ var(--theme-surface-tint)
+ );
+ --chart-4: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 40%,
+ var(--theme-surface-tint)
+ );
+ --chart-5: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 25%,
+ var(--theme-surface-tint)
+ );
}
/* ---- shared derivation for the LIGHT palettes (light surface, dark fg) ---- */
@@ -154,16 +226,44 @@
--background: color-mix(in oklab, var(--theme-surface-tint) 90%, white);
--card: color-mix(in oklab, var(--theme-surface-tint) 55%, white);
--popover: color-mix(in oklab, var(--theme-surface-tint) 45%, white);
- --sidebar: color-mix(in oklab, var(--theme-foreground-tint) 4%, var(--theme-surface-tint));
- --muted: color-mix(in oklab, var(--theme-foreground-tint) 6%, var(--theme-surface-tint));
- --accent: color-mix(in oklab, var(--theme-foreground-tint) 9%, var(--theme-surface-tint));
- --secondary: color-mix(in oklab, var(--theme-foreground-tint) 6%, var(--theme-surface-tint));
+ --sidebar: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 4%,
+ var(--theme-surface-tint)
+ );
+ --muted: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 6%,
+ var(--theme-surface-tint)
+ );
+ --accent: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 9%,
+ var(--theme-surface-tint)
+ );
+ --secondary: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 6%,
+ var(--theme-surface-tint)
+ );
--input: color-mix(in oklab, var(--theme-surface-tint) 62%, white);
- --sidebar-accent: color-mix(in oklab, var(--theme-foreground-tint) 9%, var(--theme-surface-tint));
+ --sidebar-accent: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 9%,
+ var(--theme-surface-tint)
+ );
/* primary: dark warm surface (buttons), light text */
- --primary: color-mix(in oklab, var(--theme-foreground-tint) 90%, var(--theme-surface-tint));
- --primary-foreground: color-mix(in oklab, var(--theme-surface-tint) 92%, white);
+ --primary: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 90%,
+ var(--theme-surface-tint)
+ );
+ --primary-foreground: color-mix(
+ in oklab,
+ var(--theme-surface-tint) 92%,
+ white
+ );
--sidebar-primary: var(--primary);
--sidebar-primary-foreground: var(--primary-foreground);
@@ -171,14 +271,34 @@
--foreground: color-mix(in oklab, var(--theme-foreground-tint) 92%, black);
--card-foreground: var(--foreground);
--popover-foreground: var(--foreground);
- --sidebar-foreground: color-mix(in oklab, var(--theme-foreground-tint) 88%, black);
- --muted-foreground: color-mix(in oklab, var(--theme-foreground-tint) 60%, transparent);
- --secondary-foreground: color-mix(in oklab, var(--theme-foreground-tint) 85%, black);
- --accent-foreground: color-mix(in oklab, var(--theme-foreground-tint) 85%, black);
+ --sidebar-foreground: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 88%,
+ black
+ );
+ --muted-foreground: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 60%,
+ transparent
+ );
+ --secondary-foreground: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 85%,
+ black
+ );
+ --accent-foreground: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 85%,
+ black
+ );
--sidebar-accent-foreground: var(--accent-foreground);
--border: color-mix(in oklab, var(--theme-foreground-tint) 14%, transparent);
- --sidebar-border: color-mix(in oklab, var(--theme-foreground-tint) 12%, transparent);
+ --sidebar-border: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 12%,
+ transparent
+ );
--ring: color-mix(in oklab, var(--theme-foreground-tint) 45%, transparent);
--sidebar-ring: var(--ring);
@@ -186,10 +306,26 @@
--destructive-foreground: oklch(0.985 0 0);
--chart-1: var(--theme-foreground-tint);
- --chart-2: color-mix(in oklab, var(--theme-foreground-tint) 78%, var(--theme-surface-tint));
- --chart-3: color-mix(in oklab, var(--theme-foreground-tint) 58%, var(--theme-surface-tint));
- --chart-4: color-mix(in oklab, var(--theme-foreground-tint) 40%, var(--theme-surface-tint));
- --chart-5: color-mix(in oklab, var(--theme-foreground-tint) 25%, var(--theme-surface-tint));
+ --chart-2: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 78%,
+ var(--theme-surface-tint)
+ );
+ --chart-3: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 58%,
+ var(--theme-surface-tint)
+ );
+ --chart-4: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 40%,
+ var(--theme-surface-tint)
+ );
+ --chart-5: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 25%,
+ var(--theme-surface-tint)
+ );
}
/* ---- layered premium shadows (shared): inset highlight + soft ambient +
@@ -256,7 +392,15 @@
--theme-foreground-tint: rgb(255 248 229);
--theme-gradient:
linear-gradient(rgb(0 0 0 / 0.9), rgb(0 0 0 / 0.9)) fixed 0 0 / cover,
- linear-gradient(162.27deg, #142215 11.2%, #2d4d39 29.93%, #454c32 48.64%, #5a7c58 67.85%, #a98e4b 83.54%) fixed 0 0 / cover;
+ linear-gradient(
+ 162.27deg,
+ #142215 11.2%,
+ #2d4d39 29.93%,
+ #454c32 48.64%,
+ #5a7c58 67.85%,
+ #a98e4b 83.54%
+ )
+ fixed 0 0 / cover;
--theme-shadow-color: 130 60% 8%;
}
@@ -275,7 +419,8 @@
--theme-surface-tint: rgb(255 238 204);
--theme-foreground-tint: rgb(77 23 0);
--theme-gradient:
- linear-gradient(rgb(255 255 255 / 0.85), rgb(255 255 255 / 0.85)) fixed 0 0 / cover,
+ linear-gradient(rgb(255 255 255 / 0.85), rgb(255 255 255 / 0.85)) fixed 0 0
+ / cover,
linear-gradient(180deg, #f3b336 31.1%, #ee8558 67.09%) fixed 0 0 / cover;
--theme-shadow-color: 28 55% 45%;
}
@@ -351,14 +496,23 @@
/* Text selection tinted from the foreground tint. */
:is(.theme-dark, .theme-light) ::selection {
- background: color-mix(in oklab, var(--theme-foreground-tint) 22%, transparent);
+ background: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 22%,
+ transparent
+ );
color: var(--foreground);
}
/* Thin, rounded, low-contrast scrollbars. */
:is(.theme-dark, .theme-light) * {
scrollbar-width: thin;
- scrollbar-color: color-mix(in oklab, var(--theme-foreground-tint) 14%, transparent) transparent;
+ scrollbar-color: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 14%,
+ transparent
+ )
+ transparent;
}
:is(.theme-dark, .theme-light) *::-webkit-scrollbar {
width: 10px;
@@ -368,13 +522,21 @@
background: transparent;
}
:is(.theme-dark, .theme-light) *::-webkit-scrollbar-thumb {
- background: color-mix(in oklab, var(--theme-foreground-tint) 12%, transparent);
+ background: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 12%,
+ transparent
+ );
border-radius: 9999px;
border: 2px solid transparent;
background-clip: padding-box;
}
:is(.theme-dark, .theme-light) *::-webkit-scrollbar-thumb:hover {
- background: color-mix(in oklab, var(--theme-foreground-tint) 22%, transparent);
+ background: color-mix(
+ in oklab,
+ var(--theme-foreground-tint) 22%,
+ transparent
+ );
background-clip: padding-box;
}
@@ -389,7 +551,8 @@
[data-slot="textarea"],
[data-slot="card"]
) {
- transition-property: color, background-color, border-color, box-shadow, transform, opacity;
+ transition-property:
+ color, background-color, border-color, box-shadow, transform, opacity;
transition-duration: 165ms;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
@@ -494,7 +657,14 @@
background: linear-gradient(48.17deg, #5348ca, #140730);
}
.theme-swatch-forest {
- background: linear-gradient(162.27deg, #142215, #2d4d39, #454c32, #5a7c58, #a98e4b);
+ background: linear-gradient(
+ 162.27deg,
+ #142215,
+ #2d4d39,
+ #454c32,
+ #5a7c58,
+ #a98e4b
+ );
}
.theme-swatch-dusk {
background: linear-gradient(180deg, #665069, #91a3d1);
From 3036f1e51a9a0ab1a8865726f27cfb0b1970e916 Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Wed, 1 Jul 2026 19:29:10 +0530
Subject: [PATCH 03/16] fix(dashboard): add width to theme selection dropdown
---
apps/dashboard/src/components/theme-toggle.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/dashboard/src/components/theme-toggle.tsx b/apps/dashboard/src/components/theme-toggle.tsx
index 5a7b7768..2facf8fe 100644
--- a/apps/dashboard/src/components/theme-toggle.tsx
+++ b/apps/dashboard/src/components/theme-toggle.tsx
@@ -51,7 +51,7 @@ export function ModeToggle() {
}
/>
-
+
{BASE_THEMES.map(renderItem)}
{NITRO_THEMES.map(renderItem)}
From 1c15a7eae7b1733b26f4a046d7318d1a3cd11ba6 Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Wed, 1 Jul 2026 19:29:41 +0530
Subject: [PATCH 04/16] fix(dashboard): adjust transition duration for theme
elements to reduce motion
---
apps/dashboard/src/styles.css | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/apps/dashboard/src/styles.css b/apps/dashboard/src/styles.css
index 1c4986cb..a6312e30 100644
--- a/apps/dashboard/src/styles.css
+++ b/apps/dashboard/src/styles.css
@@ -557,8 +557,19 @@
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
@media (prefers-reduced-motion: reduce) {
- :is(.theme-dark, .theme-light) * {
- transition-duration: 0ms !important;
+ /* Mirror the selector above so specificity ties and this later rule wins —
+ neutralizes the added motion without needing !important. */
+ :is(.theme-dark, .theme-light)
+ :is(
+ a,
+ [data-slot="button"],
+ [data-slot="table-row"],
+ [data-slot="sidebar-menu-button"],
+ [data-slot="input"],
+ [data-slot="textarea"],
+ [data-slot="card"]
+ ) {
+ transition-duration: 0.01ms;
}
}
From f8c0e40e834f24e759f0494d6e2bcdb58c644764 Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Thu, 2 Jul 2026 00:10:02 +0530
Subject: [PATCH 05/16] fix(dashboard): enhance theme class application and
update gradient styles
---
.../src/components/theme-provider.tsx | 13 +-
apps/dashboard/src/styles.css | 357 +++++++++---------
2 files changed, 180 insertions(+), 190 deletions(-)
diff --git a/apps/dashboard/src/components/theme-provider.tsx b/apps/dashboard/src/components/theme-provider.tsx
index dccf1438..767d76e9 100644
--- a/apps/dashboard/src/components/theme-provider.tsx
+++ b/apps/dashboard/src/components/theme-provider.tsx
@@ -11,8 +11,11 @@ export type Theme =
| "dusk"
| "citrus-sherbet";
-// Custom palettes derive their tokens from the shared `.theme-dark` /
-// `.theme-light` markers, added alongside the palette class in the effect below.
+// Custom palettes are applied to as a `theme-` class (e.g.
+// `theme-sepia`) — the `theme-` prefix keeps them from colliding with Tailwind
+// utility classes of the same name (notably `sepia`, `grayscale`, `invert`).
+// Each derives its tokens from the shared `.theme-dark` / `.theme-light` marker,
+// added alongside the palette class in the effect below.
const DARK_THEMES = [
"crimson-moon",
"sepia",
@@ -59,7 +62,7 @@ export function ThemeProvider({
"dark",
"theme-dark",
"theme-light",
- ...CUSTOM_THEMES,
+ ...CUSTOM_THEMES.map((t) => `theme-${t}`),
);
if (theme === "system") {
@@ -73,12 +76,12 @@ export function ThemeProvider({
}
if ((DARK_THEMES as readonly string[]).includes(theme)) {
- root.classList.add(theme, "theme-dark");
+ root.classList.add(`theme-${theme}`, "theme-dark");
return;
}
if ((LIGHT_THEMES as readonly string[]).includes(theme)) {
- root.classList.add(theme, "theme-light");
+ root.classList.add(`theme-${theme}`, "theme-light");
return;
}
diff --git a/apps/dashboard/src/styles.css b/apps/dashboard/src/styles.css
index a6312e30..5f59c441 100644
--- a/apps/dashboard/src/styles.css
+++ b/apps/dashboard/src/styles.css
@@ -101,89 +101,71 @@
.theme-dark {
color-scheme: dark;
- /* surfaces: surface tint on an elevation ramp (mixed toward white) */
- --background: color-mix(
- in oklab,
- var(--theme-surface-tint) 95%,
- white
- ); /* +5% canvas */
- --card: color-mix(
- in oklab,
- var(--theme-surface-tint) 92%,
- white
- ); /* +8% one step up */
- --popover: color-mix(
- in oklab,
- var(--theme-surface-tint) 86%,
- white
- ); /* +14% elevated */
- --sidebar: color-mix(
- in oklab,
- var(--theme-surface-tint) 97%,
- black
- ); /* darker than bg */
- --muted: color-mix(
- in oklab,
- var(--theme-surface-tint) 89%,
- white
- ); /* +11% fills */
- --accent: color-mix(
- in oklab,
- var(--theme-surface-tint) 87%,
- white
- ); /* +13% hover fills */
- --secondary: color-mix(in oklab, var(--theme-surface-tint) 89%, white);
- --input: color-mix(in oklab, var(--theme-surface-tint) 86%, white);
- --sidebar-accent: color-mix(in oklab, var(--theme-surface-tint) 87%, white);
+ /* Each STRUCTURAL surface paints `scrim + color gradient`,
+ viewport-fixed + cover, so they all sample ONE continuous
+ gradient and differ only by scrim opacity (elevation). Painted on the
+ structural containers below; component tokens stay solid (crisp). */
+ --grad-chrome:
+ linear-gradient(rgb(0 0 0 / 0.86), rgb(0 0 0 / 0.86)) fixed 0 0 / cover,
+ var(--theme-grad-color) fixed 0 0 / cover;
+ --grad-base:
+ linear-gradient(rgb(0 0 0 / 0.82), rgb(0 0 0 / 0.82)) fixed 0 0 / cover,
+ var(--theme-grad-color) fixed 0 0 / cover;
+ --grad-raised:
+ linear-gradient(rgb(0 0 0 / 0.58), rgb(0 0 0 / 0.58)) fixed 0 0 / cover,
+ var(--theme-grad-color) fixed 0 0 / cover;
+
+ /* neutral hover / selected overlays */
+ --mod-hover: color-mix(in oklab, white 6%, transparent);
+ --mod-active: color-mix(in oklab, white 12%, transparent);
+
+ /* TRANSLUCENT component surfaces: veils over the painted gradient, so every
+ input / chip / menu / tab picks up the theme instead of reading as flat gray.
+ Dark veils recess (input, muted, popover); light veils lift (card, chips,
+ hovers). Legible because they sit over the already-dark gradient. */
+ --sidebar: color-mix(in oklab, oklch(0.16 0 0) 55%, transparent);
+ --background: color-mix(in oklab, oklch(0.16 0 0) 14%, transparent);
+ --card: color-mix(in oklab, white 5%, transparent);
+ --popover: color-mix(in oklab, oklch(0.15 0 0) 82%, transparent);
+ --muted: color-mix(in oklab, oklch(0 0 0) 22%, transparent);
+ --secondary: color-mix(in oklab, white 7%, transparent);
+ --accent: color-mix(in oklab, white 11%, transparent);
+ --sidebar-accent: color-mix(in oklab, white 10%, transparent);
+ --input: color-mix(in oklab, oklch(0 0 0) 42%, transparent);
+ --header-bg: color-mix(in oklab, oklch(0.14 0 0) 55%, transparent);
/* primary: bright surface (buttons), deep-tint text */
--primary: color-mix(
in oklab,
- var(--theme-foreground-tint) 88%,
+ var(--theme-foreground-tint) 90%,
var(--theme-surface-tint)
);
--primary-foreground: color-mix(
in oklab,
- var(--theme-surface-tint) 90%,
+ var(--theme-surface-tint) 88%,
black
);
--sidebar-primary: var(--primary);
--sidebar-primary-foreground: var(--primary-foreground);
- /* text: foreground tint toward pure white (subtle tint, never loud) */
- --foreground: color-mix(in oklab, var(--theme-foreground-tint) 55%, white);
+ /* text: crisp near-white, negligible tint */
+ --foreground: color-mix(in oklab, var(--theme-foreground-tint) 16%, white);
--card-foreground: var(--foreground);
--popover-foreground: var(--foreground);
--sidebar-foreground: color-mix(
in oklab,
- var(--theme-foreground-tint) 60%,
- white
- );
- --muted-foreground: color-mix(
- in oklab,
- var(--theme-foreground-tint) 92%,
- transparent
- );
- --secondary-foreground: color-mix(
- in oklab,
- var(--theme-foreground-tint) 70%,
- white
- );
- --accent-foreground: color-mix(
- in oklab,
- var(--theme-foreground-tint) 70%,
+ var(--theme-foreground-tint) 22%,
white
);
- --sidebar-accent-foreground: var(--accent-foreground);
+ --muted-foreground: color-mix(in oklab, var(--foreground) 62%, transparent);
+ --secondary-foreground: var(--foreground);
+ --accent-foreground: var(--foreground);
+ --sidebar-accent-foreground: var(--foreground);
- /* borders at low alpha; ring is a tinted glow derived from the foreground */
- --border: color-mix(in oklab, var(--theme-foreground-tint) 7%, transparent);
- --sidebar-border: color-mix(
- in oklab,
- var(--theme-foreground-tint) 6%,
- transparent
- );
- --ring: color-mix(in oklab, var(--theme-foreground-tint) 60%, transparent);
+ /* borders / ring: neutral, low alpha */
+ --border: color-mix(in oklab, white 10%, transparent);
+ --sidebar-border: color-mix(in oklab, white 7%, transparent);
+ --ring: color-mix(in oklab, var(--theme-foreground-tint) 55%, transparent);
--sidebar-ring: var(--ring);
/* destructive stays a true red across every theme */
@@ -222,36 +204,37 @@
.theme-light {
color-scheme: light;
- /* surfaces: cards/popovers climb toward white; fills recede toward the fg tint */
- --background: color-mix(in oklab, var(--theme-surface-tint) 90%, white);
- --card: color-mix(in oklab, var(--theme-surface-tint) 55%, white);
- --popover: color-mix(in oklab, var(--theme-surface-tint) 45%, white);
- --sidebar: color-mix(
- in oklab,
- var(--theme-foreground-tint) 4%,
- var(--theme-surface-tint)
- );
- --muted: color-mix(
- in oklab,
- var(--theme-foreground-tint) 6%,
- var(--theme-surface-tint)
- );
- --accent: color-mix(
- in oklab,
- var(--theme-foreground-tint) 9%,
- var(--theme-surface-tint)
- );
- --secondary: color-mix(
- in oklab,
- var(--theme-foreground-tint) 6%,
- var(--theme-surface-tint)
- );
- --input: color-mix(in oklab, var(--theme-surface-tint) 62%, white);
- --sidebar-accent: color-mix(
- in oklab,
- var(--theme-foreground-tint) 9%,
- var(--theme-surface-tint)
- );
+ /* light mirror: structural surfaces paint the color gradient under a WHITE
+ scrim (lighter scrim = more color), viewport-fixed + cover. */
+ --grad-chrome:
+ linear-gradient(rgb(255 255 255 / 0.6), rgb(255 255 255 / 0.6)) fixed 0 0 /
+ cover,
+ var(--theme-grad-color) fixed 0 0 / cover;
+ --grad-base:
+ linear-gradient(rgb(255 255 255 / 0.5), rgb(255 255 255 / 0.5)) fixed 0 0 /
+ cover,
+ var(--theme-grad-color) fixed 0 0 / cover;
+ --grad-raised:
+ linear-gradient(rgb(255 255 255 / 0.24), rgb(255 255 255 / 0.24)) fixed 0 0
+ / cover,
+ var(--theme-grad-color) fixed 0 0 / cover;
+
+ --mod-hover: color-mix(in oklab, black 5%, transparent);
+ --mod-active: color-mix(in oklab, black 9%, transparent);
+
+ /* TRANSLUCENT component surfaces (mirror of the dark theme): veils over the
+ painted gradient so components pick up the theme. White veils lift, black
+ veils recess. */
+ --sidebar: color-mix(in oklab, white 55%, transparent);
+ --background: color-mix(in oklab, white 16%, transparent);
+ --card: color-mix(in oklab, white 32%, transparent);
+ --popover: color-mix(in oklab, white 82%, transparent);
+ --muted: color-mix(in oklab, black 6%, transparent);
+ --secondary: color-mix(in oklab, black 5%, transparent);
+ --accent: color-mix(in oklab, black 8%, transparent);
+ --sidebar-accent: color-mix(in oklab, black 8%, transparent);
+ --input: color-mix(in oklab, white 55%, transparent);
+ --header-bg: color-mix(in oklab, white 55%, transparent);
/* primary: dark warm surface (buttons), light text */
--primary: color-mix(
@@ -267,38 +250,22 @@
--sidebar-primary: var(--primary);
--sidebar-primary-foreground: var(--primary-foreground);
- /* text: foreground tint toward black (raise contrast on light surfaces) */
- --foreground: color-mix(in oklab, var(--theme-foreground-tint) 92%, black);
+ /* text: near-black with a whisper of hue */
+ --foreground: color-mix(in oklab, var(--theme-foreground-tint) 88%, black);
--card-foreground: var(--foreground);
--popover-foreground: var(--foreground);
--sidebar-foreground: color-mix(
in oklab,
- var(--theme-foreground-tint) 88%,
- black
- );
- --muted-foreground: color-mix(
- in oklab,
- var(--theme-foreground-tint) 60%,
- transparent
- );
- --secondary-foreground: color-mix(
- in oklab,
- var(--theme-foreground-tint) 85%,
- black
- );
- --accent-foreground: color-mix(
- in oklab,
- var(--theme-foreground-tint) 85%,
+ var(--theme-foreground-tint) 82%,
black
);
- --sidebar-accent-foreground: var(--accent-foreground);
+ --muted-foreground: color-mix(in oklab, var(--foreground) 58%, transparent);
+ --secondary-foreground: var(--foreground);
+ --accent-foreground: var(--foreground);
+ --sidebar-accent-foreground: var(--foreground);
- --border: color-mix(in oklab, var(--theme-foreground-tint) 14%, transparent);
- --sidebar-border: color-mix(
- in oklab,
- var(--theme-foreground-tint) 12%,
- transparent
- );
+ --border: color-mix(in oklab, black 12%, transparent);
+ --sidebar-border: color-mix(in oklab, black 9%, transparent);
--ring: color-mix(in oklab, var(--theme-foreground-tint) 45%, transparent);
--sidebar-ring: var(--ring);
@@ -328,101 +295,75 @@
);
}
-/* ---- layered premium shadows (shared): inset highlight + soft ambient +
- a subtle colored glow tinted by each palette's --theme-shadow-color.
- Applied per data-slot below (Tailwind v4 inlines shadow-* utilities at
- build time, so we set box-shadow directly rather than override tokens). ---- */
+/* ---- layered shadows (shared): a faint inset highlight + soft NEUTRAL ambient.
+ Elevation now comes mostly from the scrim lightness, so shadows stay subtle
+ and neutral — no colored glow (that was a source of muddiness). Applied per
+ data-slot below (Tailwind v4 inlines shadow-* utilities at build time). ---- */
.theme-dark,
.theme-light {
--cm-shadow-sm:
- inset 0 1px 0 0 hsl(0 0% 100% / 0.05),
- 0 1px 2px 0 hsl(var(--theme-shadow-color) / 0.4),
- 0 2px 6px -1px hsl(var(--theme-shadow-color) / 0.3);
+ inset 0 1px 0 0 hsl(0 0% 100% / 0.04), 0 1px 2px 0 hsl(0 0% 0% / 0.35);
--cm-shadow-lg:
- inset 0 1px 0 0 hsl(0 0% 100% / 0.06),
- 0 4px 8px -2px hsl(var(--theme-shadow-color) / 0.42),
- 0 12px 28px -6px hsl(var(--theme-shadow-color) / 0.4),
- 0 0 40px -8px hsl(var(--theme-shadow-color) / 0.25);
+ inset 0 1px 0 0 hsl(0 0% 100% / 0.05), 0 6px 16px -4px hsl(0 0% 0% / 0.4),
+ 0 12px 32px -8px hsl(0 0% 0% / 0.3);
--cm-shadow-xl:
- inset 0 1px 0 0 hsl(0 0% 100% / 0.07),
- 0 8px 16px -4px hsl(var(--theme-shadow-color) / 0.45),
- 0 20px 48px -10px hsl(var(--theme-shadow-color) / 0.45),
- 0 0 64px -12px hsl(var(--theme-shadow-color) / 0.28);
+ inset 0 1px 0 0 hsl(0 0% 100% / 0.06), 0 12px 32px -6px hsl(0 0% 0% / 0.5),
+ 0 24px 56px -12px hsl(0 0% 0% / 0.4);
}
/* =========================================================================
- Palettes — each declares only its three tints, a full-page gradient (dim
- wash + color layer, already fixed/cover), and a shadow hue (bare HSL
- channels consumed by the shadow recipes above).
+ Palettes — each declares only its three tints + the raw color gradient
+ (`--theme-grad-color`, no scrim). The shared blocks above build the fixed
+ scrim-elevation levels and derive every token from these.
========================================================================= */
/* Crimson Moon */
-.crimson-moon {
+.theme-crimson-moon {
--theme-surface-tint: rgb(26 0 0);
--theme-foreground-tint: rgb(255 229 229);
- --theme-gradient:
- linear-gradient(rgb(0 0 0 / 0.82), rgb(0 0 0 / 0.82)) fixed 0 0 / cover,
- linear-gradient(64.92deg, #950909 16.17%, #000000 72%) fixed 0 0 / cover;
- --theme-shadow-color: 0 72% 12%;
+ --theme-grad-color: linear-gradient(64.92deg, #950909 16.17%, #000000 72%);
}
/* Sepia */
-.sepia {
+.theme-sepia {
--theme-surface-tint: rgb(26 15 0);
--theme-foreground-tint: rgb(255 243 229);
- --theme-gradient:
- linear-gradient(rgb(0 0 0 / 0.9), rgb(0 0 0 / 0.9)) fixed 0 0 / cover,
- linear-gradient(69.98deg, #857664 14.14%, #5b4421 60.35%) fixed 0 0 / cover;
- --theme-shadow-color: 28 70% 10%;
+ --theme-grad-color: linear-gradient(69.98deg, #857664 14.14%, #5b4421 60.35%);
}
/* Midnight Blurple */
-.midnight-blurple {
+.theme-midnight-blurple {
--theme-surface-tint: rgb(8 0 26);
--theme-foreground-tint: rgb(162 153 255);
- --theme-gradient:
- linear-gradient(rgb(0 0 0 / 0.9), rgb(0 0 0 / 0.9)) fixed 0 0 / cover,
- linear-gradient(48.17deg, #5348ca 11.21%, #140730 61.92%) fixed 0 0 / cover;
- --theme-shadow-color: 250 65% 14%;
+ --theme-grad-color: linear-gradient(48.17deg, #5348ca 11.21%, #140730 61.92%);
}
/* Forest */
-.forest {
+.theme-forest {
--theme-surface-tint: rgb(0 26 2);
--theme-foreground-tint: rgb(255 248 229);
- --theme-gradient:
- linear-gradient(rgb(0 0 0 / 0.9), rgb(0 0 0 / 0.9)) fixed 0 0 / cover,
- linear-gradient(
- 162.27deg,
- #142215 11.2%,
- #2d4d39 29.93%,
- #454c32 48.64%,
- #5a7c58 67.85%,
- #a98e4b 83.54%
- )
- fixed 0 0 / cover;
- --theme-shadow-color: 130 60% 8%;
+ --theme-grad-color: linear-gradient(
+ 162.27deg,
+ #142215 11.2%,
+ #2d4d39 29.93%,
+ #454c32 48.64%,
+ #5a7c58 67.85%,
+ #a98e4b 83.54%
+ );
}
/* Dusk */
-.dusk {
+.theme-dusk {
--theme-surface-tint: rgb(22 0 26);
--theme-foreground-tint: rgb(153 182 255);
- --theme-gradient:
- linear-gradient(rgb(0 0 0 / 0.9), rgb(0 0 0 / 0.9)) fixed 0 0 / cover,
- linear-gradient(180deg, #665069 12.84%, #91a3d1 85.99%) fixed 0 0 / cover;
- --theme-shadow-color: 285 45% 14%;
+ --theme-grad-color: linear-gradient(180deg, #665069 12.84%, #91a3d1 85.99%);
}
/* Citrus Sherbet (light) */
-.citrus-sherbet {
+.theme-citrus-sherbet {
--theme-surface-tint: rgb(255 238 204);
--theme-foreground-tint: rgb(77 23 0);
- --theme-gradient:
- linear-gradient(rgb(255 255 255 / 0.85), rgb(255 255 255 / 0.85)) fixed 0 0
- / cover,
- linear-gradient(180deg, #f3b336 31.1%, #ee8558 67.09%) fixed 0 0 / cover;
- --theme-shadow-color: 28 55% 45%;
+ --theme-grad-color: linear-gradient(180deg, #f3b336 31.1%, #ee8558 67.09%);
}
@theme inline {
@@ -488,10 +429,56 @@
original stone themes) are never matched.
========================================================================= */
-/* Atmospheric page background: the palette's full gradient value (dim wash +
- color layer, already fixed/cover) reads as depth behind the panels. */
:is(.theme-dark, .theme-light) body {
- background: var(--theme-gradient);
+ background: var(--grad-base);
+}
+:is(.theme-dark, .theme-light) [data-slot="sidebar-inner"] {
+ background: var(--grad-chrome); /* left nav — darkest chrome */
+}
+:is(.theme-dark, .theme-light) [data-slot="sidebar-inset"] {
+ background: var(--grad-base); /* main content — same level as the canvas */
+}
+:is(.theme-dark, .theme-light) [data-slot="card"] {
+ background: var(--grad-raised); /* elevated — lightest scrim, glows */
+ /* a hairline ring so cards always separate from the canvas, even where the
+ gradient is near-black and the scrim difference alone is invisible */
+ box-shadow:
+ var(--cm-shadow-sm),
+ inset 0 0 0 1px var(--border);
+}
+
+/* Header: frosted glass over the fixed gradient (sticky, so content blurs under it). */
+:is(.theme-dark, .theme-light) header {
+ background: var(--header-bg);
+ backdrop-filter: blur(12px) saturate(1.2);
+ -webkit-backdrop-filter: blur(12px) saturate(1.2);
+}
+
+/* Floating overlays: dark glass (translucent `--popover`) + blur — transform-safe
+ (a `fixed` gradient would break under their translate()); the translucency lets
+ the theme tint through. */
+:is(.theme-dark, .theme-light)
+ :is(
+ [data-slot="popover-content"],
+ [data-slot="dropdown-menu-content"],
+ [data-slot="select-content"],
+ [data-slot="dialog-content"],
+ [data-slot="alert-dialog-content"],
+ [data-slot="sheet-content"],
+ [data-slot="drawer-content"],
+ [data-slot="tooltip-content"]
+ ) {
+ background: var(--popover);
+ backdrop-filter: blur(16px) saturate(1.2);
+ -webkit-backdrop-filter: blur(16px) saturate(1.2);
+}
+
+/* Tabs: the default (pill) active tab uses `bg-input/30`, which is invisible over
+ a translucent input — give it a clear neutral lift instead (skip line variant). */
+:is(.theme-dark, .theme-light)
+ [data-slot="tabs-list"]:not([data-variant="line"])
+ [data-slot="tabs-trigger"][data-active] {
+ background: var(--mod-active);
}
/* Text selection tinted from the foreground tint. */
@@ -616,18 +603,18 @@
transform: translateY(0);
}
-/* Tables: tinted hover + selected rows. */
+/* Tables: neutral hover + selected rows */
:is(.theme-dark, .theme-light) [data-slot="table-row"]:hover {
- background: color-mix(in oklab, var(--theme-foreground-tint) 4%, transparent);
+ background: var(--mod-hover);
}
:is(.theme-dark, .theme-light) [data-slot="table-row"][data-state="selected"] {
- background: color-mix(in oklab, var(--theme-foreground-tint) 7%, transparent);
+ background: var(--mod-active);
}
-/* Inputs: tinted fill, restrained blur, themed focus glow. */
+/* Inputs: recessed translucent fill, restrained blur, themed focus glow. */
:is(.theme-dark, .theme-light)
:is([data-slot="input"], [data-slot="textarea"]) {
- background: color-mix(in oklab, var(--input) 88%, transparent);
+ background: var(--input);
backdrop-filter: blur(6px);
-webkit-backdrop-filter: blur(6px);
}
@@ -638,9 +625,9 @@
0 0 18px -4px color-mix(in oklab, var(--ring) 40%, transparent);
}
-/* Sidebar menu: gentle tinted hover, no loud background. */
+/* Sidebar menu: gentle neutral hover, no loud background. */
:is(.theme-dark, .theme-light) [data-slot="sidebar-menu-button"]:hover {
- background: color-mix(in oklab, var(--theme-foreground-tint) 5%, transparent);
+ background: var(--mod-hover);
}
/* =========================================================================
From 7e5d2b9efe66126506c6be6bf538c856b03193a4 Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Thu, 2 Jul 2026 00:25:37 +0530
Subject: [PATCH 06/16] feat(dashboard): add Blurple Twilight and Aurora themes
---
.../src/components/theme-provider.tsx | 4 +++
.../dashboard/src/components/theme-toggle.tsx | 2 ++
apps/dashboard/src/styles.css | 34 +++++++++++++++++++
3 files changed, 40 insertions(+)
diff --git a/apps/dashboard/src/components/theme-provider.tsx b/apps/dashboard/src/components/theme-provider.tsx
index 767d76e9..7c713751 100644
--- a/apps/dashboard/src/components/theme-provider.tsx
+++ b/apps/dashboard/src/components/theme-provider.tsx
@@ -7,8 +7,10 @@ export type Theme =
| "crimson-moon"
| "sepia"
| "midnight-blurple"
+ | "blurple-twilight"
| "forest"
| "dusk"
+ | "aurora"
| "citrus-sherbet";
// Custom palettes are applied to as a `theme-` class (e.g.
@@ -20,8 +22,10 @@ const DARK_THEMES = [
"crimson-moon",
"sepia",
"midnight-blurple",
+ "blurple-twilight",
"forest",
"dusk",
+ "aurora",
] as const;
const LIGHT_THEMES = ["citrus-sherbet"] as const;
const CUSTOM_THEMES: readonly string[] = [...DARK_THEMES, ...LIGHT_THEMES];
diff --git a/apps/dashboard/src/components/theme-toggle.tsx b/apps/dashboard/src/components/theme-toggle.tsx
index 2facf8fe..68b9a8cb 100644
--- a/apps/dashboard/src/components/theme-toggle.tsx
+++ b/apps/dashboard/src/components/theme-toggle.tsx
@@ -20,8 +20,10 @@ const NITRO_THEMES: { key: Theme; label: string }[] = [
{ key: "crimson-moon", label: "Crimson Moon" },
{ key: "sepia", label: "Sepia" },
{ key: "midnight-blurple", label: "Midnight Blurple" },
+ { key: "blurple-twilight", label: "Blurple Twilight" },
{ key: "forest", label: "Forest" },
{ key: "dusk", label: "Dusk" },
+ { key: "aurora", label: "Aurora" },
{ key: "citrus-sherbet", label: "Citrus Sherbet" },
];
diff --git a/apps/dashboard/src/styles.css b/apps/dashboard/src/styles.css
index 5f59c441..d24555ce 100644
--- a/apps/dashboard/src/styles.css
+++ b/apps/dashboard/src/styles.css
@@ -338,6 +338,13 @@
--theme-grad-color: linear-gradient(48.17deg, #5348ca 11.21%, #140730 61.92%);
}
+/* Blurple Twilight */
+.theme-blurple-twilight {
+ --theme-surface-tint: rgb(2 0 26);
+ --theme-foreground-tint: rgb(153 163 255);
+ --theme-grad-color: linear-gradient(47.61deg, #2c3fe7 11.18%, #261d83 64.54%);
+}
+
/* Forest */
.theme-forest {
--theme-surface-tint: rgb(0 26 2);
@@ -359,6 +366,20 @@
--theme-grad-color: linear-gradient(180deg, #665069 12.84%, #91a3d1 85.99%);
}
+/* Aurora */
+.theme-aurora {
+ --theme-surface-tint: rgb(0 9 26);
+ --theme-foreground-tint: rgb(153 171 255);
+ --theme-grad-color: linear-gradient(
+ 239.16deg,
+ #062053 10.39%,
+ #191fbb 26.87%,
+ #13929a 48.31%,
+ #218573 64.98%,
+ #051a81 92.5%
+ );
+}
+
/* Citrus Sherbet (light) */
.theme-citrus-sherbet {
--theme-surface-tint: rgb(255 238 204);
@@ -654,6 +675,9 @@
.theme-swatch-midnight-blurple {
background: linear-gradient(48.17deg, #5348ca, #140730);
}
+.theme-swatch-blurple-twilight {
+ background: linear-gradient(47.61deg, #2c3fe7, #261d83);
+}
.theme-swatch-forest {
background: linear-gradient(
162.27deg,
@@ -667,6 +691,16 @@
.theme-swatch-dusk {
background: linear-gradient(180deg, #665069, #91a3d1);
}
+.theme-swatch-aurora {
+ background: linear-gradient(
+ 239.16deg,
+ #062053,
+ #191fbb,
+ #13929a,
+ #218573,
+ #051a81
+ );
+}
.theme-swatch-citrus-sherbet {
background: linear-gradient(180deg, #f3b336, #ee8558);
}
From c30e17e05a12967f1807ac934471d61cb992fb9f Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Thu, 2 Jul 2026 20:35:17 +0530
Subject: [PATCH 07/16] fix(dashboard): refine dark and light theme gradients
and component surfaces
---
apps/dashboard/src/styles.css | 152 ++++++++++++++++++----------------
1 file changed, 80 insertions(+), 72 deletions(-)
diff --git a/apps/dashboard/src/styles.css b/apps/dashboard/src/styles.css
index d24555ce..170077b0 100644
--- a/apps/dashboard/src/styles.css
+++ b/apps/dashboard/src/styles.css
@@ -101,38 +101,42 @@
.theme-dark {
color-scheme: dark;
- /* Each STRUCTURAL surface paints `scrim + color gradient`,
- viewport-fixed + cover, so they all sample ONE continuous
- gradient and differ only by scrim opacity (elevation). Painted on the
- structural containers below; component tokens stay solid (crisp). */
- --grad-chrome:
- linear-gradient(rgb(0 0 0 / 0.86), rgb(0 0 0 / 0.86)) fixed 0 0 / cover,
- var(--theme-grad-color) fixed 0 0 / cover;
- --grad-base:
- linear-gradient(rgb(0 0 0 / 0.82), rgb(0 0 0 / 0.82)) fixed 0 0 / cover,
- var(--theme-grad-color) fixed 0 0 / cover;
- --grad-raised:
- linear-gradient(rgb(0 0 0 / 0.58), rgb(0 0 0 / 0.58)) fixed 0 0 / cover,
- var(--theme-grad-color) fixed 0 0 / cover;
+ /* The gradient is painted ONCE, on the fixed `body::before` shell layer
+ (scrim over `--theme-grad-color`). Every surface above it is either an
+ alpha-neutral veil (guaranteed monotonic darken/lighten over the shell)
+ or a fully OPAQUE solid mixed from the surface tint (chrome, floating). */
+ --shell-scrim: rgb(0 0 0 / 0.82);
+
+ /* chrome: sidebar darkens the shell; header + mobile sidebar are opaque */
+ --surface-chrome: rgb(0 0 0 / 0.25);
+ --surface-chrome-solid: color-mix(
+ in oklab,
+ var(--theme-surface-tint) 65%,
+ oklch(0.17 0 0)
+ );
/* neutral hover / selected overlays */
--mod-hover: color-mix(in oklab, white 6%, transparent);
--mod-active: color-mix(in oklab, white 12%, transparent);
- /* TRANSLUCENT component surfaces: veils over the painted gradient, so every
- input / chip / menu / tab picks up the theme instead of reading as flat gray.
- Dark veils recess (input, muted, popover); light veils lift (card, chips,
- hovers). Legible because they sit over the already-dark gradient. */
+ /* Component surfaces. Veils are alpha-neutral so they composite predictably
+ over the shell; the card lift comes from the near-white foreground tint,
+ which is STRICTLY lighter than any backdrop — even pure black gradient
+ stops — so cards always separate. Floating (`--popover`) is opaque:
+ overlays cover arbitrary content and must never bleed it through. */
--sidebar: color-mix(in oklab, oklch(0.16 0 0) 55%, transparent);
--background: color-mix(in oklab, oklch(0.16 0 0) 14%, transparent);
- --card: color-mix(in oklab, white 5%, transparent);
- --popover: color-mix(in oklab, oklch(0.15 0 0) 82%, transparent);
+ --card: color-mix(in oklab, var(--theme-foreground-tint) 7%, transparent);
+ --popover: color-mix(
+ in oklab,
+ var(--theme-surface-tint) 55%,
+ oklch(0.23 0 0)
+ );
--muted: color-mix(in oklab, oklch(0 0 0) 22%, transparent);
--secondary: color-mix(in oklab, white 7%, transparent);
--accent: color-mix(in oklab, white 11%, transparent);
--sidebar-accent: color-mix(in oklab, white 10%, transparent);
- --input: color-mix(in oklab, oklch(0 0 0) 42%, transparent);
- --header-bg: color-mix(in oklab, oklch(0.14 0 0) 55%, transparent);
+ --input: color-mix(in oklab, black 25%, transparent);
/* primary: bright surface (buttons), deep-tint text */
--primary: color-mix(
@@ -157,13 +161,13 @@
var(--theme-foreground-tint) 22%,
white
);
- --muted-foreground: color-mix(in oklab, var(--foreground) 62%, transparent);
+ --muted-foreground: color-mix(in oklab, var(--foreground) 72%, transparent);
--secondary-foreground: var(--foreground);
--accent-foreground: var(--foreground);
--sidebar-accent-foreground: var(--foreground);
/* borders / ring: neutral, low alpha */
- --border: color-mix(in oklab, white 10%, transparent);
+ --border: color-mix(in oklab, white 12%, transparent);
--sidebar-border: color-mix(in oklab, white 7%, transparent);
--ring: color-mix(in oklab, var(--theme-foreground-tint) 55%, transparent);
--sidebar-ring: var(--ring);
@@ -204,37 +208,32 @@
.theme-light {
color-scheme: light;
- /* light mirror: structural surfaces paint the color gradient under a WHITE
- scrim (lighter scrim = more color), viewport-fixed + cover. */
- --grad-chrome:
- linear-gradient(rgb(255 255 255 / 0.6), rgb(255 255 255 / 0.6)) fixed 0 0 /
- cover,
- var(--theme-grad-color) fixed 0 0 / cover;
- --grad-base:
- linear-gradient(rgb(255 255 255 / 0.5), rgb(255 255 255 / 0.5)) fixed 0 0 /
- cover,
- var(--theme-grad-color) fixed 0 0 / cover;
- --grad-raised:
- linear-gradient(rgb(255 255 255 / 0.24), rgb(255 255 255 / 0.24)) fixed 0 0
- / cover,
- var(--theme-grad-color) fixed 0 0 / cover;
+ /* light mirror: WHITE shell scrim, white veils lift, black veils recess.
+ Same roles as the dark layer, so new light palettes are 3-line blocks. */
+ --shell-scrim: rgb(255 255 255 / 0.5);
+
+ --surface-chrome: rgb(255 255 255 / 0.22);
+ --surface-chrome-solid: color-mix(
+ in oklab,
+ var(--theme-surface-tint) 55%,
+ white
+ );
--mod-hover: color-mix(in oklab, black 5%, transparent);
--mod-active: color-mix(in oklab, black 9%, transparent);
- /* TRANSLUCENT component surfaces (mirror of the dark theme): veils over the
- painted gradient so components pick up the theme. White veils lift, black
- veils recess. */
+ /* Component surfaces: `--card` (white 60%) is strictly lighter than any
+ light-theme backdrop, so lift is guaranteed; `--popover` is an opaque
+ tinted off-white (nothing bleeds through floating layers). */
--sidebar: color-mix(in oklab, white 55%, transparent);
--background: color-mix(in oklab, white 16%, transparent);
- --card: color-mix(in oklab, white 32%, transparent);
- --popover: color-mix(in oklab, white 82%, transparent);
+ --card: color-mix(in oklab, white 60%, transparent);
+ --popover: color-mix(in oklab, var(--theme-surface-tint) 35%, white);
--muted: color-mix(in oklab, black 6%, transparent);
--secondary: color-mix(in oklab, black 5%, transparent);
--accent: color-mix(in oklab, black 8%, transparent);
--sidebar-accent: color-mix(in oklab, black 8%, transparent);
- --input: color-mix(in oklab, white 55%, transparent);
- --header-bg: color-mix(in oklab, white 55%, transparent);
+ --input: color-mix(in oklab, white 45%, transparent);
/* primary: dark warm surface (buttons), light text */
--primary: color-mix(
@@ -259,12 +258,12 @@
var(--theme-foreground-tint) 82%,
black
);
- --muted-foreground: color-mix(in oklab, var(--foreground) 58%, transparent);
+ --muted-foreground: color-mix(in oklab, var(--foreground) 62%, transparent);
--secondary-foreground: var(--foreground);
--accent-foreground: var(--foreground);
--sidebar-accent-foreground: var(--foreground);
- --border: color-mix(in oklab, black 12%, transparent);
+ --border: color-mix(in oklab, black 15%, transparent);
--sidebar-border: color-mix(in oklab, black 9%, transparent);
--ring: color-mix(in oklab, var(--theme-foreground-tint) 45%, transparent);
--sidebar-ring: var(--ring);
@@ -313,8 +312,8 @@
/* =========================================================================
Palettes — each declares only its three tints + the raw color gradient
- (`--theme-grad-color`, no scrim). The shared blocks above build the fixed
- scrim-elevation levels and derive every token from these.
+ (`--theme-grad-color`, no scrim). The shared blocks above paint the shell
+ scrim over it and derive every token from these.
========================================================================= */
/* Crimson Moon */
@@ -450,34 +449,42 @@
original stone themes) are never matched.
========================================================================= */
+/* The shell: the theme gradient painted exactly once, on a fixed pseudo behind
+ everything. No `background-attachment: fixed` (broken on iOS Safari, breaks
+ under transforms) — surfaces above are alpha veils, so the "one continuous
+ gradient" look survives by construction. */
:is(.theme-dark, .theme-light) body {
- background: var(--grad-base);
+ background: transparent;
}
-:is(.theme-dark, .theme-light) [data-slot="sidebar-inner"] {
- background: var(--grad-chrome); /* left nav — darkest chrome */
+:is(.theme-dark, .theme-light) body::before {
+ content: "";
+ position: fixed;
+ inset: 0;
+ z-index: -1;
+ pointer-events: none;
+ background:
+ linear-gradient(var(--shell-scrim), var(--shell-scrim)),
+ var(--theme-grad-color);
}
-:is(.theme-dark, .theme-light) [data-slot="sidebar-inset"] {
- background: var(--grad-base); /* main content — same level as the canvas */
+:is(.theme-dark, .theme-light) [data-slot="sidebar-inner"] {
+ background: var(--surface-chrome); /* left nav — darkens the shell */
}
:is(.theme-dark, .theme-light) [data-slot="card"] {
- background: var(--grad-raised); /* elevated — lightest scrim, glows */
- /* a hairline ring so cards always separate from the canvas, even where the
- gradient is near-black and the scrim difference alone is invisible */
+ /* lifted by the near-white tint veil — strictly lighter than any backdrop —
+ plus a hairline ring as the second separation channel */
+ background: var(--card);
box-shadow:
var(--cm-shadow-sm),
inset 0 0 0 1px var(--border);
}
-/* Header: frosted glass over the fixed gradient (sticky, so content blurs under it). */
+/* Header: opaque chrome, same layer family as the sidebar. */
:is(.theme-dark, .theme-light) header {
- background: var(--header-bg);
- backdrop-filter: blur(12px) saturate(1.2);
- -webkit-backdrop-filter: blur(12px) saturate(1.2);
+ background: var(--surface-chrome-solid);
}
-/* Floating overlays: dark glass (translucent `--popover`) + blur — transform-safe
- (a `fixed` gradient would break under their translate()); the translucency lets
- the theme tint through. */
+/* Floating overlays: fully OPAQUE tinted surface (`--popover`), no blur —
+ they cover arbitrary content, so nothing may bleed through. */
:is(.theme-dark, .theme-light)
:is(
[data-slot="popover-content"],
@@ -490,8 +497,13 @@
[data-slot="tooltip-content"]
) {
background: var(--popover);
- backdrop-filter: blur(16px) saturate(1.2);
- -webkit-backdrop-filter: blur(16px) saturate(1.2);
+}
+
+/* Mobile sidebar sheet (its popup's data-slot is overridden to "sidebar"):
+ opaque chrome, never a translucent veil floating over page content. */
+:is(.theme-dark, .theme-light) [data-slot="sidebar"][data-mobile="true"] {
+ background: var(--surface-chrome-solid);
+ box-shadow: var(--cm-shadow-xl);
}
/* Tabs: the default (pill) active tab uses `bg-input/30`, which is invisible over
@@ -581,10 +593,8 @@
}
}
-/* Layered shadows on the shadow-bearing slots (sm cards, lg menus, xl modals). */
-:is(.theme-dark, .theme-light) [data-slot="card"] {
- box-shadow: var(--cm-shadow-sm);
-}
+/* Layered shadows on the shadow-bearing slots (lg menus, xl modals; the card
+ shadow lives in the card rule above, merged with its hairline ring). */
:is(.theme-dark, .theme-light)
:is(
[data-slot="popover-content"],
@@ -632,12 +642,10 @@
background: var(--mod-active);
}
-/* Inputs: recessed translucent fill, restrained blur, themed focus glow. */
+/* Inputs: recessed translucent fill, themed focus glow. */
:is(.theme-dark, .theme-light)
:is([data-slot="input"], [data-slot="textarea"]) {
background: var(--input);
- backdrop-filter: blur(6px);
- -webkit-backdrop-filter: blur(6px);
}
:is(.theme-dark, .theme-light)
:is([data-slot="input"], [data-slot="textarea"]):focus-visible {
From 59200a252dbd43705af40b00e3188237703dcba2 Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Thu, 2 Jul 2026 23:01:13 +0530
Subject: [PATCH 08/16] fix(dashboard): update header transparency and backdrop
filter
---
apps/dashboard/src/styles.css | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/apps/dashboard/src/styles.css b/apps/dashboard/src/styles.css
index 170077b0..94ae196f 100644
--- a/apps/dashboard/src/styles.css
+++ b/apps/dashboard/src/styles.css
@@ -107,7 +107,8 @@
or a fully OPAQUE solid mixed from the surface tint (chrome, floating). */
--shell-scrim: rgb(0 0 0 / 0.82);
- /* chrome: sidebar darkens the shell; header + mobile sidebar are opaque */
+ /* chrome: sidebar darkens the shell; mobile sidebar is opaque; the header
+ is transparent (shell gradient shows through, blur-on-scroll only) */
--surface-chrome: rgb(0 0 0 / 0.25);
--surface-chrome-solid: color-mix(
in oklab,
@@ -478,9 +479,12 @@
inset 0 0 0 1px var(--border);
}
-/* Header: opaque chrome, same layer family as the sidebar. */
+/* Header: fully transparent — the shell gradient shows straight through. The
+ blur only becomes visible when content scrolls underneath (keeps it legible). */
:is(.theme-dark, .theme-light) header {
- background: var(--surface-chrome-solid);
+ background: transparent;
+ backdrop-filter: blur(12px) saturate(1.2);
+ -webkit-backdrop-filter: blur(12px) saturate(1.2);
}
/* Floating overlays: fully OPAQUE tinted surface (`--popover`), no blur —
@@ -499,6 +503,12 @@
background: var(--popover);
}
+/* Tooltip ships inverted colors (`bg-foreground text-background`); with its
+ background overridden to `--popover` above, its text must follow suit. */
+:is(.theme-dark, .theme-light) [data-slot="tooltip-content"] {
+ color: var(--popover-foreground);
+}
+
/* Mobile sidebar sheet (its popup's data-slot is overridden to "sidebar"):
opaque chrome, never a translucent veil floating over page content. */
:is(.theme-dark, .theme-light) [data-slot="sidebar"][data-mobile="true"] {
From eebc8b738fdb165780fbc32fc44e23aa2c58e53b Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Thu, 2 Jul 2026 23:16:19 +0530
Subject: [PATCH 09/16] feat(dashboard): add new themes
---
.../src/components/theme-provider.tsx | 24 +++-
.../dashboard/src/components/theme-toggle.tsx | 9 ++
apps/dashboard/src/styles.css | 129 ++++++++++++++++++
3 files changed, 160 insertions(+), 2 deletions(-)
diff --git a/apps/dashboard/src/components/theme-provider.tsx b/apps/dashboard/src/components/theme-provider.tsx
index 7c713751..7368c9dd 100644
--- a/apps/dashboard/src/components/theme-provider.tsx
+++ b/apps/dashboard/src/components/theme-provider.tsx
@@ -11,7 +11,16 @@ export type Theme =
| "forest"
| "dusk"
| "aurora"
- | "citrus-sherbet";
+ | "sunset"
+ | "mars"
+ | "retro-storm"
+ | "under-the-sea"
+ | "citrus-sherbet"
+ | "desert-khaki"
+ | "sunrise"
+ | "hanami"
+ | "cotton-candy"
+ | "mint-apple";
// Custom palettes are applied to as a `theme-` class (e.g.
// `theme-sepia`) — the `theme-` prefix keeps them from colliding with Tailwind
@@ -26,8 +35,19 @@ const DARK_THEMES = [
"forest",
"dusk",
"aurora",
+ "sunset",
+ "mars",
+ "retro-storm",
+ "under-the-sea",
+] as const;
+const LIGHT_THEMES = [
+ "citrus-sherbet",
+ "desert-khaki",
+ "sunrise",
+ "hanami",
+ "cotton-candy",
+ "mint-apple",
] as const;
-const LIGHT_THEMES = ["citrus-sherbet"] as const;
const CUSTOM_THEMES: readonly string[] = [...DARK_THEMES, ...LIGHT_THEMES];
type ThemeProviderProps = {
diff --git a/apps/dashboard/src/components/theme-toggle.tsx b/apps/dashboard/src/components/theme-toggle.tsx
index 68b9a8cb..86162067 100644
--- a/apps/dashboard/src/components/theme-toggle.tsx
+++ b/apps/dashboard/src/components/theme-toggle.tsx
@@ -24,7 +24,16 @@ const NITRO_THEMES: { key: Theme; label: string }[] = [
{ key: "forest", label: "Forest" },
{ key: "dusk", label: "Dusk" },
{ key: "aurora", label: "Aurora" },
+ { key: "sunset", label: "Sunset" },
+ { key: "mars", label: "Mars" },
+ { key: "retro-storm", label: "Retro Storm" },
+ { key: "under-the-sea", label: "Under the Sea" },
{ key: "citrus-sherbet", label: "Citrus Sherbet" },
+ { key: "desert-khaki", label: "Desert Khaki" },
+ { key: "sunrise", label: "Sunrise" },
+ { key: "hanami", label: "Hanami" },
+ { key: "cotton-candy", label: "Cotton Candy" },
+ { key: "mint-apple", label: "Mint Apple" },
];
export function ModeToggle() {
diff --git a/apps/dashboard/src/styles.css b/apps/dashboard/src/styles.css
index 94ae196f..81f1b1ed 100644
--- a/apps/dashboard/src/styles.css
+++ b/apps/dashboard/src/styles.css
@@ -380,6 +380,53 @@
);
}
+/* Sunset */
+.theme-sunset {
+ --theme-surface-tint: rgb(8 0 26);
+ --theme-foreground-tint: rgb(255 239 229);
+ --theme-grad-color: linear-gradient(
+ 141.68deg,
+ #48288c 27.57%,
+ #db7f4b 71.25%
+ );
+}
+
+/* Mars */
+.theme-mars {
+ --theme-surface-tint: rgb(26 6 0);
+ --theme-foreground-tint: rgb(255 236 229);
+ --theme-grad-color: linear-gradient(
+ 170.82deg,
+ #895240 14.61%,
+ #8f4343 74.62%
+ );
+}
+
+/* Retro Storm */
+.theme-retro-storm {
+ --theme-surface-tint: rgb(0 16 26);
+ --theme-foreground-tint: rgb(153 218 255);
+ --theme-grad-color: linear-gradient(
+ 148.71deg,
+ #3a7ca1 5.64%,
+ #58579a 26.38%,
+ #58579a 49.92%,
+ #3a7ca1 73.12%
+ );
+}
+
+/* Under the Sea */
+.theme-under-the-sea {
+ --theme-surface-tint: rgb(2 26 0);
+ --theme-foreground-tint: rgb(229 255 253);
+ --theme-grad-color: linear-gradient(
+ 179.14deg,
+ #647962 1.91%,
+ #588575 48.99%,
+ #6a8482 96.35%
+ );
+}
+
/* Citrus Sherbet (light) */
.theme-citrus-sherbet {
--theme-surface-tint: rgb(255 238 204);
@@ -387,6 +434,61 @@
--theme-grad-color: linear-gradient(180deg, #f3b336 31.1%, #ee8558 67.09%);
}
+/* Desert Khaki (light) */
+.theme-desert-khaki {
+ --theme-surface-tint: rgb(255 228 204);
+ --theme-foreground-tint: rgb(77 64 0);
+ --theme-grad-color: linear-gradient(
+ 38.99deg,
+ #e7dbd0 12.92%,
+ #dfd0b2 32.92%,
+ #e0d6a3 52.11%
+ );
+}
+
+/* Sunrise (light) */
+.theme-sunrise {
+ --theme-surface-tint: rgb(255 247 204);
+ --theme-foreground-tint: rgb(77 0 42);
+ --theme-grad-color: linear-gradient(
+ 154.19deg,
+ #9f4175 8.62%,
+ #c49064 48.07%,
+ #a6953d 76.04%
+ );
+}
+
+/* Hanami (light) */
+.theme-hanami {
+ --theme-surface-tint: rgb(208 255 204);
+ --theme-foreground-tint: rgb(77 0 10);
+ --theme-grad-color: linear-gradient(
+ 38.08deg,
+ #efaab3 3.56%,
+ #efd696 35.49%,
+ #a6daa2 68.78%
+ );
+}
+
+/* Cotton Candy (light) */
+.theme-cotton-candy {
+ --theme-surface-tint: rgb(204 215 255);
+ --theme-foreground-tint: rgb(77 0 14);
+ --theme-grad-color: linear-gradient(180.14deg, #f4abb8 8.5%, #b1c2fc 94.28%);
+}
+
+/* Mint Apple (light) */
+.theme-mint-apple {
+ --theme-surface-tint: rgb(232 255 204);
+ --theme-foreground-tint: rgb(0 77 58);
+ --theme-grad-color: linear-gradient(
+ 180deg,
+ #56b69f 6.15%,
+ #63bc61 48.7%,
+ #9eca67 93.07%
+ );
+}
+
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
@@ -722,3 +824,30 @@
.theme-swatch-citrus-sherbet {
background: linear-gradient(180deg, #f3b336, #ee8558);
}
+.theme-swatch-sunset {
+ background: linear-gradient(141.68deg, #48288c, #db7f4b);
+}
+.theme-swatch-mars {
+ background: linear-gradient(170.82deg, #895240, #8f4343);
+}
+.theme-swatch-retro-storm {
+ background: linear-gradient(148.71deg, #3a7ca1, #58579a, #58579a, #3a7ca1);
+}
+.theme-swatch-under-the-sea {
+ background: linear-gradient(179.14deg, #647962, #588575, #6a8482);
+}
+.theme-swatch-desert-khaki {
+ background: linear-gradient(38.99deg, #e7dbd0, #dfd0b2, #e0d6a3);
+}
+.theme-swatch-sunrise {
+ background: linear-gradient(154.19deg, #9f4175, #c49064, #a6953d);
+}
+.theme-swatch-hanami {
+ background: linear-gradient(38.08deg, #efaab3, #efd696, #a6daa2);
+}
+.theme-swatch-cotton-candy {
+ background: linear-gradient(180.14deg, #f4abb8, #b1c2fc);
+}
+.theme-swatch-mint-apple {
+ background: linear-gradient(180deg, #56b69f, #63bc61, #9eca67);
+}
From 7c1f82d9bb795333e3bf26b9e4e5f4f1d83f170e Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Thu, 2 Jul 2026 23:58:39 +0530
Subject: [PATCH 10/16] feat(dashboard): add new themes
---
.../src/components/theme-provider.tsx | 4 +++
.../dashboard/src/components/theme-toggle.tsx | 2 ++
apps/dashboard/src/styles.css | 30 +++++++++++++++++++
3 files changed, 36 insertions(+)
diff --git a/apps/dashboard/src/components/theme-provider.tsx b/apps/dashboard/src/components/theme-provider.tsx
index 7368c9dd..05caa68a 100644
--- a/apps/dashboard/src/components/theme-provider.tsx
+++ b/apps/dashboard/src/components/theme-provider.tsx
@@ -15,6 +15,8 @@ export type Theme =
| "mars"
| "retro-storm"
| "under-the-sea"
+ | "strawberry-lemonade"
+ | "neon-nights"
| "citrus-sherbet"
| "desert-khaki"
| "sunrise"
@@ -39,6 +41,8 @@ const DARK_THEMES = [
"mars",
"retro-storm",
"under-the-sea",
+ "strawberry-lemonade",
+ "neon-nights",
] as const;
const LIGHT_THEMES = [
"citrus-sherbet",
diff --git a/apps/dashboard/src/components/theme-toggle.tsx b/apps/dashboard/src/components/theme-toggle.tsx
index 86162067..88a1e8df 100644
--- a/apps/dashboard/src/components/theme-toggle.tsx
+++ b/apps/dashboard/src/components/theme-toggle.tsx
@@ -28,6 +28,8 @@ const NITRO_THEMES: { key: Theme; label: string }[] = [
{ key: "mars", label: "Mars" },
{ key: "retro-storm", label: "Retro Storm" },
{ key: "under-the-sea", label: "Under the Sea" },
+ { key: "strawberry-lemonade", label: "Strawberry Lemonade" },
+ { key: "neon-nights", label: "Neon Nights" },
{ key: "citrus-sherbet", label: "Citrus Sherbet" },
{ key: "desert-khaki", label: "Desert Khaki" },
{ key: "sunrise", label: "Sunrise" },
diff --git a/apps/dashboard/src/styles.css b/apps/dashboard/src/styles.css
index 81f1b1ed..b0b1c1a0 100644
--- a/apps/dashboard/src/styles.css
+++ b/apps/dashboard/src/styles.css
@@ -427,6 +427,30 @@
);
}
+/* Strawberry Lemonade */
+.theme-strawberry-lemonade {
+ --theme-surface-tint: rgb(26 0 14);
+ --theme-foreground-tint: rgb(255 246 229);
+ --theme-grad-color: linear-gradient(
+ 161.03deg,
+ #af1a6c 18.79%,
+ #c26b20 49.76%,
+ #e7a525 80.72%
+ );
+}
+
+/* Neon Nights */
+.theme-neon-nights {
+ --theme-surface-tint: rgb(26 0 20);
+ --theme-foreground-tint: rgb(229 255 253);
+ --theme-grad-color: linear-gradient(
+ 180deg,
+ #01a89e 0%,
+ #7d60ba 50%,
+ #b43898 100%
+ );
+}
+
/* Citrus Sherbet (light) */
.theme-citrus-sherbet {
--theme-surface-tint: rgb(255 238 204);
@@ -833,6 +857,12 @@
.theme-swatch-retro-storm {
background: linear-gradient(148.71deg, #3a7ca1, #58579a, #58579a, #3a7ca1);
}
+.theme-swatch-strawberry-lemonade {
+ background: linear-gradient(161.03deg, #af1a6c, #c26b20, #e7a525);
+}
+.theme-swatch-neon-nights {
+ background: linear-gradient(180deg, #01a89e, #7d60ba, #b43898);
+}
.theme-swatch-under-the-sea {
background: linear-gradient(179.14deg, #647962, #588575, #6a8482);
}
From 621d5ea277d49277aed347613e66e08b18c5676d Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Thu, 2 Jul 2026 23:59:49 +0530
Subject: [PATCH 11/16] feat(dashboard): add scroll area to theme dropdown
---
apps/dashboard/src/components/theme-toggle.tsx | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/apps/dashboard/src/components/theme-toggle.tsx b/apps/dashboard/src/components/theme-toggle.tsx
index 88a1e8df..2229b1a9 100644
--- a/apps/dashboard/src/components/theme-toggle.tsx
+++ b/apps/dashboard/src/components/theme-toggle.tsx
@@ -8,6 +8,7 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
+import { ScrollArea } from "@/components/ui/scroll-area";
import { cn } from "@/lib/utils";
const BASE_THEMES: { key: Theme; label: string }[] = [
@@ -67,7 +68,9 @@ export function ModeToggle() {
{BASE_THEMES.map(renderItem)}
- {NITRO_THEMES.map(renderItem)}
+
+ {NITRO_THEMES.map(renderItem)}
+
);
From 96a4a225c9f7930f82ed571b222a8aceee72343a Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Fri, 3 Jul 2026 00:00:07 +0530
Subject: [PATCH 12/16] fix(dashboard): hide native scrollbars in scroll area
to prevent double bars
---
apps/dashboard/src/styles.css | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/apps/dashboard/src/styles.css b/apps/dashboard/src/styles.css
index b0b1c1a0..d8eb7f6d 100644
--- a/apps/dashboard/src/styles.css
+++ b/apps/dashboard/src/styles.css
@@ -696,6 +696,18 @@
background-clip: padding-box;
}
+/* ScrollArea (base-ui) draws its own themed thumb; the global `*` scrollbar
+ rules above would re-force the NATIVE scrollbar onto its viewport, giving
+ double bars (and the reserved 10px width causes phantom horizontal
+ overflow). Hide native scrollbars there entirely. */
+:is(.theme-dark, .theme-light) [data-slot="scroll-area-viewport"] {
+ scrollbar-width: none;
+}
+:is(.theme-dark, .theme-light)
+ [data-slot="scroll-area-viewport"]::-webkit-scrollbar {
+ display: none;
+}
+
/* Premium hover timing (150–180ms) on the surfaces users actually touch. */
:is(.theme-dark, .theme-light)
:is(
From 846d699a1c86d34036d353977aa1a82e875e0a17 Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Fri, 3 Jul 2026 00:00:28 +0530
Subject: [PATCH 13/16] fix(dashboard): ensure tooltip colors and arrow match
popover background
---
apps/dashboard/src/styles.css | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/apps/dashboard/src/styles.css b/apps/dashboard/src/styles.css
index d8eb7f6d..527d2993 100644
--- a/apps/dashboard/src/styles.css
+++ b/apps/dashboard/src/styles.css
@@ -630,10 +630,15 @@
}
/* Tooltip ships inverted colors (`bg-foreground text-background`); with its
- background overridden to `--popover` above, its text must follow suit. */
+ background overridden to `--popover` above, its text and its arrow (the
+ little `bg-foreground fill-foreground` diamond) must follow suit. */
:is(.theme-dark, .theme-light) [data-slot="tooltip-content"] {
color: var(--popover-foreground);
}
+:is(.theme-dark, .theme-light) [data-slot="tooltip-content"] .bg-foreground {
+ background: var(--popover);
+ fill: var(--popover);
+}
/* Mobile sidebar sheet (its popup's data-slot is overridden to "sidebar"):
opaque chrome, never a translucent veil floating over page content. */
From 8119261d69fca8a93e2d1773da89e8ae26ddc530 Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Fri, 3 Jul 2026 00:08:09 +0530
Subject: [PATCH 14/16] fix(dashboard): add checkmark to active theme in
dropdown menu
---
.../dashboard/src/components/theme-toggle.tsx | 39 ++++++++++++-------
1 file changed, 25 insertions(+), 14 deletions(-)
diff --git a/apps/dashboard/src/components/theme-toggle.tsx b/apps/dashboard/src/components/theme-toggle.tsx
index 2229b1a9..49d4cb76 100644
--- a/apps/dashboard/src/components/theme-toggle.tsx
+++ b/apps/dashboard/src/components/theme-toggle.tsx
@@ -1,4 +1,4 @@
-import { Palette } from "lucide-react";
+import { Check, Palette } from "lucide-react";
import { type Theme, useTheme } from "@/components/theme-provider";
import { Button } from "@/components/ui/button";
import {
@@ -40,20 +40,31 @@ const NITRO_THEMES: { key: Theme; label: string }[] = [
];
export function ModeToggle() {
- const { setTheme } = useTheme();
+ const { theme, setTheme } = useTheme();
- const renderItem = ({ key, label }: { key: Theme; label: string }) => (
- setTheme(key)}>
-
- {label}
-
- );
+ const renderItem = ({ key, label }: { key: Theme; label: string }) => {
+ const active = theme === key;
+ return (
+ setTheme(key)}
+ >
+
+ {label}
+
+
+ );
+ };
return (
From 93fe670798afa1e94291564f37f6ee9e6f7b72ae Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Fri, 3 Jul 2026 00:09:47 +0530
Subject: [PATCH 15/16] fix(dashboard): update settings button active state
check to use startsWith
---
apps/dashboard/src/components/sidebar/app-sidebar.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/dashboard/src/components/sidebar/app-sidebar.tsx b/apps/dashboard/src/components/sidebar/app-sidebar.tsx
index 983b6a3e..1b660582 100644
--- a/apps/dashboard/src/components/sidebar/app-sidebar.tsx
+++ b/apps/dashboard/src/components/sidebar/app-sidebar.tsx
@@ -130,7 +130,7 @@ export function AppSidebar({ ...props }: ComponentProps) {
}
>
From 7575e216d2d803ed49c0fc97faab616137a60278 Mon Sep 17 00:00:00 2001
From: Krishna Santosh <75202541+krishna-santosh@users.noreply.github.com>
Date: Fri, 3 Jul 2026 10:08:17 +0530
Subject: [PATCH 16/16] fix(dashboard): replace DropdownMenuItem with
DropdownMenuRadioItem for theme selection
---
.../dashboard/src/components/theme-toggle.tsx | 30 ++++++++++---------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/apps/dashboard/src/components/theme-toggle.tsx b/apps/dashboard/src/components/theme-toggle.tsx
index 49d4cb76..f9b8e6e4 100644
--- a/apps/dashboard/src/components/theme-toggle.tsx
+++ b/apps/dashboard/src/components/theme-toggle.tsx
@@ -1,10 +1,11 @@
-import { Check, Palette } from "lucide-react";
+import { Palette } from "lucide-react";
import { type Theme, useTheme } from "@/components/theme-provider";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
- DropdownMenuItem,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
@@ -45,11 +46,10 @@ export function ModeToggle() {
const renderItem = ({ key, label }: { key: Theme; label: string }) => {
const active = theme === key;
return (
- setTheme(key)}
>
{label}
-
-
+
);
};
@@ -77,11 +74,16 @@ export function ModeToggle() {
}
/>
- {BASE_THEMES.map(renderItem)}
-
-
- {NITRO_THEMES.map(renderItem)}
-
+ setTheme(value as Theme)}
+ >
+ {BASE_THEMES.map(renderItem)}
+
+
+ {NITRO_THEMES.map(renderItem)}
+
+
);