JK Tools Design System
A shared, no-build design layer for the tools in this repo — a baseline set of design tokens plus a hand-authored component library. Pure vanilla CSS: no framework, no bundler, no dependencies. Works in both the vanilla-JS tools and the CDN-React tool.
This folder is shared infrastructure, not a tool. It is excluded from the generated landing page (see
IGNORE_DIRSinbuild.js).
Files
| File | Purpose |
|---|---|
tokens.css |
CSS custom properties (colors, spacing, page widths, radii, shadows, typography). Colors are stored as HSL channel triplets so translucency composes via hsl(var(--token) / .9). Light/dark/system theming. |
components.css |
Class-based components: page container, button, input/textarea/select, field, switch, card, badge, table, tabs, dialog, toast, plus utilities. Requires tokens.css. |
index.html |
A living gallery of every token and component, with a light/dark toggle. Open it in a browser as the reference. |
Usage
From a tool folder one level below the repo root:
<link rel="stylesheet" href="../design-system/tokens.css">
<link rel="stylesheet" href="../design-system/components.css">
Then use the component classes:
<button class="btn">Primary</button>
<button class="btn btn-outline btn-sm">Secondary action</button>
<span class="badge badge-success">Published</span>
<label class="field">
<span>Handle</span>
<input type="text" placeholder="you.bsky.social">
</label>
<div class="card card-padded"> … </div>
Page layout
Every page wraps its header, content and footer in a single .container, which centres it, caps its width and sets a gutter that scales with the viewport (16px on phones, up to 32px). Choose the width by what the tool is for:
| Class | Max width | For |
|---|---|---|
.container |
1100px | The default |
.container container-narrow |
768px | Reading pages, setup guides, single-column forms |
.container container-wide |
1600px | Workspaces: sidebars, side-by-side panes, wide tables |
.container container-full |
none | Canvases and dashboards that should use the whole screen |
<body>
<div class="container container-wide">
<header class="tool-header">…</header>
<main>…</main>
<footer class="site-footer">…</footer>
</div>
</body>
The widths and gutter are tokens (--container-narrow, --container, --container-wide, --container-pad-x, --container-pad-y), so a tool with its own stylesheet can use them directly. Don't hard-code a page width in a tool.
On wide pages, keep long-form text readable: add .measure (72 characters) to prose blocks, and make grids collapse to minmax(0, 1fr) columns on narrow screens so long content can't push the page wider than the viewport.
Theming
The theme is driven by the data-theme attribute on <html>:
data-theme="light"/data-theme="dark"— forced.- No attribute, or
data-theme="system"— follows the OS viaprefers-color-scheme.
Tools that resolve the theme in JS (e.g. a System/Light/Dark setting) should set data-theme to the resolved light/dark value.
Conventions
- Don't redefine component styles in a tool. Tool stylesheets should only add app-specific layout (page header, grids, bespoke cards) and should reference tokens via
hsl(var(--token))so they track the theme. - Component classes are global. Keep names stable; if a tool needs a one-off, prefer a tool-scoped class over overriding a
.btn/.cardrule. - No emoji or decorative symbols in tool UI. Keep labels textual (e.g. "Refresh Feeds", "Open tool", "Saved") rather than
↻/↗/✓/📡. Functional navigation glyphs are fine where they read as controls —←for back and×for close. For anything pictorial, use an inline SVG icon, not an emoji. - Consistent header. Every tool and README page uses the same
.tool-header(← Back · title · actions) so moving between a tool and its docs feels continuous. Group the actions in a.tool-header-actionsdiv — on a tool page, outlineReadmeandChangelogbuttons — so that on narrow screens the title moves above them. - Consistent footer. End every page with
<footer class="site-footer"><a href="https://jamesking.io">jamesking.io</a></footer>inside its container. - Standard page widths. Use
.containerand its width modifiers (see Page layout) rather than a tool-specific max-width. - Adopting a new component? Add it to
components.cssand showcase it inindex.htmlso the gallery stays complete.
Status
Early/prototype. Pilot adopter: syndicate-elsewhere. Not yet rolled out to audiolog-episode-creator or other tools.