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

@david-richard/notify-ds

v1.2.0

Published

Qu Notify design system — tokens, components, and brand assets for the Qu Notify restaurant analytics app.

Downloads

1,995

Readme

notify-ds

Design system for Qu Notify — the restaurant analytics mobile app by Qu. Contains tokens, components, fonts, icons, screenshots, and brand assets.

For AI design agents: Read constraints.md first, then screen-anatomy.md, then come back here for the API surface. Those two files are load-bearing.


What's in this repo

notify-ds/
├── tokens.json          ← W3C DTCG format. Single source of truth for all values.
├── tokens.css           ← CSS custom properties. Import this in any HTML/CSS project.
├── tailwind.config.js   ← Tailwind v3 preset. Use as a preset in consuming projects.
├── constraints.md       ← Hard never/always rules. Read before building any UI.
├── screen-anatomy.md    ← Every screen decomposed spatially. Read before building any screen.
├── CHANGELOG.md         ← Decision log — why things are the way they are.
├── components/          ← React/TypeScript components
│   ├── index.ts         ← Barrel export (single import surface)
│   ├── button.tsx
│   ├── input.tsx
│   ├── checkbox.tsx
│   ├── radio.tsx
│   ├── toggle.tsx
│   ├── selector.tsx
│   ├── tabs.tsx
│   ├── switcher.tsx
│   ├── bottom-nav.tsx
│   ├── badge.tsx
│   └── metric-tile.tsx
├── assets/
│   ├── logo-notify-lockup.svg
│   ├── logo-qu.svg
│   ├── logo-q-mark.svg
│   └── icons/           ← SVG stroke icons, one file per icon
├── fonts/               ← Zilla Slab TTF (all weights). Inter + Red Hat Text via Google Fonts.
└── screenshots/         ← 27 production app screenshots, named descriptively

Product context

Qu Notify is an iOS-first mobile app used by restaurant franchisees, group managers, and store managers to monitor real-time sales, labor, and kitchen performance. It is checked multiple times daily — it is a utility, not an experience. Clarity and data density take priority over decoration.

Primary screens: Splash → Sign In → Dashboard (Sales/Labor/Store/Product tabs) → Metric detail → Menu overlay → Check Search → Tills → Kitchen Intelligence

Users: Franchisees, group managers, store managers

Data shown: Net Sales, Checks, Average Check, Payments, Gross Sales, Discounts, Cash, Tills (Open/Closed/Reconciled), Voids, Service Charges, Labor, Speed of Service, Kitchen fulfillment times


Quick start

As a Tailwind preset

// tailwind.config.js
const notifyPreset = require('notify-ds/tailwind')
module.exports = {
  presets: [notifyPreset],
  content: ['./src/**/*.{ts,tsx,html}'],
}

CSS custom properties

/* In your global CSS */
@import 'notify-ds/tokens.css';

React components

import { Button, MetricTile, TabBar, InputField } from 'notify-ds/components'

// Dashboard tile
<MetricTile label="Net Sales" value="$345.58" trend={11.8} trendLabel="vs yesterday" />

// Primary CTA
<Button variant="primary" size="lg">Sign In</Button>

// Tab bar
<TabBar tabs={["Sales", "Labor", "Store", "Product"]} value={tab} onValueChange={setTab} />

Tokens (raw JSON)

const tokens = require('notify-ds/tokens')
const techBlue = tokens.primitive.color.brand['tech-blue'].$value // "#40CCF2"

Inline SVG icons

<!-- Direct reference -->
<img src="node_modules/notify-ds/assets/icons/search.svg" />

<!-- Or import and inline (recommended) -->
import SearchIcon from 'notify-ds/assets/icons/search.svg'

Design fundamentals

Colors (key values)

| Token | Value | Usage | |---|---|---| | primitive.color.brand.tech-blue | #40CCF2 | Primary CTA buttons, input focus border, context selectors, checkbox on-state, toggle on-state | | primitive.color.brand.teal | #339FB8 | Secondary button outline/text, link text, action labels, check numbers | | primitive.color.neutral.black | #000000 | Primary text, tab/nav selected fill | | primitive.color.neutral.white | #FFFFFF | Card backgrounds, text on dark fills | | primitive.color.neutral.gray-50 | #F4F4F4 | App screen background (never white at page level) | | primitive.color.neutral.gray-100 | #DEDEDE | Tab bar container, switcher container, inactive button bg | | primitive.color.brand.red | #EF2149 | Error borders, error text, required asterisk, toast bg |

Critical: #40CCF2 (cyan) is the CTA button color. #000000 (black) is the selected tab/nav color. These are separate roles and must not be swapped.

Typography

| Family | Role | Usage | |---|---|---| | Inter | Primary | Body text, data labels, metric values, captions | | Red Hat Text | Secondary | Page headers, input labels, button labels, section titles | | Zilla Slab | Display | Splash screen, H2 display headings, pull quotes only |

Font loading is the consumer's responsibility. tokens.css declares font families (--font-primary, --font-display, etc.) but does not load any font files — the canonical mechanism is a single HTML <link> to Google Fonts covering all four families:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
  rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=Red+Hat+Text:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=Red+Hat+Display:wght@400;500;600;700;800;900&family=Zilla+Slab:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&display=swap"
>

For meta-frameworks (TanStack Start, Next, Remix, etc.) put the equivalent <link> in the root route's head(). Don't try to @import url('https://fonts.googleapis.com/...') from your CSS — Tailwind v4 / Vite inline tokens.css and strip the @import statement silently, so fonts won't load.

Zilla Slab TTF files ship at dist/fonts/ for offline / self-hosting scenarios, but tokens.css does not reference them by default. If you need to self-host, add your own @font-face declarations in your project CSS pointing at copies in your public/ directory.

Shapes

  • Inputs: Always border-radius: 9999px (full pill). No exceptions.
  • Buttons: Always border-radius: 9999px (full pill). No exceptions.
  • Metric tiles: border-radius: 16px
  • Modals: border-radius: 24px
  • Bottom nav: border-radius: 60px
  • Tab bar container: border-radius: 9999px
  • Switcher container: border-radius: 8px (not pill — this distinguishes it from TabBar)

Disabled states

Always opacity: 0.5 on the entire component. Never a color swap. The component's current fill/stroke colors remain intact underneath the opacity reduction.

Dark mode

Two modes ship: Light (default) and Dark. Dark is opt-in — set data-theme="dark" (or class="dark") on a root element (<html> or any wrapper):

<html data-theme="dark"> … </html>

Only the semantic color aliases that change are redeclared under the dark selector in tokens.css (surfaces invert to near-black, text to white, nav-selected flips, etc.). Primitives, spacing, radius, typography, and the brand/accent/status colors are mode-stable. Components consume semantic tokens, so they re-theme automatically with no per-component work. The dark values are ported 1:1 from the Figma "Semantic" collection (Dark mode) and documented in tokens.json under $extensions.qu.modes.dark. Tailwind's dark: variant is wired to both the .dark class and [data-theme="dark"].


Component API

Button

<Button
  variant="primary"    // primary | secondary | tertiary | link
  size="md"            // xsm | sm | md | lg
  state="active"       // active | inactive
  iconOnly={false}
  disabled={false}
>
  Sign In
</Button>

<IconButton variant="primary" size="md"><SearchIcon /></IconButton>

InputField

<InputField
  type="default"         // default | password | search
  label="Username"
  required
  placeholder="[email protected]"
  state="normal"         // normal | active | filled | error | disabled | readonly
  errorMessage="Invalid email"
  helperText="We'll never share your email"
/>

Checkbox / Radio / Toggle

<Checkbox label="Remember me" defaultChecked />
<Checkbox label="Select all" indeterminate />

<RadioGroup name="period" value={val} onChange={setVal} label="Time period">
  <Radio value="day"   label="Day" />
  <Radio value="week"  label="Week" />
  <Radio value="month" label="Month" />
</RadioGroup>

<Toggle label="Enable notifications" checked={on} onChange={setOn} />

Selector

<Selector label="All Stores" variant="primary" state="active" open={isOpen} />
<Selector label="This Week"  variant="secondary" state="active" />
<SelectorGroup>
  <Selector label="StoreName" icon={<StoreIcon />} />
  <Selector label="01/06/26"  icon={<CalendarIcon />} />
</SelectorGroup>

TabBar

<TabBar
  tabs={["Sales", "Labor", "Store", "Product"]}
  value={activeTab}
  onValueChange={setActiveTab}
/>
// With content panels:
<TabPanels value={activeTab}>
  <TabPanel value="Sales"><SalesView /></TabPanel>
  <TabPanel value="Labor"><LaborView /></TabPanel>
</TabPanels>

Switcher

<Switcher
  segments={["Day", "Week", "Month"]}
  defaultValue="Week"
  onValueChange={setPeriod}
/>
// With icon segments:
<Switcher segments={[{value:"list", label:"List", icon:<ListIcon/>}, ...]} />

BottomNav

<BottomNavContainer>
  <BottomNav
    items={[
      { value: "dashboard", label: "Dashboard", icon: <DashboardIcon /> },
      { value: "inventory", label: "Inventory", icon: <BoxIcon />, badge: 3 },
      { value: "menu",      label: "Menu",      icon: <MenuIcon /> },
    ]}
    value={activeRoute}
    onValueChange={(v) => router.push(v)}
  />
</BottomNavContainer>

BottomNavContainer positions the nav as fixed bottom-6 left-1/2 -translate-x-1/2.

MetricTile

<MetricTile
  label="Net Sales"
  value="$345.58"
  trend={11.8}
  trendLabel="vs yesterday"
/>

<MetricTileGrid cols={2}>
  <MetricTile label="Net Sales"   value="$345.58" trend={11.8} />
  <MetricTile label="Checks"      value="11"      trend={18.1} />
  <MetricTile label="Avg Check"   value="$33.86"  trend={7.7} />
  <MetricTile label="Gross Sales" value="$368.40" trend={11.4} />
</MetricTileGrid>

// Loading state:
<MetricTile label="Net Sales" value="" trend={0} loading />

Badge / TrendBadge

<Badge variant="success">Open</Badge>
<Badge variant="error">Closed</Badge>
<Badge variant="brand">NEW</Badge>

// Auto-picks color from sign:
<TrendBadge value={11.8} />    // → green "+11.8%"
<TrendBadge value={-5.6} />   // → red "−5.6%"

Screenshots

27 production screenshots in screenshots/. Key ones for design reference:

| File | Shows | |---|---| | sales-dashboard.png | Full dashboard, metric tile grid, context bar, tab bar, bottom nav | | sign-in.png | Auth screen, input field states, primary button, "Powered by" footer | | menu-overlay.png | Bottom sheet, dark scrim, menu structure, "NEW" badge | | net-sales.png | Detail screen, line chart, selected table row, back navigation | | check-search.png | Check cards, teal check numbers, section headers | | dashboard-store-kitchen.png | Nested tab bars, data table, teal action link | | open-tills.png | Empty state pattern, 3-tab bar | | enable-face-id.png | Modal overlay pattern | | loading.png | Splash screen, brand illustration treatment | | dashboard-loading-error-with-toast.png | Error state, toast pattern |


Voice & copy

  • Direct and factual. No marketing copy in UI. "Net Sales" not "Your earnings today."
  • Metric-first. Lead with the number; context follows.
  • Sentence case for all UI copy. ALL CAPS only for NOTIFY wordmark and section category labels (KITCHEN, NETWORK).
  • No emoji. Ever.
  • Present tense for states: "Sign in to continue", "No Tills Found", "Something Went Wrong".
  • Button labels are definitive: "Sign In", "Refresh", "Enable Face ID" — no ellipsis, no "ing" forms.
  • Error toast copy (production): "Ooops, we are having problems"

Known gaps (v1.0.0)

  • Toast component (anatomy in screen-anatomy.md)
  • Data table component (anatomy in screen-anatomy.md)
  • Kitchen Intelligence screen components (dark surface, 72px score, day-part switcher)
  • Chart components (recommend Recharts with cyan/gray color scheme)