243 lines
7.2 KiB
Markdown
243 lines
7.2 KiB
Markdown
# IGNY8 Design System Guide
|
|
|
|
> **Single Source of Truth for UI Components**
|
|
>
|
|
> 🔒 **STYLE LOCKED** - This design system is enforced by ESLint. All frontend code must comply.
|
|
|
|
**Last Updated:** January 20, 2026
|
|
**Version:** 1.8.4
|
|
|
|
---
|
|
|
|
## Quick Links
|
|
|
|
| Resource | Path | Description |
|
|
|----------|------|-------------|
|
|
| **Component System** | [COMPONENT-SYSTEM.md](COMPONENT-SYSTEM.md) | Full component reference with props, examples, and usage |
|
|
| **Design Tokens Doc** | [DESIGN-TOKENS.md](DESIGN-TOKENS.md) | Detailed token documentation |
|
|
| **ESLint Plugin** | `frontend/eslint/` | Custom rules enforcing design system |
|
|
| **Live Demo** | `/ui-elements` route | Interactive component showcase |
|
|
| **CSS Tokens** | `frontend/src/styles/design-system.css` | CSS variables source file |
|
|
| **Icons** | `frontend/src/icons/` | All SVG icons |
|
|
|
|
---
|
|
|
|
## 🎨 Color System (CRITICAL!)
|
|
|
|
### Only 6 Base Colors in Entire System
|
|
|
|
All colors derive from 6 primary hex values defined in `design-system.css`:
|
|
|
|
| Token | Hex | Purpose |
|
|
|-------|-----|---------|
|
|
| `--color-primary` | #0077B6 | Brand Blue - main CTA, links |
|
|
| `--color-success` | #2CA18E | Success Green - confirmations |
|
|
| `--color-warning` | #D9A12C | Warning Amber - alerts |
|
|
| `--color-danger` | #A12C40 | Danger Red - errors, destructive |
|
|
| `--color-purple` | #2C40A1 | Purple - premium features |
|
|
| `--color-gray-base` | #667085 | Neutral gray - text, borders |
|
|
|
|
### Tailwind Color Utilities
|
|
|
|
**⚠️ Tailwind default colors are DISABLED!** Only use:
|
|
|
|
```css
|
|
/* ✅ AVAILABLE */
|
|
brand-50 through brand-950 /* Primary blue scale */
|
|
gray-25 through gray-950 /* Neutral scale */
|
|
success-25 through success-950 /* Green scale */
|
|
error-25 through error-950 /* Red scale */
|
|
warning-25 through warning-950 /* Amber scale */
|
|
purple-25 through purple-950 /* Purple scale */
|
|
|
|
/* ❌ DISABLED - These will NOT work */
|
|
blue-*, red-*, green-*, emerald-*, amber-*, indigo-*,
|
|
pink-*, rose-*, sky-*, teal-*, cyan-*, etc.
|
|
```
|
|
|
|
### Usage Examples
|
|
|
|
```tsx
|
|
// ✅ CORRECT
|
|
<div className="bg-brand-500 text-white">Primary Button</div>
|
|
<div className="text-gray-700 bg-gray-50">Card content</div>
|
|
<Badge tone="success">Active</Badge>
|
|
<Alert variant="error" message="Failed" />
|
|
|
|
// ❌ WRONG
|
|
<div className="bg-blue-500">...</div> // Default blue disabled
|
|
<div className="bg-[#0693e3]">...</div> // Hardcoded hex
|
|
<div style={{ color: '#ff0000' }}>...</div> // Inline style
|
|
```
|
|
|
|
---
|
|
|
|
## Core Principles
|
|
|
|
### 1. Use Components, Never Raw HTML
|
|
|
|
```tsx
|
|
// ❌ NEVER
|
|
<button className="...">Click</button>
|
|
<input type="text" className="..." />
|
|
<select className="...">...</select>
|
|
<textarea className="..."></textarea>
|
|
|
|
// ✅ ALWAYS
|
|
<Button variant="primary">Click</Button>
|
|
<InputField type="text" label="Name" />
|
|
<Select options={options} />
|
|
<TextArea rows={4} />
|
|
```
|
|
|
|
### 2. Import Icons from Central Location
|
|
|
|
```tsx
|
|
// ❌ NEVER
|
|
import { XIcon } from '@heroicons/react/24/outline';
|
|
import { Trash } from 'lucide-react';
|
|
|
|
// ✅ ALWAYS
|
|
import { CloseIcon, TrashBinIcon } from '../../icons';
|
|
```
|
|
|
|
### 3. Consistent Sizing
|
|
|
|
```tsx
|
|
// Icons in buttons/badges
|
|
<Icon className="w-4 h-4" />
|
|
|
|
// Standalone icons
|
|
<Icon className="w-5 h-5" />
|
|
|
|
// Large/header icons
|
|
<Icon className="w-6 h-6" />
|
|
```
|
|
|
|
---
|
|
|
|
## Component Quick Reference
|
|
|
|
| Need | Component | Import |
|
|
|------|-----------|--------|
|
|
| Action button | `Button` | `components/ui/button/Button` |
|
|
| Icon-only button | `IconButton` | `components/ui/button/IconButton` |
|
|
| Text input | `InputField` | `components/form/input/InputField` |
|
|
| Checkbox | `Checkbox` | `components/form/input/Checkbox` |
|
|
| Radio | `Radio` | `components/form/input/Radio` |
|
|
| Dropdown | `Select` | `components/form/Select` |
|
|
| Multi-line text | `TextArea` | `components/form/input/TextArea` |
|
|
| Toggle | `Switch` | `components/form/switch/Switch` |
|
|
| Status label | `Badge` | `components/ui/badge/Badge` |
|
|
| Container | `Card` | `components/ui/card/Card` |
|
|
| Popup | `Modal` | `components/ui/modal` |
|
|
| Loading | `Spinner` | `components/ui/spinner/Spinner` |
|
|
| Notification | `useToast` | `components/ui/toast/ToastContainer` |
|
|
|
|
**→ See [COMPONENT-SYSTEM.md](docs/30-FRONTEND/COMPONENT-SYSTEM.md) for full props and examples**
|
|
|
|
---
|
|
|
|
## ESLint Enforcement
|
|
|
|
### Rules
|
|
|
|
| Rule | Level | Action |
|
|
|------|-------|--------|
|
|
| `no-raw-button` | warn | Use `Button` or `IconButton` |
|
|
| `no-raw-input` | warn | Use `InputField`, `Checkbox`, `Radio` |
|
|
| `no-raw-select` | warn | Use `Select` or `SelectDropdown` |
|
|
| `no-raw-textarea` | warn | Use `TextArea` |
|
|
| `no-icon-children` | warn | Use `startIcon`/`endIcon` props instead of icon children |
|
|
| `no-restricted-imports` | error | Block `@heroicons/*`, `lucide-react`, `@mui/icons-material` |
|
|
|
|
### Check Violations
|
|
|
|
```bash
|
|
# Inside container
|
|
docker exec -it igny8_frontend npm run lint
|
|
|
|
# Or directly
|
|
cd frontend
|
|
npm run lint
|
|
```
|
|
|
|
### Plugin Location
|
|
|
|
The custom ESLint plugin is at: `frontend/eslint/eslint-plugin-igny8-design-system.cjs`
|
|
|
|
---
|
|
|
|
## For AI Agents
|
|
|
|
When working on this codebase:
|
|
|
|
1. **Read first**: [docs/30-FRONTEND/COMPONENT-SYSTEM.md](docs/30-FRONTEND/COMPONENT-SYSTEM.md)
|
|
2. **Never use**: `<button>`, `<input>`, `<select>`, `<textarea>` tags
|
|
3. **Import icons from**: `src/icons` only
|
|
4. **Verify after changes**: `npm run lint`
|
|
5. **Reference pages**: Planner and Writer modules use correct patterns
|
|
|
|
### Correct Import Paths
|
|
|
|
```tsx
|
|
// From a page in src/pages/
|
|
import Button from '../components/ui/button/Button';
|
|
import IconButton from '../components/ui/button/IconButton';
|
|
import InputField from '../components/form/input/InputField';
|
|
import { PlusIcon, CloseIcon } from '../icons';
|
|
|
|
// From a component in src/components/
|
|
import Button from '../../components/ui/button/Button';
|
|
import { PlusIcon } from '../../icons';
|
|
|
|
// From a nested component
|
|
// Adjust ../ based on depth
|
|
```
|
|
|
|
---
|
|
|
|
## File Structure
|
|
|
|
```
|
|
frontend/
|
|
├── eslint/
|
|
│ └── eslint-plugin-igny8-design-system.cjs # Custom rules
|
|
├── src/
|
|
│ ├── components/
|
|
│ │ ├── ui/ # Display components
|
|
│ │ │ ├── button/ # Button, IconButton
|
|
│ │ │ ├── badge/ # Badge
|
|
│ │ │ ├── card/ # Card
|
|
│ │ │ ├── modal/ # Modal
|
|
│ │ │ └── ...
|
|
│ │ └── form/ # Form components
|
|
│ │ ├── input/ # InputField, Checkbox, Radio, TextArea
|
|
│ │ ├── switch/ # Switch
|
|
│ │ ├── Select.tsx
|
|
│ │ └── ...
|
|
│ ├── icons/ # All SVG icons
|
|
│ │ └── index.ts # Export all icons
|
|
│ └── styles/
|
|
│ └── design-system.css # Design tokens
|
|
docs/
|
|
└── 30-FRONTEND/
|
|
└── COMPONENT-SYSTEM.md # Full component documentation
|
|
```
|
|
|
|
---
|
|
|
|
## Migration Checklist
|
|
|
|
When fixing violations:
|
|
|
|
- [ ] Replace `<button>` with `Button` or `IconButton`
|
|
- [ ] Replace `<input type="text/email/password/number">` with `InputField`
|
|
- [ ] Replace `<input type="checkbox">` with `Checkbox`
|
|
- [ ] Replace `<input type="radio">` with `Radio`
|
|
- [ ] Replace `<select>` with `Select` or `SelectDropdown`
|
|
- [ ] Replace `<textarea>` with `TextArea`
|
|
- [ ] Replace external icon imports with `src/icons`
|
|
- [ ] Run `npm run lint` to verify
|
|
- [ ] Run `npm run build` to confirm no errors
|