import { Meta } from '@storybook/addon-docs/blocks';

<Meta title="Architecture" />

<div className="sb-doc">

# System Architecture

<p className="excerpt">Shade is built as a layered system, with each layer building upon the previous to create a complete design system. This document outlines how these layers work together.</p>

## Read This First (60 seconds)

If you are not sure where code belongs, use this:

- `tokens`: visual values only (color, type, radius, motion)
- `primitives`: layout structure only (`Stack`, `Inline`, `Box`, `Container`, `Grid`, `Text`)
- `components`: reusable generic controls (button, input, dialog)
- `patterns`: repeated product workflows (filters, resource flows)
- `app`: app shell and transitional domain exports
- `utils`: design-system-safe generic helpers only

Fast decision rule:

- If it changes spacing/alignment/layout, use `primitives`.
- If it is a generic control, use `components`.
- If it encodes product workflow, use `patterns`.

## File Structure

```
/apps/shade/
├── src/
│   ├── components/
│   │   ├── ui/           # Base ShadCN components
│   │   ├── layout/       # Composed, reusable layout components
│   │   └── features/     # Feature-specific, higher-level components
│   ├── hooks/            # Custom React hooks
│   ├── providers/        # Context providers
│   ├── lib/ds-utils.ts   # DS-safe utilities
│   ├── lib/app-utils.ts  # Transitional domain utilities
│   └── docs/             # Documentation
├── .storybook/          # Storybook configuration
├── styles.css           # Tailwind imports + runtime variables
└── tailwind.theme.css   # CSS-first token definitions (@theme)
```

## Export Entrypoints

Shade now uses layered package entrypoints:

- `@tryghost/shade/tokens` and `@tryghost/shade/tokens.css`
- `@tryghost/shade/primitives`
- `@tryghost/shade/components`
- `@tryghost/shade/patterns`
- `@tryghost/shade/app`
- `@tryghost/shade/utils`

The root `@tryghost/shade` entrypoint remains a compatibility lane during migration, but new code should import from a layer-specific subpath.
The root entrypoint now keeps compatibility for DS layers only (`tokens`, `primitives`, `components`, `patterns`).
`app` and `utils` are intentionally subpath-only.

## Layer Ownership Rules

- `tokens`: token definitions and helpers only (CSS variables, token names, token lookup helpers).
- `primitives`: structure/layout building blocks with no product/domain behavior.
- `components`: reusable UI controls and visual assets/icons.
- `patterns`: feature-level reusable compositions and interaction rules.
- `app`: app shell/provider/context APIs and transitional domain exports.
- `utils`: DS-safe helpers, generic hooks, and third-party namespaces.

## Human and AI Decision Protocol

Run this order before implementing UI:

1. Choose the layer (`tokens` -> `primitives` -> `components` -> `patterns`).
2. Reuse existing API first.
3. If no fit, keep code local and add it to Shade only after repeated use.
4. Keep shared APIs product-agnostic.

Stop and re-evaluate when:

- a shared component needs workflow-specific props
- a layout abstraction starts carrying business logic
- ownership between `components` and `patterns` is unclear

When to add code to Shade:

- Keep code local first, then add it to Shade when it is reused across surfaces.
- Add to `primitives` when the abstraction is structural.
- Add to `components` when the abstraction is a reusable control.
- Add to `patterns` when repeated product workflows emerge.
- Do not place domain/product helpers in `utils`; route them through `app` during migration and then toward app-local/pattern ownership.

## Primitive Composition Rules and Guarantees

Primitive composition has these fixed rules:

- Primitive set: `Stack`, `Inline`, `Box`, `Container`, `Grid`, `Text`.
- Spacing API: semantic steps `none | xs | sm | md | lg | xl | 2xl`.
- Text depth: minimal `Text` primitive with compatibility heading wrappers (`H1`-`H4`, `HTable`).
- Migration scope: `apps/shade/src/components/layout/*` only.
- Compatibility policy: keep existing `@tryghost/shade/primitives` exports available during migration and deprecate without hard removals.

## Component Rules and Guarantees Layer

This layer keeps shared control APIs explicit and stable in `components/ui`:

- Define explicit API and state rules for Wave A controls (`Button`, `Input`, `Field`, `Select`, `Tabs`, `Table`, `Dialog`, `DropdownMenu`, `Card`).
- Keep shared controls product-agnostic.
- Preserve compatibility through deprecation notes, not hard removals.

## Component Types

### Base Components (UI)
Located in `/src/components/ui/`:
- Built on ShadCN/UI primitives
- Use RadixUI for accessibility
- Follow composable pattern
- Examples: Button, Input, Card

### Layout Components (Composed)
Located in `/src/components/layout/`:
- Compose base UI into reusable layout primitives (Page, Header, Heading, ViewHeader)
- Shared across surfaces; no product logic
- Follow same patterns as base components

### Feature Components
Located in `/src/components/features/`:
- Higher-level, feature-specific compositions (e.g., PostShareModal, SourceTabs)
- May bundle multiple UI and layout parts for a specific workflow
- Still reusable across apps when the feature exists

## Dependencies

### Core Dependencies
- **React**: UI library
- **TailwindCSS**: Utility-first styling
- **ShadCN/UI**: Component primitives
- **RadixUI**: Accessible primitives
- **Lucide**: Default icon system

> ⚠️ Note: When using third-party libraries that might have naming conflicts (like Recharts), we alias all exports (e.g., `export * as Recharts from "recharts"`).

## Component Implementation

### Naming Conventions

- Filenames: ShadCN-generated files keep kebab-case; file-scoped components live alongside their stories
- Components: `PascalCase`
- Functions/vars/types: `camelCase`

> ⚠️ Note: ShadCN/UI CLI creates files in kebab-case. We accept this inconsistency due to case-sensitivity issues.

### Component Structure

```tsx
// Basic component structure
import { cn } from "@/lib/utils"
import { cva } from "class-variance-authority"

const componentVariants = cva(
    "base-styles",
    {
        variants: {
            variant: {
                default: "variant-styles",
                // Add variants...
            }
        },
        defaultVariants: {
            variant: "default"
        }
    }
)

export interface ComponentProps {
    className?: string;
    // Other props...
}

export function Component({ className, ...props }: ComponentProps) {
    return (
        <div className={cn(componentVariants(), className)} {...props} />
    )
}
```

### Component API

- Use RadixUI primitives for accessibility
- Expose RadixUI props when available
- Always include `className` prop
- Use Class Variance Authority for variants

## Icons

Shade defaults to using Lucide icons. Since all exports are aliased as `LucideIcon` in `index.ts`, the way to use icons in apps happens through referencing the LucideIcon package:

   ```tsx
   import { LucideIcon } from 'lucide-react';

   <LucideIcon.Search size={16} />
   ```

## ShadCN/UI Configuration

Key configuration in `components.json`:
```json
{
    "style": "new-york",
    "baseColor": "gray",
    "cssVariables": true
}
```

## Best Practices

### Component Design
- Create composable, not configurable components
- Keep components focused and single-purpose
- Maintain consistent prop patterns
- Document all variants and props

### Styling
- Use design tokens via Tailwind classes sourced from CSS-first `@theme` tokens
- Always merge className prop using cn utility
- Maintain dark mode support
- Follow responsive design patterns

### Implementation Flow

1. **Start with ShadCN/UI**
   - Install via CLI if available
   - Customize implementation
   - Add/modify variants

2. **Add Documentation**
   - Create stories
   - Document variants
   - Show usage examples

3. **Export Component**
   ```ts
   // index.ts
   export * from './components/ui/component';
   ```

</div>
