restructure theme css
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
// Package jsruntime is the JS/TS tree of kjol: the Solid component kit, the
|
||||
// vendored Solid runtime, the FontAwesome SVG source kit, the shared Tailwind
|
||||
// @theme scaffold, and the generic TS scaffolding (auth, hooks, ssr, utils).
|
||||
// vendored Solid runtime, the FontAwesome SVG source kit, and the generic TS
|
||||
// scaffolding (auth, hooks, ssr, utils).
|
||||
//
|
||||
// The shared Tailwind design tokens are NOT here — they live in kjol/tw as the
|
||||
// extension layer (tw/kjol_theme.css), which the Tailwind engine layers between
|
||||
// its own defaults and an app's brand. See tw.CompileApp.
|
||||
//
|
||||
// It holds no Go beyond this file. The package exists so the tree has a stable
|
||||
// home inside the Go module rather than a sibling directory the build has to go
|
||||
@@ -26,9 +30,6 @@
|
||||
// per-app registry (@appgen/faIcons); the registry is app-owned and is
|
||||
// not committed here. An app's own frontend/icons is searched first, so
|
||||
// an app with a fuller kit keeps it (see jsbundler.iconsDirs).
|
||||
// styles/ theme.css — the @theme scaffold + :root fa vars, prepended to the
|
||||
// app's brand style.css by the bundler. Brand color/font tokens stay
|
||||
// app-side.
|
||||
//
|
||||
// The rest (auth/ hooks/ ssr/ utils/ env.ts basic.ts finance.ts superfun.ts) is
|
||||
// generic TS scaffolding; apps import it as @kjol/*. Concrete permission
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
/* ---------------------------------------------------------------------------
|
||||
kjol — shared Tailwind v4 scaffold for the JS (Solid) kit.
|
||||
---------------------------------------------------------------------------
|
||||
The bundler PREPENDS this file to the app's own css/style.css (see
|
||||
jsbundler/css.go), so it is the first thing the Tailwind engine sees. That is
|
||||
why the `@import "tailwindcss"` lives here rather than in the app's stylesheet:
|
||||
an @import has to come first, and the app's file no longer is.
|
||||
|
||||
An app adopting the shared tree therefore DROPS `@import "tailwindcss"` from
|
||||
its own style.css and keeps only what is genuinely its own — its brand palette,
|
||||
its fonts, its one-off rules. In single-tree mode (WebDir unset) this file is
|
||||
not prepended at all and the app's style.css stays complete, which is why
|
||||
cdrateline and Hotlap still import Tailwind themselves.
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
@import "tailwindcss";
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
Dark mode: `dark:` as a CLASS, not a media query.
|
||||
---------------------------------------------------------------------------
|
||||
Tailwind's built-in dark variant follows the operating system. A site with its
|
||||
own theme switch cannot use it: the OS says one thing, the switch says another,
|
||||
the media query wins, and the button appears to do nothing.
|
||||
|
||||
This redefines the variant against a class on <html>, which the Theme controller
|
||||
(uikit/Theme.tsx) toggles. The OS is still respected — it is the DEFAULT, applied
|
||||
by the boot script before first paint — just no longer the last word.
|
||||
--------------------------------------------------------------------------- */
|
||||
@custom-variant dark (&:where(.dark, .dark *));
|
||||
|
||||
/* Icon family for uikit/Icons.tsx, read at runtime via getComputedStyle:
|
||||
--fa-style: classic → far/fas, sharp → fasr/fass; --fa-default-solid: 0|1.
|
||||
Kept in :root (not @theme) so Tailwind doesn't tree-shake it as unused — it is
|
||||
never named by a utility class, so nothing would mark it as reachable. */
|
||||
:root {
|
||||
--fa-style: classic;
|
||||
--fa-default-solid: 0;
|
||||
}
|
||||
|
||||
@theme {
|
||||
/* Custom text sizes */
|
||||
--text-ss: 0.8rem; /* Override: Tailwind default is 0.75rem */
|
||||
|
||||
/* Custom breakpoints (Tailwind defaults + xs + ultrawide) */
|
||||
--breakpoint-xs: 375px;
|
||||
--breakpoint-sm: 640px;
|
||||
--breakpoint-md: 768px;
|
||||
--breakpoint-lg: 1024px;
|
||||
--breakpoint-xl: 1280px;
|
||||
--breakpoint-2xl: 1536px;
|
||||
--breakpoint-ultrawide: 3840px;
|
||||
|
||||
/* Custom containers */
|
||||
--container-8xl: 88rem;
|
||||
--container-9xl: 96rem;
|
||||
--container-10xl: 104rem;
|
||||
--container-ultrawide: 240rem;
|
||||
|
||||
/* Custom radius */
|
||||
--radius-default: var(--radius-sm);
|
||||
|
||||
/* ---- THE THEME CONTRACT ------------------------------------------------
|
||||
Every component in the kit says bg-surface / border-line / text-ink and
|
||||
NEVER names a colour. These are the tokens it is allowed to name.
|
||||
|
||||
That is the whole trick. A theme is the twenty values below, not a `dark:`
|
||||
variant on four hundred class strings — so switching to dark is a rule that
|
||||
re-points these, and not one component knows it happened.
|
||||
|
||||
The vocabulary is deliberately identical to the Go/WASM kit's (webui.
|
||||
ThemeTokens). Two kits, one contract: a designer changes `surface` once and
|
||||
both layers of the site move together. */
|
||||
|
||||
/* Surfaces, in ascending prominence. */
|
||||
--color-surface: #ffffff;
|
||||
--color-surface-muted: #fafafa;
|
||||
--color-surface-raised: #f5f5f5;
|
||||
--color-surface-strong: #e5e5e5;
|
||||
|
||||
/* Lines. */
|
||||
--color-line: #e5e5e5;
|
||||
--color-line-strong: #d4d4d4;
|
||||
|
||||
/* Ink, in descending prominence. */
|
||||
--color-ink: #171717;
|
||||
--color-ink-soft: #525252;
|
||||
--color-ink-muted: #737373;
|
||||
--color-ink-faint: #a3a3a3;
|
||||
|
||||
/* The solid neutral button. It INVERTS: a dark button on a light page, a light
|
||||
button on a dark one. That is why it is three tokens and not `bg-ink` — the
|
||||
text on top of it has to invert with it, and `text-white` would vanish the
|
||||
moment the fill went pale. */
|
||||
--color-fill-neutral: #404040;
|
||||
--color-fill-neutral-hover: #262626;
|
||||
--color-on-fill-neutral: #ffffff;
|
||||
|
||||
/* The accent, in four parts, because a single "brand colour" cannot do four jobs.
|
||||
Same names as the Go kit (webui.ThemeTokens) — one vocabulary, two kits.
|
||||
|
||||
primary is a FILL: it carries white text, so it has to stay dark enough for white
|
||||
to sit on it. accent is TEXT and icons: it has to stay readable ON the surface.
|
||||
One value cannot be both, and in dark mode they diverge completely — the fill
|
||||
stays put while the text has to climb.
|
||||
|
||||
primary-subtle / primary-border are the tinted panel: a callout, a selected row.
|
||||
|
||||
Brand supplies the values; see the app's style.css. These defaults keep the kit
|
||||
legible before an app has themed anything, NOT so that it can skip theming. */
|
||||
--color-primary: #404040;
|
||||
--color-primary-hover: #262626;
|
||||
--color-primary-subtle: #f5f5f5;
|
||||
--color-primary-border: #d4d4d4;
|
||||
--color-accent: #262626;
|
||||
|
||||
/* ---- deliberately-dark chrome (the kit's `onDark` prop) ----------------
|
||||
Not the same thing as dark MODE. Several components take onDark, for when
|
||||
they sit on a dark bar or panel in an otherwise light page — so these stay
|
||||
dark in BOTH themes and are not overridden below.
|
||||
|
||||
They were named by the components (bg-dark, text-text-on-dark, …) and
|
||||
defined by nobody, so until now every one of them compiled to no colour at
|
||||
all and the onDark paths silently rendered unstyled. */
|
||||
--color-dark: #101013;
|
||||
--color-dark-raised: #1f1f24;
|
||||
--color-text-on-dark: #f9fafb;
|
||||
--color-text-on-dark-muted: #9ca3af;
|
||||
--color-text-on-dark-faint: #6b7280;
|
||||
--color-border-on-dark: #2a2a30;
|
||||
|
||||
/* State colours. These DO name a colour, because they mean one: an alert that
|
||||
is not red is not an alert. Their tinted BACKGROUNDS are the one place the
|
||||
kit still carries a `dark:` variant — a red-50 wash is invisible on a near
|
||||
black surface, and no re-pointed token can fix that. */
|
||||
--color-info: var(--color-sky-500);
|
||||
--color-on-info: var(--color-white);
|
||||
--color-success: var(--color-green-500);
|
||||
--color-on-success: var(--color-white);
|
||||
--color-warning: var(--color-amber-500);
|
||||
--color-on-warning: var(--color-white);
|
||||
--color-danger: var(--color-red-500);
|
||||
--color-on-danger: var(--color-white);
|
||||
|
||||
/* ---- the categorical CHART palette -------------------------------------
|
||||
Eight fixed slots for uikit/Chart.tsx. A series is painted by its INDEX
|
||||
(slot 1, 2, 3 …) and never by a cycled/derived hue — a ninth series folds
|
||||
into "Other" rather than inventing a colour. Unlike the state colours these
|
||||
are a set, tuned as a set: the ordering maximises the minimum colour-blind
|
||||
ΔE between neighbouring slots, so adjacent series stay distinguishable under
|
||||
protanopia/deuteranopia (worst adjacent ΔE 24 in light, 10 in dark — see the
|
||||
data-viz palette validator).
|
||||
|
||||
These CAN be named in a component because a chart is SVG and SVG fills read
|
||||
CSS variables (a canvas cannot, so it would need a literal hex). The dark
|
||||
column below is the same eight hues stepped for the near-black surface, not a
|
||||
second palette. Brand overrides by redefining these (or passing `palette` to a
|
||||
single chart). */
|
||||
--color-chart-1: #2a78d6; /* blue */
|
||||
--color-chart-2: #1baf7a; /* aqua */
|
||||
--color-chart-3: #eda100; /* yellow */
|
||||
--color-chart-4: #008300; /* green */
|
||||
--color-chart-5: #4a3aa7; /* violet */
|
||||
--color-chart-6: #e34948; /* red */
|
||||
--color-chart-7: #e87ba4; /* magenta */
|
||||
--color-chart-8: #eb6834; /* orange */
|
||||
|
||||
/* Sequential ramp for the choropleth (uikit/USHeatmap): one hue, light→dark, six
|
||||
steps low→high. Unlike the categorical slots it means MAGNITUDE, so it is a single
|
||||
blue stepped by lightness. Dark mode re-points it below: on a near-black surface a
|
||||
high value must read as BRIGHTER, not darker, so the ramp inverts its lightness
|
||||
direction while keeping the same hue. */
|
||||
--color-choropleth-1: #dbe9fb;
|
||||
--color-choropleth-2: #b3d0f6;
|
||||
--color-choropleth-3: #85b3ee;
|
||||
--color-choropleth-4: #5591e4;
|
||||
--color-choropleth-5: #2f6fca;
|
||||
--color-choropleth-6: #124f8f;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
The dark theme.
|
||||
---------------------------------------------------------------------------
|
||||
Only the token VALUES change. Not one component knows this block exists — they
|
||||
ask for bg-surface and text-ink, and here is where those come to mean something
|
||||
else.
|
||||
|
||||
This is a plain rule, not another @theme block: @theme GENERATES utilities, and
|
||||
these are overrides of utilities that already exist.
|
||||
|
||||
The surfaces are not pure black. Black gives a dark UI a hard, glaring edge
|
||||
against white text and makes every border invisible; a very dark grey leaves room
|
||||
for the raised surfaces and the lines above it to actually be seen.
|
||||
--------------------------------------------------------------------------- */
|
||||
.dark {
|
||||
--color-surface: #101013;
|
||||
--color-surface-muted: #17171b;
|
||||
--color-surface-raised: #1f1f24;
|
||||
--color-surface-strong: #2c2c33;
|
||||
|
||||
--color-line: #2a2a30;
|
||||
--color-line-strong: #3d3d45;
|
||||
|
||||
--color-ink: #f2f2f3;
|
||||
--color-ink-soft: #c6c6cc;
|
||||
--color-ink-muted: #9a9aa3;
|
||||
--color-ink-faint: #71717a;
|
||||
|
||||
/* Inverted, as promised above: pale fill, dark text. */
|
||||
--color-fill-neutral: #e5e5e5;
|
||||
--color-fill-neutral-hover: #ffffff;
|
||||
--color-on-fill-neutral: #171717;
|
||||
|
||||
/* The fill stays where it is — white text still has to be readable on it — but the
|
||||
tinted panel and the accent TEXT both have to move, or they vanish into a near
|
||||
black surface. This is exactly why they are separate tokens. */
|
||||
--color-primary-subtle: #1f1f24;
|
||||
--color-primary-border: #3d3d45;
|
||||
--color-accent: #e5e5e5;
|
||||
|
||||
/* The chart palette, re-stepped for the dark surface. Same eight hues, lifted
|
||||
into the dark-mode lightness band so every slot clears 3:1 against #101013 —
|
||||
a light-mode aqua or yellow would sink into the surface. Validated as a set
|
||||
against the dark surface, exactly as the light column was against white. */
|
||||
--color-chart-1: #3987e5;
|
||||
--color-chart-2: #199e70;
|
||||
--color-chart-3: #c98500;
|
||||
--color-chart-4: #008300;
|
||||
--color-chart-5: #9085e9;
|
||||
--color-chart-6: #e66767;
|
||||
--color-chart-7: #d55181;
|
||||
--color-chart-8: #d95926;
|
||||
|
||||
/* Same blue hue, stepped for the dark surface and inverted in direction: step 1 (low)
|
||||
is the dimmest, step 6 (high) the brightest, so "more" reads as "brighter". */
|
||||
--color-choropleth-1: #1b2a44;
|
||||
--color-choropleth-2: #21406c;
|
||||
--color-choropleth-3: #2c5f97;
|
||||
--color-choropleth-4: #3f80c8;
|
||||
--color-choropleth-5: #649de8;
|
||||
--color-choropleth-6: #93c2f7;
|
||||
}
|
||||
|
||||
/* The page's own background — painted before anything mounts, and behind it
|
||||
afterwards. Without this a dark app sits in a white window. */
|
||||
html {
|
||||
background-color: var(--color-surface);
|
||||
color: var(--color-ink);
|
||||
}
|
||||
Reference in New Issue
Block a user