From b106f67288bce838a794832c37ecf97abe33a657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Mon, 17 Aug 2026 00:49:13 +0000 Subject: [PATCH] twenty tokens is the contract; eleven palettes prove it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Officer now ships fourteen themes. Eleven of them were written by other people, ported unchanged, and none of them knows that panels, docks, glass, grids or scrollbars exist. ── What changed ── `base.css` derives every surface from the standard tokens: a panel is `card` at 92%, the header is `card` at 85%, grid lines are `border` faded, scrollbars are `muted-foreground`. Those defaults sit on `:root`; a theme sits on `[data-theme='x']` and both land on , so a theme's own declaration simply outranks them. No machinery. State tones are defaulted too — shadcn's vocabulary has `destructive` and nothing else, and green-means-good is a convention rather than a palette decision. That is what drops the required contract from 29 to 20: exactly the tokens every published shadcn palette already ships. So there are now three tiers, and an author picks one: palette 20 tokens Tokyo Night, Gruvbox, Nord — surfaces derived textured + a few surfaces glass, blur, radius, a wallpaper of its own white-label + assets its own logo and background Duck is tier three and is untouched — verified by probe: it still reports `panel=#ffffff1f`, `blur=24px` and its own grid, because its declarations outrank the new defaults. ── Verified before committing, not assumed ── The whole HSL-triplet design existed to make `bg-card/50` work. Tested it: Tailwind v4 emits `color-mix(in oklab, var(--card) 50%, transparent)` for a HEX token, with a `@supports` fallback. The unwrapped triplets were never necessary, and the ported palettes are plain hex. Six themes probed in the browser: each derives panels from its own card colour, including the light one (Catppuccin Latte). ── Credit ── The eleven palettes and the idea of a small standard contract come from the owner's `vimazing` repository, which solved this more simply than we had. What Officer adds is the surface layer underneath, so a palette gets a textured app for free. ── One open decision ── `--logo-src` defaults to empty, so a palette theme shows no mark at all. Correct for a third-party theme; probably wrong for Officer, where the alternative is defaulting to the officer.dev logo and letting a white-label theme replace it. One line either way. tsgo clean, suite unchanged, builds. Co-Authored-By: Claude Opus 5 --- src/workspaces/theme/css/base.css | 118 ++++++++++++++++++ src/workspaces/theme/css/index.css | 13 ++ .../theme/css/themes/catppuccin-latte.css | 45 +++++++ .../theme/css/themes/catppuccin-mocha.css | 45 +++++++ .../theme/css/themes/everforest.css | 45 +++++++ src/workspaces/theme/css/themes/gruvbox.css | 45 +++++++ src/workspaces/theme/css/themes/kanagawa.css | 45 +++++++ .../theme/css/themes/matte-black.css | 45 +++++++ src/workspaces/theme/css/themes/nord.css | 45 +++++++ .../theme/css/themes/osaka-jade.css | 45 +++++++ src/workspaces/theme/css/themes/ristretto.css | 45 +++++++ src/workspaces/theme/css/themes/rose-pine.css | 45 +++++++ .../theme/css/themes/tokyo-night.css | 45 +++++++ src/workspaces/theme/src/themes.ts | 19 +++ 14 files changed, 645 insertions(+) create mode 100644 src/workspaces/theme/css/themes/catppuccin-latte.css create mode 100644 src/workspaces/theme/css/themes/catppuccin-mocha.css create mode 100644 src/workspaces/theme/css/themes/everforest.css create mode 100644 src/workspaces/theme/css/themes/gruvbox.css create mode 100644 src/workspaces/theme/css/themes/kanagawa.css create mode 100644 src/workspaces/theme/css/themes/matte-black.css create mode 100644 src/workspaces/theme/css/themes/nord.css create mode 100644 src/workspaces/theme/css/themes/osaka-jade.css create mode 100644 src/workspaces/theme/css/themes/ristretto.css create mode 100644 src/workspaces/theme/css/themes/rose-pine.css create mode 100644 src/workspaces/theme/css/themes/tokyo-night.css diff --git a/src/workspaces/theme/css/base.css b/src/workspaces/theme/css/base.css index cb918747..18bdb1fd 100644 --- a/src/workspaces/theme/css/base.css +++ b/src/workspaces/theme/css/base.css @@ -192,3 +192,121 @@ background-size: cover; } } + +/* + DERIVED SURFACES — the defaults that make a 29-value theme a complete one. + ============================================================================================ + + A theme is required to supply the 29 standard tokens: shadcn's 20 plus the state tones shadcn lacks + (success, warning, info, busy). Everything below is then computed from them, so a palette-only theme — + Tokyo Night, Gruvbox, anything published in the shadcn vocabulary — renders a complete application + without knowing that panels, docks, glass or scrollbars exist. + + ── How an override works ── + + These live on `:root`; a theme lives on `[data-theme='x']`, and both land on the same element. A + theme's own declaration is more specific, so it simply wins. Nothing here has to know which themes exist, + and a theme only declares what it actually cares about. + + That is the difference between a contract of 29 and a contract of 84. Duck has a TEXTURE — glass over a + photograph — and declares its surfaces. Tokyo Night has a palette and declares none of them. + + `color-mix` rather than opacity variants because these are complete CSS values: a surface may be a + gradient or an image in a theme that wants one, and an alpha channel cannot express that. +*/ +@layer base { + :root { + /* + State tones, which shadcn's vocabulary does not have. + + Defaulted rather than required, because green-means-good is a convention rather than a palette + decision, and a theme published elsewhere will never have thought about them. A theme that cares + overrides; every ported palette gets something legible for free. + + This is what drops the required contract from 29 to 20 — the twenty tokens every shadcn palette + already ships. + */ + --success: #16a34a; + --success-foreground: #ffffff; + --warning: #f59e0b; + --warning-foreground: #1c1917; + --info: #6366f1; + --info-foreground: #ffffff; + --busy: #f59e0b; + --busy-foreground: #1c1917; + --busy-ink: #b45309; + + /* The page */ + --page-bg: var(--background); + --page-bg-src: ''; + --pixel-grid-color: color-mix(in srgb, var(--border) 35%, transparent); + + /* Panels — the cornerstone of the layout */ + --panel-bg: color-mix(in srgb, var(--card) 92%, transparent); + --panel-border: var(--border); + --panel-border-bare: var(--border); + --panel-raised-bg: var(--card); + --panel-raised-border: var(--border); + --panel-radius: var(--radius); + --panel-blur: 0px; + --panel-header-bg: color-mix(in srgb, var(--muted) 60%, transparent); + --panel-header-fg: var(--foreground); + --panel-accent: var(--primary); + --panel-grid-color: color-mix(in srgb, var(--border) 25%, transparent); + + /* The header */ + --header-bg: color-mix(in srgb, var(--card) 85%, transparent); + --header-border: var(--border); + --header-fg: var(--foreground); + --header-blur: 0px; + + /* Other surfaces */ + --glass-bg: color-mix(in srgb, var(--card) 75%, transparent); + --glass-border: var(--border); + --dock-bg: color-mix(in srgb, var(--card) 85%, transparent); + --dock-border: var(--border); + --dock-tooltip-bg: var(--popover); + --card-bg: var(--card); + --card-grid-color: color-mix(in srgb, var(--border) 25%, transparent); + + /* Chrome */ + --scrollbar-thumb: color-mix(in srgb, var(--muted-foreground) 60%, transparent); + --scrollbar-thumb-hover: var(--muted-foreground); + --scrollbar-thin-thumb: color-mix(in srgb, var(--muted-foreground) 40%, transparent); + --scrollbar-thin-thumb-hover: color-mix(in srgb, var(--muted-foreground) 70%, transparent); + + /* The mark. Empty is correct: a theme that ships no logo should show none rather than someone else's. */ + --logo-src: ''; + + /* Brand slots, until the `duck-*` utilities are renamed. A palette theme should never think about these. */ + --brand-primary: var(--primary); + --brand-accent: var(--accent); + --brand-warm: var(--destructive); + --brand-deep: var(--primary); + --ink: var(--foreground); + --surface-warm: var(--muted); + --duck-teal: var(--brand-primary); + --duck-dark: var(--ink); + --duck-yellow: var(--brand-accent); + --duck-forest: var(--brand-deep); + --duck-beige: var(--surface-warm); + --duck-orange: var(--brand-warm); + + /* Officer leftovers, kept alive until their few call sites go. */ + --cta: var(--primary); + --cta-foreground: var(--primary-foreground); + --ctahover: var(--primary); + --naturegreen: var(--success); + --naturegreen-foreground: var(--success-foreground); + --brand: var(--primary); + --brand-foreground: var(--primary-foreground); + --brand-muted: color-mix(in srgb, var(--primary) 20%, transparent); + + /* Data, when a theme has not said. */ + --chart-primary: var(--primary); + --chart-secondary: color-mix(in srgb, var(--primary) 50%, transparent); + --status-success: var(--success); + --status-warning: var(--warning); + --status-in-progress: var(--info); + } +} diff --git a/src/workspaces/theme/css/index.css b/src/workspaces/theme/css/index.css index cd933494..c06dd520 100644 --- a/src/workspaces/theme/css/index.css +++ b/src/workspaces/theme/css/index.css @@ -17,4 +17,17 @@ @import './themes/duck-dark.css'; @import './themes/plain.css'; +/* Palette themes — 20 standard tokens each, every surface derived. */ +@import './themes/tokyo-night.css'; +@import './themes/catppuccin-mocha.css'; +@import './themes/catppuccin-latte.css'; +@import './themes/everforest.css'; +@import './themes/gruvbox.css'; +@import './themes/kanagawa.css'; +@import './themes/matte-black.css'; +@import './themes/nord.css'; +@import './themes/osaka-jade.css'; +@import './themes/ristretto.css'; +@import './themes/rose-pine.css'; + @import './chrome.css'; diff --git a/src/workspaces/theme/css/themes/catppuccin-latte.css b/src/workspaces/theme/css/themes/catppuccin-latte.css new file mode 100644 index 00000000..9942ae27 --- /dev/null +++ b/src/workspaces/theme/css/themes/catppuccin-latte.css @@ -0,0 +1,45 @@ +/* + CATPPUCCIN LATTE — ported from the published palette, unchanged. + + A PALETTE theme: it supplies the standard tokens and nothing else. Panels, the header, the dock, glass, + grid lines and scrollbars are all derived from these by `base.css`, so this file never mentions them. + + That is the contract working as intended — a theme anyone has already written, dropped in whole. Compare + `duck-*.css`, which additionally declares a texture. +*/ + +[data-theme='catppuccin-latte'] { + --radius: 0.625rem; + --background: #eff1f5; + --foreground: #4c4f69; + --card: #e6e9ef; + --card-foreground: #4c4f69; + --popover: #e6e9ef; + --popover-foreground: #4c4f69; + --primary: #1e66f5; + --primary-foreground: #eff1f5; + --secondary: #ccd0da; + --secondary-foreground: #4c4f69; + --muted: #dce0e8; + --muted-foreground: #6c6f85; + --accent: #04a5e5; + --accent-foreground: #eff1f5; + --destructive: #d20f39; + --destructive-foreground: #eff1f5; + --border: #ccd0da; + --input: #ccd0da; + --ring: #1e66f5; + --chart-1: #1e66f5; + --chart-2: #df8e1d; + --chart-3: #40a02b; + --chart-4: #179299; + --chart-5: #8839ef; + --sidebar: #e6e9ef; + --sidebar-foreground: #6c6f85; + --sidebar-primary: #1e66f5; + --sidebar-primary-foreground: #eff1f5; + --sidebar-accent: #dce0e8; + --sidebar-accent-foreground: #4c4f69; + --sidebar-border: #ccd0da; + --sidebar-ring: #1e66f5; +} diff --git a/src/workspaces/theme/css/themes/catppuccin-mocha.css b/src/workspaces/theme/css/themes/catppuccin-mocha.css new file mode 100644 index 00000000..3087ba49 --- /dev/null +++ b/src/workspaces/theme/css/themes/catppuccin-mocha.css @@ -0,0 +1,45 @@ +/* + CATPPUCCIN MOCHA — ported from the published palette, unchanged. + + A PALETTE theme: it supplies the standard tokens and nothing else. Panels, the header, the dock, glass, + grid lines and scrollbars are all derived from these by `base.css`, so this file never mentions them. + + That is the contract working as intended — a theme anyone has already written, dropped in whole. Compare + `duck-*.css`, which additionally declares a texture. +*/ + +[data-theme='catppuccin-mocha'] { + --radius: 0.625rem; + --background: #1e1e2e; + --foreground: #cdd6f4; + --card: #181825; + --card-foreground: #cdd6f4; + --popover: #181825; + --popover-foreground: #cdd6f4; + --primary: #89b4fa; + --primary-foreground: #1e1e2e; + --secondary: #45475a; + --secondary-foreground: #cdd6f4; + --muted: #313244; + --muted-foreground: #7f849c; + --accent: #89dceb; + --accent-foreground: #1e1e2e; + --destructive: #f38ba8; + --destructive-foreground: #1e1e2e; + --border: #45475a; + --input: #45475a; + --ring: #89b4fa; + --chart-1: #89b4fa; + --chart-2: #f9e2af; + --chart-3: #a6e3a1; + --chart-4: #94e2d5; + --chart-5: #cba6f7; + --sidebar: #181825; + --sidebar-foreground: #7f849c; + --sidebar-primary: #89b4fa; + --sidebar-primary-foreground: #1e1e2e; + --sidebar-accent: #313244; + --sidebar-accent-foreground: #cdd6f4; + --sidebar-border: #45475a; + --sidebar-ring: #89b4fa; +} diff --git a/src/workspaces/theme/css/themes/everforest.css b/src/workspaces/theme/css/themes/everforest.css new file mode 100644 index 00000000..d9fd595a --- /dev/null +++ b/src/workspaces/theme/css/themes/everforest.css @@ -0,0 +1,45 @@ +/* + EVERFOREST — ported from the published palette, unchanged. + + A PALETTE theme: it supplies the standard tokens and nothing else. Panels, the header, the dock, glass, + grid lines and scrollbars are all derived from these by `base.css`, so this file never mentions them. + + That is the contract working as intended — a theme anyone has already written, dropped in whole. Compare + `duck-*.css`, which additionally declares a texture. +*/ + +[data-theme='everforest'] { + --radius: 0.625rem; + --background: #2d353b; + --foreground: #d3c6aa; + --card: #272e33; + --card-foreground: #d3c6aa; + --popover: #272e33; + --popover-foreground: #d3c6aa; + --primary: #a7c080; + --primary-foreground: #2d353b; + --secondary: #3d484d; + --secondary-foreground: #d3c6aa; + --muted: #374247; + --muted-foreground: #859289; + --accent: #83c092; + --accent-foreground: #2d353b; + --destructive: #e67e80; + --destructive-foreground: #d3c6aa; + --border: #3d484d; + --input: #3d484d; + --ring: #a7c080; + --chart-1: #a7c080; + --chart-2: #dbbc7f; + --chart-3: #83c092; + --chart-4: #7fbbb3; + --chart-5: #d699b6; + --sidebar: #272e33; + --sidebar-foreground: #859289; + --sidebar-primary: #a7c080; + --sidebar-primary-foreground: #2d353b; + --sidebar-accent: #374247; + --sidebar-accent-foreground: #d3c6aa; + --sidebar-border: #3d484d; + --sidebar-ring: #a7c080; +} diff --git a/src/workspaces/theme/css/themes/gruvbox.css b/src/workspaces/theme/css/themes/gruvbox.css new file mode 100644 index 00000000..bab45756 --- /dev/null +++ b/src/workspaces/theme/css/themes/gruvbox.css @@ -0,0 +1,45 @@ +/* + GRUVBOX — ported from the published palette, unchanged. + + A PALETTE theme: it supplies the standard tokens and nothing else. Panels, the header, the dock, glass, + grid lines and scrollbars are all derived from these by `base.css`, so this file never mentions them. + + That is the contract working as intended — a theme anyone has already written, dropped in whole. Compare + `duck-*.css`, which additionally declares a texture. +*/ + +[data-theme='gruvbox'] { + --radius: 0.625rem; + --background: #282828; + --foreground: #ebdbb2; + --card: #1d2021; + --card-foreground: #ebdbb2; + --popover: #1d2021; + --popover-foreground: #ebdbb2; + --primary: #83a598; + --primary-foreground: #282828; + --secondary: #504945; + --secondary-foreground: #ebdbb2; + --muted: #3c3836; + --muted-foreground: #a89984; + --accent: #8ec07c; + --accent-foreground: #282828; + --destructive: #fb4934; + --destructive-foreground: #ebdbb2; + --border: #504945; + --input: #504945; + --ring: #83a598; + --chart-1: #83a598; + --chart-2: #fabd2f; + --chart-3: #b8bb26; + --chart-4: #8ec07c; + --chart-5: #d3869b; + --sidebar: #1d2021; + --sidebar-foreground: #a89984; + --sidebar-primary: #83a598; + --sidebar-primary-foreground: #282828; + --sidebar-accent: #3c3836; + --sidebar-accent-foreground: #ebdbb2; + --sidebar-border: #504945; + --sidebar-ring: #83a598; +} diff --git a/src/workspaces/theme/css/themes/kanagawa.css b/src/workspaces/theme/css/themes/kanagawa.css new file mode 100644 index 00000000..5e7627e3 --- /dev/null +++ b/src/workspaces/theme/css/themes/kanagawa.css @@ -0,0 +1,45 @@ +/* + KANAGAWA — ported from the published palette, unchanged. + + A PALETTE theme: it supplies the standard tokens and nothing else. Panels, the header, the dock, glass, + grid lines and scrollbars are all derived from these by `base.css`, so this file never mentions them. + + That is the contract working as intended — a theme anyone has already written, dropped in whole. Compare + `duck-*.css`, which additionally declares a texture. +*/ + +[data-theme='kanagawa'] { + --radius: 0.625rem; + --background: #1f1f28; + --foreground: #dcd7ba; + --card: #16161d; + --card-foreground: #dcd7ba; + --popover: #16161d; + --popover-foreground: #dcd7ba; + --primary: #7e9cd8; + --primary-foreground: #1f1f28; + --secondary: #2a2a37; + --secondary-foreground: #dcd7ba; + --muted: #223249; + --muted-foreground: #727169; + --accent: #7fb4ca; + --accent-foreground: #1f1f28; + --destructive: #e82424; + --destructive-foreground: #dcd7ba; + --border: #2a2a37; + --input: #2a2a37; + --ring: #7e9cd8; + --chart-1: #7e9cd8; + --chart-2: #ffa066; + --chart-3: #98bb6c; + --chart-4: #7aa89f; + --chart-5: #957fb8; + --sidebar: #16161d; + --sidebar-foreground: #727169; + --sidebar-primary: #7e9cd8; + --sidebar-primary-foreground: #1f1f28; + --sidebar-accent: #223249; + --sidebar-accent-foreground: #dcd7ba; + --sidebar-border: #2a2a37; + --sidebar-ring: #7e9cd8; +} diff --git a/src/workspaces/theme/css/themes/matte-black.css b/src/workspaces/theme/css/themes/matte-black.css new file mode 100644 index 00000000..c9c29a8c --- /dev/null +++ b/src/workspaces/theme/css/themes/matte-black.css @@ -0,0 +1,45 @@ +/* + MATTE BLACK — ported from the published palette, unchanged. + + A PALETTE theme: it supplies the standard tokens and nothing else. Panels, the header, the dock, glass, + grid lines and scrollbars are all derived from these by `base.css`, so this file never mentions them. + + That is the contract working as intended — a theme anyone has already written, dropped in whole. Compare + `duck-*.css`, which additionally declares a texture. +*/ + +[data-theme='matte-black'] { + --radius: 0.625rem; + --background: #0a0a0a; + --foreground: #e0e0e0; + --card: #121212; + --card-foreground: #e0e0e0; + --popover: #121212; + --popover-foreground: #e0e0e0; + --primary: #ffffff; + --primary-foreground: #0a0a0a; + --secondary: #2a2a2a; + --secondary-foreground: #e0e0e0; + --muted: #1a1a1a; + --muted-foreground: #9a9a9a; + --accent: #d0d0d0; + --accent-foreground: #0a0a0a; + --destructive: #ff4444; + --destructive-foreground: #e0e0e0; + --border: #2a2a2a; + --input: #2a2a2a; + --ring: #ffffff; + --chart-1: #ffffff; + --chart-2: #cccccc; + --chart-3: #999999; + --chart-4: #666666; + --chart-5: #444444; + --sidebar: #121212; + --sidebar-foreground: #9a9a9a; + --sidebar-primary: #ffffff; + --sidebar-primary-foreground: #0a0a0a; + --sidebar-accent: #1a1a1a; + --sidebar-accent-foreground: #e0e0e0; + --sidebar-border: #2a2a2a; + --sidebar-ring: #ffffff; +} diff --git a/src/workspaces/theme/css/themes/nord.css b/src/workspaces/theme/css/themes/nord.css new file mode 100644 index 00000000..702c3a96 --- /dev/null +++ b/src/workspaces/theme/css/themes/nord.css @@ -0,0 +1,45 @@ +/* + NORD — ported from the published palette, unchanged. + + A PALETTE theme: it supplies the standard tokens and nothing else. Panels, the header, the dock, glass, + grid lines and scrollbars are all derived from these by `base.css`, so this file never mentions them. + + That is the contract working as intended — a theme anyone has already written, dropped in whole. Compare + `duck-*.css`, which additionally declares a texture. +*/ + +[data-theme='nord'] { + --radius: 0.625rem; + --background: #2e3440; + --foreground: #eceff4; + --card: #3b4252; + --card-foreground: #eceff4; + --popover: #3b4252; + --popover-foreground: #eceff4; + --primary: #88c0d0; + --primary-foreground: #2e3440; + --secondary: #434c5e; + --secondary-foreground: #eceff4; + --muted: #3b4252; + --muted-foreground: #d8dee9; + --accent: #8fbcbb; + --accent-foreground: #2e3440; + --destructive: #bf616a; + --destructive-foreground: #eceff4; + --border: #434c5e; + --input: #434c5e; + --ring: #88c0d0; + --chart-1: #88c0d0; + --chart-2: #ebcb8b; + --chart-3: #a3be8c; + --chart-4: #8fbcbb; + --chart-5: #b48ead; + --sidebar: #3b4252; + --sidebar-foreground: #d8dee9; + --sidebar-primary: #88c0d0; + --sidebar-primary-foreground: #2e3440; + --sidebar-accent: #434c5e; + --sidebar-accent-foreground: #eceff4; + --sidebar-border: #4c566a; + --sidebar-ring: #88c0d0; +} diff --git a/src/workspaces/theme/css/themes/osaka-jade.css b/src/workspaces/theme/css/themes/osaka-jade.css new file mode 100644 index 00000000..ca6fefd1 --- /dev/null +++ b/src/workspaces/theme/css/themes/osaka-jade.css @@ -0,0 +1,45 @@ +/* + OSAKA JADE — ported from the published palette, unchanged. + + A PALETTE theme: it supplies the standard tokens and nothing else. Panels, the header, the dock, glass, + grid lines and scrollbars are all derived from these by `base.css`, so this file never mentions them. + + That is the contract working as intended — a theme anyone has already written, dropped in whole. Compare + `duck-*.css`, which additionally declares a texture. +*/ + +[data-theme='osaka-jade'] { + --radius: 0.625rem; + --background: #1a1b26; + --foreground: #c5cdd9; + --card: #16161e; + --card-foreground: #c5cdd9; + --popover: #16161e; + --popover-foreground: #c5cdd9; + --primary: #2ac3de; + --primary-foreground: #1a1b26; + --secondary: #292e42; + --secondary-foreground: #c5cdd9; + --muted: #1f2335; + --muted-foreground: #565f89; + --accent: #0db9d7; + --accent-foreground: #1a1b26; + --destructive: #f7768e; + --destructive-foreground: #c5cdd9; + --border: #292e42; + --input: #292e42; + --ring: #2ac3de; + --chart-1: #2ac3de; + --chart-2: #e0af68; + --chart-3: #9ece6a; + --chart-4: #1abc9c; + --chart-5: #bb9af7; + --sidebar: #16161e; + --sidebar-foreground: #565f89; + --sidebar-primary: #2ac3de; + --sidebar-primary-foreground: #1a1b26; + --sidebar-accent: #1f2335; + --sidebar-accent-foreground: #c5cdd9; + --sidebar-border: #292e42; + --sidebar-ring: #2ac3de; +} diff --git a/src/workspaces/theme/css/themes/ristretto.css b/src/workspaces/theme/css/themes/ristretto.css new file mode 100644 index 00000000..678e215d --- /dev/null +++ b/src/workspaces/theme/css/themes/ristretto.css @@ -0,0 +1,45 @@ +/* + RISTRETTO — ported from the published palette, unchanged. + + A PALETTE theme: it supplies the standard tokens and nothing else. Panels, the header, the dock, glass, + grid lines and scrollbars are all derived from these by `base.css`, so this file never mentions them. + + That is the contract working as intended — a theme anyone has already written, dropped in whole. Compare + `duck-*.css`, which additionally declares a texture. +*/ + +[data-theme='ristretto'] { + --radius: 0.625rem; + --background: #403d39; + --foreground: #ebe5df; + --card: #352f2a; + --card-foreground: #ebe5df; + --popover: #352f2a; + --popover-foreground: #ebe5df; + --primary: #fc9867; + --primary-foreground: #403d39; + --secondary: #5f574f; + --secondary-foreground: #ebe5df; + --muted: #4d4743; + --muted-foreground: #ada49d; + --accent: #fbb360; + --accent-foreground: #403d39; + --destructive: #d76c6c; + --destructive-foreground: #ebe5df; + --border: #5f574f; + --input: #5f574f; + --ring: #fc9867; + --chart-1: #fc9867; + --chart-2: #fbb360; + --chart-3: #8ca589; + --chart-4: #86a3a3; + --chart-5: #a38dac; + --sidebar: #352f2a; + --sidebar-foreground: #ada49d; + --sidebar-primary: #fc9867; + --sidebar-primary-foreground: #403d39; + --sidebar-accent: #4d4743; + --sidebar-accent-foreground: #ebe5df; + --sidebar-border: #5f574f; + --sidebar-ring: #fc9867; +} diff --git a/src/workspaces/theme/css/themes/rose-pine.css b/src/workspaces/theme/css/themes/rose-pine.css new file mode 100644 index 00000000..7c9ee88e --- /dev/null +++ b/src/workspaces/theme/css/themes/rose-pine.css @@ -0,0 +1,45 @@ +/* + ROSÉ PINE — ported from the published palette, unchanged. + + A PALETTE theme: it supplies the standard tokens and nothing else. Panels, the header, the dock, glass, + grid lines and scrollbars are all derived from these by `base.css`, so this file never mentions them. + + That is the contract working as intended — a theme anyone has already written, dropped in whole. Compare + `duck-*.css`, which additionally declares a texture. +*/ + +[data-theme='rose-pine'] { + --radius: 0.625rem; + --background: #191724; + --foreground: #e0def4; + --card: #1f1d2e; + --card-foreground: #e0def4; + --popover: #1f1d2e; + --popover-foreground: #e0def4; + --primary: #c4a7e7; + --primary-foreground: #191724; + --secondary: #26233a; + --secondary-foreground: #e0def4; + --muted: #26233a; + --muted-foreground: #908caa; + --accent: #ebbcba; + --accent-foreground: #191724; + --destructive: #eb6f92; + --destructive-foreground: #e0def4; + --border: #26233a; + --input: #26233a; + --ring: #c4a7e7; + --chart-1: #c4a7e7; + --chart-2: #f6c177; + --chart-3: #9ccfd8; + --chart-4: #31748f; + --chart-5: #eb6f92; + --sidebar: #1f1d2e; + --sidebar-foreground: #908caa; + --sidebar-primary: #c4a7e7; + --sidebar-primary-foreground: #191724; + --sidebar-accent: #26233a; + --sidebar-accent-foreground: #e0def4; + --sidebar-border: #403d52; + --sidebar-ring: #c4a7e7; +} diff --git a/src/workspaces/theme/css/themes/tokyo-night.css b/src/workspaces/theme/css/themes/tokyo-night.css new file mode 100644 index 00000000..cc13564b --- /dev/null +++ b/src/workspaces/theme/css/themes/tokyo-night.css @@ -0,0 +1,45 @@ +/* + TOKYO NIGHT — ported from the published palette, unchanged. + + A PALETTE theme: it supplies the standard tokens and nothing else. Panels, the header, the dock, glass, + grid lines and scrollbars are all derived from these by `base.css`, so this file never mentions them. + + That is the contract working as intended — a theme anyone has already written, dropped in whole. Compare + `duck-*.css`, which additionally declares a texture. +*/ + +[data-theme='tokyo-night'] { + --radius: 0.625rem; + --background: #222436; + --foreground: #c8d3f5; + --card: #1e2030; + --card-foreground: #c8d3f5; + --popover: #1e2030; + --popover-foreground: #c8d3f5; + --primary: #82aaff; + --primary-foreground: #1b1d2b; + --secondary: #3b4261; + --secondary-foreground: #c8d3f5; + --muted: #2f334d; + --muted-foreground: #828bb8; + --accent: #86e1fc; + --accent-foreground: #1b1d2b; + --destructive: #c53b53; + --destructive-foreground: #c8d3f5; + --border: #3b4261; + --input: #3b4261; + --ring: #82aaff; + --chart-1: #82aaff; + --chart-2: #ffc777; + --chart-3: #c3e88d; + --chart-4: #4fd6be; + --chart-5: #c099ff; + --sidebar: #1e2030; + --sidebar-foreground: #828bb8; + --sidebar-primary: #82aaff; + --sidebar-primary-foreground: #1b1d2b; + --sidebar-accent: #2f334d; + --sidebar-accent-foreground: #c8d3f5; + --sidebar-border: #3b4261; + --sidebar-ring: #82aaff; +} diff --git a/src/workspaces/theme/src/themes.ts b/src/workspaces/theme/src/themes.ts index f4ffff1f..8d2f1360 100644 --- a/src/workspaces/theme/src/themes.ts +++ b/src/workspaces/theme/src/themes.ts @@ -36,6 +36,25 @@ export const THEMES: readonly Theme[] = [ // and Plain exists to show what the app looks like without any of them. applyDarkClass: false, }, + + /* + Palette themes, ported unchanged from published colour schemes. Each supplies only the standard tokens; + `base.css` derives panels, header, dock, glass, grid and scrollbars from them. + + `applyDarkClass` is set for the dark ones so the 396 `dark:` utilities still written into components + resolve. It says nothing about the theme beyond "treat this as a dark ground". + */ + { id: 'tokyo-night', name: 'Tokyo Night', family: 'Tokyo Night', applyDarkClass: true }, + { id: 'catppuccin-mocha', name: 'Catppuccin Mocha', family: 'Catppuccin', applyDarkClass: true }, + { id: 'catppuccin-latte', name: 'Catppuccin Latte', family: 'Catppuccin', applyDarkClass: false }, + { id: 'everforest', name: 'Everforest', family: 'Everforest', applyDarkClass: true }, + { id: 'gruvbox', name: 'Gruvbox', family: 'Gruvbox', applyDarkClass: true }, + { id: 'kanagawa', name: 'Kanagawa', family: 'Kanagawa', applyDarkClass: true }, + { id: 'matte-black', name: 'Matte Black', family: 'Matte Black', applyDarkClass: true }, + { id: 'nord', name: 'Nord', family: 'Nord', applyDarkClass: true }, + { id: 'osaka-jade', name: 'Osaka Jade', family: 'Osaka Jade', applyDarkClass: true }, + { id: 'ristretto', name: 'Ristretto', family: 'Ristretto', applyDarkClass: true }, + { id: 'rose-pine', name: 'Rosé Pine', family: 'Rosé Pine', applyDarkClass: true }, ] as const; /** What the app wears when nobody has chosen — its appearance before this refactor. */