npm package: @strategicnerds/nerdsui-web
Description: Design token package for Strategic Nerds web apps. Provides a Tailwind CSS preset, spacing/radius/color tokens, palette CSS files, and utility hooks. Does not provide UI components -- use shadcn/ui for that.
Latest version: 0.1.1

# NerdsUI Web

Design token package for Strategic Nerds web apps. Provides a Tailwind CSS preset, spacing/radius/color tokens, palette CSS files, and utility hooks. Does not provide UI components -- use shadcn/ui for that.

## Requirements

- React 19+
- Tailwind CSS 4+
- TypeScript 5.7+

## Quick start

### 1. Install

```bash
pnpm add @strategicnerds/nerdsui-web
```

### 2. Import globals and a palette

```css
@import "@strategicnerds/nerdsui-web/preset/globals.css";
@import "@strategicnerds/nerdsui-web/preset/palettes/conjugator.css";
```

`globals.css` defines all default token values. The palette CSS overrides brand colors.

### 3. Map tokens in your Tailwind @theme block

In your `globals.css`, map NerdsUI tokens into Tailwind's theme system. Spacing tokens must be prefixed with `n-` to avoid colliding with Tailwind v4's built-in named sizes (`max-w-lg`, `shadow-lg`, etc.). Radius tokens use standard names since shadcn components use `rounded-lg`, `rounded-md`, etc.

```css
@theme inline {
  /* Colors */
  --color-primary: var(--primary);
  --color-background: var(--background);
  /* ... */

  /* Spacing -- MUST prefix with n- to avoid Tailwind collisions */
  --spacing-n-sm: var(--n-spacing-sm);
  --spacing-n-md: var(--n-spacing-md);
  --spacing-n-lg: var(--n-spacing-lg);
  /* ... */

  /* Radius -- standard names (safe, used by shadcn) */
  --radius-sm: var(--n-radius-sm);
  --radius-md: var(--n-radius-md);
  --radius-lg: var(--n-radius-lg);
  /* ... */
}
```

### 4. Use tokens with shadcn/ui

```tsx
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";

function MyPage() {
  return (
    <div className="min-h-screen bg-background text-foreground p-n-lg">
      <Card>
        <CardContent className="p-n-lg space-y-n-md">
          <h2 className="text-lg font-semibold">Settings</h2>
          <p className="text-sm text-muted-foreground">Manage your account.</p>
          <Button>Save</Button>
        </CardContent>
      </Card>
    </div>
  );
}
```

## What this package provides

- **Tailwind preset** -- maps NerdsUI tokens to Tailwind utility classes
- **CSS globals** -- default token values as CSS custom properties
- **Palette CSS files** -- per-app color overrides
- **Token constants** -- `NSpacing`, `NRadius`, color type definitions (TypeScript)
- **Hooks** -- `useNerdsTheme()`, `useIsMobile()`, `useIsTablet()`, `useIsDesktop()`
- **Utility** -- `cn()` classname merger

## Token reference

### Spacing classes

`p-n-xxxs` (2px), `p-n-xxs` (4px), `p-n-xs` (6px), `p-n-sm` (8px), `p-n-md` (12px), `p-n-lg` (16px), `p-n-xl` (20px), `p-n-xxl` (24px), `p-n-xxxl` (32px), `p-n-huge` (48px)

Works with all Tailwind spacing utilities: `m-n-*`, `p-n-*`, `gap-n-*`, `space-x-n-*`, etc.

**Important:** Spacing tokens use the `n-` prefix to avoid colliding with Tailwind v4's built-in named sizes. Without the prefix, `--spacing-lg` in `@theme` causes `max-w-lg`, `shadow-lg`, and other built-in utilities to resolve to NerdsUI's small spacing value instead of their intended sizes.

### Radius classes

`rounded-xs` (4px), `rounded-sm` (8px), `rounded-md` (12px), `rounded-lg` (16px), `rounded-xl` (20px), `rounded-2xl` (24px), `rounded-full` (9999px)

### Color classes

`bg-primary`, `text-primary`, `border-primary`, `bg-muted`, `text-muted-foreground`, `bg-card`, `text-foreground`, `border-border`, `bg-destructive`, `bg-success`, `bg-warning`, `bg-info`, `text-accent-foreground`, etc.

## Available palettes

| Palette | CSS import |
|---------|-----------|
| Conjugator | `@strategicnerds/nerdsui-web/preset/palettes/conjugator.css` |
| CalorieNerds | `@strategicnerds/nerdsui-web/preset/palettes/calorie-nerds.css` |
| Vinho | `@strategicnerds/nerdsui-web/preset/palettes/vinho.css` |
| TripMaster | `@strategicnerds/nerdsui-web/preset/palettes/tripmaster.css` |
| EventNerds | `@strategicnerds/nerdsui-web/preset/palettes/eventnerds.css` |
| HackNerds | `@strategicnerds/nerdsui-web/preset/palettes/hacknerds.css` |
| FutureNerds | `@strategicnerds/nerdsui-web/preset/palettes/futurenerds.css` |

## Theme hook

```tsx
import { NerdsThemeProvider, useNerdsTheme } from "@strategicnerds/nerdsui-web";

<NerdsThemeProvider value={{ palette: "conjugator" }}>
  <App />
</NerdsThemeProvider>

const { palette } = useNerdsTheme();
```

## Media query hooks

```tsx
import { useIsMobile, useIsTablet, useIsDesktop } from "@strategicnerds/nerdsui-web";
const isMobile = useIsMobile();
```

## Creating a custom palette

Create a CSS file at `src/preset/palettes/<app-name>.css`:

```css
:root {
  --primary: oklch(0.55 0.17 150);
  --primary-foreground: oklch(0.98 0 0);
  --ring: oklch(0.55 0.17 150);
  --accent: oklch(0.92 0.05 150);
  --accent-foreground: oklch(0.3 0.1 150);
}
```

Only override the variables that differ from `globals.css`. Import after globals in your app CSS.

## File structure

```
src/
  preset/
    globals.css
    palettes/<app-name>.css
    index.ts
  tokens/
    spacing.ts
    radius.ts
    typography.ts
    colors.ts
  hooks/
    use-nerds-theme.ts
    use-media-query.ts
  lib/
    cn.ts
  index.ts
```

## Scripts

```bash
npm run test        # Run tests with Vitest
npm run typecheck   # TypeScript type checking
```