516 lines
15 KiB
Markdown
516 lines
15 KiB
Markdown
# IGNY8 Design Standard Reference
|
|
**Standardized UI patterns used across Planner, Writer, and Dashboard modules**
|
|
|
|
This document defines the locked design patterns and component usage standards for the IGNY8 application. All modules (including Sites) should follow these patterns to maintain visual consistency.
|
|
|
|
---
|
|
|
|
## Core Component Library
|
|
|
|
### 1. Button Component
|
|
**Location:** `frontend/src/components/ui/button/Button.tsx`
|
|
**Status:** 🔒 STYLE LOCKED - See `DESIGN_SYSTEM.md`
|
|
|
|
#### Variants (5 total)
|
|
- `solid` - Filled background (primary action)
|
|
- `soft` - Light background (secondary action)
|
|
- `outline` - Border only (tertiary action)
|
|
- `ghost` - No border or background (minimal action)
|
|
- `gradient` - Gradient background with shadow (premium/highlight action)
|
|
|
|
#### Sizes (4 total)
|
|
- `xs` - Extra small
|
|
- `sm` - Small
|
|
- `md` - Medium (default)
|
|
- `lg` - Large
|
|
|
|
#### Tones (5 total)
|
|
- `brand` - Primary brand color (blue)
|
|
- `success` - Green
|
|
- `warning` - Orange
|
|
- `danger` - Red/Error
|
|
- `neutral` - Gray
|
|
|
|
#### Usage Example
|
|
```tsx
|
|
import Button from '../../components/ui/button/Button';
|
|
|
|
<Button variant="solid" tone="brand" size="md" startIcon={<Icon />}>
|
|
Click Me
|
|
</Button>
|
|
```
|
|
|
|
#### ⚠️ Anti-Pattern
|
|
```tsx
|
|
// ❌ DON'T: Raw HTML buttons with inline Tailwind
|
|
<button className="px-4 py-2 bg-blue-500 text-white rounded-lg">
|
|
Click Me
|
|
</button>
|
|
|
|
// ✅ DO: Use Button component
|
|
<Button variant="solid" tone="brand">
|
|
Click Me
|
|
</Button>
|
|
```
|
|
|
|
---
|
|
|
|
### 2. ComponentCard
|
|
**Location:** `frontend/src/components/common/ComponentCard.tsx`
|
|
**Purpose:** Standard card wrapper for sections with title and description
|
|
|
|
#### Props
|
|
- `title` (required) - Section title (string or ReactNode)
|
|
- `desc` (optional) - Description text below title
|
|
- `children` (required) - Card content
|
|
- `className` (optional) - Additional styling
|
|
|
|
#### Usage Example
|
|
```tsx
|
|
import ComponentCard from '../../components/common/ComponentCard';
|
|
|
|
<ComponentCard title="Quick Actions" desc="Common planning tasks and shortcuts">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
{/* Content */}
|
|
</div>
|
|
</ComponentCard>
|
|
```
|
|
|
|
#### Structure
|
|
- **Header:** Title + optional description (gray text)
|
|
- **Body:** Border-top separated content area with padding
|
|
- **Dark mode:** Automatic theme support
|
|
|
|
#### ⚠️ Anti-Pattern
|
|
```tsx
|
|
// ❌ DON'T: Raw Card component with manual header
|
|
<Card>
|
|
<div className="px-6 py-5">
|
|
<h3 className="text-base font-medium">Quick Actions</h3>
|
|
</div>
|
|
<div className="p-6">
|
|
{/* Content */}
|
|
</div>
|
|
</Card>
|
|
|
|
// ✅ DO: Use ComponentCard
|
|
<ComponentCard title="Quick Actions">
|
|
{/* Content */}
|
|
</ComponentCard>
|
|
```
|
|
|
|
---
|
|
|
|
### 3. EnhancedMetricCard
|
|
**Location:** `frontend/src/components/dashboard/EnhancedMetricCard.tsx`
|
|
**Purpose:** Display metrics with optional trends, tooltips, and navigation
|
|
|
|
#### Key Props
|
|
- `title` (required) - Metric label
|
|
- `value` (required) - Main metric value (string | number)
|
|
- `subtitle` (optional) - Additional context below value
|
|
- `icon` (optional) - Icon component
|
|
- `accentColor` (required) - Border accent color
|
|
- `trend` (optional) - { direction: 'up' | 'down', value: string }
|
|
- `href` (optional) - React Router navigation path
|
|
- `onClick` (optional) - Click handler (alternative to href)
|
|
- `tooltip` (optional) - Tooltip text on hover
|
|
- `details` (optional) - Array of tooltip detail breakdowns
|
|
|
|
#### Accent Colors (6 total)
|
|
- `blue` - Primary/default metrics
|
|
- `green` - Success/positive metrics
|
|
- `orange` - Warning/attention metrics
|
|
- `purple` - Special/premium metrics
|
|
- `red` - Error/critical metrics
|
|
- `success` - Alternative green (var(--color-success))
|
|
|
|
#### Usage Example
|
|
```tsx
|
|
import EnhancedMetricCard from '../../components/dashboard/EnhancedMetricCard';
|
|
|
|
<EnhancedMetricCard
|
|
title="Active Keywords"
|
|
value={1234}
|
|
subtitle="Across all clusters"
|
|
icon={<ListIcon className="h-5 w-5" />}
|
|
accentColor="blue"
|
|
trend={{ direction: 'up', value: '+12%' }}
|
|
href="/planner/keywords"
|
|
tooltip="View all active keywords"
|
|
details={[
|
|
{ label: 'Tracked', value: '800' },
|
|
{ label: 'Untracked', value: '434' },
|
|
]}
|
|
/>
|
|
```
|
|
|
|
#### Features
|
|
- Automatic Link wrapping when `href` provided
|
|
- Hover effects and transitions
|
|
- Dark mode support
|
|
- Tooltip with optional details breakdown
|
|
- Trend indicators with arrows
|
|
|
|
#### ⚠️ Anti-Pattern
|
|
```tsx
|
|
// ❌ DON'T: Custom metric cards with inline styles
|
|
<div className="bg-white rounded-xl border-2 border-slate-200 p-6">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className="text-sm text-gray-600">Active Keywords</p>
|
|
<p className="text-3xl font-bold">1,234</p>
|
|
</div>
|
|
<ListIcon className="h-8 w-8 text-blue-500" />
|
|
</div>
|
|
</div>
|
|
|
|
// ✅ DO: Use EnhancedMetricCard
|
|
<EnhancedMetricCard
|
|
title="Active Keywords"
|
|
value={1234}
|
|
icon={<ListIcon className="h-5 w-5" />}
|
|
accentColor="blue"
|
|
/>
|
|
```
|
|
|
|
---
|
|
|
|
### 4. PageHeader
|
|
**Location:** `frontend/src/components/common/PageHeader.tsx`
|
|
**Purpose:** Standardized page header with title, site/sector info, and selectors
|
|
|
|
#### Key Props
|
|
- `title` (required) - Page title
|
|
- `lastUpdated` (optional) - Last refresh timestamp
|
|
- `badge` (optional) - { icon: ReactNode, color: 'blue' | 'green' | ... }
|
|
- `showRefresh` (optional) - Show refresh button
|
|
- `onRefresh` (optional) - Refresh button handler
|
|
- `hideSiteSector` (optional) - Hide site/sector info for global pages
|
|
- `className` (optional) - Additional styling
|
|
|
|
#### Badge Colors (6 total)
|
|
Same as Button/Metric: `blue`, `green`, `purple`, `orange`, `red`, `indigo`
|
|
|
|
#### Usage Example
|
|
```tsx
|
|
import PageHeader from '../../components/common/PageHeader';
|
|
import { ListIcon } from '../../icons';
|
|
|
|
<PageHeader
|
|
title="Keyword Dashboard"
|
|
lastUpdated={new Date()}
|
|
badge={{ icon: <ListIcon className="h-5 w-5" />, color: 'blue' }}
|
|
showRefresh={true}
|
|
onRefresh={handleRefresh}
|
|
/>
|
|
```
|
|
|
|
#### Features
|
|
- Automatic site/sector display from stores
|
|
- SiteAndSectorSelector integration
|
|
- Responsive layout (stack on mobile)
|
|
- Badge with icon support
|
|
- Last updated timestamp
|
|
|
|
#### ⚠️ Anti-Pattern
|
|
```tsx
|
|
// ❌ DON'T: Custom page headers with manual layout
|
|
<div className="flex items-center justify-between mb-6">
|
|
<div>
|
|
<h2 className="text-2xl font-bold">Keyword Dashboard</h2>
|
|
<p className="text-sm text-gray-500">
|
|
Site: {site.name} • Sector: {sector.name}
|
|
</p>
|
|
</div>
|
|
<button onClick={refresh}>Refresh</button>
|
|
</div>
|
|
|
|
// ✅ DO: Use PageHeader
|
|
<PageHeader
|
|
title="Keyword Dashboard"
|
|
showRefresh={true}
|
|
onRefresh={refresh}
|
|
/>
|
|
```
|
|
|
|
---
|
|
|
|
### 5. Link Component (React Router)
|
|
**Location:** `react-router-dom`
|
|
**Purpose:** Standard navigation with automatic prefetching and accessibility
|
|
|
|
#### Usage Example
|
|
```tsx
|
|
import { Link } from 'react-router-dom';
|
|
|
|
<Link
|
|
to="/planner/keywords"
|
|
className="flex items-center gap-4 p-6 rounded-xl border-2 border-slate-200 bg-white hover:border-[var(--color-primary)] hover:shadow-lg transition-all group"
|
|
>
|
|
<div>Navigate to Keywords</div>
|
|
</Link>
|
|
```
|
|
|
|
#### Benefits Over Button + Navigate
|
|
- ✅ Proper semantic HTML (`<a>` tag)
|
|
- ✅ Keyboard navigation (Tab + Enter)
|
|
- ✅ Right-click "Open in new tab" support
|
|
- ✅ Screen reader accessibility
|
|
- ✅ Browser history support
|
|
- ✅ Automatic prefetching
|
|
|
|
#### ⚠️ Anti-Pattern
|
|
```tsx
|
|
// ❌ DON'T: Button with onClick navigate
|
|
<button onClick={() => navigate('/planner/keywords')}>
|
|
Go to Keywords
|
|
</button>
|
|
|
|
// ✅ DO: Use Link component
|
|
<Link to="/planner/keywords">
|
|
Go to Keywords
|
|
</Link>
|
|
```
|
|
|
|
---
|
|
|
|
## Design Patterns
|
|
|
|
### Quick Actions Grid
|
|
**Standard pattern used in:** Planner Dashboard, Writer Dashboard
|
|
|
|
#### Structure
|
|
```tsx
|
|
<ComponentCard title="Quick Actions" desc="Common planning tasks and shortcuts">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
<Link
|
|
to="/path"
|
|
className="flex items-center gap-4 p-6 rounded-xl border-2 border-slate-200 bg-white hover:border-[var(--color-primary)] hover:shadow-lg transition-all group"
|
|
>
|
|
{/* Gradient Icon */}
|
|
<div className="size-12 rounded-xl bg-gradient-to-br from-[var(--color-primary)] to-[var(--color-primary-dark)] flex items-center justify-center text-white shadow-lg">
|
|
<Icon className="h-6 w-6" />
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<div className="flex-1 text-left">
|
|
<h4 className="font-semibold text-slate-900 mb-1">Action Title</h4>
|
|
<p className="text-sm text-slate-600">Action description</p>
|
|
</div>
|
|
|
|
{/* Arrow Icon */}
|
|
<ArrowRightIcon className="h-5 w-5 text-slate-400 group-hover:text-[var(--color-primary)] transition" />
|
|
</Link>
|
|
</div>
|
|
</ComponentCard>
|
|
```
|
|
|
|
#### Key Elements
|
|
1. **ComponentCard wrapper** - Title + description
|
|
2. **Responsive grid** - 1 col mobile, 2 col tablet, 4 col desktop
|
|
3. **Link component** - Not button
|
|
4. **Gradient icon box** - 48px (size-12), gradient from primary to primary-dark
|
|
5. **Content area** - Title (font-semibold) + description (text-sm)
|
|
6. **Arrow icon** - Right-pointing, changes color on hover
|
|
7. **Hover effects** - Border color + shadow on hover
|
|
|
|
#### Gradient Color Variants
|
|
```tsx
|
|
// Primary (Blue)
|
|
from-[var(--color-primary)] to-[var(--color-primary-dark)]
|
|
|
|
// Success (Green)
|
|
from-[var(--color-success)] to-[var(--color-success-dark)]
|
|
|
|
// Warning (Orange)
|
|
from-[var(--color-warning)] to-[var(--color-warning-dark)]
|
|
|
|
// Purple
|
|
from-[var(--color-purple)] to-[var(--color-purple-dark)]
|
|
```
|
|
|
|
#### ⚠️ Anti-Pattern - Sites Dashboard Current Implementation
|
|
```tsx
|
|
// ❌ DON'T: Button with navigate + manual styling
|
|
<button
|
|
onClick={() => navigate(`/sites/${siteId}/pages`)}
|
|
className="flex items-center gap-4 p-6 rounded-xl border-2 border-slate-200 bg-white hover:border-[var(--color-primary)] hover:shadow-lg transition-all group"
|
|
>
|
|
{/* ... */}
|
|
</button>
|
|
|
|
// ✅ DO: Link component
|
|
<Link
|
|
to={`/sites/${siteId}/pages`}
|
|
className="flex items-center gap-4 p-6 rounded-xl border-2 border-slate-200 bg-white hover:border-[var(--color-primary)] hover:shadow-lg transition-all group"
|
|
>
|
|
{/* ... */}
|
|
</Link>
|
|
```
|
|
|
|
---
|
|
|
|
### Metrics Dashboard Grid
|
|
**Standard pattern used in:** Planner Dashboard, Writer Dashboard
|
|
|
|
#### Structure
|
|
```tsx
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
<EnhancedMetricCard
|
|
title="Metric Name"
|
|
value={1234}
|
|
icon={<Icon className="h-5 w-5" />}
|
|
accentColor="blue"
|
|
href="/path"
|
|
/>
|
|
</div>
|
|
```
|
|
|
|
#### Grid Breakpoints
|
|
- **Mobile (< 768px):** 1 column
|
|
- **Tablet (768px - 1024px):** 2 columns
|
|
- **Desktop (> 1024px):** 3 columns
|
|
|
|
#### Best Practices
|
|
- Use `href` prop for navigation (not `onClick`)
|
|
- Consistent icon sizing: `h-5 w-5`
|
|
- Map accent colors to metric meaning (blue = neutral, green = success, orange = warning, red = error)
|
|
- Include tooltips for complex metrics
|
|
- Add trend indicators when comparing periods
|
|
|
|
---
|
|
|
|
## Color System
|
|
|
|
### CSS Variables
|
|
```css
|
|
--color-primary: #0693e3; /* Brand Blue */
|
|
--color-primary-dark: #0570b8;
|
|
--color-success: #0bbf87; /* Green */
|
|
--color-success-dark: #089968;
|
|
--color-warning: #ff7a00; /* Orange */
|
|
--color-warning-dark: #cc6200;
|
|
--color-purple: #5d4ae3;
|
|
--color-purple-dark: #4a3bb5;
|
|
--color-error: #f44336; /* Red */
|
|
```
|
|
|
|
### Tailwind Color Classes
|
|
- `brand-*` - Primary blue (50-900)
|
|
- `success-*` - Green (50-900)
|
|
- `warning-*` - Orange (50-900)
|
|
- `error-*` - Red (50-900)
|
|
- `purple-*` - Purple (50-900)
|
|
- `gray-*` - Neutral (50-900)
|
|
|
|
---
|
|
|
|
## Sites Module Refactor Checklist
|
|
|
|
### Current Inconsistencies (Sites Dashboard Example)
|
|
- ❌ Uses `<button onClick={() => navigate(...)}` instead of `<Link to={...}>`
|
|
- ❌ Missing ComponentCard wrapper for Quick Actions section
|
|
- ❌ Manual heading instead of ComponentCard title prop
|
|
- ⚠️ Uses Button component correctly (partial compliance)
|
|
- ✅ Uses EnhancedMetricCard correctly
|
|
|
|
### Required Changes
|
|
1. **Replace all `<button onClick={() => navigate(...)}` with `<Link to={...}>`**
|
|
- Better accessibility
|
|
- Standard keyboard navigation
|
|
- Consistent with Planner/Writer modules
|
|
|
|
2. **Wrap Quick Actions in ComponentCard**
|
|
- Current: Manual `<h2>` heading
|
|
- Target: `<ComponentCard title="Quick Actions" desc="...">`
|
|
|
|
3. **Extract ActionCard component (if repeated)**
|
|
- DRY principle for Quick Action cards
|
|
- Reusable across Sites module
|
|
|
|
4. **Standardize Button usage**
|
|
- Verify all buttons use `variant` prop (not custom classes)
|
|
- Ensure consistent tone/size across module
|
|
|
|
5. **Add missing EnhancedMetricCard features**
|
|
- Tooltips for complex metrics
|
|
- Trend indicators where applicable
|
|
|
|
---
|
|
|
|
## Implementation Priority
|
|
|
|
### Phase 1: Navigation (High Impact)
|
|
1. Replace `button + navigate` with `Link` components
|
|
2. Update click handlers to href props
|
|
3. Test keyboard navigation and accessibility
|
|
|
|
### Phase 2: Component Wrapping (Medium Impact)
|
|
1. Wrap sections in ComponentCard
|
|
2. Replace manual headings with ComponentCard title prop
|
|
3. Verify consistent spacing and styling
|
|
|
|
### Phase 3: Component Extraction (Low Impact)
|
|
1. Create reusable ActionCard component
|
|
2. Create SiteMetricCard if Sites-specific logic needed
|
|
3. Update DESIGN_SYSTEM.md with new components
|
|
|
|
### Phase 4: Polish (Continuous)
|
|
1. Add missing tooltips
|
|
2. Add trend indicators
|
|
3. Verify dark mode consistency
|
|
4. Test responsive layouts
|
|
|
|
---
|
|
|
|
## Testing Checklist
|
|
|
|
### Visual Consistency
|
|
- [ ] Quick Actions match Planner/Writer pattern
|
|
- [ ] Metrics grid matches dashboard standards
|
|
- [ ] Button variants consistent across pages
|
|
- [ ] Color usage matches design system
|
|
|
|
### Accessibility
|
|
- [ ] All navigation uses Link (not button)
|
|
- [ ] Keyboard navigation works (Tab, Enter)
|
|
- [ ] Screen reader labels present
|
|
- [ ] Focus indicators visible
|
|
|
|
### Functionality
|
|
- [ ] All routes navigate correctly
|
|
- [ ] Hover states work consistently
|
|
- [ ] Dark mode renders properly
|
|
- [ ] Responsive breakpoints work
|
|
|
|
### Code Quality
|
|
- [ ] No raw `<button>` for navigation
|
|
- [ ] No inline Tailwind for common patterns
|
|
- [ ] TypeScript errors resolved
|
|
- [ ] Component props properly typed
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
### Key Files
|
|
- `frontend/DESIGN_SYSTEM.md` - Locked component variants
|
|
- `frontend/src/components/ui/button/Button.tsx` - Button component
|
|
- `frontend/src/components/common/ComponentCard.tsx` - Card wrapper
|
|
- `frontend/src/components/dashboard/EnhancedMetricCard.tsx` - Metric display
|
|
- `frontend/src/components/common/PageHeader.tsx` - Page header
|
|
- `frontend/src/pages/Planner/Dashboard.tsx` - Reference implementation
|
|
- `frontend/src/pages/Writer/Dashboard.tsx` - Reference implementation
|
|
|
|
### Related Documentation
|
|
- `master-docs/API-COMPLETE-REFERENCE.md` - API contracts
|
|
- `REFACTOR_DOCS_INDEX.md` - Refactor documentation
|
|
- `.github/copilot-instructions.md` - AI agent guidelines
|
|
|
|
---
|
|
|
|
**Last Updated:** 2025-01-21
|
|
**Maintained By:** IGNY8 Development Team
|
|
**Status:** Living Document - Update when design patterns change
|