--- name: design-component description: Design Component skill for Empathy Ledger. Use for storyteller cards, story cards, profile displays, and any UI component requiring cultural sensitivity. Provides data mapping, AI enrichment patterns, and design system guidelines. --- # Design Component Skill This skill provides comprehensive guidance for designing and implementing UI components in Empathy Ledger, with special focus on storyteller cards, data display patterns, and AI-powered content enrichment. ## Design System Foundation ### Color Palette (CSS Variables) ```css /* Use semantic colors for dark mode support */ --background /* Page background */ --foreground /* Primary text */ --card /* Card surfaces */ --card-foreground/* Card text */ --muted /* Muted backgrounds */ --muted-foreground /* Secondary text */ --popover /* Dropdown/popover backgrounds */ --border /* Borders */ --primary /* Primary actions */ --accent /* Accent/highlight (sunshine yellow) */ --destructive /* Errors/warnings */ ``` ### Cultural Color Meanings | Color | Meaning | Usage | |-------|---------|-------| | Amber/Gold | Elder wisdom, featured | Elder badges, featured indicators | | Emerald | Growth, community | Story counts, active status | | Purple | Sacred, knowledge | Knowledge keeper badges | | Terracotta | Earth, connection | Cultural affiliations | | Sage | Calm, respectful | General UI elements | ## Storyteller Card Data Model ### Core Display Fields ```typescript interface StorytellerCardData { // Identity (Always Show) id: string display_name: string avatar_url?: string pronouns?: string // Cultural Context (Show When Available) cultural_background?: string cultural_affiliations?: string[] traditional_territory?: string languages_spoken?: string[] // Status Indicators is_elder: boolean is_featured: boolean status: 'active' | 'inactive' | 'pending' traditional_knowledge_keeper?: boolean // Story Metrics story_count: number featured_quote?: string expertise_themes?: string[] // Professional Context occupation?: string years_of_experience?: number specialties?: string[] // AI-Enriched Fields ai_summary?: string theme_expertise?: string[] connection_strength?: number suggested_connections?: string[] } ``` ### Data Priority Hierarchy ``` TIER 1 - Always Display: ├── display_name ├── avatar (or initials fallback) ├── cultural_background └── story_count TIER 2 - Show on Card: ├── elder_status badge ├── featured badge ├── top 3 specialties ├── primary location └── featured_quote (if available) TIER 3 - Show on Hover/Expand: ├── full bio ├── all specialties ├── languages ├── organisations └── theme expertise TIER 4 - Profile Page Only: ├── contact info ├── full story list ├── connection graph └── detailed analytics ``` ## Card Variants ### Default Card ```tsx ``` - 320px min width, responsive - Avatar, name, cultural background - Story count, specialties (max 3) - Elder/Featured badges - Hover effect with arrow ### Compact Card ```tsx ``` - 280px width, inline layout - Avatar (smaller), name only - Story count as badge - Good for sidebars, lists ### Featured Card ```tsx ``` - Full width, larger avatar - Featured quote displayed - Theme expertise badges - Gradient background - Enhanced hover animations ### List View Row ```tsx ``` - Full width horizontal - More data visible - Action buttons on right - Good for admin views ## AI Enrichment Opportunities ### 1. Bio Enhancement ```typescript // API: POST /api/storytellers/{id}/enhance-bio interface BioEnhancement { original_bio: string enhanced_bio: string // Grammar, flow improvements key_themes: string[] // Extracted from bio suggested_specialties: string[] cultural_keywords: string[] } ``` ### 2. Featured Quote Extraction ```typescript // From storyteller's stories, extract compelling quotes interface QuoteExtraction { quotes: Array<{ text: string story_id: string themes: string[] impact_score: number }> suggested_featured: string // Best quote for card } ``` ### 3. Theme Expertise Analysis ```typescript // Analyze all stories to determine expertise areas interface ThemeExpertise { primary_themes: string[] // Top 3 most discussed secondary_themes: string[] // Supporting themes unique_perspective: string // What makes them unique theme_depth_scores: Record } ``` ### 4. Connection Suggestions ```typescript // Find storytellers with complementary themes interface ConnectionSuggestion { storyteller_id: string connection_type: 'theme_overlap' | 'geographic' | 'community' overlap_score: number reason: string // "Both share expertise in healing stories" } ``` ### 5. Summary Generation ```typescript // Generate concise storyteller summary interface StoritellerSummary { one_liner: string // "Elder from Wurundjeri Country..." card_summary: string // 50-100 chars for cards full_summary: string // 200-300 chars for profiles voice_style: string // "Warm and reflective storytelling" } ``` ## Component Implementation Patterns ### Avatar with Status Indicators ```tsx
{/* Status Badges - Position top-right */}
{storyteller.is_featured && ( )} {storyteller.is_elder && ( )}
``` ### Cultural Background Display ```tsx {/* Respectful cultural display */}
{storyteller.cultural_background} {storyteller.traditional_territory && ( ({storyteller.traditional_territory}) )}
``` ### Story Metrics Display ```tsx
{storyteller.story_count} {storyteller.story_count === 1 ? 'Story' : 'Stories'}
{storyteller.years_of_experience && (
{storyteller.years_of_experience} Years
)}
``` ### Theme/Specialty Badges ```tsx {/* Show max 3 on card, rest on hover/detail */}
{storyteller.specialties?.slice(0, 3).map((specialty, i) => ( {specialty} ))} {(storyteller.specialties?.length || 0) > 3 && ( +{storyteller.specialties!.length - 3} more )}
``` ### Featured Quote Display ```tsx {storyteller.featured_quote && (

"{storyteller.featured_quote}"

)} ``` ## AI Enrichment API Patterns ### Trigger Enrichment ```typescript // POST /api/storytellers/{id}/enrich async function enrichStoryteller(storytellerId: string) { const response = await fetch(`/api/storytellers/${storytellerId}/enrich`, { method: 'POST', body: JSON.stringify({ enrich_bio: true, extract_quotes: true, analyze_themes: true, suggest_connections: true }) }) // Returns enrichment job ID for polling return response.json() } ``` ### Display Enriched Data ```tsx // Check for AI-enriched fields const hasAIData = storyteller.ai_summary || storyteller.theme_expertise?.length {hasAIData && (
AI Enhanced
)} ``` ## Database Fields for AI Enrichment ### Profiles Table Additions ```sql -- AI-generated summary ALTER TABLE profiles ADD COLUMN ai_summary TEXT; -- Extracted theme expertise (from stories analysis) ALTER TABLE profiles ADD COLUMN theme_expertise TEXT[]; -- AI-generated featured quote selection ALTER TABLE profiles ADD COLUMN featured_quote TEXT; ALTER TABLE profiles ADD COLUMN featured_quote_story_id UUID; -- Connection strength scores ALTER TABLE profiles ADD COLUMN connection_scores JSONB DEFAULT '{}'; -- Enrichment status ALTER TABLE profiles ADD COLUMN ai_enrichment_status TEXT DEFAULT 'pending'; ALTER TABLE profiles ADD COLUMN ai_enriched_at TIMESTAMPTZ; ``` ### Story Suggestions View ```sql CREATE VIEW storyteller_connections AS SELECT p1.id as storyteller_id, p2.id as connected_storyteller_id, array_length( ARRAY(SELECT unnest(p1.theme_expertise) INTERSECT SELECT unnest(p2.theme_expertise)), 1 ) as theme_overlap, p1.cultural_background = p2.cultural_background as same_culture FROM profiles p1 CROSS JOIN profiles p2 WHERE p1.id != p2.id AND p1.is_storyteller = true AND p2.is_storyteller = true; ``` ## Component Checklist ### Before Creating a Card Component - [ ] Identify all data fields needed - [ ] Define which fields are required vs optional - [ ] Plan fallback states for missing data - [ ] Consider dark mode colors - [ ] Add hover states - [ ] Plan loading skeleton - [ ] Add accessibility labels ### Cultural Sensitivity - [ ] Respectful terminology used - [ ] Elder status prominently displayed - [ ] Cultural background shown with respect - [ ] Traditional territory acknowledged - [ ] No appropriation of cultural symbols - [ ] Languages displayed respectfully ### AI Enrichment - [ ] Mark AI-generated content - [ ] Allow user override of AI suggestions - [ ] Handle missing AI data gracefully - [ ] Show enrichment in progress states ## Reference Components | Component | Location | Purpose | |-----------|----------|---------| | `StorytellerCard` | `src/components/storyteller/storyteller-card.tsx` | Main card component | | `UnifiedStorytellerCard` | `src/components/storyteller/unified-storyteller-card.tsx` | Flexible card variants | | `ElegantStorytellerCard` | `src/components/storyteller/elegant-storyteller-card.tsx` | Premium design variant | | `StoryCard` | `src/components/story/story-card.tsx` | Story display card | | `QuoteCard` | `src/components/ui/quote-card.tsx` | Quote display | | `ThemeBadge` | `src/components/ui/theme-badge.tsx` | Theme display | ## Syndication Dashboard Design Patterns (NEW - Sprint 4) ### Consent Status Badge **Purpose:** Visual indicator of syndication consent status **Variants:** ```typescript type ConsentStatus = 'approved' | 'pending' | 'revoked' | 'expired' const statusConfig = { approved: { color: 'sage', icon: CheckCircle, label: 'Active' }, pending: { color: 'amber', icon: Clock, label: 'Pending' }, revoked: { color: 'ember', icon: XCircle, label: 'Revoked' }, expired: { color: 'muted', icon: AlertCircle, label: 'Expired' } } ``` **Design:** ```tsx {label} ``` --- ### Consent Card Layout **Purpose:** Display individual syndication consent with site info and controls **Structure:** ``` ┌─────────────────────────────────────────────┐ │ [Site Logo] JusticeHub │ │ justicehub.org.au │ │ │ │ Status: [Active Badge] │ │ Cultural Level: Public │ │ Created: Jan 5, 2026 │ │ │ │ 📊 456 views • Last accessed 2 hours ago │ │ │ │ [View Analytics] [Revoke Access] │ └─────────────────────────────────────────────┘ ``` **Colors:** - **Card Border:** Use site brand color (if provided) - **Status Badge:** Follow status config above - **Cultural Level:** Use cultural color (clay/sage/sky) - **Actions:** Primary (sage) for analytics, destructive (ember) for revoke --- ### Embed Token Display **Purpose:** Show token with security-conscious masking **Pattern:** ```tsx
{tokenMasked ? 'LRK••••••••••XA' : token}
``` **Security:** - Default: Token masked - Click to reveal (temporary, 10 seconds) - Copy button with confirmation toast - Never log unmasked tokens --- ### Analytics Chart Styling **Purpose:** Consistent chart design across dashboards **Colors (Recharts):** ```typescript const siteColors = { justicehub: '#C85A54', // Ember actfarm: '#6B8E72', // Sage theharvest: '#D97757', // Clay actplacemat: '#4A90A4' // Sky } // Usage ``` **Grid & Axes:** ```typescript ``` --- ### Revocation Dialog **Purpose:** Confirm consent revocation with cultural messaging **Layout:** ```tsx Revoke Consent for JusticeHub? This will immediately remove JusticeHub's access to your story. They will no longer be able to display it on their platform.

✨ You maintain full control

Your story remains on Empathy Ledger. You can grant consent again at any time.