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)
/* 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
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
<StorytellerCard
storyteller={storyteller}
variant="default"
showStories={true}
showActions={true}
/>
- 320px min width, responsive
- Avatar, name, cultural background
- Story count, specialties (max 3)
- Elder/Featured badges
- Hover effect with arrow
Compact Card
<StorytellerCard
storyteller={storyteller}
variant="compact"
/>
- 280px width, inline layout
- Avatar (smaller), name only
- Story count as badge
- Good for sidebars, lists
Featured Card
<StorytellerCard
storyteller={storyteller}
variant="featured"
/>
- Full width, larger avatar
- Featured quote displayed
- Theme expertise badges
- Gradient background
- Enhanced hover animations
List View Row
<StorytellerListCard storyteller={storyteller} />
- Full width horizontal
- More data visible
- Action buttons on right
- Good for admin views
AI Enrichment Opportunities
1. Bio Enhancement
// 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
// 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
// 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<string, number>
}
4. Connection Suggestions
// 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
// 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
<div className="relative">
<Avatar
src={storyteller.avatar_url}
fallback={getInitials(storyteller.display_name)}
className="w-16 h-16 border-2 border-background shadow-md"
/>
{/* Status Badges - Position top-right */}
<div className="absolute -top-1 -right-1 flex gap-1">
{storyteller.is_featured && (
<Badge variant="featured" size="icon">
<Star className="w-3 h-3" />
</Badge>
)}
{storyteller.is_elder && (
<Badge variant="elder" size="icon">
<Crown className="w-3 h-3" />
</Badge>
)}
</div>
</div>
Cultural Background Display
{/* Respectful cultural display */}
<div className="flex items-center gap-2 text-muted-foreground">
<MapPin className="w-4 h-4 text-terracotta-500" />
<span className="text-sm">
{storyteller.cultural_background}
{storyteller.traditional_territory && (
<span className="text-xs ml-1">
({storyteller.traditional_territory})
</span>
)}
</span>
</div>
Story Metrics Display
<div className="flex items-center gap-4">
<div className="flex items-center gap-1.5">
<BookOpen className="w-4 h-4 text-emerald-500" />
<span className="font-semibold">{storyteller.story_count}</span>
<span className="text-muted-foreground text-sm">
{storyteller.story_count === 1 ? 'Story' : 'Stories'}
</span>
</div>
{storyteller.years_of_experience && (
<div className="flex items-center gap-1.5">
<Calendar className="w-4 h-4 text-blue-500" />
<span className="font-semibold">{storyteller.years_of_experience}</span>
<span className="text-muted-foreground text-sm">Years</span>
</div>
)}
</div>
Theme/Specialty Badges
{/* Show max 3 on card, rest on hover/detail */}
<div className="flex flex-wrap gap-1.5">
{storyteller.specialties?.slice(0, 3).map((specialty, i) => (
<Badge
key={specialty}
variant="secondary"
className={cn(
"text-xs",
specialtyColors[i % specialtyColors.length]
)}
>
{specialty}
</Badge>
))}
{(storyteller.specialties?.length || 0) > 3 && (
<Badge variant="outline" className="text-xs text-muted-foreground">
+{storyteller.specialties!.length - 3} more
</Badge>
)}
</div>
Featured Quote Display
{storyteller.featured_quote && (
<div className="mt-4 p-3 bg-muted/50 rounded-lg border-l-2 border-accent">
<Quote className="w-4 h-4 text-accent mb-1" />
<p className="text-sm italic text-foreground/80 line-clamp-2">
"{storyteller.featured_quote}"
</p>
</div>
)}
AI Enrichment API Patterns
Trigger Enrichment
// POST /api/storytellers/{id}/enrich
async function enrichS