{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "calendar-1",
  "title": "Month Grid With Day Detail",
  "description": "Month calendar grid with previous and next navigation, a Today shortcut, selectable days, and a detail panel for the chosen day's event.",
  "dependencies": [
    "@base-ui/react"
  ],
  "registryDependencies": [
    "badge",
    "button",
    "separator"
  ],
  "files": [
    {
      "path": "registry/blocks/calendar/1/calendar-block.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Badge } from \"@/components/ui/badge\"\nimport { Button } from \"@/components/ui/button\"\nimport { Separator } from \"@/components/ui/separator\"\nimport { cn } from \"@/lib/utils\"\nimport { IconPlaceholder } from \"@/components/icons/icon-placeholder\"\n\nconst WEEKDAYS = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"]\nconst MONTH_NAMES = [\n  \"January\",\n  \"February\",\n  \"March\",\n  \"April\",\n  \"May\",\n  \"June\",\n  \"July\",\n  \"August\",\n  \"September\",\n  \"October\",\n  \"November\",\n  \"December\",\n]\n\ninterface CalEvent {\n  label: string\n  variant: \"default\" | \"secondary\" | \"outline\"\n  time: string\n  location: string\n  description: string\n}\n\nconst EVENTS: Record<string, CalEvent> = {\n  \"2025-5-5\": {\n    label: \"Team sync\",\n    variant: \"secondary\",\n    time: \"10:00 – 10:30\",\n    location: \"Zoom\",\n    description: \"Weekly cross-functional sync to align on priorities.\",\n  },\n  \"2025-5-12\": {\n    label: \"Q2 review\",\n    variant: \"secondary\",\n    time: \"14:00 – 15:30\",\n    location: \"Conf room A\",\n    description: \"Quarterly business review with leadership.\",\n  },\n  \"2025-5-17\": {\n    label: \"Launch\",\n    variant: \"default\",\n    time: \"All day\",\n    location: \"Company-wide\",\n    description: \"Public launch of the new platform release.\",\n  },\n  \"2025-5-23\": {\n    label: \"Design sprint\",\n    variant: \"secondary\",\n    time: \"11:00 – 17:00\",\n    location: \"Studio 2\",\n    description: \"Full-day design sprint for the onboarding flow.\",\n  },\n  \"2025-5-28\": {\n    label: \"Board meeting\",\n    variant: \"outline\",\n    time: \"15:00 – 16:00\",\n    location: \"Main boardroom\",\n    description: \"Monthly board meeting and financial review.\",\n  },\n  \"2025-6-3\": {\n    label: \"All-hands\",\n    variant: \"default\",\n    time: \"16:00 – 17:00\",\n    location: \"Auditorium\",\n    description: \"Company all-hands with Q3 kickoff.\",\n  },\n  \"2025-6-15\": {\n    label: \"Offsite\",\n    variant: \"secondary\",\n    time: \"All day\",\n    location: \"Lakeside resort\",\n    description: \"Annual team offsite and strategy planning.\",\n  },\n}\n\nconst TODAY = { year: 2025, month: 5, day: 17 }\n\nfunction keyFor(year: number, month: number, day: number) {\n  return `${year}-${month}-${day}`\n}\n\nfunction buildCells(year: number, month: number): (number | null)[] {\n  const leadingBlanks = new Date(year, month, 1).getDay()\n  const totalDays = new Date(year, month + 1, 0).getDate()\n  const cells: (number | null)[] = [\n    ...Array(leadingBlanks).fill(null),\n    ...Array.from({ length: totalDays }, (_, i) => i + 1),\n  ]\n  while (cells.length % 7 !== 0) cells.push(null)\n  return cells\n}\n\nexport default function CalendarBlock() {\n  const [view, setView] = React.useState({ year: 2025, month: 5 })\n  const [selected, setSelected] = React.useState<string | null>(() =>\n    keyFor(TODAY.year, TODAY.month, TODAY.day)\n  )\n\n  const cells = React.useMemo(() => buildCells(view.year, view.month), [view])\n\n  function shiftMonth(delta: number) {\n    setView((prev) => {\n      const next = new Date(prev.year, prev.month + delta, 1)\n      return { year: next.getFullYear(), month: next.getMonth() }\n    })\n  }\n\n  function goToday() {\n    setView({ year: TODAY.year, month: TODAY.month })\n    setSelected(keyFor(TODAY.year, TODAY.month, TODAY.day))\n  }\n\n  const [selYear, selMonth, selDay] = selected\n    ? selected.split(\"-\").map(Number)\n    : [0, 0, 0]\n  const selectedInView =\n    selected !== null && selYear === view.year && selMonth === view.month\n  const selectedEvent = selected ? EVENTS[selected] : undefined\n\n  return (\n    <section className=\"flex w-full items-center justify-center bg-background px-6 py-12 text-foreground\">\n      <div className=\"w-full max-w-sm\">\n        <div className=\"overflow-hidden rounded-xl border border-border bg-card text-card-foreground\">\n          <div className=\"flex items-center justify-between gap-2 px-4 py-3\">\n            <span className=\"text-sm font-semibold tracking-wide tabular-nums\">\n              {MONTH_NAMES[view.month]} {view.year}\n            </span>\n\n            <div className=\"flex items-center gap-1\">\n              <Button variant=\"outline\" size=\"sm\" onClick={goToday}>\n                Today\n              </Button>\n              <Button\n                variant=\"ghost\"\n                size=\"icon-sm\"\n                aria-label=\"Previous month\"\n                onClick={() => shiftMonth(-1)}\n              >\n                <IconPlaceholder\n                  lucide=\"ChevronLeft\"\n                  tabler=\"IconChevronLeft\"\n                  hugeicons=\"ArrowLeft01Icon\"\n                  phosphor=\"CaretLeft\"\n                  remixicon=\"RiArrowLeftSLine\"\n                  aria-hidden=\"true\"\n                />\n              </Button>\n              <Button\n                variant=\"ghost\"\n                size=\"icon-sm\"\n                aria-label=\"Next month\"\n                onClick={() => shiftMonth(1)}\n              >\n                <IconPlaceholder\n                  lucide=\"ChevronRight\"\n                  tabler=\"IconChevronRight\"\n                  hugeicons=\"ArrowRight01Icon\"\n                  phosphor=\"CaretRight\"\n                  remixicon=\"RiArrowRightSLine\"\n                  aria-hidden=\"true\"\n                />\n              </Button>\n            </div>\n          </div>\n\n          <Separator />\n\n          <div className=\"grid grid-cols-7 border-b border-border\">\n            {WEEKDAYS.map((day) => (\n              <div\n                key={day}\n                className=\"py-2 text-center text-xs font-medium text-muted-foreground\"\n              >\n                {day}\n              </div>\n            ))}\n          </div>\n\n          <div className=\"grid grid-cols-7\">\n            {cells.map((day, idx) => {\n              const key = day ? keyFor(view.year, view.month, day) : \"\"\n              const event = day ? EVENTS[key] : undefined\n              const isToday =\n                day === TODAY.day &&\n                view.month === TODAY.month &&\n                view.year === TODAY.year\n              const isSelected = day !== null && key === selected\n              const isLastRow = idx >= cells.length - 7\n\n              return (\n                <button\n                  key={idx}\n                  type=\"button\"\n                  disabled={day === null}\n                  aria-pressed={isSelected}\n                  aria-label={\n                    day\n                      ? `${MONTH_NAMES[view.month]} ${day}, ${view.year}`\n                      : undefined\n                  }\n                  onClick={() => key && setSelected(key)}\n                  className={cn(\n                    \"flex min-h-[3.75rem] min-w-0 flex-col gap-1 overflow-hidden border-border p-1 text-left align-top transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset\",\n                    idx % 7 !== 6 && \"border-r\",\n                    !isLastRow && \"border-b\",\n                    day === null ? \"bg-muted/30\" : \"hover:bg-muted/50\",\n                    isSelected &&\n                      \"bg-primary/10 ring-1 ring-primary/50 ring-inset hover:bg-primary/10\"\n                  )}\n                >\n                  {day !== null && (\n                    <>\n                      <span\n                        className={cn(\n                          \"flex size-6 items-center justify-center self-end rounded-md text-xs font-medium\",\n                          isToday\n                            ? \"bg-primary text-primary-foreground\"\n                            : \"text-foreground\"\n                        )}\n                      >\n                        {day}\n                      </span>\n\n                      {event && (\n                        <Badge\n                          variant={event.variant}\n                          className=\"block w-full max-w-full min-w-0 justify-start truncate text-left text-[10px]\"\n                        >\n                          {event.label}\n                        </Badge>\n                      )}\n                    </>\n                  )}\n                </button>\n              )\n            })}\n          </div>\n\n          {selectedInView && (\n            <>\n              <Separator />\n              <div className=\"px-4 py-3\">\n                <div className=\"flex items-center gap-2\">\n                  <IconPlaceholder\n                    lucide=\"CalendarDays\"\n                    tabler=\"IconCalendarEvent\"\n                    hugeicons=\"CalendarDaysIcon\"\n                    phosphor=\"CalendarDots\"\n                    remixicon=\"RiCalendarEventLine\"\n                    className=\"size-4 text-muted-foreground\"\n                    aria-hidden=\"true\"\n                  />\n                  <h3 className=\"font-heading text-sm font-semibold\">\n                    {MONTH_NAMES[selMonth]} {selDay}, {selYear}\n                  </h3>\n                </div>\n\n                {selectedEvent ? (\n                  <div className=\"mt-2.5 flex flex-col gap-2\">\n                    <Badge\n                      variant={selectedEvent.variant}\n                      className=\"self-start text-[10px]\"\n                    >\n                      {selectedEvent.label}\n                    </Badge>\n                    <p className=\"text-xs/relaxed text-foreground\">\n                      {selectedEvent.description}\n                    </p>\n                    <div className=\"flex flex-col gap-1.5 text-muted-foreground\">\n                      <span className=\"flex items-center gap-1.5 text-xs\">\n                        <IconPlaceholder\n                          lucide=\"Clock\"\n                          tabler=\"IconClock\"\n                          hugeicons=\"TimeIcon\"\n                          phosphor=\"Clock\"\n                          remixicon=\"RiTimeLine\"\n                          className=\"size-3.5 shrink-0\"\n                          aria-hidden=\"true\"\n                        />\n                        {selectedEvent.time}\n                      </span>\n                      <span className=\"flex items-center gap-1.5 text-xs\">\n                        <IconPlaceholder\n                          lucide=\"MapPin\"\n                          tabler=\"IconMapPin\"\n                          hugeicons=\"MapPinIcon\"\n                          phosphor=\"MapPin\"\n                          remixicon=\"RiMapPinLine\"\n                          className=\"size-3.5 shrink-0\"\n                          aria-hidden=\"true\"\n                        />\n                        {selectedEvent.location}\n                      </span>\n                    </div>\n                  </div>\n                ) : (\n                  <p className=\"mt-2 text-xs text-muted-foreground\">\n                    No events scheduled.\n                  </p>\n                )}\n              </div>\n            </>\n          )}\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "meta": {
    "height": "641px",
    "tier": "free"
  },
  "categories": [
    "calendar"
  ],
  "type": "registry:block"
}