jpskill.com
🎨 デザイン コミュニティ

design-component

Empathy LedgerのUI部品(ストーリーテラーカードやプロフィール表示など)を、文化的な配慮が必要な場合に、データ連携やAIによる情報付加、デザインガイドラインに基づいて適切に設計するSkill。

📜 元の英語説明(参考)

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.

🇯🇵 日本人クリエイター向け解説

一言でいうと

Empathy LedgerのUI部品(ストーリーテラーカードやプロフィール表示など)を、文化的な配慮が必要な場合に、データ連携やAIによる情報付加、デザインガイドラインに基づいて適切に設計するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o design-component.zip https://jpskill.com/download/16991.zip && unzip -o design-component.zip && rm design-component.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/16991.zip -OutFile "$d\design-component.zip"; Expand-Archive "$d\design-component.zip" -DestinationPath $d -Force; ri "$d\design-component.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して design-component.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → design-component フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

デザインコンポーネントスキル

このスキルは、Empathy Ledger での UI コンポーネントの設計と実装に関する包括的なガイダンスを提供します。特に、ストーリーテラーカード、データ表示パターン、および AI を活用したコンテンツのエンリッチメントに焦点を当てています。

デザインシステム基盤

カラーパレット (CSS 変数)

/* ダークモードをサポートするためにセマンティックカラーを使用します */
--background     /* ページ背景 */
--foreground     /* プライマリテキスト */
--card           /* カード表面 */
--card-foreground/* カードテキスト */
--muted          /* ミュートされた背景 */
--muted-foreground /* セカンダリテキスト */
--popover        /* ドロップダウン/ポップオーバーの背景 */
--border         /* ボーダー */
--primary        /* プライマリアクション */
--accent         /* アクセント/ハイライト (サンシャインイエロー) */
--destructive    /* エラー/警告 */

文化的な色の意味

意味 用途
Amber/Gold 長老の知恵、注目の的 Elder バッジ、featured インジケーター
Emerald 成長、コミュニティ ストーリー数、アクティブステータス
Purple 神聖、知識 Knowledge keeper バッジ
Terracotta 地球、つながり 文化的な所属
Sage 穏やか、敬意 一般的な UI 要素

ストーリーテラーカードデータモデル

コア表示フィールド

interface StorytellerCardData {
  // アイデンティティ (常に表示)
  id: string
  display_name: string
  avatar_url?: string
  pronouns?: string

  // 文化的な背景 (利用可能な場合に表示)
  cultural_background?: string
  cultural_affiliations?: string[]
  traditional_territory?: string
  languages_spoken?: string[]

  // ステータスインジケーター
  is_elder: boolean
  is_featured: boolean
  status: 'active' | 'inactive' | 'pending'
  traditional_knowledge_keeper?: boolean

  // ストーリーメトリクス
  story_count: number
  featured_quote?: string
  expertise_themes?: string[]

  // プロフェッショナルな背景
  occupation?: string
  years_of_experience?: number
  specialties?: string[]

  // AI エンリッチされたフィールド
  ai_summary?: string
  theme_expertise?: string[]
  connection_strength?: number
  suggested_connections?: string[]
}

データ優先度階層

TIER 1 - 常に表示:
├── display_name
├── avatar (またはイニシャルのフォールバック)
├── cultural_background
└── story_count

TIER 2 - カードに表示:
├── elder_status バッジ
├── featured バッジ
├── 上位3つの specialties
├── プライマリロケーション
└── featured_quote (利用可能な場合)

TIER 3 - ホバー/展開時に表示:
├── full bio
├── すべての specialties
├── languages
├── organisations
└── theme expertise

TIER 4 - プロフィールページのみ:
├── contact info
├── full story list
├── connection graph
└── detailed analytics

カードバリアント

デフォルトカード

<StorytellerCard
  storyteller={storyteller}
  variant="default"
  showStories={true}
  showActions={true}
/>
  • 320px 最小幅、レスポンシブ
  • Avatar、名前、cultural background
  • ストーリー数、specialties (最大 3)
  • Elder/Featured バッジ
  • 矢印付きのホバーエフェクト

コンパクトカード

<StorytellerCard
  storyteller={storyteller}
  variant="compact"
/>
  • 280px 幅、インラインレイアウト
  • Avatar (より小さい)、名前のみ
  • バッジとしてのストーリー数
  • サイドバー、リストに最適

Featured カード

<StorytellerCard
  storyteller={storyteller}
  variant="featured"
/>
  • フル幅、より大きな avatar
  • Featured quote が表示される
  • Theme expertise バッジ
  • グラデーション背景
  • 強化されたホバーアニメーション

リストビュー行

<StorytellerListCard storyteller={storyteller} />
  • フル幅の水平方向
  • より多くのデータが表示される
  • 右側のアクションボタン
  • 管理ビューに最適

AI エンリッチメントの機会

1. Bio の強化

// API: POST /api/storytellers/{id}/enhance-bio
interface BioEnhancement {
  original_bio: string
  enhanced_bio: string        // 文法、フローの改善
  key_themes: string[]        // bio から抽出
  suggested_specialties: string[]
  cultural_keywords: string[]
}

2. Featured Quote の抽出

// ストーリーテラーのストーリーから、魅力的な引用を抽出
interface QuoteExtraction {
  quotes: Array<{
    text: string
    story_id: string
    themes: string[]
    impact_score: number
  }>
  suggested_featured: string  // カードに最適な引用
}

3. Theme Expertise 分析

// すべてのストーリーを分析して、専門分野を決定
interface ThemeExpertise {
  primary_themes: string[]      // 最も議論された上位3つ
  secondary_themes: string[]    // サポートテーマ
  unique_perspective: string    // 彼らをユニークにするもの
  theme_depth_scores: Record<string, number>
}

4. Connection の提案

// 補完的なテーマを持つストーリーテラーを見つける
interface ConnectionSuggestion {
  storyteller_id: string
  connection_type: 'theme_overlap' | 'geographic' | 'community'
  overlap_score: number
  reason: string  // "両方とも癒しの物語の専門知識を共有しています"
}

5. Summary の生成

// 簡潔なストーリーテラーの summary を生成
interface StoritellerSummary {
  one_liner: string      // "Wurundjeri Country 出身の長老..."
  card_summary: string   // カード用の 50-100 文字
  full_summary: string   // プロフィール用の 200-300 文字
  voice_style: string    // "温かく内省的なストーリーテリング"
}

コンポーネント実装パターン

ステータスインジケーター付き Avatar

<div className="relative">
  <Avatar
    src={storyteller.avatar_url}
    fallback={getInitials(storyteller.display_name)}
    className="w-16 h-16 border-2 border-background shadow-md"
  />

  {/* ステータスバッジ - 右上に配置 */}
  <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 の表示


{/* 敬意を払った文化的な表示 */}
<div className="flex items-center gap-2 text-muted-foreground">
  <MapPin className="w-4 h-4 tex
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

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 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

// Check for AI-enriched fields
const hasAIData = storyteller.ai_summary || storyteller.theme_expertise?.length

{hasAIData && (
  <div className="flex items-center gap-1 text-xs text-muted-foreground">
    <Sparkles className="w-3 h-3 text-accent" />
    <span>AI Enhanced</span>
  </div>
)}

Database Fields for AI Enrichment

Profiles Table Additions

-- 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

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:

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:

<Badge className={cn(
  "flex items-center gap-1.5",
  status === 'approved' && "bg-sage-100 text-sage-900",
  status === 'pending' && "bg-amber-100 text-amber-900",
  status === 'revoked' && "bg-ember-100 text-ember-900",
  status === 'expired' && "bg-muted text-muted-foreground"
)}>
  <Icon className="h-3 w-3" />
  {label}
</Badge>

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:

<div className="flex items-center gap-2">
  <code className="flex-1 px-3 py-2 bg-muted rounded font-mono text-sm">
    {tokenMasked ? 'LRK••••••••••XA' : token}
  </code>
  <Button variant="ghost" size="sm" onClick={() => setTokenMasked(!tokenMasked)}>
    {tokenMasked ? <Eye className="h-4 w-4" /> : <EyeOff className="h-4 w-4" />}
  </Button>
  <Button variant="ghost" size="sm" onClick={handleCopy}>
    <Copy className="h-4 w-4" />
  </Button>
</div>

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):

const siteColors = {
  justicehub: '#C85A54', // Ember
  actfarm: '#6B8E72',    // Sage
  theharvest: '#D97757', // Clay
  actplacemat: '#4A90A4' // Sky
}

// Usage
<Line
  type="monotone"
  dataKey="justicehub"
  stroke={siteColors.justicehub}
  strokeWidth={2}
  dot={{ fill: siteColors.justicehub, r: 4 }}
  activeDot={{ r: 6 }}
/>

Grid & Axes:

<CartesianGrid strokeDasharray="3 3" stroke="hsl(var(--border))" />
<XAxis
  dataKey="date"
  stroke="hsl(var(--muted-foreground))"
  fontSize={12}
/>
<YAxis
  stroke="hsl(var(--muted-foreground))"
  fontSize={12}
/>

Revocation Dialog

Purpose: Confirm consent revocation with cultural messaging

Layout:

<Dialog>
  <DialogHeader>
    <DialogTitle className="text-ember-900">
      Revoke Consent for JusticeHub?
    </DialogTitle>
    <DialogDescription>
      This will immediately remove JusticeHub's access to your story.
      They will no longer be able to display it on their platform.
    </DialogDescription>
  </DialogHeader>

  <div className="space-y-4">
    <div className="rounded-lg bg-sky-50 p-4 border border-sky-200">
      <p className="text-sm text-sky-900 font-medium">
        ✨ You maintain full control
      </p>
      <p className="text-sm text-sky-700 mt-1">
        Your story remains on Empathy Ledger. You can grant consent
        again at any time.
      </p>
    </div>

    <div className="space-y-2">
      <Label htmlFor="reason">Reason for revoking (optional)</Label>
      <Textarea
        id="reason"
        placeholder="E.g., Story needs updating, not ready for external sharing..."
        rows={3}
      />
      <p className="text-xs text-muted-foreground">
        This helps us improve the platform (shared anonymously with
        JusticeHub if consent was active).
      </p>
    </div>
  </div>

  <DialogFooter>
    <Button variant="outline" onClick={onCancel}>
      Keep Consent
    </Button>
    <Button variant="destructive" onClick={handleRevoke}>
      Revoke Access
    </Button>
  </DialogFooter>
</Dialog>

Messaging Principles:

  • ✅ Affirm storyteller control ("You maintain full control")
  • ✅ Explain consequences clearly ("immediately remove access")
  • ✅ Reassure reversibility ("grant consent again")
  • ❌ No guilt-tripping ("Are you sure?")
  • ❌ No fear language ("This cannot be undone")

Cultural Permission Level Indicator

Purpose: Show content sensitivity level with cultural context

Levels:

const culturalLevels = {
  public: {
    color: 'sage',
    icon: Globe,
    label: 'Public',
    description: 'Safe to share widely'
  },
  community: {
    color: 'clay',
    icon: Users,
    label: 'Community',
    description: 'Indigenous communities only'
  },
  restricted: {
    color: 'amber',
    icon: Lock,
    label: 'Restricted',
    description: 'Requires elder approval'
  },
  sacred: {
    color: 'ember',
    icon: ShieldAlert,
    label: 'Sacred',
    description: 'Not for external sharing'
  }
}

Component:

<div className="flex items-center gap-2">
  <Icon className="h-4 w-4 text-{color}-700" />
  <div>
    <p className="text-sm font-medium">{label}</p>
    <p className="text-xs text-muted-foreground">{description}</p>
  </div>
</div>

Empty States for Syndication

No Consents Yet:

<div className="text-center py-12 space-y-4">
  <div className="mx-auto w-16 h-16 rounded-full bg-sage-100 flex items-center justify-center">
    <Share2 className="h-8 w-8 text-sage-700" />
  </div>
  <div>
    <h3 className="text-lg font-semibold">No syndication consents yet</h3>
    <p className="text-muted-foreground mt-1">
      Your stories are safe with you. When you're ready to share with
      external platforms like JusticeHub, you'll see them here.
    </p>
  </div>
  <Button onClick={handleCreateConsent}>
    <Plus className="mr-2 h-4 w-4" />
    Share a Story
  </Button>
</div>

All Consents Revoked:

<div className="text-center py-12 space-y-4">
  <div className="mx-auto w-16 h-16 rounded-full bg-sky-100 flex items-center justify-center">
    <ShieldCheck className="h-8 w-8 text-sky-700" />
  </div>
  <div>
    <h3 className="text-lg font-semibold">You're in control</h3>
    <p className="text-muted-foreground mt-1">
      All your stories have been removed from external platforms.
      You can re-share whenever you're ready.
    </p>
  </div>
</div>

When to Use This Skill

Invoke when:

  • Designing new card components
  • Adding fields to storyteller/story cards
  • Implementing AI enrichment features
  • Creating profile displays
  • Building list views with storyteller data
  • Adding cultural indicators to UI
  • Implementing hover/expand states
  • Creating loading skeletons
  • Designing syndication dashboard UI
  • Building consent management interfaces
  • Creating analytics visualizations
  • Implementing revocation workflows