{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "components-animate-github-stars-wheel",
  "title": "GitHub Stars Wheel",
  "description": "A scrolling wheel that displays GitHub stars count.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "@animate-ui/primitives-effects-particles",
    "@animate-ui/primitives-texts-scrolling-number"
  ],
  "files": [
    {
      "path": "registry/components/animate/github-stars-wheel/index.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { StarIcon } from 'lucide-react';\n\nimport {\n  ScrollingNumber as ScrollingNumberPrimitive,\n  ScrollingNumberContainer as ScrollingNumberContainerPrimitive,\n  ScrollingNumberItems as ScrollingNumberItemsPrimitive,\n  ScrollingNumberHighlight as ScrollingNumberHighlightPrimitive,\n  type ScrollingNumberContainerProps as ScrollingNumberContainerPrimitiveProps,\n} from '@/components/animate-ui/primitives/texts/scrolling-number';\nimport { cn } from '@/lib/utils';\nimport {\n  Particles,\n  ParticlesEffect,\n} from '@/components/animate-ui/primitives/effects/particles';\n\nfunction percentageBetween(value: number, min: number, max: number): number {\n  return ((value - min) / (max - min)) * 100;\n}\n\ntype GitHubStarsWheelProps = {\n  username?: string;\n  repo?: string;\n  direction?: 'btt' | 'ttb';\n  delay?: number;\n  value?: number;\n  step?: number;\n} & Omit<\n  ScrollingNumberContainerPrimitiveProps,\n  'direction' | 'number' | 'step'\n>;\n\nfunction GitHubStarsWheel({\n  username,\n  repo,\n  direction = 'btt',\n  itemsSize = 35,\n  sideItemsCount = 2,\n  delay = 0,\n  step = 100,\n  value,\n  className,\n  ...props\n}: GitHubStarsWheelProps) {\n  const [stars, setStars] = React.useState(value ?? 0);\n  const [currentStars, setCurrentStars] = React.useState(0);\n  const [isLoading, setIsLoading] = React.useState(true);\n  const roundedStars = React.useMemo(\n    () => Math.round(stars / step) * step,\n    [stars, step],\n  );\n  const isCompleted = React.useMemo(\n    () => currentStars === roundedStars,\n    [currentStars, roundedStars],\n  );\n  const fillPercentage = React.useMemo(\n    () => percentageBetween(currentStars, 0, roundedStars),\n    [currentStars, roundedStars],\n  );\n\n  React.useEffect(() => {\n    if (value !== undefined && username && repo) return;\n\n    const timeout = setTimeout(() => {\n      fetch(`https://api.github.com/repos/${username}/${repo}`)\n        .then((response) => response.json())\n        .then((data) => {\n          if (data && typeof data.stargazers_count === 'number') {\n            setStars(data.stargazers_count);\n          }\n        })\n        .catch(console.error)\n        .finally(() => setIsLoading(false));\n    }, delay);\n\n    return () => clearTimeout(timeout);\n  }, [username, repo, value, delay]);\n\n  return (\n    !isLoading && (\n      <ScrollingNumberContainerPrimitive\n        key={direction}\n        className={cn('w-28', className)}\n        direction={direction}\n        number={roundedStars}\n        step={step}\n        itemsSize={itemsSize}\n        onNumberChange={setCurrentStars}\n        {...props}\n      >\n        <div\n          className=\"absolute top-0 left-0 w-full bg-gradient-to-t from-transparent to-background z-10\"\n          style={{\n            height: `${itemsSize * sideItemsCount}px`,\n          }}\n        />\n        <div\n          className=\"absolute bottom-0 left-0 w-full bg-gradient-to-b from-transparent to-background z-10\"\n          style={{\n            height: `${itemsSize * sideItemsCount}px`,\n          }}\n        />\n        <ScrollingNumberPrimitive delay={delay}>\n          <ScrollingNumberItemsPrimitive className=\"flex items-center justify-start pl-8\" />\n        </ScrollingNumberPrimitive>\n        <ScrollingNumberHighlightPrimitive className=\"bg-accent/40 border rounded-md size-full flex items-center pl-2\">\n          <Particles animate={isCompleted}>\n            <StarIcon\n              aria-hidden=\"true\"\n              className=\"fill-neutral-300 stroke-neutral-300 dark:fill-neutral-700 dark:stroke-neutral-700 size-4\"\n            />\n            <StarIcon\n              aria-hidden=\"true\"\n              className=\"absolute top-0 left-0 size-4 fill-yellow-500 stroke-yellow-500\"\n              style={{\n                clipPath: `inset(${100 - (isCompleted ? fillPercentage : fillPercentage - 10)}% 0 0 0)`,\n              }}\n            />\n            <ParticlesEffect\n              delay={0.5}\n              className=\"size-1 rounded-full bg-yellow-500\"\n            />\n          </Particles>\n        </ScrollingNumberHighlightPrimitive>\n      </ScrollingNumberContainerPrimitive>\n    )\n  );\n}\n\nexport { GitHubStarsWheel, type GitHubStarsWheelProps };\n",
      "type": "registry:ui",
      "target": "components/animate-ui/components/animate/github-stars-wheel.tsx"
    }
  ],
  "type": "registry:ui"
}