15 KiB
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 smallsm- Smallmd- Medium (default)lg- Large
Tones (5 total)
brand- Primary brand color (blue)success- Greenwarning- Orangedanger- Red/Errorneutral- Gray
Usage Example
import Button from '../../components/ui/button/Button';
<Button variant="solid" tone="brand" size="md" startIcon={<Icon />}>
Click Me
</Button>
⚠️ Anti-Pattern
// ❌ 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 titlechildren(required) - Card contentclassName(optional) - Additional styling
Usage Example
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
// ❌ 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 labelvalue(required) - Main metric value (string | number)subtitle(optional) - Additional context below valueicon(optional) - Icon componentaccentColor(required) - Border accent colortrend(optional) - { direction: 'up' | 'down', value: string }href(optional) - React Router navigation pathonClick(optional) - Click handler (alternative to href)tooltip(optional) - Tooltip text on hoverdetails(optional) - Array of tooltip detail breakdowns
Accent Colors (6 total)
blue- Primary/default metricsgreen- Success/positive metricsorange- Warning/attention metricspurple- Special/premium metricsred- Error/critical metricssuccess- Alternative green (var(--color-success))
Usage Example
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
hrefprovided - Hover effects and transitions
- Dark mode support
- Tooltip with optional details breakdown
- Trend indicators with arrows
⚠️ Anti-Pattern
// ❌ 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 titlelastUpdated(optional) - Last refresh timestampbadge(optional) - { icon: ReactNode, color: 'blue' | 'green' | ... }showRefresh(optional) - Show refresh buttononRefresh(optional) - Refresh button handlerhideSiteSector(optional) - Hide site/sector info for global pagesclassName(optional) - Additional styling
Badge Colors (6 total)
Same as Button/Metric: blue, green, purple, orange, red, indigo
Usage Example
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
// ❌ 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
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
// ❌ 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
<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
- ComponentCard wrapper - Title + description
- Responsive grid - 1 col mobile, 2 col tablet, 4 col desktop
- Link component - Not button
- Gradient icon box - 48px (size-12), gradient from primary to primary-dark
- Content area - Title (font-semibold) + description (text-sm)
- Arrow icon - Right-pointing, changes color on hover
- Hover effects - Border color + shadow on hover
Gradient Color Variants
// 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
// ❌ 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
<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
hrefprop for navigation (notonClick) - 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
--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
-
Replace all
<button onClick={() => navigate(...)}with<Link to={...}>- Better accessibility
- Standard keyboard navigation
- Consistent with Planner/Writer modules
-
Wrap Quick Actions in ComponentCard
- Current: Manual
<h2>heading - Target:
<ComponentCard title="Quick Actions" desc="...">
- Current: Manual
-
Extract ActionCard component (if repeated)
- DRY principle for Quick Action cards
- Reusable across Sites module
-
Standardize Button usage
- Verify all buttons use
variantprop (not custom classes) - Ensure consistent tone/size across module
- Verify all buttons use
-
Add missing EnhancedMetricCard features
- Tooltips for complex metrics
- Trend indicators where applicable
Implementation Priority
Phase 1: Navigation (High Impact)
- Replace
button + navigatewithLinkcomponents - Update click handlers to href props
- Test keyboard navigation and accessibility
Phase 2: Component Wrapping (Medium Impact)
- Wrap sections in ComponentCard
- Replace manual headings with ComponentCard title prop
- Verify consistent spacing and styling
Phase 3: Component Extraction (Low Impact)
- Create reusable ActionCard component
- Create SiteMetricCard if Sites-specific logic needed
- Update DESIGN_SYSTEM.md with new components
Phase 4: Polish (Continuous)
- Add missing tooltips
- Add trend indicators
- Verify dark mode consistency
- 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 variantsfrontend/src/components/ui/button/Button.tsx- Button componentfrontend/src/components/common/ComponentCard.tsx- Card wrapperfrontend/src/components/dashboard/EnhancedMetricCard.tsx- Metric displayfrontend/src/components/common/PageHeader.tsx- Page headerfrontend/src/pages/Planner/Dashboard.tsx- Reference implementationfrontend/src/pages/Writer/Dashboard.tsx- Reference implementation
Related Documentation
master-docs/API-COMPLETE-REFERENCE.md- API contractsREFACTOR_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