diff --git a/website/AGENTS.md b/website/AGENTS.md new file mode 100644 index 0000000..4915f83 --- /dev/null +++ b/website/AGENTS.md @@ -0,0 +1,54 @@ +# Website + +## Tailwind dark mode + +Dark mode uses `prefers-color-scheme` media query, configured in `globals.css`: + +```css +@custom-variant dark (@media (prefers-color-scheme: dark)); +``` + +### `@variant dark` rules + +1. **Must be nested inside a selector**, never at the top level: + +```css +/* WRONG - silently produces no output */ +@variant dark { + .my-class { color: white; } +} + +/* CORRECT - nest inside the selector */ +.my-class { + @variant dark { + color: white; + } +} + +/* CORRECT - define variables inside :root */ +:root { + @variant dark { + --my-var: white; + } +} +``` + +2. **Only works in CSS files that are part of the Tailwind compilation chain.** Files must be imported via CSS `@import` from `globals.css` (which has `@import "tailwindcss"`). JS/TS `import "file.css"` in route files does NOT go through Tailwind — `@variant dark` will silently fail. + +```css +/* globals.css — this is the Tailwind entry point */ +@import "tailwindcss"; +@import "./liveline.css"; /* these get Tailwind processing */ +@import "./liveline-prism.css"; +@custom-variant dark (@media (prefers-color-scheme: dark)); +``` + +If you create a new CSS file that needs `@variant dark`, add it as a CSS `@import` in `globals.css`. Do NOT import it from a `.tsx` file. + +### For many dark overrides, use CSS variables on `:root` + +For files with many dark mode selectors (like prism syntax colors), define CSS variables in `:root { @variant dark { ... } }` and reference them in selectors. This avoids repeating `@variant dark` in every rule. + +## No localStorage dark mode toggle + +There is no JS-based `.dark` class toggle. Do not add inline scripts to toggle `.dark` on ``. The site follows the OS preference only via `prefers-color-scheme`. diff --git a/website/src/components/markdown.tsx b/website/src/components/markdown.tsx index 6e823a8..d670a41 100644 --- a/website/src/components/markdown.tsx +++ b/website/src/components/markdown.tsx @@ -214,14 +214,15 @@ export function SectionHeading({ id, children }: { id: string; children: React.R export function P({ children, className = "" }: { children: React.ReactNode; className?: string }) { return (
@@ -541,7 +542,7 @@ export function ComparisonTable({ style={{ padding: "4.8px 12px 4.8px 0", fontSize: "11px", - fontWeight: 400, + fontWeight: 500, fontFamily: "var(--ll-font-code)", color: "var(--ll-text-primary)", borderBottom: "1px solid var(--ll-border)", @@ -554,9 +555,9 @@ export function ComparisonTable({ style={{ padding: "4.8px 12px 4.8px 0", fontSize: "11px", - fontWeight: 400, + fontWeight: 500, fontFamily: "var(--ll-font-code)", - color: "var(--ll-text-muted)", + color: "var(--ll-text-primary)", borderBottom: "1px solid var(--ll-border)", whiteSpace: "nowrap", }} @@ -567,9 +568,9 @@ export function ComparisonTable({ style={{ padding: "4.8px 12px 4.8px 0", fontSize: "11px", - fontWeight: 400, + fontWeight: 500, fontFamily: "var(--ll-font-code)", - color: "var(--ll-text-muted)", + color: "var(--ll-text-primary)", borderBottom: "1px solid var(--ll-border)", }} > diff --git a/website/src/routes/liveline.tsx b/website/src/routes/liveline.tsx index a831873..1d13050 100644 --- a/website/src/routes/liveline.tsx +++ b/website/src/routes/liveline.tsx @@ -6,8 +6,6 @@ import type { MetaFunction } from "react-router"; import dedent from "string-dedent"; -import "website/src/styles/liveline.css"; -import "website/src/styles/liveline-prism.css"; import { EditorialPage, P, diff --git a/website/src/styles/globals.css b/website/src/styles/globals.css index ab8e28c..123301e 100644 --- a/website/src/styles/globals.css +++ b/website/src/styles/globals.css @@ -1,4 +1,6 @@ @import "tailwindcss"; +@import "./liveline.css"; +@import "./liveline-prism.css"; @custom-variant dark (@media (prefers-color-scheme: dark)); @plugin "@tailwindcss/typography"; diff --git a/website/src/styles/liveline-prism.css b/website/src/styles/liveline-prism.css index a48b686..3be7550 100644 --- a/website/src/styles/liveline-prism.css +++ b/website/src/styles/liveline-prism.css @@ -138,95 +138,150 @@ pre[class*="language-"] { /* ====================================================================== Dark mode - GitHub Dark inspired palette. - Uses @variant dark from globals.css so the strategy is defined in - one place (@custom-variant dark in globals.css). + @variant dark works here because globals.css imports this file via + CSS @import (part of Tailwind compilation chain). Dark colors are + defined as CSS variables on :root, then referenced in selectors. ====================================================================== */ -@variant dark { - code[class*="language-"], - pre[class*="language-"] { - color: #e6edf3; - } - - .token.keyword, - .token.module, - .token.imports, - .token.control-flow { - color: #ff7b72; - } - - .token.string, - .token.template-string, - .token.attr-value { - color: #a5d6ff; - } - - .token.function, - .token.class-name { - color: #d2a8ff; - } - - .token.property, - .token.parameter { - color: #ffa657; - } - - .token.tag .token.tag { - color: #7ee787; - } - - .token.tag .token.class-name { - color: #7ee787; - } - - .token.tag .token.attr-name, - .token.attr-name { - color: #79c0ff; - } - - .token.number { - color: #79c0ff; - } - - .token.operator { - color: #ff7b72; - } - - .token.punctuation { - color: #e6edf3; - } - - .token.boolean, - .token.constant, - .token.builtin { - color: #79c0ff; - } - - .token.comment, - .token.prolog, - .token.doctype, - .token.cdata { - color: #8b949e; - font-style: italic; - } - - .token.tag .token.punctuation { - color: #e6edf3; - } - - .token.spread { - color: #ff7b72; - } - - .token.plain-text { - color: #e6edf3; - } - - .token.regex { - color: #a5d6ff; - } - - .language-bash .token.function { - color: #79c0ff; +:root { + @variant dark { + --prism-fg: #e6edf3; + --prism-keyword: #ff7b72; + --prism-string: #a5d6ff; + --prism-function: #d2a8ff; + --prism-property: #ffa657; + --prism-tag: #7ee787; + --prism-attr: #79c0ff; + --prism-number: #79c0ff; + --prism-operator: #ff7b72; + --prism-punctuation: #e6edf3; + --prism-builtin: #79c0ff; + --prism-comment: #8b949e; + --prism-spread: #ff7b72; + --prism-regex: #a5d6ff; + --prism-bash-fn: #79c0ff; + } +} + +code[class*="language-"], +pre[class*="language-"] { + @variant dark { + color: var(--prism-fg); + } +} + +.token.keyword, +.token.module, +.token.imports, +.token.control-flow { + @variant dark { + color: var(--prism-keyword); + } +} + +.token.string, +.token.template-string, +.token.attr-value { + @variant dark { + color: var(--prism-string); + } +} + +.token.function, +.token.class-name { + @variant dark { + color: var(--prism-function); + } +} + +.token.property, +.token.parameter { + @variant dark { + color: var(--prism-property); + } +} + +.token.tag .token.tag { + @variant dark { + color: var(--prism-tag); + } +} + +.token.tag .token.class-name { + @variant dark { + color: var(--prism-tag); + } +} + +.token.tag .token.attr-name, +.token.attr-name { + @variant dark { + color: var(--prism-attr); + } +} + +.token.number { + @variant dark { + color: var(--prism-number); + } +} + +.token.operator { + @variant dark { + color: var(--prism-operator); + } +} + +.token.punctuation { + @variant dark { + color: var(--prism-punctuation); + } +} + +.token.boolean, +.token.constant, +.token.builtin { + @variant dark { + color: var(--prism-builtin); + } +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + @variant dark { + color: var(--prism-comment); + font-style: italic; + } +} + +.token.tag .token.punctuation { + @variant dark { + color: var(--prism-punctuation); + } +} + +.token.spread { + @variant dark { + color: var(--prism-spread); + } +} + +.token.plain-text { + @variant dark { + color: var(--prism-fg); + } +} + +.token.regex { + @variant dark { + color: var(--prism-regex); + } +} + +.language-bash .token.function { + @variant dark { + color: var(--prism-bash-fn); } } diff --git a/website/src/styles/liveline.css b/website/src/styles/liveline.css index f1dcdfa..8b55495 100644 --- a/website/src/styles/liveline.css +++ b/website/src/styles/liveline.css @@ -113,55 +113,56 @@ --ll-fade-12: rgba(255, 255, 255, 0); } -/* Dark mode overrides — uses @variant dark from globals.css - so the strategy is defined in one place */ -@variant dark { +/* Dark mode overrides — @variant dark works here because globals.css + imports this file via CSS @import (part of Tailwind compilation chain). + Must be nested inside a selector, not at the top level. */ .liveline-page { - --ll-text-primary: rgba(255, 255, 255, 0.9); - --ll-text-secondary: rgba(255, 255, 255, 0.45); - --ll-text-tertiary: rgba(255, 255, 255, 0.25); - --ll-text-muted: rgba(255, 255, 255, 0.35); - --ll-text-hover: rgba(255, 255, 255, 0.7); - --ll-bg: rgb(17, 17, 17); - --ll-border: rgba(255, 255, 255, 0.1); - --ll-divider: rgba(255, 255, 255, 0.06); - --ll-code-bg: rgba(255, 255, 255, 0.05); - --ll-code-line-nr: rgba(255, 255, 255, 0.3); - --ll-selection-bg: rgba(255, 255, 255, 0.1); + @variant dark { + --ll-text-primary: rgba(255, 255, 255, 0.9); + --ll-text-secondary: rgba(255, 255, 255, 0.45); + --ll-text-tertiary: rgba(255, 255, 255, 0.25); + --ll-text-muted: rgba(255, 255, 255, 0.35); + --ll-text-hover: rgba(255, 255, 255, 0.7); + --ll-bg: rgb(17, 17, 17); + --ll-border: rgba(255, 255, 255, 0.1); + --ll-divider: rgba(255, 255, 255, 0.06); + --ll-code-bg: rgba(255, 255, 255, 0.05); + --ll-code-line-nr: rgba(255, 255, 255, 0.3); + --ll-selection-bg: rgba(255, 255, 255, 0.1); - --ll-btn-bg: rgb(30, 30, 30); - --ll-btn-shadow: rgba(255, 255, 255, 0.05) 0px 2px 8px, - rgba(255, 255, 255, 0.02) 0px 4px 16px, - rgba(255, 255, 255, 0.06) 0px 0px 0px 1px inset; + --ll-btn-bg: rgb(30, 30, 30); + --ll-btn-shadow: rgba(255, 255, 255, 0.05) 0px 2px 8px, + rgba(255, 255, 255, 0.02) 0px 4px 16px, + rgba(255, 255, 255, 0.06) 0px 0px 0px 1px inset; - --ll-accent: #58a6ff; - --ll-primary: #60a5fa; - --ll-secondary: #f5a623; + --ll-accent: #58a6ff; + --ll-primary: #60a5fa; + --ll-secondary: #f5a623; - --ll-overlay-bg: hsla(0, 0%, 7%, 0.8); - --ll-overlay-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06), - 0 1.625rem 3.375rem rgba(0, 0, 0, 0.3), - 0 1rem 2rem rgba(0, 0, 0, 0.2), - 0 0.625rem 1rem rgba(0, 0, 0, 0.15), - 0 0.3125rem 0.5rem rgba(0, 0, 0, 0.1), - 0 0.125rem 0.25rem rgba(0, 0, 0, 0.08), - 0 0 0.125rem rgba(0, 0, 0, 0.05); + --ll-overlay-bg: hsla(0, 0%, 7%, 0.8); + --ll-overlay-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06), + 0 1.625rem 3.375rem rgba(0, 0, 0, 0.3), + 0 1rem 2rem rgba(0, 0, 0, 0.2), + 0 0.625rem 1rem rgba(0, 0, 0, 0.15), + 0 0.3125rem 0.5rem rgba(0, 0, 0, 0.1), + 0 0.125rem 0.25rem rgba(0, 0, 0, 0.08), + 0 0 0.125rem rgba(0, 0, 0, 0.05); - /* Header fade gradient stops (dark) */ - --ll-fade-0: rgb(17, 17, 17); - --ll-fade-1: rgba(17, 17, 17, 0.737); - --ll-fade-2: rgba(17, 17, 17, 0.541); - --ll-fade-3: rgba(17, 17, 17, 0.382); - --ll-fade-4: rgba(17, 17, 17, 0.278); - --ll-fade-5: rgba(17, 17, 17, 0.194); - --ll-fade-6: rgba(17, 17, 17, 0.126); - --ll-fade-7: rgba(17, 17, 17, 0.075); - --ll-fade-8: rgba(17, 17, 17, 0.042); - --ll-fade-9: rgba(17, 17, 17, 0.021); - --ll-fade-10: rgba(17, 17, 17, 0.008); - --ll-fade-11: rgba(17, 17, 17, 0.002); - --ll-fade-12: rgba(17, 17, 17, 0); -} + /* Header fade gradient stops (dark) */ + --ll-fade-0: rgb(17, 17, 17); + --ll-fade-1: rgba(17, 17, 17, 0.737); + --ll-fade-2: rgba(17, 17, 17, 0.541); + --ll-fade-3: rgba(17, 17, 17, 0.382); + --ll-fade-4: rgba(17, 17, 17, 0.278); + --ll-fade-5: rgba(17, 17, 17, 0.194); + --ll-fade-6: rgba(17, 17, 17, 0.126); + --ll-fade-7: rgba(17, 17, 17, 0.075); + --ll-fade-8: rgba(17, 17, 17, 0.042); + --ll-fade-9: rgba(17, 17, 17, 0.021); + --ll-fade-10: rgba(17, 17, 17, 0.008); + --ll-fade-11: rgba(17, 17, 17, 0.002); + --ll-fade-12: rgba(17, 17, 17, 0); + } } @supports (color: color(display-p3 1 1 1)) { @@ -184,6 +185,12 @@ background: var(--ll-selection-bg); } +/* Bold and inline code inside prose punch through the reduced opacity */ +.ll-prose strong, +.ll-prose .ll-inline-code { + opacity: calc(1 / 0.82); +} + /* ======================================================================== Stagger-in animation ======================================================================== */ @@ -260,12 +267,14 @@ z-index: -1; } -@variant dark { - .ll-inline-code { +.ll-inline-code { + @variant dark { color: rgba(255, 255, 255, 0.75); } +} - .ll-inline-code::before { +.ll-inline-code::before { + @variant dark { background: rgba(255, 255, 255, 0.08); } }