@half-built/css 0.1.0 → 0.3.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/README.md +80 -0
- package/package.json +7 -1
- package/src/tokens/primitives.css +39 -17
- package/src/tokens/theme-dark.css +17 -9
- package/src/tokens/theme-light.css +16 -8
package/README.md
CHANGED
|
@@ -9,3 +9,83 @@ Extracted from the private `half-built-robots-blog` repository, where
|
|
|
9
9
|
this CSS was built and used in production. The extraction review that
|
|
10
10
|
checked it for blog-specific assumptions before the move is the design
|
|
11
11
|
record for this package.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Import order matters. In your base layout, load the layer declaration
|
|
16
|
+
first, then tokens, then the base entry, then the patterns you use:
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
import "@half-built/css/layers";
|
|
20
|
+
import "@half-built/css/tokens";
|
|
21
|
+
import "@half-built/css";
|
|
22
|
+
import "@half-built/css/patterns.css";
|
|
23
|
+
import "@half-built/css/prose.css";
|
|
24
|
+
import "@half-built/css/code.css";
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The island stylesheets (`lightbox.css`, `plate-modal.css`,
|
|
28
|
+
`path-player.css`) load the same way, from whichever layout or
|
|
29
|
+
component mounts their island. The `.` entry is the base layer (reset,
|
|
30
|
+
shell, link-tip, scroll-top); it is not the whole system, which is why
|
|
31
|
+
the explicit order above exists.
|
|
32
|
+
|
|
33
|
+
The breakpoints are `@custom-media` rules, so your build needs
|
|
34
|
+
`postcss-custom-media` with `@csstools/postcss-global-data` fed the
|
|
35
|
+
breakpoints file:
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
// postcss.config.mjs
|
|
39
|
+
import { fileURLToPath } from "node:url";
|
|
40
|
+
const breakpoints = fileURLToPath(
|
|
41
|
+
import.meta.resolve("@half-built/css/tokens/breakpoints.css"),
|
|
42
|
+
);
|
|
43
|
+
// plugins: [postcssGlobalData({ files: [breakpoints] }), postcssCustomMedia()]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Sites add their own `site` cascade layer after these imports for local
|
|
47
|
+
overrides. The layer order in `layers.css` already declares it.
|
|
48
|
+
|
|
49
|
+
## Theming
|
|
50
|
+
|
|
51
|
+
The entire third-party theming surface is six primitives: two brand
|
|
52
|
+
families, three stops each. Override any or all of them in your
|
|
53
|
+
`site` layer; every other token in the system derives from these six.
|
|
54
|
+
|
|
55
|
+
| Variable | Default | Role |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| `--brand-1-500` | `#ffaa3c` | Base: lines and fills, dark-theme text ink, light-theme focus ring. |
|
|
58
|
+
| `--brand-1-600` | `#d1820f` | Chart kin; light-theme track-x. |
|
|
59
|
+
| `--brand-1-700` | `#a36300` | Text ink on the light paper. |
|
|
60
|
+
| `--brand-2-300` | `#8ee6f2` | Light kin: dark-theme text ink and track-y. |
|
|
61
|
+
| `--brand-2-500` | `#3cc7dd` | Base: lines and fills, dark-theme focus ring. |
|
|
62
|
+
| `--brand-2-700` | `#1a7f90` | Text ink on the light paper. |
|
|
63
|
+
|
|
64
|
+
An override looks like this:
|
|
65
|
+
|
|
66
|
+
```css
|
|
67
|
+
/* half-built palette override, generated at ui.half-built-robots.com */
|
|
68
|
+
:root {
|
|
69
|
+
--brand-1-500: #3cc74a;
|
|
70
|
+
--brand-1-600: #2a9c38;
|
|
71
|
+
--brand-1-700: #1c6b27;
|
|
72
|
+
--brand-2-300: #a0e8b0;
|
|
73
|
+
--brand-2-500: #34b350;
|
|
74
|
+
--brand-2-700: #1f7a38;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
A derived ramp is built to three thresholds: the 700 stops clear 4.5:1
|
|
79
|
+
against white, the 300 stop clears 4.5:1 against `#111111`, and the
|
|
80
|
+
600 stop clears 3:1 against white. The shipped defaults clear all
|
|
81
|
+
three (the 600 stop was retuned to `#d1820f` for the 3:1 non-text
|
|
82
|
+
gate in 0.2.0). These are targets the derivation satisfies, not a
|
|
83
|
+
floor the system enforces on your behalf. If
|
|
84
|
+
you write your own six values instead of deriving them, you own their
|
|
85
|
+
contrast.
|
|
86
|
+
|
|
87
|
+
The reference site generates a compliant block for you: give it two
|
|
88
|
+
base colors and its palette editor derives the other four stops and
|
|
89
|
+
prints a ready-to-paste override in exactly the shape above. It will
|
|
90
|
+
live at `ui.half-built-robots.com` once deployed; today the source for
|
|
91
|
+
that derivation is `site/src/lib/derive-palette.ts` in this repo.
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@half-built/css",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Design tokens, base, patterns, and prose CSS for the half-built design system.",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/curthenrichs/half-built-ui.git",
|
|
9
|
+
"directory": "packages/css"
|
|
10
|
+
},
|
|
6
11
|
"type": "module",
|
|
7
12
|
"files": ["src"],
|
|
8
13
|
"dependencies": {
|
|
@@ -12,6 +17,7 @@
|
|
|
12
17
|
".": "./src/global.css",
|
|
13
18
|
"./layers": "./src/layers.css",
|
|
14
19
|
"./tokens": "./src/tokens.css",
|
|
20
|
+
"./package.json": "./package.json",
|
|
15
21
|
"./*": "./src/*"
|
|
16
22
|
},
|
|
17
23
|
"publishConfig": { "access": "public" }
|
|
@@ -36,27 +36,49 @@
|
|
|
36
36
|
--gray-750: #3a3a3a;
|
|
37
37
|
--gray-400: #9a9a9a;
|
|
38
38
|
|
|
39
|
-
/*
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
39
|
+
/* Brand ramps, the entire third-party theming surface. Family 1 is
|
|
40
|
+
the ecosystem amber by default, family 2 its cyan complement; the
|
|
41
|
+
names are hue-neutral because a consumer may override all six
|
|
42
|
+
(spec: docs/superpowers/specs/2026-09-05-reference-site-design.md).
|
|
43
|
+
500 is the base, 700 its AA text ink on the light paper, 600 the
|
|
44
|
+
chart kin, 300 the light kin legible as text on the dark ground.
|
|
45
|
+
Brand-1-700 is tuned here for this site the way brand-2-700 was:
|
|
46
|
+
the amber hue at full saturation, taken down until it clears WCAG
|
|
47
|
+
AA (4.5:1) as body text on the white surface (4.84) and on the
|
|
48
|
+
accent's 6% tint (4.66). It replaced #b5680c, a value borrowed
|
|
49
|
+
from BEADZ that sat at 4.24:1 on white (owner call 2026-09-03;
|
|
50
|
+
BEADZ is not a source of values). Family 2 (owner request
|
|
51
|
+
2026-08-26) was chosen to sit where family 1 sits: brand-2-500
|
|
52
|
+
matches brand-1-500's contrast on both grounds (line and fill,
|
|
53
|
+
not text on white) and brand-2-700 is its legible kin for text on
|
|
54
|
+
the light ground. Brand-1-600 was retuned 2026-09-05 (owner call)
|
|
55
|
+
from #d98a1f, which sat at 2.76:1 on white: walked down in OKLCH
|
|
56
|
+
with hue and chroma held until it clears 3:1 as a non-text chart
|
|
57
|
+
line on the light paper (now 3.04). */
|
|
58
|
+
--brand-1-500: #ffaa3c;
|
|
59
|
+
--brand-1-600: #d1820f;
|
|
60
|
+
--brand-1-700: #a36300;
|
|
61
|
+
--brand-2-300: #8ee6f2;
|
|
62
|
+
--brand-2-500: #3cc7dd;
|
|
63
|
+
--brand-2-700: #1a7f90;
|
|
64
|
+
/* Code-viewer kin of family 1 (spec 2026-09-06, live code colors):
|
|
65
|
+
the values the Shiki theme has always baked, promoted to
|
|
66
|
+
primitives so the code token roles below them can follow a
|
|
67
|
+
palette override. 300 is a true lightness stop (OKLCH L 0.885,
|
|
68
|
+
above the 500's 0.804), the family's light kin the way
|
|
69
|
+
brand-2-300 is. "vivid" is deliberately not a numbered stop: at
|
|
70
|
+
L 0.684 it sits at the 600's lightness with more chroma
|
|
71
|
+
(0.159 vs 0.146), so a ramp number would misstate what it is. */
|
|
72
|
+
--brand-1-300: #ffd18a;
|
|
73
|
+
--brand-1-vivid: #e07c14;
|
|
55
74
|
--red-800: #7a1f16;
|
|
56
75
|
--red-300: #ff8a7a;
|
|
57
|
-
--ochre-600: #d98a1f;
|
|
58
76
|
--violet-600: #7a5aa0;
|
|
59
77
|
--violet-300: #b39ad6;
|
|
78
|
+
/* Fixed system color like red and violet above, so it keeps a hue
|
|
79
|
+
name: the code comment ink, a dim warm gray that stays put when
|
|
80
|
+
the brand families are overridden. */
|
|
81
|
+
--umber-500: #8a7a63;
|
|
60
82
|
|
|
61
83
|
/* Strokes, spacing, elevation, motion */
|
|
62
84
|
--stroke-1: 1px;
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
|
|
24
24
|
/* The bright amber is legible as text on the dark ground, so the
|
|
25
25
|
accent and its ink form collapse to one value here. */
|
|
26
|
-
--accent-1: var(--
|
|
27
|
-
--accent-1-ink: var(--
|
|
28
|
-
--accent-2: var(--
|
|
29
|
-
--accent-2-ink: var(--
|
|
26
|
+
--accent-1: var(--brand-1-500);
|
|
27
|
+
--accent-1-ink: var(--brand-1-500);
|
|
28
|
+
--accent-2: var(--brand-2-500);
|
|
29
|
+
--accent-2-ink: var(--brand-2-300);
|
|
30
30
|
--on-accent-1: var(--black-900);
|
|
31
31
|
--on-accent-2: var(--black-900);
|
|
32
32
|
--error-ink: var(--red-300);
|
|
@@ -36,15 +36,23 @@
|
|
|
36
36
|
--code-bg: var(--ink-900);
|
|
37
37
|
--code-fg: var(--parchment);
|
|
38
38
|
--code-line: var(--ink-800);
|
|
39
|
+
/* Syntax token roles (spec 2026-09-06): what the Shiki theme bakes
|
|
40
|
+
as hex, restated as variables so the code-vars transformer can
|
|
41
|
+
emit tokens that follow a palette override. Identical in both
|
|
42
|
+
themes because the code surface is always the warm dark block. */
|
|
43
|
+
--code-token-keyword: var(--brand-1-500);
|
|
44
|
+
--code-token-function: var(--brand-1-300);
|
|
45
|
+
--code-token-string: var(--brand-1-vivid);
|
|
46
|
+
--code-token-comment: var(--umber-500);
|
|
39
47
|
|
|
40
48
|
--veil: var(--black-a60);
|
|
41
49
|
--mat-line: var(--gray-800);
|
|
42
50
|
/* Keyboard ring: the second accent by night, the first by day
|
|
43
51
|
(owner call 2026-08-26). */
|
|
44
|
-
--focus-ring: var(--
|
|
52
|
+
--focus-ring: var(--brand-2-500);
|
|
45
53
|
|
|
46
|
-
--track-x: var(--
|
|
47
|
-
--track-y: var(--
|
|
54
|
+
--track-x: var(--brand-1-500);
|
|
55
|
+
--track-y: var(--brand-2-300);
|
|
48
56
|
--track-z: var(--violet-300);
|
|
49
57
|
|
|
50
58
|
/* The subscribe panel inverts by night: a dark panel with an amber
|
|
@@ -53,8 +61,8 @@
|
|
|
53
61
|
2026-08-26). */
|
|
54
62
|
--panel-bg: var(--black-850);
|
|
55
63
|
--panel-ink: var(--parchment);
|
|
56
|
-
--panel-rule: var(--
|
|
64
|
+
--panel-rule: var(--brand-1-500);
|
|
57
65
|
--panel-error: var(--red-300);
|
|
58
|
-
--panel-ring: var(--
|
|
66
|
+
--panel-ring: var(--brand-1-500);
|
|
59
67
|
}
|
|
60
68
|
}
|
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
/* Amber survives inside the code island and as a line or fill
|
|
22
22
|
color; --accent-1-ink is its legible kin for any text on the
|
|
23
23
|
surface (the tagline's box, Callout tip and warning types). */
|
|
24
|
-
--accent-1: var(--
|
|
25
|
-
--accent-1-ink: var(--
|
|
24
|
+
--accent-1: var(--brand-1-500);
|
|
25
|
+
--accent-1-ink: var(--brand-1-700);
|
|
26
26
|
/* Second accent (cyan), the amber's complement. Same split: the
|
|
27
27
|
bright value is a line or fill, the dark one is text. No component
|
|
28
28
|
reads it yet; its jobs are an owner decision (2026-08-26). */
|
|
29
|
-
--accent-2: var(--
|
|
30
|
-
--accent-2-ink: var(--
|
|
29
|
+
--accent-2: var(--brand-2-500);
|
|
30
|
+
--accent-2-ink: var(--brand-2-700);
|
|
31
31
|
/* Text on an accent fill (a hovered or pressed accent button). */
|
|
32
32
|
--on-accent-1: var(--ink-900);
|
|
33
33
|
--on-accent-2: var(--ink-900);
|
|
@@ -37,6 +37,14 @@
|
|
|
37
37
|
--code-bg: var(--ink-900);
|
|
38
38
|
--code-fg: var(--parchment);
|
|
39
39
|
--code-line: var(--ink-800);
|
|
40
|
+
/* Syntax token roles (spec 2026-09-06): what the Shiki theme bakes
|
|
41
|
+
as hex, restated as variables so the code-vars transformer can
|
|
42
|
+
emit tokens that follow a palette override. Identical in both
|
|
43
|
+
themes because the code surface is always the warm dark block. */
|
|
44
|
+
--code-token-keyword: var(--brand-1-500);
|
|
45
|
+
--code-token-function: var(--brand-1-300);
|
|
46
|
+
--code-token-string: var(--brand-1-vivid);
|
|
47
|
+
--code-token-comment: var(--umber-500);
|
|
40
48
|
|
|
41
49
|
/* Plate-modal chrome (spec 2026-07-30): veil over the blurred page,
|
|
42
50
|
and the viewbox mat one step lighter than --hairline. Values
|
|
@@ -45,16 +53,16 @@
|
|
|
45
53
|
--mat-line: var(--gray-075);
|
|
46
54
|
|
|
47
55
|
/* Path-player timeline series (spec 2026-08-22, owner question 1). */
|
|
48
|
-
--track-x: var(--
|
|
56
|
+
--track-x: var(--brand-1-600);
|
|
49
57
|
/* The second data track is the second accent (owner call 2026-08-26). */
|
|
50
|
-
--track-y: var(--
|
|
58
|
+
--track-y: var(--brand-2-500);
|
|
51
59
|
--track-z: var(--violet-600);
|
|
52
60
|
|
|
53
61
|
/* The subscribe panel, the amber block that bridges every property
|
|
54
62
|
back to the blog. By day: amber ground, warm-dark ink and rule, a
|
|
55
63
|
dark button with white text. By night the panel inverts (see
|
|
56
64
|
theme-dark.css) so the button stays the brightest thing in it. */
|
|
57
|
-
--panel-bg: var(--
|
|
65
|
+
--panel-bg: var(--brand-1-500);
|
|
58
66
|
--panel-ink: var(--ink-900);
|
|
59
67
|
--panel-rule: var(--ink-900);
|
|
60
68
|
--panel-error: var(--red-800);
|
|
@@ -66,7 +74,7 @@
|
|
|
66
74
|
so it reads on both grounds and never means the same as hover. */
|
|
67
75
|
/* Keyboard ring: the first accent by day, the second by night
|
|
68
76
|
(owner call 2026-08-26). */
|
|
69
|
-
--focus-ring: var(--
|
|
77
|
+
--focus-ring: var(--brand-1-500);
|
|
70
78
|
|
|
71
79
|
/* The signature stroke: 2px here, 3px on BEADZ. */
|
|
72
80
|
--stroke: var(--stroke-2);
|