# ADR-012: Frontend Component Library and Design System

**Date**: 2025-12-12

**Status**: Partially Implemented

## Context

The frontend is built with React, but there is no formal strategy for component reuse, styling consistency, or UI documentation. As more features are added, this can lead to a fragmented user experience, duplicated effort, and a codebase that is difficult to maintain.

## Decision

We will establish a formal Design System and Component Library. This will involve using a tool like **Storybook** to develop, document, and test UI components in isolation. It will establish clear guidelines for styling, theming (e.g., dark mode), and accessibility.

## Consequences

- **Positive**: Ensures a consistent and high-quality user interface. Accelerates frontend development by providing reusable, well-documented components. Improves maintainability and reduces technical debt.
- **Negative**: Requires an initial investment in setting up Storybook and migrating existing components. Adds a new dependency and a new workflow for frontend development.

## Implementation Status

### What's Implemented

The codebase has a solid foundation for a design system:

- ✅ **Tailwind CSS v4.1.17** as the styling solution
- ✅ **Dark mode** fully implemented with system preference detection
- ✅ **55 custom icon components** for consistent iconography
- ✅ **Component organization** with shared vs. feature-specific separation
- ✅ **Accessibility patterns** with ARIA attributes and focus management

### What's Not Yet Implemented

- ❌ **Storybook** is not yet installed or configured
- ❌ **Formal design token documentation** (colors, typography, spacing)
- ❌ **Visual regression testing** for component changes

## Implementation Details

### Component Library Structure

```text
src/
├── components/              # 30+ shared UI components
│   ├── icons/              # 55 SVG icon components
│   ├── Header.tsx
│   ├── Footer.tsx
│   ├── LoadingSpinner.tsx
│   ├── ErrorDisplay.tsx
│   ├── ConfirmationModal.tsx
│   ├── DarkModeToggle.tsx
│   ├── StatCard.tsx
│   ├── PasswordInput.tsx
│   └── ...
├── features/               # Feature-specific components
│   ├── charts/            # PriceChart, PriceHistoryChart
│   ├── flyer/             # FlyerDisplay, FlyerList, FlyerUploader
│   ├── shopping/          # ShoppingListComponent, WatchedItemsList
│   └── voice-assistant/   # VoiceAssistant
├── layouts/               # Page layouts
│   └── MainLayout.tsx
├── pages/                 # Page components
│   └── admin/components/  # Admin-specific components
└── providers/             # Context providers
```

### Styling Approach

**Tailwind CSS** with utility-first classes:

```typescript
// Component example with consistent styling patterns
<button className="px-4 py-2 bg-brand-primary text-white rounded-lg
                   hover:bg-brand-dark transition-colors duration-200
                   focus:outline-none focus:ring-2 focus:ring-brand-primary
                   focus:ring-offset-2 dark:focus:ring-offset-gray-800">
  Click me
</button>
```

**Common Utility Patterns**:

| Pattern | Classes |
| ------- | ------- |
| Card container | `bg-white dark:bg-gray-800 rounded-lg shadow-md p-6` |
| Primary button | `bg-brand-primary hover:bg-brand-dark text-white rounded-lg px-4 py-2` |
| Secondary button | `bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200` |
| Input field | `border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2` |
| Focus ring | `focus:outline-none focus:ring-2 focus:ring-brand-primary` |

### Color System

**Brand Colors** (Tailwind theme extensions):

- `brand-primary` - Primary brand color (blue/teal)
- `brand-light` - Lighter variant
- `brand-dark` - Darker variant for hover states
- `brand-secondary` - Secondary accent color

**Semantic Colors**:

- Gray scale: `gray-50` through `gray-950`
- Error: `red-500`, `red-600`
- Success: `green-500`, `green-600`
- Warning: `yellow-500`, `orange-500`
- Info: `blue-500`, `blue-600`

### Dark Mode Implementation

Dark mode is fully implemented using Tailwind's `dark:` variant:

```typescript
// Initialization in useAppInitialization hook
const initializeDarkMode = () => {
  // Priority: user profile > localStorage > system preference
  const stored = localStorage.getItem('darkMode');
  const systemPreference = window.matchMedia('(prefers-color-scheme: dark)').matches;
  const isDarkMode = stored ? stored === 'true' : systemPreference;

  document.documentElement.classList.toggle('dark', isDarkMode);
  return isDarkMode;
};
```

**Usage in components**:

```typescript
<div className="bg-white dark:bg-gray-800 text-gray-900 dark:text-white">
  Content adapts to theme
</div>
```

### Icon System

**55 custom SVG icon components** in `src/components/icons/`:

```typescript
// Icon component pattern
interface IconProps extends React.SVGProps<SVGSVGElement> {
  title?: string;
}

export const CheckCircleIcon: React.FC<IconProps> = ({ title, ...props }) => (
  <svg {...props} fill="currentColor" viewBox="0 0 24 24">
    {title && <title>{title}</title>}
    <path d="..." />
  </svg>
);
```

**Usage**:

```typescript
<CheckCircleIcon className="w-5 h-5 text-green-500" title="Success" />
```

**External icons**: Lucide React (`lucide-react` v0.555.0) used for additional icons.

### Accessibility Patterns

**ARIA Attributes**:

```typescript
// Modal pattern
<div role="dialog" aria-modal="true" aria-labelledby="modal-title">
  <h2 id="modal-title">Modal Title</h2>
</div>

// Button with label
<button aria-label="Close modal">
  <XMarkIcon aria-hidden="true" />
</button>

// Loading state
<div role="status" aria-live="polite">
  <LoadingSpinner />
</div>
```

**Focus Management**:

- Consistent focus rings: `focus:ring-2 focus:ring-brand-primary focus:ring-offset-2`
- Dark mode offset: `dark:focus:ring-offset-gray-800`
- No outline: `focus:outline-none` (using ring instead)

### State Management

**Context Providers** (see ADR-005):

| Provider | Purpose |
| -------- | ------- |
| `AuthProvider` | Authentication state |
| `ModalProvider` | Modal open/close state |
| `FlyersProvider` | Flyer data |
| `MasterItemsProvider` | Grocery items |
| `UserDataProvider` | User-specific data |

**Provider Hierarchy** in `AppProviders.tsx`:

```typescript
<QueryClientProvider>
  <ModalProvider>
    <AuthProvider>
      <FlyersProvider>
        <MasterItemsProvider>
          <UserDataProvider>
            {children}
          </UserDataProvider>
        </MasterItemsProvider>
      </FlyersProvider>
    </AuthProvider>
  </ModalProvider>
</QueryClientProvider>
```

## Key Files

- `tailwind.config.js` - Tailwind CSS configuration
- `src/index.css` - Tailwind CSS entry point
- `src/components/` - Shared UI components
- `src/components/icons/` - Icon component library (55 icons)
- `src/providers/AppProviders.tsx` - Context provider composition
- `src/hooks/useAppInitialization.ts` - Dark mode initialization

## Component Guidelines

### When to Create Shared Components

Create a shared component in `src/components/` when:

1. Used in 3+ places across the application
2. Represents a reusable UI pattern (buttons, cards, modals)
3. Has consistent styling/behavior requirements

### Naming Conventions

- **Components**: PascalCase (`LoadingSpinner.tsx`)
- **Icons**: PascalCase with `Icon` suffix (`CheckCircleIcon.tsx`)
- **Hooks**: camelCase with `use` prefix (`useModal.ts`)
- **Contexts**: PascalCase with `Context` suffix (`AuthContext.tsx`)

### Styling Guidelines

1. Use Tailwind utility classes exclusively
2. Include dark mode variants for all colors: `bg-white dark:bg-gray-800`
3. Add focus states for interactive elements
4. Use semantic color names from the design system

## Future Enhancements (Storybook Setup)

To complete ADR-012 implementation:

1. **Install Storybook**:

   ```bash
   npx storybook@latest init
   ```

2. **Create stories for core components**:
   - Button variants
   - Form inputs (PasswordInput, etc.)
   - Modal components
   - Loading states
   - Icon showcase

3. **Add visual regression testing** with Chromatic or Percy

4. **Document design tokens** formally in Storybook

5. **Create component composition guidelines**
