npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lagabote/design-system

v0.7.1

Published

Lagabøte design system: tokens, fonts, CSS and React components.

Downloads

1,109

Readme

Lagabøte design system

One system for every Lagabøte surface (the app, the website, Lagabøte-konto, the trust center and the operator tools): tokens, fonts and React components. It is the coded form of the "Lagabøte" Claude Design system (https://claude.ai/artifact/81ZvnrKje36bAMXTueXVNY), whose principles apply here: verifiable, calm, source text in serif and our own words in sans, status always visible, Norwegian first.

The Magnus repository owns this package (packages/design-system). The app depends on it with a file: dependency; every other repository installs @lagabote/design-system from npm and never keeps a copy. Release Please releases this path as the component design-system (tag design-system-vX.Y.Z), and each consumer takes a new version by bumping its dependency. The package has no build step and no app-specific imports.

Publishing: the publish-design-system job in release-please.yml is meant to publish over npm trusted publishing, but npm refuses the OIDC exchange for this repository (npm/cli#9969). Until npm fixes that, an owner of the npm org lagabote publishes each release by hand, with 2FA:

git checkout design-system-vX.Y.Z
cd packages/design-system && npm publish

Use

/* Any bundler: tokens, base and components as plain CSS. */
@import "@lagabote/design-system/styles.css";

/* With Tailwind CSS 4, after `@import "tailwindcss"`: token utilities. */
@import "@lagabote/design-system/tailwind.css";
import { Button, Citation, SourceCard } from "@lagabote/design-system";
  • Fonts. The tokens name Newsreader, Hanken Grotesk and IBM Plex Mono. @import "@lagabote/design-system/fonts.css" self-hosts them (latin subset, OFL); the bundler copies the files, so nothing loads from a third party and the CSP needs only font-src 'self'. Next.js apps may instead override --font-serif, --font-sans and --font-mono on :root with next/font.
  • Themes. Light is the default. Set data-theme="dark" on <html>, or on any subtree.
  • Root size. Sizes are in rem and assume a 16 px root.
  • Navigation. Components that take href render <a>. Pass the router's link as linkAs to navigate without a page load.
  • Icons. icon takes a name from the built-in set or any element, for example a Lucide icon with strokeWidth={1.5}.
  • Classes. The lb-* classes are public. Put them on your own markup when a component does not fit: lb-prose for an answer rendered from Markdown, lb-reading for source text that arrives as HTML, lb-menu on a context menu, lb-toast-viewport around toasts, lb-play for an illustration that acts out a task (the website).
  • Strict CSP. Everything works under style-src 'self': no inline styles and no injected style elements. Dialog and its parts (DialogRoot, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose, DialogTrigger) are Radix's: focus stays in the dialog and returns to what opened it, a menu's button included (focusOrigin, returnFocus).
  • Next.js. Add the package to transpilePackages.

Layout

| Path | What | | ---------------------------- | ------------------------------------------------------- | | tokens.json | The source of truth, in the Claude Design token format | | scripts/build-tokens.mjs | Generates tokens.css and tailwind.css | | scripts/check-contrast.mjs | WCAG contrast for every text and control pairing | | src/styles/tokens.css | Generated: custom properties for both themes | | src/styles/tailwind.css | Generated: bg-surface, text-ink-muted, type-body… | | src/styles/base.css | Body, focus ring, selection, reduced motion | | src/styles/components.css | The lb-* component classes | | src/components | The React components, grouped as in Claude Design | | src/fonts | The self-hosted faces, fonts.css and their licences |

Change a token in tokens.json, run pnpm tokens, and bring the Claude Design system in step. pnpm check fails when the generated files are stale or a pairing loses contrast.

Across Lagabøte

The products are separate repositories on separate hosts, but to a customer and to an operator they are one Lagabøte. Notion is the reference: one quiet workspace, one accent, the same words everywhere. Every surface uses one of three shells:

| Shell | Where | Built from | | --- | --- | --- | | Page | website, trust center | TopBar, content on bg, the shared footer | | Card | sign-in and sign-up (Lagabøte-konto, the app's sign-in) | Logo above one Card on bg | | Workspace | the app, konto's customer and staff screens, Corpus, Acquisition | SideNav on bg-sunken with Logo and the surface's name muted (Lagabøte · Corpus), TopBar with Breadcrumbs |

  • Colours only from tokens; no palette of your own and no raw values.
  • Fonts from fonts.css (or next/font with the same faces).
  • Bokmål in the interface, also for operators.
  • Status in the app's words with StatusTag: «Pågår», «Venter på svar», «Til gjennomgang», «Satt på pause», «Avbrutt».
  • Icons from Icon, or Lucide at strokeWidth={1.5}; no glyphs.
  • The product is Lagabøte; only the assistant is Magnus.
  • Footers of the page and card shells link the same set: Lagabøte (www), Tillitssenter (trust), Personvern, Vilkår and Logg inn.

Tokens

  • Surfaces: surface (white) is cards and the app's work surface. bg is the ground of a page that holds surfaces: the website and the sign-in pages. bg-sunken is alternating website sections and the app's sidebar, surface-muted the source panel, surface-raised menus and dialogs, and surface-inverse the dark band and the toast.
  • Text: ink, ink-secondary, ink-muted, ink-subtle, ink-disabled, ink-inverse, ink-inverse-muted.
  • Lines: line, line-subtle, line-strong (controls), line-inverse.
  • Accent: accent with -hover, -pressed, -soft, -soft-hover; on-accent, link, focus-ring. One accent; one primary action per view.
  • Signals: success, warning, danger, info, each with -soft.
  • Sources: src-lov, src-forarbeid, src-praksis, src-forvaltning, src-eos, src-litteratur. Always next to a text label.
  • Other: highlight, highlight-strong, hover, scrim, viz-1–4, and the stein-* and fjord-* primitives for special cases.
  • Type: --type-<style> font shorthands and type-<style> utilities: display-xl, display-l, display-m, heading-l, heading-m, reading, reading-s, lead, title, body, body-s, label, caption, overline, ref.
  • Scale: space-1–32 (4 px rhythm), radius-xs–xl and full, shadow-sm, -md, -lg, -frame, control-sm, -md, -lg, sidebar-w, source-panel-w, content-max, reading-max, z-*.

Components

  • Brand: Logo, Icon, Avatar, Kbd
  • Actions: Button, IconButton, Menu, DropdownMenu*
  • Forms: TextField, TextArea, Select, Checkbox, RadioGroup, Switch, SegmentedControl, SearchField, Field, Input, Textarea
  • Status and feedback: Badge, StatusTag, Chip, Alert, Toast, Tooltip, Spinner, Skeleton
  • Legal sources: SourceTypeChip, Citation, SourceCard, LegalText
  • Assistant: UserMessage, AnswerBlock, Composer
  • Navigation: TopBar, SideNav, Tabs, TabPanel, Breadcrumbs
  • Structure: Card, ListRow, Table, Dialog, Popover, EmptyState
  • Website: SectionHeader, PricingCard

The website's /design-system page shows them all in both themes.

Beyond the Claude Design system

Added because the app needs them: Popover, Chip, ListRow, SegmentedControl, Field, Input, Textarea, the DropdownMenu* parts (groups, checkable items, switch items for on/off settings, submenus), TabPanel, SideNav collapsed, Skeleton shape="block", Card variant, StatusTag tone, Citation href, the annet source type, lb-prose and lb-reading, and the tokens line-inverse, highlight-strong and hover.

Changed on purpose:

  • AnswerBlock shows certainty only when it is given. The app does not grade legal certainty today, and a default of "Klar rett" would invent one.
  • Dialog, Menu, Tooltip and Tabs have real behaviour (focus, keyboard, placement); in Claude Design they are drawings.
  • Switch, RadioGroup and SegmentedControl are native inputs and need no JavaScript.
  • Sizes are rem instead of px, and the fluid display sizes and the overline's casing are token data instead of prose.
  • Menu rows are 32 px instead of 36 and grow with their text, and a checked item's check trails its label, so checkable and plain items line up.
  • DropdownMenu is modal, as in Radix: a click outside only closes it. Radix locks scrolling with an injected <style>, so a page whose CSP forbids inline styles (the website) passes modal={false}.
  • lb-current is the current item of a list or toggle the app builds itself: a surface with a hairline, never a tint.
  • Small fields use 14 px text, like small buttons, so a dense toolbar reads as one size.
  • A disabled quiet button has no ground, native checkboxes and radios take the accent, a tooltip can sit on any side, and a popover that takes focus shows no ring of its own.
  • Escape closes an open tooltip and is then passed on, so the panel or dialog behind it closes on the same press instead of needing a second one. A press that a menu or dialog has already taken is not passed on.

In the Lagabøte app

The app (apps/frontend) is written on this system; there is no alias layer. Where the old app and this system disagreed, this system decided:

  • Root size: 16 px (html { font-size: 93.75% } is gone).
  • Weights: 400, 500 and 600, with no remapping.
  • Corners: rounded-md is 4 px (was 8).
  • Fonts: Newsreader, Hanken Grotesk and IBM Plex Mono replaced Fraunces, Inter and JetBrains Mono in public/fonts and fonts.css.
  • Accent: primary actions, links and citations are accent; they were ink.
  • Density: controls are 32, 40 and 48 px; the app uses size="sm".

src/app/styles/global.css imports this package and keeps only what is the app's own (shell widths, icon sizes, easings). The architecture test fails on any colour utility that is not a token of this package.

These modules stay in the app on Radix, because their call sites depend on behaviour this package's simpler components do not have, and are drawn with this package's classes: context-menu.tsx (lb-menu), toast.tsx (lb-toast), side-panel.tsx, panel.tsx and theme.tsx.

The tables below map the old names to this system; the modules above are the exceptions. Not yet moved: the source rows in EvidencePanel, the composer and .prose-answer, which use the tokens but their own markup.

Tokens and utilities

| Today in the app | In this system | | ----------------------------------------- | ----------------------------------------------- | | background | surface (bg on a page that holds a card) | | card, input | surface | | panel-strong, popover surfaces | surface-raised | | secondary, muted, rail-bg | bg-sunken | | foreground, ink-1, nav-fg-strong | ink | | ink-2, nav-fg, akn-accent | ink-secondary | | muted-foreground, ink-3 | ink-muted | | ink-4, nav-fg-faint | ink-subtle | | ink-5 | ink-disabled | | primary, primary-foreground | accent, on-accent | | border, rule | line | | rule-2, rail-border | line-subtle | | border-strong | line-strong (controls only) | | ring | focus-ring (global; drop ring-ring classes) | | destructive, destructive-foreground | danger, on-danger | | row-hover, accent-quiet, nav-tint | hover | | row-selected | accent-soft | | flag-bg, flag-ink, flag-dot | warning-soft, warning | | verify-bg, verify-ink, verify-dot | success-soft, success | | hl, hl-strong | highlight, highlight-strong | | state-{info,warning,success}-bg | {info,warning,success}-soft | | state-{info,warning,success}-fg | info, warning, success | | state-*-border | none; tinted surfaces have no border | | shadow, shadow-lg | shadow-sm, shadow-lg | | text-label, text-meta, text-caption | type-caption | | text-body-sm, text-sm on controls | type-body-s, type-label | | doc-font-*, doc-measure | type-reading, reading-max | | sidebar-w (232 px) | sidebar-w (264 px) | | rounded-2xl, rounded-pill | rounded-xl, rounded-full |

The utility follows the token: bg-background becomes bg-surface, bg-muted becomes bg-bg-sunken, text-muted-foreground becomes text-ink-muted, border-border becomes border-line.

Components

| Today in the app | In this system | | --------------------------------------- | ------------------------------------------------------------- | | Button default, destructive | Button variant="primary", "danger" | | Button outline, secondary | Button (secondary is the default) | | Button ghost, link | Button variant="quiet", "link" | | Button size sm and default, lg | size="sm", "md" | | Button size icon, icon-sm, icon-touch | IconButton with size and a required label | | Input, Textarea, NativeSelect | Input, Textarea, Select | | Label + control + FieldError | TextField, TextArea, Select, or Field | | ErrorSummary, Alert | Alert tone="danger" | | Badge default, secondary, muted | Badge tone="accent", neutral | | Badge flag, verify, destructive | Badge tone="warning", "success", "danger" | | Panel default, muted, dashed | Card compact with variant | | Panel info, warning, success | Alert | | Skeleton | Skeleton shape="block" | | Tabs, SegmentedFilter | SegmentedControl, Tabs, or TabsRoot and its parts | | Dialog parts, ConfirmDialog | Dialog; keep useConfirm and render Dialog in it | | DropdownMenu* | DropdownMenu* (same names), or Menu with items | | ContextMenu* | Radix context menu with the lb-menu classes | | Popover* | Popover* | | ToastProvider, useToast | Keep; render Toast. Errors that need action: Alert | | ListRow, EmptyState | ListRow, EmptyState | | CitationChip, CitationPopover | Citation, Popover with lb-source__excerpt | | Source rows in EvidencePanel | SourceCard | | SourceFamilyChip, context chips | Chip with selected | | docTypeLabel text | SourceTypeChip type (the family) with the label as children | | AsOfChip, in-force and repealed text | StatusTag | | WorkStatus, EntitlementBadge | Badge with icon, or StatusTag tone | | MagnusComposer | Composer, or its lb-composer classes | | .product-nav-*, .product-topbar | SideNav (with collapsed), TopBar | | .prose-answer | lb-prose (inside AnswerBlock) | | .akn-* reading styles | lb-reading, type-reading, highlight | | Loader2 with animate-spin, <kbd> | Spinner, Kbd | | The "M" tile and the teal favicon | Logo, assets/lagabote-symbol.svg | | SidePanel, ThemeProvider, data grid | Stay in the app; restyle with tokens |