{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "habit-streak-tracker",
  "title": "Habit Streak Tracker",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/habit-streak-tracker/HabitStreakTracker.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\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-react'\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\n  weekIndex: number\n  count: number\n  level: number\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  className?: string\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)\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 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\nfunction getHabitIcon(icon: string): React.ComponentType<{ className?: string }> {\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\nexport function HabitStreakTracker({\n  initialStreak = 24,\n  longestStreak = '48 Days in Q2',\n  consistencyRate = 94.2,\n  activeHabitsCount = 5,\n  monthTitle = 'August 2026',\n  habits = defaultHabits,\n  className,\n}: HabitStreakTrackerProps) {\n  const [habitsList, setHabitsList] = React.useState<HabitItem[]>(() => JSON.parse(JSON.stringify(habits)))\n  const [activeCategory, setActiveCategory] = React.useState<string>('All')\n  const [showNewHabitModal, setShowNewHabitModal] = React.useState<boolean>(false)\n  const [hoveredCell, setHoveredCell] = React.useState<DayHeatmapCell | null>(null)\n\n  const [newHabitTitle, setNewHabitTitle] = React.useState('')\n  const [newHabitDescription, setNewHabitDescription] = React.useState('')\n  const [newHabitCategory, setNewHabitCategory] = React.useState<HabitCategory>('Engineering')\n  const [newHabitIcon, setNewHabitIcon] = React.useState('code')\n\n  const heatmapData = React.useMemo(() => generate52WeekHeatmap(initialStreak), [initialStreak])\n\n  const categories = React.useMemo(() => {\n    const cats = ['All']\n    habitsList.forEach((h) => {\n      if (!cats.includes(h.category)) cats.push(h.category)\n    })\n    return cats\n  }, [habitsList])\n\n  const filteredHabits = React.useMemo(() => {\n    if (activeCategory === 'All') return habitsList\n    return habitsList.filter((h) => h.category === activeCategory)\n  }, [habitsList, activeCategory])\n\n  const todayCompletedCount = habitsList.filter((h) => h.weekHistory[6]).length\n  const totalHabitsCount = habitsList.length\n\n  const toggleDay = (habitId: string, dayIndex: number) => {\n    setHabitsList((prev) =>\n      prev.map((habit) => {\n        if (habit.id !== habitId) return habit\n        const nextWeekHistory = [...habit.weekHistory]\n        nextWeekHistory[dayIndex] = !nextWeekHistory[dayIndex]\n        const completedInWeek = nextWeekHistory.filter(Boolean).length\n        const completionRate = Math.min(100, Math.round((completedInWeek / 7) * 100))\n        let streakDays = habit.streakDays\n        if (dayIndex === 6) {\n          streakDays = nextWeekHistory[6] ? streakDays + 1 : Math.max(0, streakDays - 1)\n        }\n        return {\n          ...habit,\n          weekHistory: nextWeekHistory,\n          completionRate,\n          streakDays,\n        }\n      }),\n    )\n  }\n\n  const toggleToday = (habitId: string) => {\n    toggleDay(habitId, 6)\n  }\n\n  const handleAddHabit = () => {\n    if (!newHabitTitle.trim()) return\n    const newHabit: HabitItem = {\n      id: `habit-${Date.now()}`,\n      title: newHabitTitle.trim(),\n      description: newHabitDescription.trim() || 'Daily tracked routine',\n      category: newHabitCategory,\n      icon: newHabitIcon,\n      streakDays: 1,\n      completionRate: 100,\n      weekHistory: [false, false, false, false, false, false, true],\n    }\n    setHabitsList((prev) => [...prev, newHabit])\n    setNewHabitTitle('')\n    setNewHabitDescription('')\n    setShowNewHabitModal(false)\n  }\n\n  return (\n    <div className={cn('w-full space-y-6', className)} data-slot=\"habit-streak-tracker\">\n      {/* Header Section */}\n      <div className=\"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        <div className=\"flex items-start gap-3.5 sm:items-center\">\n          <div className=\"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            <Flame className=\"size-5.5 animate-pulse\" />\n          </div>\n          <div className=\"space-y-1\">\n            <div className=\"flex flex-wrap items-center gap-2.5\">\n              <h1 className=\"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                className=\"border-warning/30 bg-warning/15 text-warning gap-1 text-xs font-semibold\"\n              >\n                <Flame className=\"fill-warning text-warning size-3.5\" />\n                <span className=\"font-mono tabular-nums\">🔥 {initialStreak}-Day Streak · Personal Best!</span>\n              </Badge>\n            </div>\n            <p className=\"text-muted-foreground text-xs\">\n              {monthTitle} · Real-time habit adherence, 52-week GitHub matrix, and routine tracker.\n            </p>\n          </div>\n        </div>\n\n        <div className=\"flex flex-wrap items-center gap-2.5 self-end sm:self-auto\">\n          <div className=\"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            <Calendar className=\"size-3.5\" />\n            <span>{monthTitle}</span>\n          </div>\n          <Button\n            aria-label=\"Close new habit dialog\"\n            size=\"sm\"\n            className=\"gap-1.5 shadow-xs\"\n            onClick={() => setShowNewHabitModal(!showNewHabitModal)}\n          >\n            <Plus className=\"size-4\" />\n            <span>New Habit</span>\n          </Button>\n        </div>\n      </div>\n\n      {/* Quick Add Inline Card (Collapsible) */}\n      {showNewHabitModal && (\n        <div className=\"border-border/80 bg-card text-card-foreground space-y-3 rounded-xl border p-4 shadow-xs sm:p-5\">\n          <div className=\"flex items-center justify-between\">\n            <div className=\"space-y-0.5\">\n              <p className=\"text-foreground text-sm font-semibold\">Create New Habit Routine</p>\n              <p className=\"text-muted-foreground text-xs\">\n                Define a daily target to track against your annual matrix.\n              </p>\n            </div>\n            <Button\n              variant=\"ghost\"\n              size=\"icon-sm\"\n              className=\"size-7\"\n              aria-label=\"Close new habit dialog\"\n              onClick={() => setShowNewHabitModal(false)}\n            >\n              <X className=\"size-4\" />\n            </Button>\n          </div>\n\n          <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-12\">\n            <div className=\"sm:col-span-4\">\n              <label className=\"text-foreground mb-1 block text-xs font-medium\">Habit Title</label>\n              <input\n                type=\"text\"\n                value={newHabitTitle}\n                onChange={(e) => setNewHabitTitle(e.target.value)}\n                placeholder=\"e.g. Write 500 Words Technical Notes\"\n                className=\"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                onKeyDown={(e) => {\n                  if (e.key === 'Enter') handleAddHabit()\n                }}\n              />\n            </div>\n\n            <div className=\"sm:col-span-4\">\n              <label className=\"text-foreground mb-1 block text-xs font-medium\">Description</label>\n              <input\n                type=\"text\"\n                value={newHabitDescription}\n                onChange={(e) => setNewHabitDescription(e.target.value)}\n                placeholder=\"e.g. Daily engineering documentation\"\n                className=\"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                onKeyDown={(e) => {\n                  if (e.key === 'Enter') handleAddHabit()\n                }}\n              />\n            </div>\n\n            <div className=\"sm:col-span-2\">\n              <label className=\"text-foreground mb-1 block text-xs font-medium\">Category</label>\n              <select\n                value={newHabitCategory}\n                onChange={(e) => setNewHabitCategory(e.target.value as HabitCategory)}\n                className=\"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 className=\"sm:col-span-2\">\n              <label className=\"text-foreground mb-1 block text-xs font-medium\">Icon</label>\n              <select\n                value={newHabitIcon}\n                onChange={(e) => setNewHabitIcon(e.target.value)}\n                className=\"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 className=\"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              className=\"text-xs\"\n              onClick={() => setShowNewHabitModal(false)}\n            >\n              Cancel\n            </Button>\n            <Button size=\"sm\" className=\"text-xs\" disabled={!newHabitTitle.trim()} onClick={handleAddHabit}>\n              Add Routine\n            </Button>\n          </div>\n        </div>\n      )}\n\n      {/* 4 Streak Metric Cards Grid */}\n      <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n        {/* Card 1: Current Streak */}\n        <Card className=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n          <CardHeader className=\"p-4 pb-2\">\n            <div className=\"flex items-center justify-between\">\n              <span className=\"text-muted-foreground text-xs font-medium\">Current Streak</span>\n              <div className=\"border-warning/25 bg-warning/10 text-warning flex size-7 items-center justify-center rounded-md border\">\n                <Flame className=\"fill-warning text-warning size-4\" />\n              </div>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-1 p-4 pt-1\">\n            <div className=\"flex items-baseline gap-2\">\n              <span className=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n                {initialStreak} Days\n              </span>\n              <Badge wrap variant=\"warning\" className=\"text-xs font-medium\">\n                Active\n              </Badge>\n            </div>\n            <p className=\"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 className=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n          <CardHeader className=\"p-4 pb-2\">\n            <div className=\"flex items-center justify-between\">\n              <span className=\"text-muted-foreground text-xs font-medium\">Longest Streak</span>\n              <div className=\"border-chart-2/25 bg-chart-2/10 text-chart-2 flex size-7 items-center justify-center rounded-md border\">\n                <Trophy className=\"size-4\" />\n              </div>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-1 p-4 pt-1\">\n            <div className=\"flex items-baseline gap-2\">\n              <span className=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n                {longestStreak}\n              </span>\n              <Badge wrap variant=\"secondary\" className=\"text-xs font-medium\">\n                Record\n              </Badge>\n            </div>\n            <p className=\"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 className=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n          <CardHeader className=\"p-4 pb-2\">\n            <div className=\"flex items-center justify-between\">\n              <span className=\"text-muted-foreground text-xs font-medium\">Overall Consistency</span>\n              <div className=\"border-success/25 bg-success/10 text-success flex size-7 items-center justify-center rounded-md border\">\n                <TrendingUp className=\"size-4\" />\n              </div>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-1 p-4 pt-1\">\n            <div className=\"flex items-baseline gap-2\">\n              <span className=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n                {consistencyRate}%\n              </span>\n              <Badge wrap variant=\"success\" className=\"text-xs font-medium\">\n                +3.1% MoM\n              </Badge>\n            </div>\n            <p className=\"text-muted-foreground text-xs\">\n              {heatmapData.totalCompletions} targets completed in 52 weeks\n            </p>\n          </CardContent>\n        </Card>\n\n        {/* Card 4: Total Habits Active */}\n        <Card className=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n          <CardHeader className=\"p-4 pb-2\">\n            <div className=\"flex items-center justify-between\">\n              <span className=\"text-muted-foreground text-xs font-medium\">Total Habits Active</span>\n              <div className=\"border-info/25 bg-info/10 text-info flex size-7 items-center justify-center rounded-md border\">\n                <Target className=\"size-4\" />\n              </div>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-1 p-4 pt-1\">\n            <div className=\"flex items-baseline gap-2\">\n              <span className=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n                {totalHabitsCount} Daily Habits\n              </span>\n              <Badge\n                wrap\n                variant={todayCompletedCount === totalHabitsCount ? 'success' : 'secondary'}\n                className=\"text-xs font-medium\"\n              >\n                {todayCompletedCount}/{totalHabitsCount} Done\n              </Badge>\n            </div>\n            <p className=\"text-muted-foreground text-xs\">\n              {todayCompletedCount === totalHabitsCount\n                ? 'All daily targets logged!'\n                : `${totalHabitsCount - todayCompletedCount} remaining for today`}\n            </p>\n          </CardContent>\n        </Card>\n      </div>\n\n      {/* 52-Week Contribution Grid / Heatmap Matrix */}\n      <Card className=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n        <CardHeader className=\"p-4 pb-3 sm:p-5 sm:pb-3\">\n          <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n            <div>\n              <CardTitle className=\"text-sm font-semibold tracking-tight\">52-Week Habit Consistency Matrix</CardTitle>\n              <CardDescription className=\"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 className=\"text-muted-foreground flex items-center gap-2 text-xs\">\n              {hoveredCell ? (\n                <div className=\"text-foreground bg-muted/60 border-border flex items-center gap-1.5 rounded-md border px-2 py-1 font-medium\">\n                  <span className=\"bg-success size-2 rounded-full\" />\n                  <span>{hoveredCell.formattedDate} · </span>\n                  <span className=\"font-mono font-semibold\">{hoveredCell.count}/5 habits</span>\n                  <span className=\"text-muted-foreground\">({Math.round((hoveredCell.count / 5) * 100)}%)</span>\n                </div>\n              ) : (\n                <div className=\"flex items-center gap-1.5\">\n                  <CheckCircle2 className=\"text-success size-3.5\" />\n                  <span className=\"text-foreground font-mono font-medium tabular-nums\">\n                    {heatmapData.totalCompletions}\n                  </span>\n                  <span>completions logged</span>\n                </div>\n              )}\n            </div>\n          </div>\n        </CardHeader>\n\n        <CardContent className=\"space-y-4 p-4 pt-1 sm:p-5 sm:pt-1\">\n          {/* Scrollable Heatmap Viewport */}\n          <div className=\"overflow-x-auto pb-2\">\n            <div className=\"max-w-[740px] min-w-full space-y-1.5\">\n              {/* Month Labels Top Row */}\n              <div className=\"text-muted-foreground flex pl-8 text-xs font-medium select-none\">\n                {heatmapData.monthLabels.map((label) => (\n                  <div\n                    key={`${label.name}-${label.weekIndex}`}\n                    className=\"truncate\"\n                    style={{ width: `${(52 / 12) * 13.8}px` }}\n                  >\n                    {label.name}\n                  </div>\n                ))}\n              </div>\n\n              {/* Matrix Rows with Day Labels on Left */}\n              <div className=\"flex gap-2\">\n                {/* Left Day-of-week labels */}\n                <div className=\"text-muted-foreground flex w-6 shrink-0 flex-col justify-between py-[1px] text-xs font-medium select-none\">\n                  <span>Mon</span>\n                  <span className=\"opacity-0\">Tue</span>\n                  <span>Wed</span>\n                  <span className=\"opacity-0\">Thu</span>\n                  <span>Fri</span>\n                  <span className=\"opacity-0\">Sat</span>\n                  <span>Sun</span>\n                </div>\n\n                {/* 52 Columns Grid */}\n                <div className=\"flex flex-1 gap-[3px]\">\n                  {heatmapData.weeks.map((week, wIdx) => (\n                    <div key={wIdx} className=\"flex flex-1 flex-col gap-[3px]\">\n                      {week.map((cell) => (\n                        <button\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                          className={cn(\n                            'size-3 cursor-pointer rounded-[2px] transition-colors duration-150 sm:size-3.5',\n                            levelClassMap[cell.level],\n                          )}\n                          onMouseEnter={() => setHoveredCell(cell)}\n                          onMouseLeave={() => setHoveredCell(null)}\n                          onFocus={() => setHoveredCell(cell)}\n                          onBlur={() => setHoveredCell(null)}\n                        />\n                      ))}\n                    </div>\n                  ))}\n                </div>\n              </div>\n            </div>\n          </div>\n\n          {/* Heatmap Footer: Legend & Summary */}\n          <div className=\"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            <div className=\"flex items-center gap-1.5\">\n              <span className=\"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 className=\"flex items-center gap-2 self-end sm:self-auto\">\n              <span>Less</span>\n              <div className=\"flex gap-1\">\n                <span\n                  className=\"bg-muted/60 dark:bg-muted/30 border-border/40 size-3 rounded-[2px] border\"\n                  title=\"0 habits\"\n                />\n                <span className=\"border-success/20 bg-success/25 size-3 rounded-[2px] border\" title=\"1-2 habits\" />\n                <span className=\"border-success/30 bg-success/50 size-3 rounded-[2px] border\" title=\"3 habits\" />\n                <span className=\"border-success/40 bg-success/75 size-3 rounded-[2px] border\" title=\"4 habits\" />\n                <span className=\"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 className=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n        <CardHeader className=\"p-4 pb-3 sm:p-5 sm:pb-3\">\n          <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n            <div className=\"space-y-0.5\">\n              <CardTitle className=\"text-sm font-semibold tracking-tight\">Today's Habit Checklist</CardTitle>\n              <CardDescription className=\"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 className=\"flex flex-wrap items-center gap-1.5\">\n              {categories.map((cat) => (\n                <Button\n                  key={cat}\n                  variant={activeCategory === cat ? 'default' : 'ghost'}\n                  size=\"sm\"\n                  className=\"h-7 px-2.5 text-xs font-medium\"\n                  onClick={() => setActiveCategory(cat)}\n                >\n                  {cat}\n                </Button>\n              ))}\n            </div>\n          </div>\n        </CardHeader>\n\n        <CardContent className=\"p-0\">\n          <div className=\"divide-border/60 divide-y\">\n            {filteredHabits.map((habit) => {\n              const HabitIcon = getHabitIcon(habit.icon)\n              return (\n                <div\n                  key={habit.id}\n                  className=\"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 className=\"flex items-start gap-3 lg:w-1/3\">\n                    <div className=\"bg-muted text-muted-foreground border-border/60 flex size-9 shrink-0 items-center justify-center rounded-lg border shadow-xs\">\n                      <HabitIcon className=\"size-4.5\" />\n                    </div>\n                    <div className=\"space-y-1\">\n                      <div className=\"flex flex-wrap items-center gap-2\">\n                        <p className=\"text-foreground text-sm leading-none font-semibold\">{habit.title}</p>\n                        <Badge className={cn('border text-xs font-medium', getCategoryBadgeClass(habit.category))}>\n                          {habit.category}\n                        </Badge>\n                      </div>\n                      <p className=\"text-muted-foreground text-xs\">{habit.description}</p>\n                    </div>\n                  </div>\n\n                  {/* Col 2: Streak Metric */}\n                  <div className=\"flex items-center gap-2 lg:w-28\">\n                    <div className=\"border-warning/30 bg-warning/10 text-warning flex size-6.5 shrink-0 items-center justify-center rounded-md border\">\n                      <Flame className=\"fill-warning text-warning size-3.5\" />\n                    </div>\n                    <div>\n                      <p className=\"text-foreground font-mono text-xs font-bold tabular-nums\">\n                        {habit.streakDays}d streak\n                      </p>\n                      <p className=\"text-muted-foreground text-xs\">unbroken</p>\n                    </div>\n                  </div>\n\n                  {/* Col 3: 7-Day Mini Checkbox Strip */}\n                  <div className=\"space-y-1 lg:w-56\">\n                    <div className=\"text-muted-foreground flex items-center justify-between px-0.5 text-xs font-medium\">\n                      {weekDayColumns.map((day, dIdx) => (\n                        <span\n                          key={dIdx}\n                          className={cn('w-6 text-center', dIdx === 6 && 'text-foreground font-semibold')}\n                        >\n                          {day.short[0]}\n                        </span>\n                      ))}\n                    </div>\n                    <div className=\"flex items-center justify-between gap-1\">\n                      {weekDayColumns.map((day, dIdx) => (\n                        <button\n                          key={dIdx}\n                          type=\"button\"\n                          aria-label={`${habit.title} on ${day.short}: ${habit.weekHistory[dIdx] ? 'Completed' : 'Incomplete'}`}\n                          className={cn(\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                          onClick={() => toggleDay(habit.id, dIdx)}\n                        >\n                          {habit.weekHistory[dIdx] ? (\n                            <Check className=\"size-3.5 stroke-[2.5]\" />\n                          ) : (\n                            <span className=\"text-xs\">{day.num}</span>\n                          )}\n                        </button>\n                      ))}\n                    </div>\n                  </div>\n\n                  {/* Col 4: Completion Rate Progress */}\n                  <div className=\"space-y-1.5 lg:w-36\">\n                    <div className=\"flex items-center justify-between text-xs\">\n                      <span className=\"text-muted-foreground\">Rate</span>\n                      <span className=\"text-foreground font-mono font-semibold tabular-nums\">\n                        {habit.completionRate}%\n                      </span>\n                    </div>\n                    <Progress value={habit.completionRate} className=\"h-1.5\" />\n                  </div>\n\n                  {/* Col 5: Action Button */}\n                  <div className=\"flex items-center justify-end lg:w-32\">\n                    {habit.weekHistory[6] ? (\n                      <Button\n                        variant=\"outline\"\n                        size=\"sm\"\n                        className=\"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                        onClick={() => toggleToday(habit.id)}\n                      >\n                        <CheckCircle2 className=\"text-success size-3.5\" />\n                        <span>Done Today</span>\n                      </Button>\n                    ) : (\n                      <Button\n                        variant=\"default\"\n                        size=\"sm\"\n                        className=\"h-8 w-full gap-1.5 text-xs font-medium shadow-xs sm:w-auto\"\n                        onClick={() => toggleToday(habit.id)}\n                      >\n                        <Check className=\"size-3.5\" />\n                        <span>Check Today</span>\n                      </Button>\n                    )}\n                  </div>\n                </div>\n              )\n            })}\n          </div>\n        </CardContent>\n      </Card>\n    </div>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/HabitStreakTracker.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/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"
  ]
}