Skip to content

Commit 7e455bf

Browse files
btraversclaude
andcommitted
Introduce btravstack design system (theme/) and consume it on the landing page
Extract the inline tokens and component CSS into a small, build-free design system under theme/: - tokens.css single source of truth (CSS custom properties) - fonts.css Montserrat + JetBrains Mono - theme.css base styles + component classes for plain HTML - vitepress.css adapter mapping tokens onto VitePress --vp-* vars - preview.html living style guide - README.md usage, distribution (Pages + jsDelivr) and versioning The landing page now links theme/theme.css instead of an inline <style> block; rendering is unchanged. Docs sites consume theme/vitepress.css. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8c7df3a commit 7e455bf

7 files changed

Lines changed: 409 additions & 38 deletions

File tree

index.html

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
<link rel="preconnect" href="https://fonts.googleapis.com">
1010
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11-
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap">
11+
12+
<!-- btravstack design system: tokens + base theme (see theme/README.md) -->
13+
<link rel="stylesheet" href="theme/theme.css">
1214

1315
<link rel="icon" type="image/svg+xml" href="assets/beetroot.svg">
1416
<link rel="icon" type="image/png" sizes="32x32" href="assets/favicon-32.png">
@@ -23,43 +25,6 @@
2325
<meta name="twitter:title" content="btravstack — an expressive, robust TypeScript backend">
2426
<meta name="twitter:description" content="Type-safe building blocks for the TypeScript backend: contracts for AMQP &amp; Temporal, and errors as values.">
2527
<meta name="twitter:image" content="https://btravstack.github.io/assets/og-btravstack.png">
26-
27-
<style>
28-
:root{
29-
--bg:#15101c; --bg-grad:#1b1326; --card:#1d1726; --card-soft:#241c31;
30-
--border:rgba(255,255,255,0.08); --border-2:rgba(255,255,255,0.12);
31-
--text:#F5EFF3; --muted:#AEA1BC; --faint:#7E7290;
32-
--accent:#E0589A; --accent-deep:#8E1A52; --green:#46B86C;
33-
--sans:'Montserrat','Segoe UI',sans-serif;
34-
--mono:'JetBrains Mono',ui-monospace,monospace;
35-
}
36-
*{box-sizing:border-box}
37-
html{scroll-behavior:smooth}
38-
body{margin:0;background:var(--bg);font-family:var(--sans);-webkit-font-smoothing:antialiased}
39-
::selection{background:rgba(224,88,154,0.32)}
40-
@keyframes floaty{0%,100%{transform:translateY(0)}50%{transform:translateY(-9px)}}
41-
@keyframes glowpulse{0%,100%{opacity:.55}50%{opacity:.8}}
42-
a.navlink{color:var(--muted);text-decoration:none;font-weight:600;font-size:14.5px;padding:8px 12px;border-radius:9px;transition:color .15s,background .15s}
43-
a.navlink:hover{color:var(--text);background:rgba(255,255,255,0.05)}
44-
.pcard{transition:transform .2s ease,border-color .2s ease,box-shadow .2s ease}
45-
.pcard:hover{transform:translateY(-4px);border-color:var(--border-2);box-shadow:0 24px 60px -28px rgba(0,0,0,0.8)}
46-
.cta-primary:hover{filter:brightness(1.07)}
47-
.cta-ghost:hover{background:rgba(255,255,255,0.06);border-color:var(--border-2)}
48-
.codeblk{cursor:pointer;transition:border-color .15s,background .15s}
49-
.codeblk:hover{border-color:var(--border-2);background:rgba(0,0,0,0.45)}
50-
.repolink{transition:color .15s}
51-
.repolink:hover{color:var(--accent)}
52-
.foot-link{color:var(--muted);text-decoration:none;font-size:14px;transition:color .15s}
53-
.foot-link:hover{color:var(--accent)}
54-
@media (max-width:880px){
55-
.grid-3{grid-template-columns:1fr !important}
56-
.foot-grid{grid-template-columns:1fr 1fr !important}
57-
}
58-
@media (max-width:560px){
59-
.nav-hide{display:none !important}
60-
.foot-grid{grid-template-columns:1fr !important}
61-
}
62-
</style>
6328
</head>
6429
<body>
6530

theme/README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# btravstack design system
2+
3+
The shared visual language for **btravstack** — this landing page and every
4+
project docs site. It is a small set of CSS files driven by design tokens
5+
(CSS custom properties). No build step, no framework.
6+
7+
```
8+
theme/
9+
├─ tokens.css Design tokens — the single source of truth.
10+
├─ fonts.css @font-face / Google Fonts (Montserrat + JetBrains Mono).
11+
├─ theme.css Base styles + component classes for plain HTML.
12+
│ Imports fonts.css + tokens.css → link this one file.
13+
├─ vitepress.css Adapter: maps tokens onto VitePress's --vp-* variables.
14+
└─ preview.html Living style guide (open it to see every token).
15+
```
16+
17+
## Use it
18+
19+
### Plain HTML (this landing page, microsites)
20+
21+
```html
22+
<link rel="stylesheet" href="theme/theme.css">
23+
```
24+
25+
Then reference tokens directly:
26+
27+
```html
28+
<button style="background:var(--accent);color:var(--accent-contrast);
29+
border-radius:var(--radius);font-family:var(--sans)">Get started</button>
30+
```
31+
32+
### VitePress docs sites (amqp-contract, temporal-contract, unthrown)
33+
34+
Both consumer types theme through CSS variables, so one import does it.
35+
In each docs repo, create/extend `.vitepress/theme/custom.css`:
36+
37+
```css
38+
@import "https://cdn.jsdelivr.net/gh/btravstack/btravstack.github.io@main/theme/vitepress.css";
39+
```
40+
41+
and ensure it's loaded by `.vitepress/theme/index.ts`:
42+
43+
```ts
44+
import DefaultTheme from 'vitepress/theme'
45+
import './custom.css'
46+
export default DefaultTheme
47+
```
48+
49+
For a full match, default the docs to dark in `.vitepress/config.ts`:
50+
51+
```ts
52+
export default defineConfig({ appearance: 'dark' })
53+
```
54+
55+
## Distribution
56+
57+
The files are served two ways — pick per consumer:
58+
59+
| URL | When |
60+
| --- | --- |
61+
| `theme/theme.css` (relative) | same-origin pages in this repo |
62+
| `https://btravstack.github.io/theme/<file>` | always-latest, the Pages site |
63+
| `https://cdn.jsdelivr.net/gh/btravstack/btravstack.github.io@<ref>/theme/<file>` | external repos; cached + **versionable** |
64+
65+
Prefer the jsDelivr URL with a **pinned ref** for the docs sites so a token
66+
change can't silently restyle published docs:
67+
68+
- `@main` — always latest (fine while iterating)
69+
- `@v1.0.0` — pinned to a git tag (recommended once stable)
70+
71+
To cut a version: `git tag v1.0.0 && git push --tags`, then bump the `@ref`
72+
in each docs repo when you want to adopt it.
73+
74+
## Changing the design
75+
76+
Edit **`tokens.css`** — it is the source of truth. Avoid hardcoding hex
77+
values anywhere else; reference a token so the change propagates. After a
78+
change, open `theme/preview.html` to eyeball every token in one place, then
79+
tag a new version and roll it out to the docs sites.
80+
81+
> Future option: if a project ever needs tokens in TypeScript/SCSS (not just
82+
> CSS), promote `tokens.css` to a `tokens.json` compiled by Style Dictionary
83+
> into multiple targets. Not needed today — every current consumer reads CSS
84+
> variables natively.

theme/fonts.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*
2+
* btravstack web fonts. Montserrat (display/UI) + JetBrains Mono (code).
3+
* Loaded from Google Fonts so the system stays zero-asset and portable;
4+
* the weights here match the --fw-* tokens in tokens.css.
5+
*/
6+
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');

theme/preview.html

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<title>btravstack design system — style guide</title>
7+
<link rel="icon" type="image/svg+xml" href="../assets/beetroot.svg">
8+
<link rel="stylesheet" href="theme.css">
9+
<style>
10+
body { padding: 48px 28px 80px; }
11+
.wrap { max-width: var(--container); margin: 0 auto; }
12+
h1 { font-weight: var(--fw-extrabold); letter-spacing: -1px; font-size: 34px; margin: 0 0 4px; }
13+
h2 { font-weight: var(--fw-bold); letter-spacing: -0.4px; font-size: 20px; margin: 44px 0 16px;
14+
padding-top: 22px; border-top: 1px solid var(--border); color: var(--text); }
15+
.sub { color: var(--muted); margin: 0 0 8px; font-size: 15px; }
16+
.swatches, .row { display: flex; flex-wrap: wrap; gap: 14px; }
17+
.sw { width: 150px; }
18+
.chip { height: 64px; border-radius: var(--radius); border: 1px solid var(--border); }
19+
.sw code { display: block; font-family: var(--mono); font-size: 12px; color: var(--muted); margin-top: 7px; }
20+
.sw b { display: block; font-size: 13px; font-weight: var(--fw-semibold); margin-top: 6px; }
21+
.card { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 22px; max-width: 320px; }
22+
.badge { font-family: var(--mono); font-size: 11.5px; font-weight: var(--fw-semibold); text-transform: uppercase;
23+
letter-spacing: 0.5px; color: var(--accent); background: rgba(var(--accent-rgb), 0.1);
24+
border: 1px solid rgba(var(--accent-rgb), 0.22); padding: 5px 10px; border-radius: var(--radius-pill); }
25+
.btn { display: inline-flex; align-items: center; text-decoration: none; font-weight: var(--fw-bold);
26+
font-size: 15px; padding: 12px 22px; border-radius: var(--radius); cursor: pointer; }
27+
.btn-primary { background: var(--accent); color: var(--accent-contrast); border: none; box-shadow: var(--shadow-accent); }
28+
.btn-ghost { background: transparent; color: var(--text); border: 1px solid var(--border-2); }
29+
.type-row { display: flex; align-items: baseline; gap: 16px; margin: 10px 0; }
30+
.type-row span { color: var(--faint); font-family: var(--mono); font-size: 12px; }
31+
</style>
32+
</head>
33+
<body>
34+
<div class="wrap">
35+
<h1><span style="color:var(--accent)">btrav</span>stack design system</h1>
36+
<p class="sub">Living style guide. Every value below comes from <code style="font-family:var(--mono)">tokens.css</code>.</p>
37+
38+
<h2>Surfaces &amp; text</h2>
39+
<div class="swatches">
40+
<div class="sw"><div class="chip" style="background:var(--bg)"></div><b>Background</b><code>--bg</code></div>
41+
<div class="sw"><div class="chip" style="background:var(--card)"></div><b>Card</b><code>--card</code></div>
42+
<div class="sw"><div class="chip" style="background:var(--card-soft)"></div><b>Card soft</b><code>--card-soft</code></div>
43+
<div class="sw"><div class="chip" style="background:var(--text)"></div><b>Text</b><code>--text</code></div>
44+
<div class="sw"><div class="chip" style="background:var(--muted)"></div><b>Muted</b><code>--muted</code></div>
45+
<div class="sw"><div class="chip" style="background:var(--faint)"></div><b>Faint</b><code>--faint</code></div>
46+
</div>
47+
48+
<h2>Brand palette</h2>
49+
<div class="swatches">
50+
<div class="sw"><div class="chip" style="background:var(--accent)"></div><b>Accent / pink</b><code>--accent</code></div>
51+
<div class="sw"><div class="chip" style="background:var(--bt-pink-soft)"></div><b>Pink soft</b><code>--bt-pink-soft</code></div>
52+
<div class="sw"><div class="chip" style="background:var(--bt-magenta)"></div><b>Magenta</b><code>--bt-magenta</code></div>
53+
<div class="sw"><div class="chip" style="background:var(--accent-deep)"></div><b>Deep</b><code>--accent-deep</code></div>
54+
<div class="sw"><div class="chip" style="background:var(--bt-leaf)"></div><b>Leaf</b><code>--bt-leaf</code></div>
55+
<div class="sw"><div class="chip" style="background:var(--green)"></div><b>Green</b><code>--green</code></div>
56+
</div>
57+
58+
<h2>Typography</h2>
59+
<div class="type-row"><div style="font-family:var(--sans);font-weight:var(--fw-extrabold);font-size:32px;letter-spacing:-1px">Montserrat ExtraBold</div><span>--sans / --fw-extrabold</span></div>
60+
<div class="type-row"><div style="font-family:var(--sans);font-weight:var(--fw-semibold);font-size:18px">Montserrat SemiBold — body and UI</div><span>--sans / --fw-semibold</span></div>
61+
<div class="type-row"><div style="font-family:var(--mono);font-size:15px;color:var(--accent)">pnpm add unthrown</div><span>--mono</span></div>
62+
63+
<h2>Radii</h2>
64+
<div class="row">
65+
<div class="sw"><div class="chip" style="background:var(--card);border-radius:var(--radius-sm)"></div><code>--radius-sm</code></div>
66+
<div class="sw"><div class="chip" style="background:var(--card);border-radius:var(--radius)"></div><code>--radius</code></div>
67+
<div class="sw"><div class="chip" style="background:var(--card);border-radius:var(--radius-lg)"></div><code>--radius-lg</code></div>
68+
<div class="sw"><div class="chip" style="background:var(--card);border-radius:var(--radius-xl)"></div><code>--radius-xl</code></div>
69+
<div class="sw"><div class="chip" style="background:var(--card);border-radius:var(--radius-pill)"></div><code>--radius-pill</code></div>
70+
</div>
71+
72+
<h2>Components</h2>
73+
<div class="row" style="align-items:flex-start">
74+
<div style="display:flex;flex-direction:column;gap:12px">
75+
<div class="row">
76+
<a class="btn btn-primary cta-primary">Primary CTA</a>
77+
<a class="btn btn-ghost cta-ghost">Ghost</a>
78+
</div>
79+
<div><span class="badge">Messaging</span></div>
80+
</div>
81+
<div class="card pcard">
82+
<span class="badge">Errors</span>
83+
<h3 style="font-weight:var(--fw-extrabold);font-size:22px;letter-spacing:-0.5px;margin:14px 0 4px">unthrown</h3>
84+
<code style="font-family:var(--mono);font-size:13px;color:var(--accent)">unthrown</code>
85+
<p style="color:var(--muted);font-size:14.5px;line-height:1.6;margin:12px 0 0">Hover me — card lift uses <code style="font-family:var(--mono)">--shadow-card</code>.</p>
86+
</div>
87+
</div>
88+
</div>
89+
</body>
90+
</html>

theme/theme.css

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* btravstack theme — base styles + reusable component classes for plain
3+
* HTML surfaces (the landing page, and any hand-authored page).
4+
*
5+
* Single entry point: linking this file pulls in the fonts and tokens too.
6+
* <link rel="stylesheet" href="theme/theme.css">
7+
*
8+
* VitePress docs sites should NOT use this file — they use vitepress.css,
9+
* which maps the same tokens onto VitePress's own theme variables.
10+
*/
11+
@import "./fonts.css";
12+
@import "./tokens.css";
13+
14+
/* ── Base ──────────────────────────────────────────────────────── */
15+
* { box-sizing: border-box; }
16+
html { scroll-behavior: smooth; }
17+
body {
18+
margin: 0;
19+
background: var(--bg);
20+
color: var(--text);
21+
font-family: var(--sans);
22+
-webkit-font-smoothing: antialiased;
23+
}
24+
::selection { background: rgba(var(--accent-rgb), 0.32); }
25+
26+
/* ── Motion ────────────────────────────────────────────────────── */
27+
@keyframes floaty { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }
28+
@keyframes glowpulse{ 0%, 100% { opacity: .55; } 50% { opacity: .8; } }
29+
30+
/* ── Links / nav ───────────────────────────────────────────────── */
31+
a.navlink {
32+
color: var(--muted);
33+
text-decoration: none;
34+
font-weight: var(--fw-semibold);
35+
font-size: 14.5px;
36+
padding: 8px 12px;
37+
border-radius: var(--radius-sm);
38+
transition: color var(--speed-fast), background var(--speed-fast);
39+
}
40+
a.navlink:hover { color: var(--text); background: rgba(255, 255, 255, 0.05); }
41+
42+
.foot-link {
43+
color: var(--muted);
44+
text-decoration: none;
45+
font-size: 14px;
46+
transition: color var(--speed-fast);
47+
}
48+
.foot-link:hover { color: var(--accent); }
49+
50+
.repolink { transition: color var(--speed-fast); }
51+
.repolink:hover { color: var(--accent); }
52+
53+
/* ── Cards ─────────────────────────────────────────────────────── */
54+
.pcard { transition: transform var(--speed) ease, border-color var(--speed) ease, box-shadow var(--speed) ease; }
55+
.pcard:hover {
56+
transform: translateY(-4px);
57+
border-color: var(--border-2);
58+
box-shadow: var(--shadow-card);
59+
}
60+
61+
/* ── Buttons ───────────────────────────────────────────────────── */
62+
.cta-primary:hover { filter: brightness(1.07); }
63+
.cta-ghost:hover { background: rgba(255, 255, 255, 0.06); border-color: var(--border-2); }
64+
65+
/* ── Code block (click-to-copy) ────────────────────────────────── */
66+
.codeblk { cursor: pointer; transition: border-color var(--speed-fast), background var(--speed-fast); }
67+
.codeblk:hover { border-color: var(--border-2); background: rgba(0, 0, 0, 0.45); }
68+
69+
/* ── Responsive helpers ────────────────────────────────────────── */
70+
@media (max-width: 880px) {
71+
.grid-3 { grid-template-columns: 1fr !important; }
72+
.foot-grid{ grid-template-columns: 1fr 1fr !important; }
73+
}
74+
@media (max-width: 560px) {
75+
.nav-hide { display: none !important; }
76+
.foot-grid{ grid-template-columns: 1fr !important; }
77+
}

0 commit comments

Comments
 (0)