@letterstory/design 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PRINCIPLES.md +60 -0
- package/README.md +90 -0
- package/package.json +63 -0
- package/styled.d.ts +77 -0
- package/styled.js +115 -0
- package/tailwind-v3.cjs +75 -0
- package/tailwind-v4.css +58 -0
- package/themes.d.ts +91 -0
- package/themes.json +411 -0
- package/tokens.css +111 -0
- package/tokens.json +117 -0
package/PRINCIPLES.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<!-- Published copy. The source is AGENTS.md at the root of github.com/letterstory/letterstory; edit there and run design/scripts/build.mjs. -->
|
|
2
|
+
|
|
3
|
+
# Letterstory design principles
|
|
4
|
+
|
|
5
|
+
## The four principles
|
|
6
|
+
|
|
7
|
+
1. **Primitives + intelligence, never a baked opinion.** Every surface is an unopinionated
|
|
8
|
+
substrate (data structures, one pipeline, storable as plain data) plus an intelligence layer
|
|
9
|
+
that pushes clients in an opinionated direction _through_ those primitives. The tell that
|
|
10
|
+
you have baked an opinion into a primitive: a consumer wants to branch on "what kind of
|
|
11
|
+
thing is this". Thesis and diagnostic in `docs/architecture/primitives-and-assembly.md`.
|
|
12
|
+
Precedents: `src/types/article-plan.ts` (an untemplated post is `preference: []`, not a
|
|
13
|
+
mode), `src/lib/collections/capabilities.ts` (branch on `brand_subject` /
|
|
14
|
+
`publish_control`, never on `profile` or `kind`).
|
|
15
|
+
|
|
16
|
+
2. **One engine.** A blog collection and a phantom are the same engine with different
|
|
17
|
+
capabilities. Templated and untemplated posts are the same writing pipeline with different
|
|
18
|
+
constraints. Fleet tabs read one derivation of one measure. If you are about to write a
|
|
19
|
+
second module "like X but for Y", stop and add a flag or a capability to X. A module that
|
|
20
|
+
stops being phantom-only loses its `phantom-` prefix in the same PR.
|
|
21
|
+
|
|
22
|
+
3. **One operation, one function, many projections.** UI route, MCP tool, REST endpoint and CLI
|
|
23
|
+
command are _projections_ of one lib function with one Zod schema. The manifest is `TOOLS`
|
|
24
|
+
in `src/lib/mcp/registry.ts`; MCP, OpenAPI and `/docs` are derived from it at request time
|
|
25
|
+
and cannot drift (`src/app/docs/AGENTS.md`). Where the UI has its own `/api/*` route, that
|
|
26
|
+
route and the tool must call the same lib function and share the schema — derive the tool
|
|
27
|
+
contract with `.omit()` for key-derived fields exactly as
|
|
28
|
+
`src/lib/validations/collection-onboard.ts` does. A `// mirrors /api/...` comment is a
|
|
29
|
+
confession, not a pattern; the ratchet freezes the existing ones.
|
|
30
|
+
|
|
31
|
+
4. **Primitives live in `components/ui`; features map meaning to tokens.** A feature decides
|
|
32
|
+
_what_ a state means (ok / warn / risk, rising / falling) and hands that to a primitive. It
|
|
33
|
+
never picks a colour, a pixel size, a table header class or a date format. Tokens are in
|
|
34
|
+
`src/app/globals.css` (`@theme inline`): `accent-peach`, `accent-mint`, `rising`,
|
|
35
|
+
`falling`, `warning`, `text-2xs`. Formatters are `src/lib/format/{date,number}.ts`.
|
|
36
|
+
The primitives in `components/ui`: `app-page` (THE page shell every `(app)` layout
|
|
37
|
+
renders; `surface="dark"` is a recorded decision, not a per-route class), `table`,
|
|
38
|
+
`empty-state`, `status-badge` (a feature passes a _tone_ — ok / warn / risk / rising /
|
|
39
|
+
falling / info / neutral — never a colour), `stat-tile` (one delta convention),
|
|
40
|
+
`copy-button` (+ `useCopyToClipboard`), `stage-progress` (one checklist for durable jobs),
|
|
41
|
+
`collapsible-section`, `tabs` (`variant="segmented"` replaced the perf tab bar). Hooks:
|
|
42
|
+
`useTabParam` / `usePersistedTab` (ONE `?tab=` URL contract) and `useConfirm` (the only
|
|
43
|
+
destructive-action confirmation; `confirm()` is an ESLint error). If the primitive you
|
|
44
|
+
need does not exist, add it there first, then use it. Cross-feature imports of another
|
|
45
|
+
feature's private module are an ESLint error.
|
|
46
|
+
|
|
47
|
+
## The two review questions
|
|
48
|
+
|
|
49
|
+
Applied to every PR (from `docs/architecture/README.md`):
|
|
50
|
+
|
|
51
|
+
> When a consumer wants to branch on what kind of thing this is, the assembly layer failed to
|
|
52
|
+
> express it as a constraint.
|
|
53
|
+
>
|
|
54
|
+
> If you can't tell from the row who decided this and whether they can undo it, you wrote an
|
|
55
|
+
> opinion into a fact.
|
|
56
|
+
|
|
57
|
+
Add a third for surfaces:
|
|
58
|
+
|
|
59
|
+
> If the app can do it and an agent cannot (or vice versa), which projection is missing, and
|
|
60
|
+
> why did the shared function not force it?
|
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# `@letterstory/design`
|
|
2
|
+
|
|
3
|
+
The cross-repo layer of Letterstory's design system: the **tokens** (colour, radius, font,
|
|
4
|
+
type scale), the **phantom theme registry** Lettersprite renders, and the **design
|
|
5
|
+
principles** as a shipped file. Framework-neutral data with one thin adapter per framework,
|
|
6
|
+
so every Letterstory repo reads the same values and none of them copies a palette.
|
|
7
|
+
|
|
8
|
+
Zero runtime dependencies, no build step to install. Published from this directory by
|
|
9
|
+
`.github/workflows/publish-design.yml` (npm Trusted Publishing, on merge to `main`);
|
|
10
|
+
`design-version-guard.yml` requires a version bump whenever a shipped file changes.
|
|
11
|
+
|
|
12
|
+
## What ships
|
|
13
|
+
|
|
14
|
+
| File | What it is |
|
|
15
|
+
| --------------------- | -------------------------------------------------------------------------------------------------- |
|
|
16
|
+
| `tokens.json` | **Source.** The token values as one grouped object: `color.{light,dark}`, `radius`, `font`, `size` |
|
|
17
|
+
| `tokens.css` | The tokens as CSS custom properties on `:root`, with the dark overrides under `.dark` |
|
|
18
|
+
| `tailwind-v4.css` | A `@theme inline` block mapping the custom properties to Tailwind v4 theme keys |
|
|
19
|
+
| `tailwind-v3.cjs` | A Tailwind v3 preset whose `theme.extend` references the custom properties |
|
|
20
|
+
| `styled.js` + `.d.ts` | A plain object of resolved values (no stylesheet needed) for styled-components and similar |
|
|
21
|
+
| `themes.json` | **Source.** The phantom theme registry: `groups` and `themes` (value, label, hint, group, tags) |
|
|
22
|
+
| `themes.d.ts` | Literal-union types for the registry (`PhantomBlogTheme`, `PhantomBlogThemeGroup`, …) |
|
|
23
|
+
| `PRINCIPLES.md` | The design principles, copied from the root `AGENTS.md` of the letterstory repo |
|
|
24
|
+
|
|
25
|
+
`tokens.json` and `themes.json` are the sources. Everything else is generated by
|
|
26
|
+
`scripts/build.mjs` and committed; a test regenerates and diffs, so editing a generated file
|
|
27
|
+
by hand fails CI. To change a value: edit the JSON, run `node design/scripts/build.mjs`,
|
|
28
|
+
commit both.
|
|
29
|
+
|
|
30
|
+
In `tokens.json`, `color.dark` holds only the values that differ from light (exactly what the
|
|
31
|
+
`.dark` block sets); `styled.js` resolves that into a full dark palette. Derived tokens keep
|
|
32
|
+
their CSS expressions (`brand-light` is `oklch(from var(--brand) …)`, `radius.sm` is
|
|
33
|
+
`calc(var(--radius) - 4px)`), so rebranding is one value: `color.light.brand`.
|
|
34
|
+
|
|
35
|
+
## Consuming it
|
|
36
|
+
|
|
37
|
+
**Tailwind v4** (letterstory, lettersprite): import the tokens, then the mapping, after
|
|
38
|
+
Tailwind itself.
|
|
39
|
+
|
|
40
|
+
```css
|
|
41
|
+
@import "tailwindcss";
|
|
42
|
+
@import "@letterstory/design/tokens.css";
|
|
43
|
+
@import "@letterstory/design/tailwind-v4.css";
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`bg-brand`, `text-accent-peach`, `text-rising`, `rounded-lg`, `text-2xs` now resolve to the
|
|
47
|
+
tokens. `--font-sans` / `--font-mono` are set under Tailwind's own names, so `font-sans` and
|
|
48
|
+
preflight's default pick up DM Sans with no mapping. Dark mode is the `.dark` class
|
|
49
|
+
(`@custom-variant dark (&:is(.dark *))` in your stylesheet).
|
|
50
|
+
|
|
51
|
+
**Tailwind v3** (lettertrace, kernels): load `tokens.css` on the page and add the preset.
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
// tailwind.config.js
|
|
55
|
+
module.exports = {
|
|
56
|
+
darkMode: "class",
|
|
57
|
+
presets: [require("@letterstory/design/tailwind-v3")],
|
|
58
|
+
};
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**styled-components** (the marketing repo): a resolved object, no stylesheet.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { tokens } from "@letterstory/design";
|
|
65
|
+
// tokens.color.light["accent-peach"] === "#ee724a"; tokens.color.dark.background; tokens.font.sans
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Plain CSS** (admin, the company site): import `tokens.css` and use `var(--brand)`,
|
|
69
|
+
`var(--accent-peach)`, `var(--radius)`, `var(--font-size-2xs)` …
|
|
70
|
+
|
|
71
|
+
**Theme registry** (lettersprite, letterstory):
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import registry from "@letterstory/design/themes"; // themes.json, typed by themes.d.ts
|
|
75
|
+
import type { PhantomBlogTheme } from "@letterstory/design/themes";
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Where the values come from
|
|
79
|
+
|
|
80
|
+
The letterstory app is a **consumer**, not a source: `src/app/globals.css` imports
|
|
81
|
+
`design/tokens.css` and `design/tailwind-v4.css` by relative path and defines no token of its
|
|
82
|
+
own, and `src/types/deployments.ts` re-exports `themes.json` as `PHANTOM_BLOG_THEMES`. Edit
|
|
83
|
+
`design/tokens.json` or `design/themes.json`, never `globals.css`. The principles in
|
|
84
|
+
`PRINCIPLES.md` are generated from the root `AGENTS.md`; edit that.
|
|
85
|
+
|
|
86
|
+
## Versioning
|
|
87
|
+
|
|
88
|
+
Bump `version` in `package.json` whenever a shipped file changes (the guard enforces it);
|
|
89
|
+
the merge to `main` publishes. Adding a token or a theme is a minor bump; changing a value is
|
|
90
|
+
a patch; renaming or removing a token is a major.
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@letterstory/design",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Letterstory design tokens, the phantom theme registry, and the design principles — one source for every Letterstory repo.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"author": "Letterstory",
|
|
8
|
+
"homepage": "https://github.com/letterstory/letterstory/tree/main/design#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/letterstory/letterstory.git",
|
|
12
|
+
"directory": "design"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/letterstory/letterstory/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"letterstory",
|
|
19
|
+
"design-tokens",
|
|
20
|
+
"tailwind",
|
|
21
|
+
"styled-components",
|
|
22
|
+
"themes"
|
|
23
|
+
],
|
|
24
|
+
"sideEffects": [
|
|
25
|
+
"*.css"
|
|
26
|
+
],
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./styled.d.ts",
|
|
30
|
+
"default": "./styled.js"
|
|
31
|
+
},
|
|
32
|
+
"./tokens.css": "./tokens.css",
|
|
33
|
+
"./tokens.json": "./tokens.json",
|
|
34
|
+
"./tailwind-v4.css": "./tailwind-v4.css",
|
|
35
|
+
"./tailwind-v3": "./tailwind-v3.cjs",
|
|
36
|
+
"./styled": {
|
|
37
|
+
"types": "./styled.d.ts",
|
|
38
|
+
"default": "./styled.js"
|
|
39
|
+
},
|
|
40
|
+
"./themes": {
|
|
41
|
+
"types": "./themes.d.ts",
|
|
42
|
+
"default": "./themes.json"
|
|
43
|
+
},
|
|
44
|
+
"./themes.json": "./themes.json",
|
|
45
|
+
"./PRINCIPLES.md": "./PRINCIPLES.md",
|
|
46
|
+
"./package.json": "./package.json"
|
|
47
|
+
},
|
|
48
|
+
"files": [
|
|
49
|
+
"tokens.css",
|
|
50
|
+
"tokens.json",
|
|
51
|
+
"tailwind-v4.css",
|
|
52
|
+
"tailwind-v3.cjs",
|
|
53
|
+
"styled.js",
|
|
54
|
+
"styled.d.ts",
|
|
55
|
+
"themes.json",
|
|
56
|
+
"themes.d.ts",
|
|
57
|
+
"PRINCIPLES.md",
|
|
58
|
+
"README.md"
|
|
59
|
+
],
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public"
|
|
62
|
+
}
|
|
63
|
+
}
|
package/styled.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// GENERATED by design/scripts/build.mjs — do not edit by hand. Source: design/tokens.json.
|
|
2
|
+
|
|
3
|
+
export interface Palette {
|
|
4
|
+
readonly brand: string;
|
|
5
|
+
readonly "brand-foreground": string;
|
|
6
|
+
readonly "brand-light": string;
|
|
7
|
+
readonly "brand-text": string;
|
|
8
|
+
readonly "accent-peach": string;
|
|
9
|
+
readonly "accent-peach-hover": string;
|
|
10
|
+
readonly "accent-mint": string;
|
|
11
|
+
readonly rising: string;
|
|
12
|
+
readonly falling: string;
|
|
13
|
+
readonly warning: string;
|
|
14
|
+
readonly background: string;
|
|
15
|
+
readonly foreground: string;
|
|
16
|
+
readonly card: string;
|
|
17
|
+
readonly "card-foreground": string;
|
|
18
|
+
readonly popover: string;
|
|
19
|
+
readonly "popover-foreground": string;
|
|
20
|
+
readonly primary: string;
|
|
21
|
+
readonly "primary-foreground": string;
|
|
22
|
+
readonly secondary: string;
|
|
23
|
+
readonly "secondary-foreground": string;
|
|
24
|
+
readonly muted: string;
|
|
25
|
+
readonly "muted-foreground": string;
|
|
26
|
+
readonly accent: string;
|
|
27
|
+
readonly "accent-foreground": string;
|
|
28
|
+
readonly destructive: string;
|
|
29
|
+
readonly border: string;
|
|
30
|
+
readonly input: string;
|
|
31
|
+
readonly ring: string;
|
|
32
|
+
readonly "chart-1": string;
|
|
33
|
+
readonly "chart-2": string;
|
|
34
|
+
readonly "chart-3": string;
|
|
35
|
+
readonly "chart-4": string;
|
|
36
|
+
readonly "chart-5": string;
|
|
37
|
+
readonly sidebar: string;
|
|
38
|
+
readonly "sidebar-foreground": string;
|
|
39
|
+
readonly "sidebar-primary": string;
|
|
40
|
+
readonly "sidebar-primary-foreground": string;
|
|
41
|
+
readonly "sidebar-accent": string;
|
|
42
|
+
readonly "sidebar-accent-foreground": string;
|
|
43
|
+
readonly "sidebar-border": string;
|
|
44
|
+
readonly "sidebar-ring": string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface Radius {
|
|
48
|
+
readonly DEFAULT: string;
|
|
49
|
+
readonly sm: string;
|
|
50
|
+
readonly md: string;
|
|
51
|
+
readonly lg: string;
|
|
52
|
+
readonly xl: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface FontFamily {
|
|
56
|
+
readonly sans: string;
|
|
57
|
+
readonly mono: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface TypeStep {
|
|
61
|
+
readonly fontSize: string;
|
|
62
|
+
readonly lineHeight: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface TypeScale {
|
|
66
|
+
readonly "2xs": TypeStep;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface DesignTokens {
|
|
70
|
+
readonly color: { readonly light: Palette; readonly dark: Palette };
|
|
71
|
+
readonly radius: Radius;
|
|
72
|
+
readonly font: FontFamily;
|
|
73
|
+
readonly size: TypeScale;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export declare const tokens: DesignTokens;
|
|
77
|
+
export default tokens;
|
package/styled.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// GENERATED by design/scripts/build.mjs — do not edit by hand. Source: design/tokens.json.
|
|
2
|
+
//
|
|
3
|
+
// The tokens as a plain object of resolved CSS values — every var() reference is
|
|
4
|
+
// inlined, so this needs no stylesheet. `color.dark` is the full dark palette (light
|
|
5
|
+
// with the dark overrides applied). For a styled-components ThemeProvider:
|
|
6
|
+
// <ThemeProvider theme={tokens}>… then ${({ theme }) => theme.color.light["accent-peach"]}
|
|
7
|
+
export const tokens = {
|
|
8
|
+
color: {
|
|
9
|
+
light: {
|
|
10
|
+
brand: "oklch(0.332 0.074 243.6)",
|
|
11
|
+
"brand-foreground": "oklch(0.985 0 0)",
|
|
12
|
+
"brand-light": "oklch(from oklch(0.332 0.074 243.6) 0.82 0.06 h)",
|
|
13
|
+
"brand-text": "oklch(0.332 0.074 243.6)",
|
|
14
|
+
"accent-peach": "#ee724a",
|
|
15
|
+
"accent-peach-hover": "#e2643b",
|
|
16
|
+
"accent-mint": "#9af2e0",
|
|
17
|
+
rising: "oklch(0.72 0.17 155)",
|
|
18
|
+
falling: "oklch(0.63 0.21 25)",
|
|
19
|
+
warning: "oklch(0.75 0.16 75)",
|
|
20
|
+
background: "oklch(1 0 0)",
|
|
21
|
+
foreground: "oklch(0.145 0 0)",
|
|
22
|
+
card: "oklch(1 0 0)",
|
|
23
|
+
"card-foreground": "oklch(0.145 0 0)",
|
|
24
|
+
popover: "oklch(1 0 0)",
|
|
25
|
+
"popover-foreground": "oklch(0.145 0 0)",
|
|
26
|
+
primary: "oklch(0.205 0 0)",
|
|
27
|
+
"primary-foreground": "oklch(0.985 0 0)",
|
|
28
|
+
secondary: "oklch(0.97 0 0)",
|
|
29
|
+
"secondary-foreground": "oklch(0.205 0 0)",
|
|
30
|
+
muted: "oklch(0.97 0 0)",
|
|
31
|
+
"muted-foreground": "oklch(0.556 0 0)",
|
|
32
|
+
accent: "oklch(0.97 0 0)",
|
|
33
|
+
"accent-foreground": "oklch(0.205 0 0)",
|
|
34
|
+
destructive: "oklch(0.577 0.245 27.325)",
|
|
35
|
+
border: "oklch(0.922 0 0)",
|
|
36
|
+
input: "oklch(0.922 0 0)",
|
|
37
|
+
ring: "oklch(0.708 0 0)",
|
|
38
|
+
"chart-1": "oklch(0.646 0.222 41.116)",
|
|
39
|
+
"chart-2": "oklch(0.6 0.118 184.704)",
|
|
40
|
+
"chart-3": "oklch(0.398 0.07 227.392)",
|
|
41
|
+
"chart-4": "oklch(0.828 0.189 84.429)",
|
|
42
|
+
"chart-5": "oklch(0.769 0.188 70.08)",
|
|
43
|
+
sidebar: "oklch(0.985 0 0)",
|
|
44
|
+
"sidebar-foreground": "oklch(0.145 0 0)",
|
|
45
|
+
"sidebar-primary": "oklch(0.205 0 0)",
|
|
46
|
+
"sidebar-primary-foreground": "oklch(0.985 0 0)",
|
|
47
|
+
"sidebar-accent": "oklch(0.97 0 0)",
|
|
48
|
+
"sidebar-accent-foreground": "oklch(0.205 0 0)",
|
|
49
|
+
"sidebar-border": "oklch(0.922 0 0)",
|
|
50
|
+
"sidebar-ring": "oklch(0.708 0 0)",
|
|
51
|
+
},
|
|
52
|
+
dark: {
|
|
53
|
+
brand: "oklch(0.332 0.074 243.6)",
|
|
54
|
+
"brand-foreground": "oklch(0.985 0 0)",
|
|
55
|
+
"brand-light": "oklch(from oklch(0.332 0.074 243.6) 0.5 0.09 h)",
|
|
56
|
+
"brand-text": "oklch(from oklch(0.332 0.074 243.6) 0.72 0.1 h)",
|
|
57
|
+
"accent-peach": "#ee724a",
|
|
58
|
+
"accent-peach-hover": "#e2643b",
|
|
59
|
+
"accent-mint": "#9af2e0",
|
|
60
|
+
rising: "oklch(0.72 0.17 155)",
|
|
61
|
+
falling: "oklch(0.63 0.21 25)",
|
|
62
|
+
warning: "oklch(0.75 0.16 75)",
|
|
63
|
+
background: "oklch(0.145 0 0)",
|
|
64
|
+
foreground: "oklch(0.985 0 0)",
|
|
65
|
+
card: "oklch(0.205 0 0)",
|
|
66
|
+
"card-foreground": "oklch(0.985 0 0)",
|
|
67
|
+
popover: "oklch(0.205 0 0)",
|
|
68
|
+
"popover-foreground": "oklch(0.985 0 0)",
|
|
69
|
+
primary: "oklch(0.922 0 0)",
|
|
70
|
+
"primary-foreground": "oklch(0.205 0 0)",
|
|
71
|
+
secondary: "oklch(0.269 0 0)",
|
|
72
|
+
"secondary-foreground": "oklch(0.985 0 0)",
|
|
73
|
+
muted: "oklch(0.269 0 0)",
|
|
74
|
+
"muted-foreground": "oklch(0.708 0 0)",
|
|
75
|
+
accent: "oklch(0.269 0 0)",
|
|
76
|
+
"accent-foreground": "oklch(0.985 0 0)",
|
|
77
|
+
destructive: "oklch(0.704 0.191 22.216)",
|
|
78
|
+
border: "oklch(1 0 0 / 10%)",
|
|
79
|
+
input: "oklch(1 0 0 / 15%)",
|
|
80
|
+
ring: "oklch(0.556 0 0)",
|
|
81
|
+
"chart-1": "oklch(0.488 0.243 264.376)",
|
|
82
|
+
"chart-2": "oklch(0.696 0.17 162.48)",
|
|
83
|
+
"chart-3": "oklch(0.769 0.188 70.08)",
|
|
84
|
+
"chart-4": "oklch(0.692 0.162 38.8)",
|
|
85
|
+
"chart-5": "oklch(0.645 0.246 16.439)",
|
|
86
|
+
sidebar: "oklch(0.205 0 0)",
|
|
87
|
+
"sidebar-foreground": "oklch(0.985 0 0)",
|
|
88
|
+
"sidebar-primary": "oklch(0.488 0.243 264.376)",
|
|
89
|
+
"sidebar-primary-foreground": "oklch(0.985 0 0)",
|
|
90
|
+
"sidebar-accent": "oklch(0.269 0 0)",
|
|
91
|
+
"sidebar-accent-foreground": "oklch(0.985 0 0)",
|
|
92
|
+
"sidebar-border": "oklch(1 0 0 / 10%)",
|
|
93
|
+
"sidebar-ring": "oklch(0.556 0 0)",
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
radius: {
|
|
97
|
+
DEFAULT: "0.625rem",
|
|
98
|
+
sm: "calc(0.625rem - 4px)",
|
|
99
|
+
md: "calc(0.625rem - 2px)",
|
|
100
|
+
lg: "0.625rem",
|
|
101
|
+
xl: "calc(0.625rem + 4px)",
|
|
102
|
+
},
|
|
103
|
+
font: {
|
|
104
|
+
sans: '"DM Sans", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
|
|
105
|
+
mono: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
|
|
106
|
+
},
|
|
107
|
+
size: {
|
|
108
|
+
"2xs": {
|
|
109
|
+
fontSize: "0.6875rem",
|
|
110
|
+
lineHeight: "1rem",
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export default tokens;
|
package/tailwind-v3.cjs
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// GENERATED by design/scripts/build.mjs — do not edit by hand. Source: design/tokens.json.
|
|
2
|
+
//
|
|
3
|
+
// Tailwind v3 adapter: a preset whose theme.extend references the custom properties in
|
|
4
|
+
// tokens.css, so `bg-brand`, `text-rising`, `rounded-lg`, `text-2xs` resolve to the
|
|
5
|
+
// tokens. Load tokens.css on the page and add to tailwind.config:
|
|
6
|
+
// presets: [require("@letterstory/design/tailwind-v3")], darkMode: "class"
|
|
7
|
+
// Opacity modifiers (bg-brand/50) do not apply to var() colours in v3; use color-mix().
|
|
8
|
+
module.exports = {
|
|
9
|
+
theme: {
|
|
10
|
+
extend: {
|
|
11
|
+
colors: {
|
|
12
|
+
brand: "var(--brand)",
|
|
13
|
+
"brand-foreground": "var(--brand-foreground)",
|
|
14
|
+
"brand-light": "var(--brand-light)",
|
|
15
|
+
"brand-text": "var(--brand-text)",
|
|
16
|
+
"accent-peach": "var(--accent-peach)",
|
|
17
|
+
"accent-peach-hover": "var(--accent-peach-hover)",
|
|
18
|
+
"accent-mint": "var(--accent-mint)",
|
|
19
|
+
rising: "var(--rising)",
|
|
20
|
+
falling: "var(--falling)",
|
|
21
|
+
warning: "var(--warning)",
|
|
22
|
+
background: "var(--background)",
|
|
23
|
+
foreground: "var(--foreground)",
|
|
24
|
+
card: "var(--card)",
|
|
25
|
+
"card-foreground": "var(--card-foreground)",
|
|
26
|
+
popover: "var(--popover)",
|
|
27
|
+
"popover-foreground": "var(--popover-foreground)",
|
|
28
|
+
primary: "var(--primary)",
|
|
29
|
+
"primary-foreground": "var(--primary-foreground)",
|
|
30
|
+
secondary: "var(--secondary)",
|
|
31
|
+
"secondary-foreground": "var(--secondary-foreground)",
|
|
32
|
+
muted: "var(--muted)",
|
|
33
|
+
"muted-foreground": "var(--muted-foreground)",
|
|
34
|
+
accent: "var(--accent)",
|
|
35
|
+
"accent-foreground": "var(--accent-foreground)",
|
|
36
|
+
destructive: "var(--destructive)",
|
|
37
|
+
border: "var(--border)",
|
|
38
|
+
input: "var(--input)",
|
|
39
|
+
ring: "var(--ring)",
|
|
40
|
+
"chart-1": "var(--chart-1)",
|
|
41
|
+
"chart-2": "var(--chart-2)",
|
|
42
|
+
"chart-3": "var(--chart-3)",
|
|
43
|
+
"chart-4": "var(--chart-4)",
|
|
44
|
+
"chart-5": "var(--chart-5)",
|
|
45
|
+
sidebar: "var(--sidebar)",
|
|
46
|
+
"sidebar-foreground": "var(--sidebar-foreground)",
|
|
47
|
+
"sidebar-primary": "var(--sidebar-primary)",
|
|
48
|
+
"sidebar-primary-foreground": "var(--sidebar-primary-foreground)",
|
|
49
|
+
"sidebar-accent": "var(--sidebar-accent)",
|
|
50
|
+
"sidebar-accent-foreground": "var(--sidebar-accent-foreground)",
|
|
51
|
+
"sidebar-border": "var(--sidebar-border)",
|
|
52
|
+
"sidebar-ring": "var(--sidebar-ring)",
|
|
53
|
+
},
|
|
54
|
+
borderRadius: {
|
|
55
|
+
DEFAULT: "var(--radius)",
|
|
56
|
+
sm: "var(--radius-sm)",
|
|
57
|
+
md: "var(--radius-md)",
|
|
58
|
+
lg: "var(--radius-lg)",
|
|
59
|
+
xl: "var(--radius-xl)",
|
|
60
|
+
},
|
|
61
|
+
fontFamily: {
|
|
62
|
+
sans: "var(--font-sans)",
|
|
63
|
+
mono: "var(--font-mono)",
|
|
64
|
+
},
|
|
65
|
+
fontSize: {
|
|
66
|
+
"2xs": [
|
|
67
|
+
"var(--font-size-2xs)",
|
|
68
|
+
{
|
|
69
|
+
lineHeight: "var(--line-height-2xs)",
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
};
|
package/tailwind-v4.css
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/* GENERATED by design/scripts/build.mjs — do not edit by hand. Source: design/tokens.json.
|
|
2
|
+
*
|
|
3
|
+
* Tailwind v4 adapter: maps the custom properties in tokens.css onto Tailwind theme
|
|
4
|
+
* keys, so `bg-brand`, `text-rising`, `rounded-lg`, `text-2xs` resolve to the
|
|
5
|
+
* tokens. Import tokens.css first, then this file, after `@import "tailwindcss"`.
|
|
6
|
+
* `inline` so utilities emit the var() reference and follow the .dark switch.
|
|
7
|
+
* Fonts are not mapped here: tokens.css sets --font-sans / --font-mono under
|
|
8
|
+
* Tailwind's own names.
|
|
9
|
+
*/
|
|
10
|
+
@theme inline {
|
|
11
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
12
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
13
|
+
--radius-lg: var(--radius);
|
|
14
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
15
|
+
--color-brand: var(--brand);
|
|
16
|
+
--color-brand-foreground: var(--brand-foreground);
|
|
17
|
+
--color-brand-light: var(--brand-light);
|
|
18
|
+
--color-brand-text: var(--brand-text);
|
|
19
|
+
--color-accent-peach: var(--accent-peach);
|
|
20
|
+
--color-accent-peach-hover: var(--accent-peach-hover);
|
|
21
|
+
--color-accent-mint: var(--accent-mint);
|
|
22
|
+
--color-rising: var(--rising);
|
|
23
|
+
--color-falling: var(--falling);
|
|
24
|
+
--color-warning: var(--warning);
|
|
25
|
+
--color-background: var(--background);
|
|
26
|
+
--color-foreground: var(--foreground);
|
|
27
|
+
--color-card: var(--card);
|
|
28
|
+
--color-card-foreground: var(--card-foreground);
|
|
29
|
+
--color-popover: var(--popover);
|
|
30
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
31
|
+
--color-primary: var(--primary);
|
|
32
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
33
|
+
--color-secondary: var(--secondary);
|
|
34
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
35
|
+
--color-muted: var(--muted);
|
|
36
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
37
|
+
--color-accent: var(--accent);
|
|
38
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
39
|
+
--color-destructive: var(--destructive);
|
|
40
|
+
--color-border: var(--border);
|
|
41
|
+
--color-input: var(--input);
|
|
42
|
+
--color-ring: var(--ring);
|
|
43
|
+
--color-chart-1: var(--chart-1);
|
|
44
|
+
--color-chart-2: var(--chart-2);
|
|
45
|
+
--color-chart-3: var(--chart-3);
|
|
46
|
+
--color-chart-4: var(--chart-4);
|
|
47
|
+
--color-chart-5: var(--chart-5);
|
|
48
|
+
--color-sidebar: var(--sidebar);
|
|
49
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
50
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
51
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
52
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
53
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
54
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
55
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
56
|
+
--text-2xs: 0.6875rem;
|
|
57
|
+
--text-2xs--line-height: 1rem;
|
|
58
|
+
}
|
package/themes.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// GENERATED by design/scripts/build.mjs — do not edit by hand. Source: design/themes.json.
|
|
2
|
+
//
|
|
3
|
+
// The phantom theme registry, typed with the literal unions the data implies, so a
|
|
4
|
+
// consumer's `theme` field is checked against the registry rather than `string`.
|
|
5
|
+
|
|
6
|
+
/** The families the theme picker groups themes under. */
|
|
7
|
+
export type PhantomBlogThemeGroup = "baseline" | "publication" | "brand" | "business" | "technology";
|
|
8
|
+
|
|
9
|
+
/** Every theme Lettersprite's THEME env var selects. */
|
|
10
|
+
export type PhantomBlogTheme =
|
|
11
|
+
| "sleek"
|
|
12
|
+
| "classic"
|
|
13
|
+
| "minimal"
|
|
14
|
+
| "magazine"
|
|
15
|
+
| "midnight"
|
|
16
|
+
| "gazette"
|
|
17
|
+
| "dispatch"
|
|
18
|
+
| "metro"
|
|
19
|
+
| "review"
|
|
20
|
+
| "signal"
|
|
21
|
+
| "current"
|
|
22
|
+
| "ledger"
|
|
23
|
+
| "atelier"
|
|
24
|
+
| "noir"
|
|
25
|
+
| "chronicle"
|
|
26
|
+
| "verdure"
|
|
27
|
+
| "couture"
|
|
28
|
+
| "atlas"
|
|
29
|
+
| "missive"
|
|
30
|
+
| "commit"
|
|
31
|
+
| "apex"
|
|
32
|
+
| "mint"
|
|
33
|
+
| "bloom"
|
|
34
|
+
| "cinder"
|
|
35
|
+
| "hearth"
|
|
36
|
+
| "harvest"
|
|
37
|
+
| "terra"
|
|
38
|
+
| "verve"
|
|
39
|
+
| "estate"
|
|
40
|
+
| "counsel"
|
|
41
|
+
| "clinic"
|
|
42
|
+
| "nook"
|
|
43
|
+
| "lumen"
|
|
44
|
+
| "cellar"
|
|
45
|
+
| "horizon"
|
|
46
|
+
| "derma"
|
|
47
|
+
| "meridian"
|
|
48
|
+
| "keystone"
|
|
49
|
+
| "vantage"
|
|
50
|
+
| "cobalt"
|
|
51
|
+
| "sterling"
|
|
52
|
+
| "momentum"
|
|
53
|
+
| "forum"
|
|
54
|
+
| "cadence"
|
|
55
|
+
| "evergreen"
|
|
56
|
+
| "beacon"
|
|
57
|
+
| "kernel"
|
|
58
|
+
| "graphite"
|
|
59
|
+
| "cortex"
|
|
60
|
+
| "cipher"
|
|
61
|
+
| "pulse"
|
|
62
|
+
| "apiwire"
|
|
63
|
+
| "bourse"
|
|
64
|
+
| "folio"
|
|
65
|
+
| "kiosk";
|
|
66
|
+
|
|
67
|
+
export interface PhantomBlogThemeGroupEntry {
|
|
68
|
+
readonly id: PhantomBlogThemeGroup;
|
|
69
|
+
readonly label: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface PhantomBlogThemeEntry {
|
|
73
|
+
readonly value: PhantomBlogTheme;
|
|
74
|
+
readonly label: string;
|
|
75
|
+
readonly hint: string;
|
|
76
|
+
readonly group: PhantomBlogThemeGroup;
|
|
77
|
+
/**
|
|
78
|
+
* Industry / aesthetic descriptors an identity generator matches against a site's
|
|
79
|
+
* inferred subject to shortlist fitting themes. Purely advisory — every theme stays
|
|
80
|
+
* user-selectable regardless of tags.
|
|
81
|
+
*/
|
|
82
|
+
readonly tags: readonly string[];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface PhantomThemeRegistry {
|
|
86
|
+
readonly groups: readonly PhantomBlogThemeGroupEntry[];
|
|
87
|
+
readonly themes: readonly PhantomBlogThemeEntry[];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
declare const registry: PhantomThemeRegistry;
|
|
91
|
+
export default registry;
|
package/themes.json
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
{
|
|
2
|
+
"groups": [
|
|
3
|
+
{
|
|
4
|
+
"id": "baseline",
|
|
5
|
+
"label": "Clean & versatile"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"id": "publication",
|
|
9
|
+
"label": "Magazine fronts"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": "brand",
|
|
13
|
+
"label": "Brand & product"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "business",
|
|
17
|
+
"label": "Business & corporate"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "technology",
|
|
21
|
+
"label": "Technology"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"themes": [
|
|
25
|
+
{
|
|
26
|
+
"value": "sleek",
|
|
27
|
+
"label": "Sleek",
|
|
28
|
+
"hint": "Clean, modern, versatile",
|
|
29
|
+
"group": "baseline",
|
|
30
|
+
"tags": ["tech", "saas", "startup", "modern", "versatile"]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"value": "classic",
|
|
34
|
+
"label": "Classic",
|
|
35
|
+
"hint": "Editorial serif, timeless",
|
|
36
|
+
"group": "baseline",
|
|
37
|
+
"tags": ["finance", "professional-services", "editorial", "timeless", "versatile"]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"value": "minimal",
|
|
41
|
+
"label": "Minimal",
|
|
42
|
+
"hint": "Bare, text-first",
|
|
43
|
+
"group": "baseline",
|
|
44
|
+
"tags": ["design", "writing", "essay", "understated", "versatile"]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"value": "magazine",
|
|
48
|
+
"label": "Magazine",
|
|
49
|
+
"hint": "Bold, image-forward",
|
|
50
|
+
"group": "baseline",
|
|
51
|
+
"tags": ["media", "consumer", "culture", "bold", "versatile"]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"value": "midnight",
|
|
55
|
+
"label": "Midnight",
|
|
56
|
+
"hint": "Dark mode, high contrast",
|
|
57
|
+
"group": "baseline",
|
|
58
|
+
"tags": ["developer", "security", "gaming", "crypto", "dark"]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"value": "gazette",
|
|
62
|
+
"label": "Gazette",
|
|
63
|
+
"hint": "Broadsheet, paper-of-record serif",
|
|
64
|
+
"group": "publication",
|
|
65
|
+
"tags": ["news", "policy", "b2b", "authoritative", "serif"]
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"value": "dispatch",
|
|
69
|
+
"label": "Dispatch",
|
|
70
|
+
"hint": "Tech-news feed",
|
|
71
|
+
"group": "publication",
|
|
72
|
+
"tags": ["tech", "startup", "developer", "news"]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"value": "metro",
|
|
76
|
+
"label": "Metro",
|
|
77
|
+
"hint": "Bold asymmetric culture mosaic",
|
|
78
|
+
"group": "publication",
|
|
79
|
+
"tags": ["culture", "urban", "creative", "media", "bold"]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"value": "review",
|
|
83
|
+
"label": "Review",
|
|
84
|
+
"hint": "Refined longform column",
|
|
85
|
+
"group": "publication",
|
|
86
|
+
"tags": ["longform", "essay", "academic", "consulting", "refined"]
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"value": "signal",
|
|
90
|
+
"label": "Signal",
|
|
91
|
+
"hint": "Vivid tech-culture hero grid",
|
|
92
|
+
"group": "publication",
|
|
93
|
+
"tags": ["tech", "media", "consumer", "vivid"]
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"value": "current",
|
|
97
|
+
"label": "Current",
|
|
98
|
+
"hint": "High-contrast electric grotesque",
|
|
99
|
+
"group": "publication",
|
|
100
|
+
"tags": ["fashion", "culture", "creative", "bold"]
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"value": "ledger",
|
|
104
|
+
"label": "Ledger",
|
|
105
|
+
"hint": "Business / markets desk",
|
|
106
|
+
"group": "publication",
|
|
107
|
+
"tags": ["finance", "markets", "fintech", "b2b", "professional"]
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"value": "atelier",
|
|
111
|
+
"label": "Atelier",
|
|
112
|
+
"hint": "Warm-paper lifestyle quarterly",
|
|
113
|
+
"group": "publication",
|
|
114
|
+
"tags": ["lifestyle", "craft", "hospitality", "warm"]
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"value": "noir",
|
|
118
|
+
"label": "Noir",
|
|
119
|
+
"hint": "Dark neon terminal",
|
|
120
|
+
"group": "publication",
|
|
121
|
+
"tags": ["developer", "security", "crypto", "gaming", "dark"]
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"value": "chronicle",
|
|
125
|
+
"label": "Chronicle",
|
|
126
|
+
"hint": "Authoritative politics + economics",
|
|
127
|
+
"group": "publication",
|
|
128
|
+
"tags": ["policy", "economics", "legal", "authoritative"]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"value": "verdure",
|
|
132
|
+
"label": "Verdure",
|
|
133
|
+
"hint": "Nutrition & wellness pinboard",
|
|
134
|
+
"group": "brand",
|
|
135
|
+
"tags": ["nutrition", "wellness", "health", "fitness", "green"]
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"value": "couture",
|
|
139
|
+
"label": "Couture",
|
|
140
|
+
"hint": "High-fashion magazine cover",
|
|
141
|
+
"group": "brand",
|
|
142
|
+
"tags": ["fashion", "luxury", "beauty"]
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"value": "atlas",
|
|
146
|
+
"label": "Atlas",
|
|
147
|
+
"hint": "Travel & exploration gallery",
|
|
148
|
+
"group": "brand",
|
|
149
|
+
"tags": ["travel", "outdoors", "hospitality", "exploration"]
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"value": "missive",
|
|
153
|
+
"label": "Missive",
|
|
154
|
+
"hint": "Personal newsletter digest",
|
|
155
|
+
"group": "brand",
|
|
156
|
+
"tags": ["newsletter", "personal", "community", "writing"]
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"value": "commit",
|
|
160
|
+
"label": "Commit",
|
|
161
|
+
"hint": "Engineering changelog timeline",
|
|
162
|
+
"group": "brand",
|
|
163
|
+
"tags": ["developer", "engineering", "saas", "technical"]
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"value": "apex",
|
|
167
|
+
"label": "Apex",
|
|
168
|
+
"hint": "Athletic performance, dark cinematic",
|
|
169
|
+
"group": "brand",
|
|
170
|
+
"tags": ["fitness", "sports", "performance", "dark"]
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"value": "mint",
|
|
174
|
+
"label": "Mint",
|
|
175
|
+
"hint": "Consumer fintech, rounded grid",
|
|
176
|
+
"group": "brand",
|
|
177
|
+
"tags": ["fintech", "consumer", "finance", "friendly"]
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"value": "bloom",
|
|
181
|
+
"label": "Bloom",
|
|
182
|
+
"hint": "Beauty editorial, blush grid",
|
|
183
|
+
"group": "brand",
|
|
184
|
+
"tags": ["beauty", "skincare", "lifestyle", "soft"]
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"value": "cinder",
|
|
188
|
+
"label": "Cinder",
|
|
189
|
+
"hint": "Gaming & esports, neon mosaic",
|
|
190
|
+
"group": "brand",
|
|
191
|
+
"tags": ["gaming", "esports", "entertainment", "dark"]
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"value": "hearth",
|
|
195
|
+
"label": "Hearth",
|
|
196
|
+
"hint": "Interior design & architecture",
|
|
197
|
+
"group": "brand",
|
|
198
|
+
"tags": ["interior-design", "architecture", "real-estate", "warm"]
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"value": "harvest",
|
|
202
|
+
"label": "Harvest",
|
|
203
|
+
"hint": "Food & recipe mosaic",
|
|
204
|
+
"group": "brand",
|
|
205
|
+
"tags": ["food", "recipes", "hospitality", "consumer"]
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"value": "terra",
|
|
209
|
+
"label": "Terra",
|
|
210
|
+
"hint": "Sustainability & climate longform",
|
|
211
|
+
"group": "brand",
|
|
212
|
+
"tags": ["sustainability", "climate", "nonprofit", "green"]
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"value": "verve",
|
|
216
|
+
"label": "Verve",
|
|
217
|
+
"hint": "Music & pop culture mosaic",
|
|
218
|
+
"group": "brand",
|
|
219
|
+
"tags": ["music", "pop-culture", "entertainment", "bold"]
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"value": "estate",
|
|
223
|
+
"label": "Estate",
|
|
224
|
+
"hint": "Luxury real estate hero",
|
|
225
|
+
"group": "brand",
|
|
226
|
+
"tags": ["real-estate", "luxury", "professional"]
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"value": "counsel",
|
|
230
|
+
"label": "Counsel",
|
|
231
|
+
"hint": "Professional-services thought leadership",
|
|
232
|
+
"group": "brand",
|
|
233
|
+
"tags": ["legal", "consulting", "professional-services", "b2b"]
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"value": "clinic",
|
|
237
|
+
"label": "Clinic",
|
|
238
|
+
"hint": "Healthcare & biotech feed",
|
|
239
|
+
"group": "brand",
|
|
240
|
+
"tags": ["healthcare", "biotech", "medical", "clean"]
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"value": "nook",
|
|
244
|
+
"label": "Nook",
|
|
245
|
+
"hint": "Parenting & family, cozy grid",
|
|
246
|
+
"group": "brand",
|
|
247
|
+
"tags": ["parenting", "family", "education", "cozy"]
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"value": "lumen",
|
|
251
|
+
"label": "Lumen",
|
|
252
|
+
"hint": "Science & ideas feature feed",
|
|
253
|
+
"group": "brand",
|
|
254
|
+
"tags": ["science", "research", "education", "clean"]
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"value": "cellar",
|
|
258
|
+
"label": "Cellar",
|
|
259
|
+
"hint": "Craft coffee & beverage journal",
|
|
260
|
+
"group": "brand",
|
|
261
|
+
"tags": ["coffee", "beverage", "craft", "hospitality"]
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"value": "horizon",
|
|
265
|
+
"label": "Horizon",
|
|
266
|
+
"hint": "B2B SaaS product marketing, glossy gradient",
|
|
267
|
+
"group": "brand",
|
|
268
|
+
"tags": ["saas", "b2b", "tech", "product-marketing"]
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"value": "derma",
|
|
272
|
+
"label": "Derma",
|
|
273
|
+
"hint": "Editorial skin/beauty, Caslon serif headlines",
|
|
274
|
+
"group": "brand",
|
|
275
|
+
"tags": ["beauty", "skincare", "wellness", "editorial", "serif"]
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"value": "meridian",
|
|
279
|
+
"label": "Meridian",
|
|
280
|
+
"hint": "Management-consulting column, brass serif",
|
|
281
|
+
"group": "business",
|
|
282
|
+
"tags": ["consulting", "management", "professional-services", "b2b", "serif"]
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"value": "keystone",
|
|
286
|
+
"label": "Keystone",
|
|
287
|
+
"hint": "Financial-services feed",
|
|
288
|
+
"group": "business",
|
|
289
|
+
"tags": ["finance", "financial-services", "banking", "b2b", "professional"]
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"value": "vantage",
|
|
293
|
+
"label": "Vantage",
|
|
294
|
+
"hint": "B2B SaaS product grid",
|
|
295
|
+
"group": "business",
|
|
296
|
+
"tags": ["saas", "b2b", "product", "tech", "professional"]
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"value": "cobalt",
|
|
300
|
+
"label": "Cobalt",
|
|
301
|
+
"hint": "Enterprise cloud & IT, dark",
|
|
302
|
+
"group": "business",
|
|
303
|
+
"tags": ["cloud", "enterprise", "it", "infrastructure", "dark"]
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"value": "sterling",
|
|
307
|
+
"label": "Sterling",
|
|
308
|
+
"hint": "Private banking & wealth column",
|
|
309
|
+
"group": "business",
|
|
310
|
+
"tags": ["wealth", "private-banking", "finance", "luxury", "professional"]
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"value": "momentum",
|
|
314
|
+
"label": "Momentum",
|
|
315
|
+
"hint": "Marketing & brand, glossy",
|
|
316
|
+
"group": "business",
|
|
317
|
+
"tags": ["marketing", "brand", "advertising", "growth", "bold"]
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
"value": "forum",
|
|
321
|
+
"label": "Forum",
|
|
322
|
+
"hint": "Economics & policy broadsheet",
|
|
323
|
+
"group": "business",
|
|
324
|
+
"tags": ["economics", "policy", "think-tank", "b2b", "authoritative"]
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"value": "cadence",
|
|
328
|
+
"label": "Cadence",
|
|
329
|
+
"hint": "People & future-of-work grid",
|
|
330
|
+
"group": "business",
|
|
331
|
+
"tags": ["hr", "future-of-work", "workplace", "people", "b2b"]
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"value": "evergreen",
|
|
335
|
+
"label": "Evergreen",
|
|
336
|
+
"hint": "Sustainability & ESG grid",
|
|
337
|
+
"group": "business",
|
|
338
|
+
"tags": ["sustainability", "esg", "climate", "corporate", "green"]
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"value": "beacon",
|
|
342
|
+
"label": "Beacon",
|
|
343
|
+
"hint": "Professional-services feed",
|
|
344
|
+
"group": "business",
|
|
345
|
+
"tags": ["professional-services", "consulting", "advisory", "b2b"]
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"value": "kernel",
|
|
349
|
+
"label": "Kernel",
|
|
350
|
+
"hint": "Developer & open-source, minimal mono",
|
|
351
|
+
"group": "technology",
|
|
352
|
+
"tags": ["developer", "open-source", "engineering", "technical", "minimal"]
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
"value": "graphite",
|
|
356
|
+
"label": "Graphite",
|
|
357
|
+
"hint": "Dark engineering writing, minimal",
|
|
358
|
+
"group": "technology",
|
|
359
|
+
"tags": ["engineering", "developer", "writing", "technical", "dark", "minimal"]
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"value": "cortex",
|
|
363
|
+
"label": "Cortex",
|
|
364
|
+
"hint": "AI / ML research lab, glossy",
|
|
365
|
+
"group": "technology",
|
|
366
|
+
"tags": ["ai", "ml", "research", "data-science", "tech"]
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
"value": "cipher",
|
|
370
|
+
"label": "Cipher",
|
|
371
|
+
"hint": "Cybersecurity feed, alert red",
|
|
372
|
+
"group": "technology",
|
|
373
|
+
"tags": ["security", "cybersecurity", "infosec", "enterprise", "dark"]
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
"value": "pulse",
|
|
377
|
+
"label": "Pulse",
|
|
378
|
+
"hint": "DevOps & observability mosaic",
|
|
379
|
+
"group": "technology",
|
|
380
|
+
"tags": ["devops", "observability", "sre", "infrastructure", "tech"]
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"value": "apiwire",
|
|
384
|
+
"label": "API Wire",
|
|
385
|
+
"hint": "Dark developer gallery, sci-fi type",
|
|
386
|
+
"group": "technology",
|
|
387
|
+
"tags": ["developer", "api", "integration", "security", "dark", "technical"]
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"value": "bourse",
|
|
391
|
+
"label": "Bourse",
|
|
392
|
+
"hint": "Creative Boom-style VC/finance magazine, stock photos",
|
|
393
|
+
"group": "business",
|
|
394
|
+
"tags": ["venture", "vc", "finance", "startup", "editorial", "magazine"]
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
"value": "folio",
|
|
398
|
+
"label": "Folio",
|
|
399
|
+
"hint": "grafill-style design magazine, immersive photo articles",
|
|
400
|
+
"group": "business",
|
|
401
|
+
"tags": ["finance", "accounting", "b2b", "saas", "editorial", "design"]
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
"value": "kiosk",
|
|
405
|
+
"label": "Kiosk",
|
|
406
|
+
"hint": "Taste-style warm editorial newsstand, riso covers",
|
|
407
|
+
"group": "publication",
|
|
408
|
+
"tags": ["editorial", "magazine", "tech", "b2b", "warm", "design"]
|
|
409
|
+
}
|
|
410
|
+
]
|
|
411
|
+
}
|
package/tokens.css
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/* GENERATED by design/scripts/build.mjs — do not edit by hand. Source: design/tokens.json.
|
|
2
|
+
*
|
|
3
|
+
* Letterstory design tokens as CSS custom properties. Framework-neutral: load this
|
|
4
|
+
* stylesheet, then map the variables with the adapter for your framework
|
|
5
|
+
* (tailwind-v4.css, tailwind-v3.cjs, styled.js) or read them with var() directly.
|
|
6
|
+
* Dark values switch on a `.dark` class on an ancestor (next-themes attribute="class").
|
|
7
|
+
*
|
|
8
|
+
* --font-sans and --font-mono deliberately use Tailwind v4's own theme names so the
|
|
9
|
+
* font-sans / font-mono utilities and preflight's html default pick them up with no
|
|
10
|
+
* @theme mapping; radii and the type scale are mirrored in each adapter instead.
|
|
11
|
+
*/
|
|
12
|
+
:root {
|
|
13
|
+
--radius: 0.625rem;
|
|
14
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
15
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
16
|
+
--radius-lg: var(--radius);
|
|
17
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
18
|
+
/* BRAND COLOR — the single source (#093959). To rebrand, change color.light.brand in tokens.json. */
|
|
19
|
+
--brand: oklch(0.332 0.074 243.6);
|
|
20
|
+
/* text/icons on a --brand background */
|
|
21
|
+
--brand-foreground: oklch(0.985 0 0);
|
|
22
|
+
/* derived from --brand (same hue, adjusted lightness/chroma) */
|
|
23
|
+
--brand-light: oklch(from var(--brand) 0.82 0.06 h);
|
|
24
|
+
/* naked brand text/icons on light surfaces */
|
|
25
|
+
--brand-text: var(--brand);
|
|
26
|
+
/* "Burnt Peach" — the product accent */
|
|
27
|
+
--accent-peach: #ee724a;
|
|
28
|
+
--accent-peach-hover: #e2643b;
|
|
29
|
+
--accent-mint: #9af2e0;
|
|
30
|
+
/* emerald — up / good */
|
|
31
|
+
--rising: oklch(0.72 0.17 155);
|
|
32
|
+
/* red — down / at risk */
|
|
33
|
+
--falling: oklch(0.63 0.21 25);
|
|
34
|
+
/* amber — needs attention, not yet at risk */
|
|
35
|
+
--warning: oklch(0.75 0.16 75);
|
|
36
|
+
--background: oklch(1 0 0);
|
|
37
|
+
--foreground: oklch(0.145 0 0);
|
|
38
|
+
--card: oklch(1 0 0);
|
|
39
|
+
--card-foreground: oklch(0.145 0 0);
|
|
40
|
+
--popover: oklch(1 0 0);
|
|
41
|
+
--popover-foreground: oklch(0.145 0 0);
|
|
42
|
+
--primary: oklch(0.205 0 0);
|
|
43
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
44
|
+
--secondary: oklch(0.97 0 0);
|
|
45
|
+
--secondary-foreground: oklch(0.205 0 0);
|
|
46
|
+
--muted: oklch(0.97 0 0);
|
|
47
|
+
--muted-foreground: oklch(0.556 0 0);
|
|
48
|
+
--accent: oklch(0.97 0 0);
|
|
49
|
+
--accent-foreground: oklch(0.205 0 0);
|
|
50
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
51
|
+
--border: oklch(0.922 0 0);
|
|
52
|
+
--input: oklch(0.922 0 0);
|
|
53
|
+
--ring: oklch(0.708 0 0);
|
|
54
|
+
--chart-1: oklch(0.646 0.222 41.116);
|
|
55
|
+
--chart-2: oklch(0.6 0.118 184.704);
|
|
56
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
57
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
58
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
59
|
+
--sidebar: oklch(0.985 0 0);
|
|
60
|
+
--sidebar-foreground: oklch(0.145 0 0);
|
|
61
|
+
--sidebar-primary: oklch(0.205 0 0);
|
|
62
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
63
|
+
--sidebar-accent: oklch(0.97 0 0);
|
|
64
|
+
--sidebar-accent-foreground: oklch(0.205 0 0);
|
|
65
|
+
--sidebar-border: oklch(0.922 0 0);
|
|
66
|
+
--sidebar-ring: oklch(0.708 0 0);
|
|
67
|
+
--font-sans:
|
|
68
|
+
"DM Sans", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
|
69
|
+
"Noto Color Emoji";
|
|
70
|
+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
71
|
+
--font-size-2xs: 0.6875rem;
|
|
72
|
+
--line-height-2xs: 1rem;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.dark {
|
|
76
|
+
/* --brand and --brand-foreground inherit from :root; only the on-dark variants are lightened */
|
|
77
|
+
--brand-light: oklch(from var(--brand) 0.5 0.09 h);
|
|
78
|
+
--brand-text: oklch(from var(--brand) 0.72 0.1 h);
|
|
79
|
+
--background: oklch(0.145 0 0);
|
|
80
|
+
--foreground: oklch(0.985 0 0);
|
|
81
|
+
--card: oklch(0.205 0 0);
|
|
82
|
+
--card-foreground: oklch(0.985 0 0);
|
|
83
|
+
--popover: oklch(0.205 0 0);
|
|
84
|
+
--popover-foreground: oklch(0.985 0 0);
|
|
85
|
+
--primary: oklch(0.922 0 0);
|
|
86
|
+
--primary-foreground: oklch(0.205 0 0);
|
|
87
|
+
--secondary: oklch(0.269 0 0);
|
|
88
|
+
--secondary-foreground: oklch(0.985 0 0);
|
|
89
|
+
--muted: oklch(0.269 0 0);
|
|
90
|
+
--muted-foreground: oklch(0.708 0 0);
|
|
91
|
+
--accent: oklch(0.269 0 0);
|
|
92
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
93
|
+
--destructive: oklch(0.704 0.191 22.216);
|
|
94
|
+
--border: oklch(1 0 0 / 10%);
|
|
95
|
+
--input: oklch(1 0 0 / 15%);
|
|
96
|
+
--ring: oklch(0.556 0 0);
|
|
97
|
+
--chart-1: oklch(0.488 0.243 264.376);
|
|
98
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
99
|
+
--chart-3: oklch(0.769 0.188 70.08);
|
|
100
|
+
/* Burnt Peach (#EE724A) */
|
|
101
|
+
--chart-4: oklch(0.692 0.162 38.8);
|
|
102
|
+
--chart-5: oklch(0.645 0.246 16.439);
|
|
103
|
+
--sidebar: oklch(0.205 0 0);
|
|
104
|
+
--sidebar-foreground: oklch(0.985 0 0);
|
|
105
|
+
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
106
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
107
|
+
--sidebar-accent: oklch(0.269 0 0);
|
|
108
|
+
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
109
|
+
--sidebar-border: oklch(1 0 0 / 10%);
|
|
110
|
+
--sidebar-ring: oklch(0.556 0 0);
|
|
111
|
+
}
|
package/tokens.json
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
{
|
|
2
|
+
"color": {
|
|
3
|
+
"light": {
|
|
4
|
+
"brand": "oklch(0.332 0.074 243.6)",
|
|
5
|
+
"brand-foreground": "oklch(0.985 0 0)",
|
|
6
|
+
"brand-light": "oklch(from var(--brand) 0.82 0.06 h)",
|
|
7
|
+
"brand-text": "var(--brand)",
|
|
8
|
+
"accent-peach": "#ee724a",
|
|
9
|
+
"accent-peach-hover": "#e2643b",
|
|
10
|
+
"accent-mint": "#9af2e0",
|
|
11
|
+
"rising": "oklch(0.72 0.17 155)",
|
|
12
|
+
"falling": "oklch(0.63 0.21 25)",
|
|
13
|
+
"warning": "oklch(0.75 0.16 75)",
|
|
14
|
+
"background": "oklch(1 0 0)",
|
|
15
|
+
"foreground": "oklch(0.145 0 0)",
|
|
16
|
+
"card": "oklch(1 0 0)",
|
|
17
|
+
"card-foreground": "oklch(0.145 0 0)",
|
|
18
|
+
"popover": "oklch(1 0 0)",
|
|
19
|
+
"popover-foreground": "oklch(0.145 0 0)",
|
|
20
|
+
"primary": "oklch(0.205 0 0)",
|
|
21
|
+
"primary-foreground": "oklch(0.985 0 0)",
|
|
22
|
+
"secondary": "oklch(0.97 0 0)",
|
|
23
|
+
"secondary-foreground": "oklch(0.205 0 0)",
|
|
24
|
+
"muted": "oklch(0.97 0 0)",
|
|
25
|
+
"muted-foreground": "oklch(0.556 0 0)",
|
|
26
|
+
"accent": "oklch(0.97 0 0)",
|
|
27
|
+
"accent-foreground": "oklch(0.205 0 0)",
|
|
28
|
+
"destructive": "oklch(0.577 0.245 27.325)",
|
|
29
|
+
"border": "oklch(0.922 0 0)",
|
|
30
|
+
"input": "oklch(0.922 0 0)",
|
|
31
|
+
"ring": "oklch(0.708 0 0)",
|
|
32
|
+
"chart-1": "oklch(0.646 0.222 41.116)",
|
|
33
|
+
"chart-2": "oklch(0.6 0.118 184.704)",
|
|
34
|
+
"chart-3": "oklch(0.398 0.07 227.392)",
|
|
35
|
+
"chart-4": "oklch(0.828 0.189 84.429)",
|
|
36
|
+
"chart-5": "oklch(0.769 0.188 70.08)",
|
|
37
|
+
"sidebar": "oklch(0.985 0 0)",
|
|
38
|
+
"sidebar-foreground": "oklch(0.145 0 0)",
|
|
39
|
+
"sidebar-primary": "oklch(0.205 0 0)",
|
|
40
|
+
"sidebar-primary-foreground": "oklch(0.985 0 0)",
|
|
41
|
+
"sidebar-accent": "oklch(0.97 0 0)",
|
|
42
|
+
"sidebar-accent-foreground": "oklch(0.205 0 0)",
|
|
43
|
+
"sidebar-border": "oklch(0.922 0 0)",
|
|
44
|
+
"sidebar-ring": "oklch(0.708 0 0)"
|
|
45
|
+
},
|
|
46
|
+
"dark": {
|
|
47
|
+
"brand-light": "oklch(from var(--brand) 0.5 0.09 h)",
|
|
48
|
+
"brand-text": "oklch(from var(--brand) 0.72 0.1 h)",
|
|
49
|
+
"background": "oklch(0.145 0 0)",
|
|
50
|
+
"foreground": "oklch(0.985 0 0)",
|
|
51
|
+
"card": "oklch(0.205 0 0)",
|
|
52
|
+
"card-foreground": "oklch(0.985 0 0)",
|
|
53
|
+
"popover": "oklch(0.205 0 0)",
|
|
54
|
+
"popover-foreground": "oklch(0.985 0 0)",
|
|
55
|
+
"primary": "oklch(0.922 0 0)",
|
|
56
|
+
"primary-foreground": "oklch(0.205 0 0)",
|
|
57
|
+
"secondary": "oklch(0.269 0 0)",
|
|
58
|
+
"secondary-foreground": "oklch(0.985 0 0)",
|
|
59
|
+
"muted": "oklch(0.269 0 0)",
|
|
60
|
+
"muted-foreground": "oklch(0.708 0 0)",
|
|
61
|
+
"accent": "oklch(0.269 0 0)",
|
|
62
|
+
"accent-foreground": "oklch(0.985 0 0)",
|
|
63
|
+
"destructive": "oklch(0.704 0.191 22.216)",
|
|
64
|
+
"border": "oklch(1 0 0 / 10%)",
|
|
65
|
+
"input": "oklch(1 0 0 / 15%)",
|
|
66
|
+
"ring": "oklch(0.556 0 0)",
|
|
67
|
+
"chart-1": "oklch(0.488 0.243 264.376)",
|
|
68
|
+
"chart-2": "oklch(0.696 0.17 162.48)",
|
|
69
|
+
"chart-3": "oklch(0.769 0.188 70.08)",
|
|
70
|
+
"chart-4": "oklch(0.692 0.162 38.8)",
|
|
71
|
+
"chart-5": "oklch(0.645 0.246 16.439)",
|
|
72
|
+
"sidebar": "oklch(0.205 0 0)",
|
|
73
|
+
"sidebar-foreground": "oklch(0.985 0 0)",
|
|
74
|
+
"sidebar-primary": "oklch(0.488 0.243 264.376)",
|
|
75
|
+
"sidebar-primary-foreground": "oklch(0.985 0 0)",
|
|
76
|
+
"sidebar-accent": "oklch(0.269 0 0)",
|
|
77
|
+
"sidebar-accent-foreground": "oklch(0.985 0 0)",
|
|
78
|
+
"sidebar-border": "oklch(1 0 0 / 10%)",
|
|
79
|
+
"sidebar-ring": "oklch(0.556 0 0)"
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"radius": {
|
|
83
|
+
"DEFAULT": "0.625rem",
|
|
84
|
+
"sm": "calc(var(--radius) - 4px)",
|
|
85
|
+
"md": "calc(var(--radius) - 2px)",
|
|
86
|
+
"lg": "var(--radius)",
|
|
87
|
+
"xl": "calc(var(--radius) + 4px)"
|
|
88
|
+
},
|
|
89
|
+
"font": {
|
|
90
|
+
"sans": [
|
|
91
|
+
"DM Sans",
|
|
92
|
+
"ui-sans-serif",
|
|
93
|
+
"system-ui",
|
|
94
|
+
"sans-serif",
|
|
95
|
+
"Apple Color Emoji",
|
|
96
|
+
"Segoe UI Emoji",
|
|
97
|
+
"Segoe UI Symbol",
|
|
98
|
+
"Noto Color Emoji"
|
|
99
|
+
],
|
|
100
|
+
"mono": [
|
|
101
|
+
"ui-monospace",
|
|
102
|
+
"SFMono-Regular",
|
|
103
|
+
"Menlo",
|
|
104
|
+
"Monaco",
|
|
105
|
+
"Consolas",
|
|
106
|
+
"Liberation Mono",
|
|
107
|
+
"Courier New",
|
|
108
|
+
"monospace"
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
"size": {
|
|
112
|
+
"2xs": {
|
|
113
|
+
"fontSize": "0.6875rem",
|
|
114
|
+
"lineHeight": "1rem"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|