@nullwert/design-system (0.1.0)

Published 2026-10-31 14:39:22 +01:00 by nullwert

Installation

@nullwert:registry=https://gitea.think-jeckel.de/api/packages/nullwert/npm/
npm install @nullwert/design-system@0.1.0
"@nullwert/design-system": "0.1.0"

About this package

OS1: monochrome-dark retro design system (Iosevka) for local web apps

OS1 — design system

A monochrome-dark retro design system (Iosevka, square corners, hard shadows, pink as the signal color) for local web apps. Zero dependencies: one CSS file with the fonts base64-inlined, plus a small vanilla JS helper.

Derived from the TypeSafeAI "TS.AI.OS1" poster — this is its dark mode.

Files

src/
  tokens.css       design tokens (colors, type, spacing, borders, shadows)
  base.css         @font-face (Iosevka 400/700), reset, focus/selection, .cursor
  components.css   all component classes
  textures.css     dither / halftone decorations
  ds.js            DS.toast / DS.dialog / DS.confirm / DS.prompt / DS.tabs
fonts/             Iosevka woff2 (latin) + license — fetched by scripts/fetch-fonts.mjs
scripts/
  fetch-fonts.mjs  downloads the fonts (only step that needs network)
  build.mjs        concatenates src/*.css, inlines fonts as base64 → dist/
dist/
  ds.css           the single-file bundle (~2.6 MB, fonts included)
  ds.js            copy of src/ds.js
preview/
  poster.html      dark-mode recreation of the poster, built from real components
  gallery.html     every component, interactive

Commands

npm run fonts    # fetch Iosevka woff2 + license (network)
npm run build    # rebuild dist/ds.css + dist/ds.js (stamped with version + git hash)
npm run preview  # serve repo root at :8123 → open /preview/poster.html

Distribution via Gitea npm registry

The bundle ships as the npm package @nullwert/design-system. The Gitea npm registry requires the scope to match the owner, so publish it from the nullwert user/org (or change the scope everywhere if you use a different owner).

One-time setup

  1. Gitea → Settings → Applications → create a token with package:write (publishing) or package:read (consuming).
  2. Copy .npmrc.example to .npmrc and export GITEA_NPM_TOKEN="<token>", then npm publish — or just push to main and let the Gitea Actions workflow (.gitea/workflows/publish.yml) publish when the version changes.

Consumer repos

dl-manager, ebook and launchctl all pin "@nullwert/design-system": "0.1.0" and carry a scripts/sync-ds.mjs + npm run sync-ds that copies node_modules/@nullwert/design-system/dist/* into place:

repo target notes
dl-manager public/ wired into npm run build (graceful fallback if not installed)
ebook src/assets/ run cargo build after — assets are include_str!-embedded
launchctl static/ same as ebook

Each repo has its own .npmrc.example (registry + ${GITEA_NPM_TOKEN} indirection, no secrets committed). Until the package is installed, sync-ds exits 0 and keeps the committed copies.

Changing the design spec

# in design-system/
npm version patch        # 0.1.0 → 0.1.1 (edit src/*.css first)
npm run build            # stamp picks up version + git hash
npm publish

# in each app repo
npm update @nullwert/design-system && npm run sync-ds
cargo build              # Rust apps only — assets embed at compile time

The first line of every deployed ds.css identifies its exact build: /*! @nullwert/design-system v0.1.0+dev built 2026-10-31 */

Tokens

token value role
--bg / --panel / --panel2 / --inset #0c0a0c / #141117 / #1b171e / #08070a surfaces
--titlebar / --titlebar-ink #e8e4ea / #0c0a0c inverted title strips
--line / --line-strong #2b262e / #554b58 borders, rules
--text / --muted / --faint #ece8ee / #938c98 / #635c68 text
--accent / --accent-ink #f2a0c6 / #1c0a14 pink signal — selection/active/focus only
--ok / --warn / --err #74c58c / #d9b36a / #e07a72 status
--font Iosevka, ui-monospace, Menlo, monospace everything
--shadow / --shadow-sm 4px 4px 0 / 2px 2px 0 black hard offset shadows

Components

  • window: .win (+ .win--flat) › .win-bar / .win-body / .win-foot, .display inverted heading chunk, .widget-body
  • badges: .badge, --solid, --accent, --inverse, --ok/--warn/--err
  • buttons: .btn, --primary, --danger, --icon, --sm; .filelabel upload
  • inputs: .input, .textarea, .select, .field label, .field-row, .checkline
  • data: .tbl (+ .tbl--stack responsive, td[data-label]), .rowlist › .row, .card, .history-row-style rows are app-level
  • nav: .tabs › .tab(.active), .tabbar bottom nav, .crumbs
  • overlays: dialog.dlg › .dlg-bar / .dlg-body / .dlg-foot, .toasts › .toast(--info/--warn/--err/--out)
  • status: .dot(--ok/--warn/--err/--busy), .pill, .statusline, .warnbox
  • misc: .progress (<b> fill / <i> square marker), .logview, .empty, .dither(--fine/--dense/--halftone), .burst, .cursor, .muted/.faint/.accent/.nowrap/.mono-file

ds.js

DS.toast(msg, kind?, ms?)                 // kind: ok | info | warn | err; ms=0 stays
DS.confirm(msg, {title, okLabel, cancelLabel, danger}) -> Promise<boolean>
DS.prompt(msg, value?, {title, ...})                -> Promise<string|null>
DS.dialog({title, body, footer})                    -> {el, open, close}
DS.tabs(container, onChange?)                       -> {set(index)}

Integration pattern (used by the three apps)

Apps serve dist/ds.css + dist/ds.js next to their HTML and keep a small page-level <style> for layout only:

  • dl-manager (Node http): files in public/, serveAsset() routes /ds.css /ds.js, <link> + <script src>.
  • ebook (axum): files in src/assets/, include_str! handlers for /ds.css /ds.js in web.rs.
  • launchctl (axum): files in static/, same include_str! pattern in main.rs.

Class-name collisions to watch for

App markup must not reuse ds component classes for other meanings. dl-manager's content panes were renamed section.tab → section.pane (ds .tab is the tab button), and its generic .row flex helper coexists with ds .rowlist .row via a late override in the page style.

Updating the committed copies (package not yet published)

Before the Gitea registry is set up, refresh the apps' committed copies directly:

node scripts/build.mjs
cp dist/ds.css dist/ds.js ../dl-manager/public/
cp dist/ds.css dist/ds.js ../../rust/ebook/src/assets/
cp dist/ds.css dist/ds.js ../../rust/launchctl/static/

Then rebuild the Rust apps (assets embed at compile time).

Details
npm
2026-10-31 14:39:22 +01:00
1
1.9 MiB
Assets (1)
Versions (16) View all
0.9.0 2026-11-08
0.7.0 2026-11-07
0.6.0 2026-11-06
0.5.0 2026-11-06
0.4.0 2026-11-06