{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "subscription-calendar",
  "type": "registry:component",
  "title": "Subscription Calendar",
  "description": "Calendar card showing subscription cycles, renewals, and upcoming billing dates.",
  "dependencies": [
    "lucide-react",
    "motion",
    "react-icons"
  ],
  "files": [
    {
      "path": "components/watermelon/subscription-calendar.tsx",
      "type": "registry:component",
      "content": "'use client';\n\nimport React, { useState } from 'react';\nimport {\n  ChevronLeft,\n  ChevronRight,\n  Plus,\n  Search,\n  Download,\n  X,\n  Loader2,\n  Check,\n} from 'lucide-react';\nimport { AnimatePresence, motion } from 'motion/react';\nimport { TbCube } from 'react-icons/tb';\n\n/* ---------- Types ---------- */\nexport interface SubscriptionDay {\n  date: number;\n  isMuted?: boolean;\n  isLogo?: React.ReactNode[];\n  indicators?: React.ReactNode[];\n}\n\nexport interface SubscriptionCalendarProps {\n  month: string;\n  year: number;\n  days: SubscriptionDay[];\n  monthlyTotal: number;\n  subscriptionsCount: number;\n  newCount: number;\n  onPrevMonth?: () => void;\n  onNextMonth?: () => void;\n}\n\n/* ---------- Motion ---------- */\nconst spring = {\n  type: 'spring',\n  stiffness: 420,\n  damping: 28,\n  mass: 0.6,\n} as const;\n\n/* ---------- Main Component ---------- */\nexport const SubscriptionCalendar: React.FC<SubscriptionCalendarProps> = ({\n  month,\n  year,\n  days,\n  monthlyTotal,\n  subscriptionsCount,\n  newCount,\n  onPrevMonth,\n  onNextMonth,\n}) => {\n  const [selectedId, setSelectedId] = useState<string | null>('day-28');\n  const [isAdding, setIsAdding] = useState(false);\n  const [isSearching, setIsSearching] = useState(false);\n  const [isSummaryOpen, setIsSummaryOpen] = useState(false);\n  const [isDownloading, setIsDownloading] = useState(false);\n\n  const handleDownload = () => {\n    setIsDownloading(true);\n    setTimeout(() => setIsDownloading(false), 2000);\n  };\n\n  return (\n    <motion.div\n      initial={{ scale: 0.96, opacity: 0 }}\n      animate={{ scale: 1, opacity: 1 }}\n      transition={spring}\n      className=\"relative w-full max-w-105 rounded-[26px] border border-zinc-200 bg-white p-4 shadow-2xl transition-all duration-500 sm:p-5 dark:border-[#1f1f1f] dark:bg-[#0f0f10]\"\n    >\n      <div className=\"mb-4 flex items-center justify-between gap-2\">\n        <div className=\"flex items-center gap-2 overflow-hidden sm:gap-3\">\n          <h2 className=\"truncate text-[12px] font-medium text-zinc-800 sm:text-[13px] dark:text-[#D8D8D8]\">\n            {month}, {year}\n          </h2>\n          <span className=\"xs:inline-block hidden cursor-default rounded-full border border-zinc-200 bg-transparent px-3 py-0.5 text-[10px] whitespace-nowrap text-zinc-500 dark:border-white/20 dark:text-[#a3a3a3]\">\n            Today\n          </span>\n          <div className=\"ml-1 flex items-center gap-1 sm:gap-2\">\n            <button\n              title=\"backward\"\n              onClick={onPrevMonth}\n              className=\"shrink-0 rounded-md p-1 text-zinc-400 transition-colors hover:bg-zinc-100 hover:text-zinc-900 dark:text-[#7c7b7b] dark:hover:bg-white/5 dark:hover:text-white\"\n            >\n              <ChevronLeft size={18} />\n            </button>\n            <button\n              title=\"forward\"\n              onClick={onNextMonth}\n              className=\"shrink-0 rounded-md p-1 text-zinc-400 transition-colors hover:bg-zinc-100 hover:text-zinc-900 dark:text-[#7c7b7b] dark:hover:bg-white/5 dark:hover:text-white\"\n            >\n              <ChevronRight size={18} />\n            </button>\n          </div>\n        </div>\n        <button\n          title=\"add event\"\n          onClick={() => setIsAdding(true)}\n          className=\"flex h-7 w-10 shrink-0 items-center justify-center rounded-full bg-[#fa6a2e] text-white shadow-[0_0_15px_rgba(250,106,46,0.2)] transition-transform hover:scale-105 active:scale-95 sm:h-7 sm:w-11 dark:text-black\"\n        >\n          <Plus size={16} />\n        </button>\n      </div>\n\n      <div className=\"\">\n        <AnimatePresence>\n          {isAdding && (\n            <motion.div\n              initial={{ opacity: 0, scale: 0.9, y: 10 }}\n              animate={{ opacity: 1, scale: 1, y: 0 }}\n              exit={{ opacity: 0, scale: 0.9, y: 10 }}\n              className=\"absolute inset-0 z-50 flex flex-col items-center justify-center rounded-[25px] bg-white/95 p-4 backdrop-blur-md sm:p-6 dark:bg-black/95\"\n            >\n              <button\n                onClick={() => setIsAdding(false)}\n                className=\"absolute top-4 right-4 text-zinc-400 hover:text-zinc-900 dark:hover:text-white\"\n              >\n                <X size={20} />\n              </button>\n              <div className=\"mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-orange-100 text-[#fa6a2e] dark:bg-orange-900/30\">\n                <Plus size={24} />\n              </div>\n              <h3 className=\"mb-1 text-sm font-bold text-zinc-900 dark:text-white\">\n                Quick Add Subscription\n              </h3>\n              <p className=\"mb-6 text-center text-[10px] text-zinc-500 dark:text-zinc-400\">\n                Enter the details of your new recurring payment.\n              </p>\n              <div className=\"flex w-full flex-col gap-2\">\n                <input\n                  type=\"text\"\n                  placeholder=\"Service Name (e.g. Netflix)\"\n                  className=\"w-full rounded-lg border border-zinc-200 bg-transparent px-3 py-2 text-[11px] outline-none focus:border-[#fa6a2e] dark:border-zinc-800 dark:focus:border-[#fa6a2e]\"\n                />\n                <div className=\"xs:flex-row flex flex-col gap-2\">\n                  <input\n                    type=\"text\"\n                    placeholder=\"Amount\"\n                    className=\"flex-1 rounded-lg border border-zinc-200 bg-transparent px-3 py-2 text-[11px] outline-none focus:border-[#fa6a2e] dark:border-zinc-800 dark:focus:border-[#fa6a2e]\"\n                  />\n                  <input\n                    type=\"text\"\n                    placeholder=\"Date\"\n                    className=\"xs:w-20 w-full rounded-lg border border-zinc-200 bg-transparent px-3 py-2 text-[11px] outline-none focus:border-[#fa6a2e] dark:border-zinc-800 dark:focus:border-[#fa6a2e]\"\n                  />\n                </div>\n                <button\n                  onClick={() => setIsAdding(false)}\n                  className=\"mt-2 flex w-full items-center justify-center gap-2 rounded-lg bg-[#fa6a2e] py-2 text-[11px] font-bold text-white transition-opacity hover:opacity-90\"\n                >\n                  <Check size={14} /> Add Subscription\n                </button>\n              </div>\n            </motion.div>\n          )}\n        </AnimatePresence>\n\n        <AnimatePresence>\n          {isSearching && (\n            <motion.div\n              initial={{ opacity: 0, scale: 0.9, y: 10 }}\n              animate={{ opacity: 1, scale: 1, y: 0 }}\n              exit={{ opacity: 0, scale: 0.9, y: 10 }}\n              className=\"absolute inset-0 z-50 flex flex-col items-center justify-center rounded-[25px] bg-white/95 p-4 backdrop-blur-md sm:p-6 dark:bg-black/95\"\n            >\n              <button\n                onClick={() => setIsSearching(false)}\n                className=\"absolute top-4 right-4 text-zinc-400 hover:text-zinc-900 dark:hover:text-white\"\n              >\n                <X size={20} />\n              </button>\n              <div className=\"mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-zinc-100 text-zinc-500 dark:bg-zinc-800/30\">\n                <Search size={24} />\n              </div>\n              <h3 className=\"mb-1 text-sm font-bold text-zinc-900 dark:text-white\">\n                Search Subscriptions\n              </h3>\n              <div className=\"mt-4 w-full\">\n                <input\n                  autoFocus\n                  type=\"text\"\n                  placeholder=\"Type to search...\"\n                  className=\"w-full rounded-lg border border-zinc-200 bg-transparent px-3 py-2 text-[11px] outline-none focus:border-[#fa6a2e] dark:border-zinc-800 dark:focus:border-[#fa6a2e]\"\n                />\n              </div>\n              <div className=\"mt-4 flex max-h-32 w-full flex-col gap-2 overflow-y-auto\">\n                <p className=\"text-center text-[10px] text-zinc-400\">\n                  Start typing to see results\n                </p>\n              </div>\n            </motion.div>\n          )}\n\n          {isSummaryOpen && (\n            <motion.div\n              initial={{ opacity: 0, scale: 0.9, y: 10 }}\n              animate={{ opacity: 1, scale: 1, y: 0 }}\n              exit={{ opacity: 0, scale: 0.9, y: 10 }}\n              className=\"absolute inset-0 z-50 flex flex-col items-center justify-center rounded-[25px] bg-white/95 p-4 backdrop-blur-md sm:p-6 dark:bg-black/95\"\n            >\n              <button\n                onClick={() => setIsSummaryOpen(false)}\n                className=\"absolute top-4 right-4 text-zinc-400 hover:text-zinc-900 dark:hover:text-white\"\n              >\n                <X size={20} />\n              </button>\n              <div className=\"mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-purple-100 text-purple-500 dark:bg-purple-900/30\">\n                <TbCube size={24} />\n              </div>\n              <h3 className=\"mb-1 text-sm font-bold text-zinc-900 dark:text-white\">\n                Monthly Summary\n              </h3>\n              <div className=\"mt-4 grid w-full grid-cols-2 gap-3\">\n                <div className=\"rounded-lg bg-zinc-50 p-3 dark:bg-zinc-900/50\">\n                  <div className=\"text-[9px] text-zinc-500\">Active</div>\n                  <div className=\"text-sm font-bold text-zinc-900 dark:text-white\">\n                    {subscriptionsCount}\n                  </div>\n                </div>\n                <div className=\"rounded-lg bg-zinc-50 p-3 dark:bg-zinc-900/50\">\n                  <div className=\"text-[9px] text-zinc-500\">New</div>\n                  <div className=\"text-sm font-bold text-zinc-900 dark:text-white\">\n                    {newCount}\n                  </div>\n                </div>\n                <div className=\"col-span-2 rounded-lg bg-orange-50 p-3 dark:bg-orange-950/20\">\n                  <div className=\"text-[9px] text-orange-600\">Total Spend</div>\n                  <div className=\"text-sm font-bold text-orange-600\">\n                    ${monthlyTotal.toFixed(2)}\n                  </div>\n                </div>\n              </div>\n            </motion.div>\n          )}\n        </AnimatePresence>\n\n        <div>\n          <div className=\"mb-2 grid grid-cols-7 gap-1 text-[8px] font-semibold tracking-wider text-zinc-500 sm:text-[9px] dark:text-[#d4d4d4]\">\n            {['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN'].map((d) => (\n              <div\n                key={d}\n                className=\"rounded-full border-zinc-100 bg-zinc-50 py-1.5 text-center dark:border-[#222] dark:bg-[#2A2A2A]/50\"\n              >\n                {d}\n              </div>\n            ))}\n          </div>\n          <div className=\"grid grid-cols-7 gap-1 sm:gap-1.5\">\n            {days.map((day, idx) => {\n              const uniqueId = `day-${day.date}-${idx}`;\n              const isActive = selectedId === uniqueId;\n\n              return (\n                <motion.button\n                  key={uniqueId}\n                  layout\n                  whileTap={{ scale: 0.95 }}\n                  onClick={() => setSelectedId(uniqueId)}\n                  transition={spring}\n                  className={`relative flex aspect-square flex-col items-center justify-center rounded-xl border text-[10px] font-medium transition-colors sm:h-12 sm:text-[11px] ${\n                    day.isMuted\n                      ? 'border-zinc-100 bg-zinc-50 text-zinc-300 dark:border-[#161616] dark:bg-[#0e0e0f] dark:text-[#333]'\n                      : 'border-zinc-100 bg-zinc-50/50 text-zinc-700 hover:border-zinc-300 dark:border-[#222] dark:bg-[#2A2A2A]/50 dark:text-[#d4d4d4] dark:hover:border-[#333]'\n                  }`}\n                >\n                  {isActive && (\n                    <motion.div\n                      layoutId=\"activeGlow\"\n                      className=\"absolute inset-0 z-0 rounded-xl border-[1.5px] border-[#b3522f] bg-orange-50 dark:bg-[#32211A]\"\n                      transition={spring}\n                    />\n                  )}\n\n                  <div className=\"relative z-10 flex flex-col items-center justify-start gap-0.5 sm:gap-1\">\n                    <span>{day.date}</span>\n                    <span className=\"scale-75 sm:scale-100\">{day.isLogo}</span>\n                  </div>\n\n                  {day.indicators && (\n                    <div className=\"absolute top-1 right-1 flex gap-0.5 sm:top-1.5 sm:right-1.5\">\n                      {day.indicators}\n                    </div>\n                  )}\n                </motion.button>\n              );\n            })}\n          </div>\n        </div>\n      </div>\n\n      {/* Footer Info*/}\n      <div className=\"mt-5 flex items-center justify-between gap-2 text-[8px] font-semibold tracking-widest text-zinc-400 sm:text-[9px] dark:text-[#555]\">\n        <div className=\"flex items-center gap-2 sm:gap-4\">\n          <span className=\"flex cursor-default items-center gap-1.5 transition-colors hover:text-[#a855f7]\">\n            <span className=\"h-1 w-1 rounded-full bg-[#a855f7] sm:h-1.5 sm:w-1.5\" />\n            MONTHLY\n          </span>\n          <span className=\"flex cursor-default items-center gap-1.5 transition-colors hover:text-[#facc15]\">\n            <span className=\"h-1 w-1 rounded-full bg-[#facc15] sm:h-1.5 sm:w-1.5\" />\n            YEARLY\n          </span>\n        </div>\n\n        <span className=\"whitespace-nowrap text-zinc-500 dark:text-[#666]\">\n          <span className=\"text-zinc-900 dark:text-[#ccc7c7]\">\n            {subscriptionsCount}\n          </span>{' '}\n          SUBS /{' '}\n          <span className=\"text-zinc-900 dark:text-[#ccc7c7]\">{newCount}</span>{' '}\n          NEW\n        </span>\n      </div>\n\n      {/* Bottom Bar*/}\n      <div className=\"mt-4 flex items-center justify-between gap-2 border-t border-zinc-100 pt-4 dark:border-[#1a1a1b]\">\n        <div className=\"flex gap-3 text-zinc-400 sm:gap-4 dark:text-[#555]\">\n          <Search\n            size={16}\n            onClick={() => setIsSearching(true)}\n            className=\"shrink-0 cursor-pointer transition-colors hover:text-zinc-900 dark:hover:text-white\"\n          />\n          <button\n            onClick={handleDownload}\n            disabled={isDownloading}\n            className=\"relative flex items-center justify-center transition-colors hover:text-zinc-900 dark:hover:text-white\"\n          >\n            {isDownloading ? (\n              <Loader2 size={16} className=\"animate-spin text-[#fa6a2e]\" />\n            ) : (\n              <Download size={16} className=\"shrink-0 cursor-pointer\" />\n            )}\n          </button>\n          <TbCube\n            size={16}\n            onClick={() => setIsSummaryOpen(true)}\n            className=\"shrink-0 cursor-pointer transition-colors hover:text-zinc-900 dark:hover:text-white\"\n          />\n        </div>\n\n        <div className=\"truncate text-[9px] font-medium text-zinc-500 sm:text-[10px] dark:text-[#666]\">\n          MONTHLY TOTAL :{' '}\n          <span className=\"ml-1 text-[11px] font-bold text-zinc-900 sm:text-[12px] dark:text-white\">\n            ${monthlyTotal.toFixed(2)}\n          </span>\n        </div>\n      </div>\n    </motion.div>\n  );\n};\n"
    }
  ]
}
