{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "habit-streak-tracker",
  "title": "Habit Streak Tracker",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/habit-streak-tracker/HabitStreakTracker.vue",
      "content": "<script setup lang=\"ts\">\nimport { ref, computed } from 'vue'\nimport type { HTMLAttributes, Component } from 'vue'\nimport {\n  BookOpen,\n  Calendar,\n  Check,\n  CheckCircle2,\n  Code2,\n  Droplets,\n  Flame,\n  Footprints,\n  Plus,\n  Target,\n  Terminal,\n  TrendingUp,\n  Trophy,\n  X,\n} from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/components/ui/card'\nimport { Progress } from '@/components/ui/progress'\n\nexport type HabitCategory = 'Engineering' | 'Health' | 'Learning' | 'Mindset' | string\n\nexport interface HabitItem {\n  id: string\n  title: string\n  description: string\n  category: HabitCategory\n  icon: 'code' | 'terminal' | 'steps' | 'book' | 'water' | 'target' | string\n  streakDays: number\n  completionRate: number\n  weekHistory: boolean[] // 7 days: [Mon, Tue, Wed, Thu, Fri, Sat, Sun]\n}\n\nexport interface DayHeatmapCell {\n  date: string\n  formattedDate: string\n  dayName: string\n  dayIndex: number // 0 = Mon, 6 = Sun\n  weekIndex: number // 0 to 51\n  count: number // 0 to 5\n  level: number // 0 to 4\n  month: string\n}\n\nexport interface MonthLabel {\n  name: string\n  weekIndex: number\n}\n\nexport interface HabitStreakTrackerProps {\n  initialStreak?: number\n  longestStreak?: string\n  consistencyRate?: number\n  activeHabitsCount?: number\n  monthTitle?: string\n  habits?: HabitItem[]\n  class?: HTMLAttributes['class']\n}\n\nconst defaultHabits: HabitItem[] = [\n  {\n    id: 'habit-1',\n    title: 'Ship 1 Component to Registry',\n    description: 'Author, test, and register a new UI block or primitive',\n    category: 'Engineering',\n    icon: 'code',\n    streakDays: 24,\n    completionRate: 96,\n    weekHistory: [true, true, true, true, true, true, true],\n  },\n  {\n    id: 'habit-2',\n    title: '1 Hour Deep Work / Code Review',\n    description: 'Uninterrupted architecture focus & PR review rounds',\n    category: 'Engineering',\n    icon: 'terminal',\n    streakDays: 19,\n    completionRate: 92,\n    weekHistory: [true, true, true, true, true, false, true],\n  },\n  {\n    id: 'habit-3',\n    title: '10,000 Steps Walking',\n    description: 'Daily outdoor walk & cardiovascular activity',\n    category: 'Health',\n    icon: 'steps',\n    streakDays: 24,\n    completionRate: 100,\n    weekHistory: [true, true, true, true, true, true, true],\n  },\n  {\n    id: 'habit-4',\n    title: 'Read 20 Pages Tech Book',\n    description: 'Systems design, TypeScript craft, or CS fundamentals',\n    category: 'Learning',\n    icon: 'book',\n    streakDays: 12,\n    completionRate: 85,\n    weekHistory: [true, true, false, true, true, true, false],\n  },\n  {\n    id: 'habit-5',\n    title: 'Drink 2.5L Water',\n    description: 'Optimal hydration tracking throughout the working day',\n    category: 'Health',\n    icon: 'water',\n    streakDays: 30,\n    completionRate: 98,\n    weekHistory: [true, true, true, true, true, true, true],\n  },\n]\n\nfunction generate52WeekHeatmap(baseStreakDays: number = 24): {\n  weeks: DayHeatmapCell[][]\n  monthLabels: MonthLabel[]\n  totalCompletions: number\n} {\n  const weeks: DayHeatmapCell[][] = []\n  const monthLabels: MonthLabel[] = []\n  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']\n  const dayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n\n  const endDate = new Date(2026, 7, 23) // Sunday Aug 23, 2026\n  let lastMonth = ''\n  let totalCompletions = 0\n\n  let seed = 1337\n  function pseudoRandom() {\n    seed = (seed * 9301 + 49297) % 233280\n    return seed / 233280\n  }\n\n  for (let w = 0; w < 52; w++) {\n    const weekDays: DayHeatmapCell[] = []\n    for (let d = 0; d < 7; d++) {\n      const daysAgo = (51 - w) * 7 + (6 - d)\n      const dateObj = new Date(endDate)\n      dateObj.setDate(endDate.getDate() - daysAgo)\n\n      const monthName = months[dateObj.getMonth()]\n      const formattedDate = `${monthName} ${dateObj.getDate()}, ${dateObj.getFullYear()}`\n      const dateStr = dateObj.toISOString().split('T')[0]\n\n      let count = 0\n      if (daysAgo <= baseStreakDays && daysAgo >= 0) {\n        count = pseudoRandom() > 0.3 ? 5 : 4\n      } else if (daysAgo >= 90 && daysAgo <= 138) {\n        count = pseudoRandom() > 0.2 ? 5 : 4\n      } else {\n        const rand = pseudoRandom()\n        if (rand > 0.82) count = 5\n        else if (rand > 0.48) count = 4\n        else if (rand > 0.22) count = 3\n        else if (rand > 0.08) count = 2\n        else if (rand > 0.03) count = 1\n        else count = 0\n      }\n\n      totalCompletions += count\n\n      let level = 0\n      if (count >= 5) level = 4\n      else if (count === 4) level = 3\n      else if (count === 3) level = 2\n      else if (count >= 1) level = 1\n      else level = 0\n\n      const cell: DayHeatmapCell = {\n        date: dateStr,\n        formattedDate,\n        dayName: dayNames[d],\n        dayIndex: d,\n        weekIndex: w,\n        count,\n        level,\n        month: monthName,\n      }\n\n      weekDays.push(cell)\n\n      if (d === 0 && monthName !== lastMonth) {\n        monthLabels.push({ name: monthName, weekIndex: w })\n        lastMonth = monthName\n      }\n    }\n    weeks.push(weekDays)\n  }\n\n  return { weeks, monthLabels, totalCompletions }\n}\n\nconst props = withDefaults(defineProps<HabitStreakTrackerProps>(), {\n  initialStreak: 24,\n  longestStreak: '48 Days in Q2',\n  consistencyRate: 94.2,\n  activeHabitsCount: 5,\n  monthTitle: 'August 2026',\n})\n\nconst habitsList = ref<HabitItem[]>(JSON.parse(JSON.stringify(props.habits ?? defaultHabits)))\nconst activeCategory = ref<string>('All')\nconst showNewHabitModal = ref<boolean>(false)\nconst hoveredCell = ref<DayHeatmapCell | null>(null)\n\nconst newHabitTitle = ref('')\nconst newHabitDescription = ref('')\nconst newHabitCategory = ref<HabitCategory>('Engineering')\nconst newHabitIcon = ref('code')\n\nconst heatmapData = computed(() => generate52WeekHeatmap(props.initialStreak))\n\nconst weekDayColumns = [\n  { short: 'Mon', num: '17' },\n  { short: 'Tue', num: '18' },\n  { short: 'Wed', num: '19' },\n  { short: 'Thu', num: '20' },\n  { short: 'Fri', num: '21' },\n  { short: 'Sat', num: '22' },\n  { short: 'Sun', num: '23' },\n]\n\nconst categories = computed(() => {\n  const cats = ['All']\n  habitsList.value.forEach((h) => {\n    if (!cats.includes(h.category)) cats.push(h.category)\n  })\n  return cats\n})\n\nconst filteredHabits = computed(() => {\n  if (activeCategory.value === 'All') return habitsList.value\n  return habitsList.value.filter((h) => h.category === activeCategory.value)\n})\n\nconst todayCompletedCount = computed(() => habitsList.value.filter((h) => h.weekHistory[6]).length)\nconst totalHabitsCount = computed(() => habitsList.value.length)\n\nfunction getHabitIcon(icon: string): Component {\n  switch (icon) {\n    case 'code':\n      return Code2\n    case 'terminal':\n      return Terminal\n    case 'steps':\n      return Footprints\n    case 'book':\n      return BookOpen\n    case 'water':\n      return Droplets\n    default:\n      return Target\n  }\n}\n\nfunction getCategoryBadgeClass(category: HabitCategory) {\n  switch (category) {\n    case 'Engineering':\n      return 'bg-info/10 text-info border-info/25'\n    case 'Health':\n      return 'bg-success/10 text-success border-success/25'\n    case 'Learning':\n      return 'bg-chart-1/10 text-chart-1 border-chart-1/25'\n    case 'Mindset':\n      return 'bg-warning/10 text-warning border-warning/25'\n    default:\n      return 'bg-muted text-muted-foreground border-border'\n  }\n}\n\nconst levelClassMap: Record<number, string> = {\n  0: 'bg-muted/60 dark:bg-muted/30 border border-border/30 hover:ring-1 hover:ring-foreground/20',\n  1: 'bg-success/25 border border-success/20 hover:ring-1 hover:ring-success/50',\n  2: 'bg-success/50 border border-success/30 hover:ring-1 hover:ring-success/70',\n  3: 'bg-success/75 border border-success/40 hover:ring-1 hover:ring-success/90',\n  4: 'bg-success border border-success/60 hover:ring-1 hover:ring-success',\n}\n\nfunction toggleDay(habitId: string, dayIndex: number) {\n  const habit = habitsList.value.find((h) => h.id === habitId)\n  if (!habit) return\n  habit.weekHistory[dayIndex] = !habit.weekHistory[dayIndex]\n  const completedInWeek = habit.weekHistory.filter(Boolean).length\n  habit.completionRate = Math.min(100, Math.round((completedInWeek / 7) * 100))\n  if (dayIndex === 6) {\n    if (habit.weekHistory[6]) {\n      habit.streakDays += 1\n    } else {\n      habit.streakDays = Math.max(0, habit.streakDays - 1)\n    }\n  }\n}\n\nfunction toggleToday(habitId: string) {\n  toggleDay(habitId, 6)\n}\n\nfunction handleAddHabit() {\n  if (!newHabitTitle.value.trim()) return\n  const newHabit: HabitItem = {\n    id: `habit-${Date.now()}`,\n    title: newHabitTitle.value.trim(),\n    description: newHabitDescription.value.trim() || 'Daily tracked routine',\n    category: newHabitCategory.value,\n    icon: newHabitIcon.value,\n    streakDays: 1,\n    completionRate: 100,\n    weekHistory: [false, false, false, false, false, false, true],\n  }\n  habitsList.value.push(newHabit)\n  newHabitTitle.value = ''\n  newHabitDescription.value = ''\n  showNewHabitModal.value = false\n}\n</script>\n\n<template>\n  <div :class=\"cn('w-full space-y-6', props.class)\" data-slot=\"habit-streak-tracker\">\n    <!-- Header Section -->\n    <div\n      class=\"border-border/80 bg-card text-card-foreground flex flex-col gap-4 rounded-xl border p-4 shadow-xs sm:p-5 md:flex-row md:items-center md:justify-between\"\n    >\n      <div class=\"flex items-start gap-3.5 sm:items-center\">\n        <div\n          class=\"border-warning/30 bg-warning/10 text-warning text-warning flex size-10 shrink-0 items-center justify-center rounded-xl border shadow-xs\"\n        >\n          <Flame class=\"size-5.5 animate-pulse\" />\n        </div>\n        <div class=\"space-y-1\">\n          <div class=\"flex flex-wrap items-center gap-2.5\">\n            <h1 class=\"text-foreground text-base leading-none font-semibold tracking-tight sm:text-lg\">\n              Daily Habits & Consistency Matrix\n            </h1>\n            <Badge\n              wrap\n              variant=\"warning\"\n              class=\"border-warning/30 bg-warning/15 text-warning gap-1 text-xs font-semibold\"\n            >\n              <Flame class=\"fill-warning text-warning size-3.5\" />\n              <span class=\"font-mono tabular-nums\">🔥 {{ props.initialStreak }}-Day Streak · Personal Best!</span>\n            </Badge>\n          </div>\n          <p class=\"text-muted-foreground text-xs\">\n            {{ props.monthTitle }} · Real-time habit adherence, 52-week GitHub matrix, and routine tracker.\n          </p>\n        </div>\n      </div>\n\n      <div class=\"flex flex-wrap items-center gap-2.5 self-end sm:self-auto\">\n        <div\n          class=\"border-border/70 bg-muted/40 text-muted-foreground flex items-center gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs font-medium\"\n        >\n          <Calendar class=\"size-3.5\" />\n          <span>{{ props.monthTitle }}</span>\n        </div>\n        <Button\n          aria-label=\"Close new habit dialog\"\n          size=\"sm\"\n          class=\"gap-1.5 shadow-xs\"\n          @click=\"showNewHabitModal = !showNewHabitModal\"\n        >\n          <Plus class=\"size-4\" />\n          <span>New Habit</span>\n        </Button>\n      </div>\n    </div>\n\n    <!-- Quick Add Inline Card (Collapsible) -->\n    <div\n      v-if=\"showNewHabitModal\"\n      class=\"border-border/80 bg-card text-card-foreground space-y-3 rounded-xl border p-4 shadow-xs sm:p-5\"\n    >\n      <div class=\"flex items-center justify-between\">\n        <div class=\"space-y-0.5\">\n          <p class=\"text-foreground text-sm font-semibold\">Create New Habit Routine</p>\n          <p class=\"text-muted-foreground text-xs\">Define a daily target to track against your annual matrix.</p>\n        </div>\n        <Button\n          variant=\"ghost\"\n          size=\"icon-sm\"\n          class=\"size-7\"\n          aria-label=\"Close new habit dialog\"\n          @click=\"showNewHabitModal = false\"\n        >\n          <X class=\"size-4\" />\n        </Button>\n      </div>\n\n      <div class=\"grid grid-cols-1 gap-3 sm:grid-cols-12\">\n        <div class=\"sm:col-span-4\">\n          <label class=\"text-foreground mb-1 block text-xs font-medium\">Habit Title</label>\n          <input\n            v-model=\"newHabitTitle\"\n            type=\"text\"\n            placeholder=\"e.g. Write 500 Words Technical Notes\"\n            class=\"border-border bg-background placeholder:text-muted-foreground focus-visible:ring-ring h-8 w-full rounded-md border px-2.5 text-xs focus-visible:ring-2 focus-visible:outline-none\"\n            @keydown.enter=\"handleAddHabit\"\n          />\n        </div>\n\n        <div class=\"sm:col-span-4\">\n          <label class=\"text-foreground mb-1 block text-xs font-medium\">Description</label>\n          <input\n            v-model=\"newHabitDescription\"\n            type=\"text\"\n            placeholder=\"e.g. Daily engineering documentation\"\n            class=\"border-border bg-background placeholder:text-muted-foreground focus-visible:ring-ring h-8 w-full rounded-md border px-2.5 text-xs focus-visible:ring-2 focus-visible:outline-none\"\n            @keydown.enter=\"handleAddHabit\"\n          />\n        </div>\n\n        <div class=\"sm:col-span-2\">\n          <label class=\"text-foreground mb-1 block text-xs font-medium\">Category</label>\n          <select\n            v-model=\"newHabitCategory\"\n            class=\"border-border bg-background text-foreground focus-visible:ring-ring h-8 w-full rounded-md border px-2 text-xs focus-visible:ring-2 focus-visible:outline-none\"\n          >\n            <option value=\"Engineering\">Engineering</option>\n            <option value=\"Health\">Health</option>\n            <option value=\"Learning\">Learning</option>\n            <option value=\"Mindset\">Mindset</option>\n          </select>\n        </div>\n\n        <div class=\"sm:col-span-2\">\n          <label class=\"text-foreground mb-1 block text-xs font-medium\">Icon</label>\n          <select\n            v-model=\"newHabitIcon\"\n            class=\"border-border bg-background text-foreground focus-visible:ring-ring h-8 w-full rounded-md border px-2 text-xs focus-visible:ring-2 focus-visible:outline-none\"\n          >\n            <option value=\"code\">Code</option>\n            <option value=\"terminal\">Terminal</option>\n            <option value=\"steps\">Steps</option>\n            <option value=\"book\">Book</option>\n            <option value=\"water\">Water</option>\n            <option value=\"target\">Target</option>\n          </select>\n        </div>\n      </div>\n\n      <div class=\"flex items-center justify-end gap-2 pt-1\">\n        <Button\n          aria-label=\"Close new habit dialog\"\n          variant=\"ghost\"\n          size=\"sm\"\n          class=\"text-xs\"\n          @click=\"showNewHabitModal = false\"\n        >\n          Cancel\n        </Button>\n        <Button size=\"sm\" class=\"text-xs\" :disabled=\"!newHabitTitle.trim()\" @click=\"handleAddHabit\">\n          Add Routine\n        </Button>\n      </div>\n    </div>\n\n    <!-- 4 Streak Metric Cards Grid -->\n    <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n      <!-- Card 1: Current Streak -->\n      <Card class=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n        <CardHeader class=\"p-4 pb-2\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Current Streak</span>\n            <div\n              class=\"border-warning/25 bg-warning/10 text-warning flex size-7 items-center justify-center rounded-md border\"\n            >\n              <Flame class=\"fill-warning text-warning size-4\" />\n            </div>\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1 p-4 pt-1\">\n          <div class=\"flex items-baseline gap-2\">\n            <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n              {{ props.initialStreak }} Days\n            </span>\n            <Badge wrap variant=\"warning\" class=\"text-xs font-medium\">Active</Badge>\n          </div>\n          <p class=\"text-muted-foreground text-xs\">Active since Jul 29 · On track today</p>\n        </CardContent>\n      </Card>\n\n      <!-- Card 2: Longest Streak -->\n      <Card class=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n        <CardHeader class=\"p-4 pb-2\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Longest Streak</span>\n            <div\n              class=\"border-chart-2/25 bg-chart-2/10 text-chart-2 flex size-7 items-center justify-center rounded-md border\"\n            >\n              <Trophy class=\"size-4\" />\n            </div>\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1 p-4 pt-1\">\n          <div class=\"flex items-baseline gap-2\">\n            <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n              {{ props.longestStreak }}\n            </span>\n            <Badge wrap variant=\"secondary\" class=\"text-xs font-medium\">Record</Badge>\n          </div>\n          <p class=\"text-muted-foreground text-xs\">48 continuous days set May 14, 2026</p>\n        </CardContent>\n      </Card>\n\n      <!-- Card 3: Overall Consistency -->\n      <Card class=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n        <CardHeader class=\"p-4 pb-2\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Overall Consistency</span>\n            <div\n              class=\"border-success/25 bg-success/10 text-success flex size-7 items-center justify-center rounded-md border\"\n            >\n              <TrendingUp class=\"size-4\" />\n            </div>\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1 p-4 pt-1\">\n          <div class=\"flex items-baseline gap-2\">\n            <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n              {{ props.consistencyRate }}%\n            </span>\n            <Badge wrap variant=\"success\" class=\"text-xs font-medium\">+3.1% MoM</Badge>\n          </div>\n          <p class=\"text-muted-foreground text-xs\">{{ heatmapData.totalCompletions }} targets completed in 52 weeks</p>\n        </CardContent>\n      </Card>\n\n      <!-- Card 4: Total Habits Active -->\n      <Card class=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n        <CardHeader class=\"p-4 pb-2\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Total Habits Active</span>\n            <div class=\"border-info/25 bg-info/10 text-info flex size-7 items-center justify-center rounded-md border\">\n              <Target class=\"size-4\" />\n            </div>\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1 p-4 pt-1\">\n          <div class=\"flex items-baseline gap-2\">\n            <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n              {{ totalHabitsCount }} Daily Habits\n            </span>\n            <Badge\n              :variant=\"todayCompletedCount === totalHabitsCount ? 'success' : 'secondary'\"\n              class=\"text-xs font-medium whitespace-normal\"\n            >\n              {{ todayCompletedCount }}/{{ totalHabitsCount }} Done\n            </Badge>\n          </div>\n          <p class=\"text-muted-foreground text-xs\">\n            {{\n              todayCompletedCount === totalHabitsCount\n                ? 'All daily targets logged!'\n                : `${totalHabitsCount - todayCompletedCount} remaining for today`\n            }}\n          </p>\n        </CardContent>\n      </Card>\n    </div>\n\n    <!-- 52-Week Contribution Grid / Heatmap Matrix -->\n    <Card class=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n      <CardHeader class=\"p-4 pb-3 sm:p-5 sm:pb-3\">\n        <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n          <div>\n            <CardTitle class=\"text-sm font-semibold tracking-tight\">52-Week Habit Consistency Matrix</CardTitle>\n            <CardDescription class=\"text-xs\">\n              Annual contribution heatmap across all daily registered routines.\n            </CardDescription>\n          </div>\n\n          <!-- Heatmap dynamic summary or hover inspector -->\n          <div class=\"text-muted-foreground flex items-center gap-2 text-xs\">\n            <div\n              v-if=\"hoveredCell\"\n              class=\"text-foreground bg-muted/60 border-border flex items-center gap-1.5 rounded-md border px-2 py-1 font-medium\"\n            >\n              <span class=\"bg-success size-2 rounded-full\" />\n              <span>{{ hoveredCell.formattedDate }} · </span>\n              <span class=\"font-mono font-semibold\">{{ hoveredCell.count }}/5 habits</span>\n              <span class=\"text-muted-foreground\">({{ Math.round((hoveredCell.count / 5) * 100) }}%)</span>\n            </div>\n            <div v-else class=\"flex items-center gap-1.5\">\n              <CheckCircle2 class=\"text-success size-3.5\" />\n              <span class=\"text-foreground font-mono font-medium tabular-nums\">{{ heatmapData.totalCompletions }}</span>\n              <span>completions logged</span>\n            </div>\n          </div>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"space-y-4 p-4 pt-1 sm:p-5 sm:pt-1\">\n        <!-- Scrollable Heatmap Viewport -->\n        <div class=\"overflow-x-auto pb-2\">\n          <div class=\"max-w-[740px] min-w-full space-y-1.5\">\n            <!-- Month Labels Top Row -->\n            <div class=\"text-muted-foreground flex pl-8 text-xs font-medium select-none\">\n              <div\n                v-for=\"label in heatmapData.monthLabels\"\n                :key=\"label.name + label.weekIndex\"\n                class=\"truncate\"\n                :style=\"{ width: `${(52 / 12) * 13.8}px` }\"\n              >\n                {{ label.name }}\n              </div>\n            </div>\n\n            <!-- Matrix Rows with Day Labels on Left -->\n            <div class=\"flex gap-2\">\n              <!-- Left Day-of-week labels -->\n              <div\n                class=\"text-muted-foreground flex w-6 shrink-0 flex-col justify-between py-[1px] text-xs font-medium select-none\"\n              >\n                <span>Mon</span>\n                <span class=\"opacity-0\">Tue</span>\n                <span>Wed</span>\n                <span class=\"opacity-0\">Thu</span>\n                <span>Fri</span>\n                <span class=\"opacity-0\">Sat</span>\n                <span>Sun</span>\n              </div>\n\n              <!-- 52 Columns Grid -->\n              <div class=\"flex flex-1 gap-[3px]\">\n                <div v-for=\"(week, wIdx) in heatmapData.weeks\" :key=\"wIdx\" class=\"flex flex-1 flex-col gap-[3px]\">\n                  <button\n                    v-for=\"cell in week\"\n                    :key=\"cell.date\"\n                    type=\"button\"\n                    :aria-label=\"`${cell.formattedDate}: ${cell.count} habits completed`\"\n                    :title=\"`${cell.formattedDate}: ${cell.count} habits completed`\"\n                    :class=\"[\n                      'size-3 cursor-pointer rounded-[2px] transition-colors duration-150 sm:size-3.5',\n                      levelClassMap[cell.level],\n                    ]\"\n                    @mouseenter=\"hoveredCell = cell\"\n                    @mouseleave=\"hoveredCell = null\"\n                    @focus=\"hoveredCell = cell\"\n                    @blur=\"hoveredCell = null\"\n                  />\n                </div>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <!-- Heatmap Footer: Legend & Summary -->\n        <div\n          class=\"border-border/50 text-muted-foreground flex flex-col gap-2 border-t pt-3 text-xs sm:flex-row sm:items-center sm:justify-between\"\n        >\n          <div class=\"flex items-center gap-1.5\">\n            <span class=\"text-foreground font-mono font-semibold tabular-nums\">94.2%</span>\n            <span>consistency baseline · 52 continuous weeks tracked</span>\n          </div>\n\n          <div class=\"flex items-center gap-2 self-end sm:self-auto\">\n            <span>Less</span>\n            <div class=\"flex gap-1\">\n              <span\n                class=\"bg-muted/60 dark:bg-muted/30 border-border/40 size-3 rounded-[2px] border\"\n                title=\"0 habits\"\n              />\n              <span class=\"border-success/20 bg-success/25 size-3 rounded-[2px] border\" title=\"1-2 habits\" />\n              <span class=\"border-success/30 bg-success/50 size-3 rounded-[2px] border\" title=\"3 habits\" />\n              <span class=\"border-success/40 bg-success/75 size-3 rounded-[2px] border\" title=\"4 habits\" />\n              <span class=\"border-success/60 bg-success size-3 rounded-[2px] border\" title=\"5 habits\" />\n            </div>\n            <span>More</span>\n          </div>\n        </div>\n      </CardContent>\n    </Card>\n\n    <!-- Daily Habits Checklist Table Section -->\n    <Card class=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n      <CardHeader class=\"p-4 pb-3 sm:p-5 sm:pb-3\">\n        <div class=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n          <div class=\"space-y-0.5\">\n            <CardTitle class=\"text-sm font-semibold tracking-tight\">Today's Habit Checklist</CardTitle>\n            <CardDescription class=\"text-xs\">\n              Interactive 7-day strip. Mark today or previous days to maintain your active flame streaks.\n            </CardDescription>\n          </div>\n\n          <!-- Category Filter Pills -->\n          <div class=\"flex flex-wrap items-center gap-1.5\">\n            <Button\n              v-for=\"cat in categories\"\n              :key=\"cat\"\n              :variant=\"activeCategory === cat ? 'default' : 'ghost'\"\n              size=\"sm\"\n              class=\"h-7 px-2.5 text-xs font-medium\"\n              @click=\"activeCategory = cat\"\n            >\n              {{ cat }}\n            </Button>\n          </div>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"p-0\">\n        <div class=\"divide-border/60 divide-y\">\n          <div\n            v-for=\"habit in filteredHabits\"\n            :key=\"habit.id\"\n            class=\"hover:bg-muted/20 flex flex-col gap-4 p-4 transition-colors sm:p-5 lg:flex-row lg:items-center lg:justify-between\"\n          >\n            <!-- Col 1: Habit Details -->\n            <div class=\"flex items-start gap-3 lg:w-1/3\">\n              <div\n                class=\"bg-muted text-muted-foreground border-border/60 flex size-9 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n              >\n                <component :is=\"getHabitIcon(habit.icon)\" class=\"size-4.5\" />\n              </div>\n              <div class=\"space-y-1\">\n                <div class=\"flex flex-wrap items-center gap-2\">\n                  <p class=\"text-foreground text-sm leading-none font-semibold\">{{ habit.title }}</p>\n                  <Badge wrap :class=\"cn('border text-xs font-medium', getCategoryBadgeClass(habit.category))\">\n                    {{ habit.category }}\n                  </Badge>\n                </div>\n                <p class=\"text-muted-foreground text-xs\">{{ habit.description }}</p>\n              </div>\n            </div>\n\n            <!-- Col 2: Streak Metric -->\n            <div class=\"flex items-center gap-2 lg:w-28\">\n              <div\n                class=\"border-warning/30 bg-warning/10 text-warning flex size-6.5 shrink-0 items-center justify-center rounded-md border\"\n              >\n                <Flame class=\"fill-warning text-warning size-3.5\" />\n              </div>\n              <div>\n                <p class=\"text-foreground font-mono text-xs font-bold tabular-nums\">{{ habit.streakDays }}d streak</p>\n                <p class=\"text-muted-foreground text-xs\">unbroken</p>\n              </div>\n            </div>\n\n            <!-- Col 3: 7-Day Mini Checkbox Strip -->\n            <div class=\"space-y-1 lg:w-56\">\n              <div class=\"text-muted-foreground flex items-center justify-between px-0.5 text-xs font-medium\">\n                <span\n                  v-for=\"(day, dIdx) in weekDayColumns\"\n                  :key=\"dIdx\"\n                  :class=\"cn('w-6 text-center', dIdx === 6 && 'text-foreground font-semibold')\"\n                >\n                  {{ day.short[0] }}\n                </span>\n              </div>\n              <div class=\"flex items-center justify-between gap-1\">\n                <button\n                  v-for=\"(day, dIdx) in weekDayColumns\"\n                  :key=\"dIdx\"\n                  type=\"button\"\n                  :aria-label=\"`${habit.title} on ${day.short}: ${habit.weekHistory[dIdx] ? 'Completed' : 'Incomplete'}`\"\n                  :class=\"[\n                    'focus-visible:ring-ring flex size-6 cursor-pointer items-center justify-center rounded-md text-xs transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                    habit.weekHistory[dIdx]\n                      ? 'bg-success hover:bg-success text-white shadow-xs'\n                      : 'border-border/80 bg-muted/40 text-muted-foreground/30 hover:bg-muted/80 hover:text-muted-foreground border',\n                    dIdx === 6 && !habit.weekHistory[dIdx] && 'border-warning/50 bg-warning/5',\n                  ]\"\n                  @click=\"toggleDay(habit.id, dIdx)\"\n                >\n                  <Check v-if=\"habit.weekHistory[dIdx]\" class=\"size-3.5 stroke-[2.5]\" />\n                  <span v-else class=\"text-xs\">{{ day.num }}</span>\n                </button>\n              </div>\n            </div>\n\n            <!-- Col 4: Completion Rate Progress -->\n            <div class=\"space-y-1.5 lg:w-36\">\n              <div class=\"flex items-center justify-between text-xs\">\n                <span class=\"text-muted-foreground\">Rate</span>\n                <span class=\"text-foreground font-mono font-semibold tabular-nums\">{{ habit.completionRate }}%</span>\n              </div>\n              <Progress :model-value=\"habit.completionRate\" class=\"h-1.5\" />\n            </div>\n\n            <!-- Col 5: Action Button -->\n            <div class=\"flex items-center justify-end lg:w-32\">\n              <Button\n                v-if=\"habit.weekHistory[6]\"\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"border-success/30 bg-success/10 text-success hover:bg-success/20 text-success h-8 w-full gap-1.5 text-xs font-medium shadow-xs sm:w-auto\"\n                @click=\"toggleToday(habit.id)\"\n              >\n                <CheckCircle2 class=\"text-success size-3.5\" />\n                <span>Done Today</span>\n              </Button>\n              <Button\n                v-else\n                variant=\"default\"\n                size=\"sm\"\n                class=\"h-8 w-full gap-1.5 text-xs font-medium shadow-xs sm:w-auto\"\n                @click=\"toggleToday(habit.id)\"\n              >\n                <Check class=\"size-3.5\" />\n                <span>Check Today</span>\n              </Button>\n            </div>\n          </div>\n        </div>\n      </CardContent>\n    </Card>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/HabitStreakTracker.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/progress.json"
  ],
  "description": "GitHub style 52-week contribution habit heatmap, flame streak counter, consistency metrics, and daily completion tracker with 7-day mini checkbox strip and progress bars.",
  "categories": [
    "productivity",
    "dashboard",
    "app"
  ]
}