CIA/e-voting-system/.claude/SHADCN_QUICK_REFERENCE.md
Alexis Bruneteau 905466dbe9 feat: Complete ShadCN/UI integration with custom dark theme
🎨 Design System Implementation:
- Added Tailwind CSS 3.3.6 with custom dark theme palette
- Created comprehensive ShadCN UI component library (8 components)
- Defined dark theme colors: accent (#e8704b), text (#e0e0e0), background (#171717)
- Implemented CSS custom properties for consistent theming

🔧 Core Components Refactored:
- Header: Now fully responsive with dark theme
- VoteCard: Migrated to ShadCN Card with styled results bars
- Alert: Uses ShadCN Alert with semantic variants
- Modal: Replaced with ShadCN Dialog (Radix UI)
- LoadingSpinner: Tailwind-based animation
- Footer: Grid layout with proper color scheme

📄 Pages Refactored:
- LoginPage: Complete refactor with split layout and dark theme
- Ready for remaining pages (RegisterPage, HomePage, Dashboard, etc.)

🏷️ Branding Updates:
- Changed app name from "React App" to "E-Voting"
- Updated HTML title and meta descriptions
- Updated package.json with proper naming

📚 Documentation (4 comprehensive guides):
- THEME_IMPLEMENTATION_GUIDE.md: How-to for remaining pages
- SHADCN_QUICK_REFERENCE.md: Component API reference
- FRONTEND_REFACTOR.md: Complete technical overview
- DEPENDENCY_FIX_NOTES.md: Dependency resolution details

 Build Status:
- npm install: 1397 packages 
- npm run build: Success (118.95 kB gzipped)
- Zero critical errors
- Ready for production deployment

🎯 Coverage:
- 40% of pages with full theming (Header, Footer, LoginPage, VoteCard)
- Infrastructure 100% complete
- Estimated 9 hours to theme remaining pages

🔄 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 16:34:43 +01:00

10 KiB
Raw Blame History

ShadCN UI Quick Reference Guide

Color Palette

Text Colors (Tailwind Classes)

text-text-primary    → #e0e0e0 (main text)
text-text-secondary  → #a3a3a3 (secondary text)
text-text-tertiary   → #737373 (muted text)

Background Colors

bg-bg-primary        → #171717
bg-bg-secondary      → #171717
bg-bg-overlay-light  → rgba(255, 255, 255, 0.05)
bg-bg-overlay-dark   → rgba(0, 0, 0, 0.8)

Accent & Semantic Colors

text-accent-warm     → #e8704b (primary accent)
text-success         → #10b981
text-warning         → #f97316
text-danger          → #ef4444
text-info            → #3b82f6

Component Reference

Button Component

import { Button } from '../lib/ui';

// Default variants
<Button variant="default">Primary</Button>
<Button variant="outline">Outline</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Danger</Button>
<Button variant="success">Success</Button>
<Button variant="link">Link</Button>

// Sizes
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
<Button size="icon">🔔</Button>

// With icons
<Button>
  <LogOut size={18} />
  Logout
</Button>

// As child (wrap Link, etc.)
<Button asChild>
  <Link to="/path">Navigate</Link>
</Button>

// Disabled
<Button disabled>Disabled</Button>

Card Component

import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '../lib/ui';

<Card>
  <CardHeader>
    <CardTitle>Card Title</CardTitle>
    <CardDescription>Card description</CardDescription>
  </CardHeader>
  <CardContent>
    Main content
  </CardContent>
  <CardFooter>
    Footer actions
  </CardFooter>
</Card>

Badge Component

import { Badge } from '../lib/ui';

<Badge variant="default">Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Error</Badge>
<Badge variant="outline">Outline</Badge>
<Badge variant="success">Success</Badge>
<Badge variant="warning">Warning</Badge>
<Badge variant="info">Info</Badge>

Alert Component

import { Alert, AlertTitle, AlertDescription } from '../lib/ui';

<Alert variant="default">
  <AlertTitle>Title</AlertTitle>
  <AlertDescription>Description</AlertDescription>
</Alert>

// With variants
<Alert variant="success">Success message</Alert>
<Alert variant="destructive">Error message</Alert>
<Alert variant="warning">Warning message</Alert>
<Alert variant="info">Info message</Alert>

Dialog/Modal Component

import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '../lib/ui';

const [open, setOpen] = useState(false);

<Dialog open={open} onOpenChange={setOpen}>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Dialog Title</DialogTitle>
      <DialogDescription>Optional description</DialogDescription>
    </DialogHeader>
    <p>Content goes here</p>
    <DialogFooter>
      <Button variant="outline" onClick={() => setOpen(false)}>Cancel</Button>
      <Button>Confirm</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>

Input Component

import { Input } from '../lib/ui';

<Input
  type="text"
  placeholder="Enter text"
  onChange={(e) => setValue(e.target.value)}
/>

<Input type="email" placeholder="Email" />
<Input type="password" placeholder="Password" />
<Input type="number" placeholder="Number" />

Label Component

import { Label } from '../lib/ui';

<Label htmlFor="input">Field Label</Label>
<Input id="input" />

Dropdown Menu Component

import {
  DropdownMenu,
  DropdownMenuTrigger,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator
} from '../lib/ui';
import { Button } from '../lib/ui';

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="outline">Menu</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem onClick={action1}>Option 1</DropdownMenuItem>
    <DropdownMenuItem onClick={action2}>Option 2</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem>Option 3</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Tailwind Utility Classes

Layout

// Flexbox
<div className="flex items-center justify-between gap-4">
<div className="flex flex-col gap-2">
<div className="flex md:flex-row">

// Grid
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">

// Spacing
className="p-4 px-6 py-2"      // padding
className="m-2 mx-auto"        // margin
className="gap-4"              // grid/flex gap

// Size
className="w-full h-screen"
className="max-w-2xl mx-auto"

Typography

// Font sizes
className="text-xs text-sm text-base text-lg text-xl text-2xl text-3xl"

// Font weights
className="font-light font-normal font-semibold font-bold"

// Text alignment
className="text-left text-center text-right"

// Line height
className="leading-tight leading-normal leading-relaxed"

Colors

// Predefined colors
className="text-text-primary"
className="bg-bg-secondary"
className="text-accent-warm"
className="border-text-tertiary"

// With opacity
className="bg-accent-warm/50"   // 50% opacity
className="text-danger/80"      // 80% opacity

Borders & Radius

className="border border-text-tertiary"
className="border-b border-t border-l border-r"
className="rounded-md rounded-lg rounded-full"
className="rounded-t rounded-b rounded-l rounded-r"

Visibility

className="block hidden"
className="flex md:hidden"     // responsive
className="invisible opacity-0"
className="sr-only"            // screen reader only

Animations

className="animate-spin"       // spinning
className="animate-pulse"      // pulsing
className="transition-all duration-300"
className="hover:opacity-80"   // hover effect

Form Patterns

Basic Form Group

<div className="form-group">
  <label className="form-label">Email Address</label>
  <Input
    type="email"
    className="form-input"
    placeholder="user@example.com"
  />
  {error && <p className="form-error">{error}</p>}
  {success && <p className="form-success">Saved!</p>}
</div>

Form with Card

<Card>
  <CardHeader>
    <CardTitle>Login</CardTitle>
  </CardHeader>
  <CardContent className="space-y-4">
    <div className="form-group">
      <Label>Email</Label>
      <Input type="email" />
    </div>
    <div className="form-group">
      <Label>Password</Label>
      <Input type="password" />
    </div>
  </CardContent>
  <CardFooter>
    <Button className="w-full">Login</Button>
  </CardFooter>
</Card>

Layout Patterns

Page Layout

<div className="min-h-screen flex flex-col">
  <Header />
  <main className="flex-1 container py-8">
    {/* page content */}
  </main>
  <Footer />
</div>

Card Grid

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
  {items.map(item => (
    <Card key={item.id}>
      {/* card content */}
    </Card>
  ))}
</div>

Two Column Layout

<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
  <div className="md:col-span-2">
    {/* main content */}
  </div>
  <div>
    {/* sidebar */}
  </div>
</div>

Common Patterns

Alert with Close

const [showAlert, setShowAlert] = useState(true);

{showAlert && (
  <Alert variant="success">
    <AlertTitle>Success</AlertTitle>
    <AlertDescription>Operation completed</AlertDescription>
    <button
      onClick={() => setShowAlert(false)}
      className="absolute right-4 top-4"
    >
      ×
    </button>
  </Alert>
)}

Button Group

<div className="flex gap-2">
  <Button variant="outline" className="flex-1">Cancel</Button>
  <Button className="flex-1">Save</Button>
</div>

Status Badge

<div className="flex items-center gap-2">
  <Badge variant="success">Active</Badge>
  <span className="text-text-secondary">Online</span>
</div>

Loading State

import LoadingSpinner from '../components/LoadingSpinner';

{isLoading && <LoadingSpinner />}
{isLoading && <LoadingSpinner fullscreen />}

Empty State

<div className="text-center py-12">
  <h3 className="text-lg font-semibold text-text-primary">No items found</h3>
  <p className="text-text-secondary">Create one to get started</p>
  <Button className="mt-4">Create New</Button>
</div>

Responsive Patterns

Mobile First

// Base style for mobile, override on larger screens
className="flex flex-col md:flex-row"
className="text-sm md:text-base lg:text-lg"
className="w-full md:w-1/2 lg:w-1/3"
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3"

Show/Hide on Breakpoint

className="hidden md:block"  // show on medium and up
className="md:hidden"        // hide on medium and up
className="block lg:hidden"  // show except on large

Performance Tips

  1. Use Tailwind for styling, not inline styles
  2. Keep components small and focused
  3. Use className merging with cn() function for dynamic classes
  4. Avoid unused Tailwind classes - Tailwind purges them in production
  5. Use semantic HTML with proper heading hierarchy
  6. Lazy load components when possible

Common Issues & Solutions

Issue: Styles not applying

Solution: Ensure:

  • Tailwind is configured correctly in tailwind.config.js
  • CSS is imported in index.css with @tailwind directives
  • PostCSS is configured in postcss.config.js

Issue: Colors not matching

Solution:

  • Check CSS variables in :root of index.css
  • Verify Tailwind config has extended colors
  • Use exact class names: text-text-primary not text-primary

Issue: Component not styled

Solution:

  • Verify component is imported from /lib/ui
  • Check cn() utility merges classes correctly
  • Ensure parent has proper className applied

Migration Checklist for New Pages

When creating or refactoring a page:

  • Use ShadCN Button for all actions
  • Use ShadCN Card for content grouping
  • Use ShadCN Alert for notifications
  • Use ShadCN Dialog for modals
  • Use ShadCN Input for form fields
  • Use ShadCN Badge for status indicators
  • Use Tailwind grid for layouts
  • Use Tailwind for spacing and sizing
  • Use custom CSS variables for colors
  • Follow mobile-first responsive design
  • Test on mobile, tablet, and desktop

Last Updated: November 6, 2025