{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "weather",
  "type": "registry:component",
  "title": "Get Weather",
  "author": "Nicklas Scharpff <https://n1cklas.com>",
  "description": "AI SDK tool that returns mock weather for a location. Includes a WeatherCard renderer.",
  "dependencies": [
    "zod",
    "ai",
    "@radix-ui/react-slot",
    "class-variance-authority",
    "lucide-react",
    "react-syntax-highlighter"
  ],
  "registryDependencies": [
    "https://ai-tools-registry.vercel.app/r/card.json",
    "https://ai-tools-registry.vercel.app/r/loader.json",
    "https://ai-tools-registry.vercel.app/r/code-block.json",
    "https://ai-tools-registry.vercel.app/r/sources.json",
    "https://ai-tools-registry.vercel.app/r/skeleton.json"
  ],
  "files": [
    {
      "path": "registry/ai-tools/tools/weather/tool.ts",
      "content": "import { UIToolInvocation, tool } from \"ai\"\nimport { z } from \"zod\"\n\n// Tool definition first\nexport const GetWeatherSchema = z.object({\n  location: z.string(),\n  unit: z.enum([\"C\", \"F\"]),\n  temperature: z.number(),\n  condition: z.string(),\n  high: z.number(),\n  low: z.number(),\n  humidity: z.number(),\n  windKph: z.number(),\n  icon: z.string().optional(),\n})\n\nexport type GetWeatherResult = z.infer<typeof GetWeatherSchema>\n\n// Tool definition first\nexport const getWeatherTool = tool({\n  name: \"weather\",\n  description: \"Get the current weather for a location.\",\n  inputSchema: z.object({\n    location: z.string().describe(\"City name, address or coordinates\"),\n    unit: z.enum([\"C\", \"F\"]).default(\"C\"),\n  }),\n  outputSchema: GetWeatherSchema,\n  execute: async ({ location, unit }) => {\n    const { latitude, longitude, name } = await geocodeLocation(location)\n\n    const params = new URLSearchParams({\n      latitude: String(latitude),\n      longitude: String(longitude),\n      current: [\n        \"temperature_2m\",\n        \"relative_humidity_2m\",\n        \"wind_speed_10m\",\n        \"weather_code\",\n      ].join(\",\"),\n      daily: [\"temperature_2m_max\", \"temperature_2m_min\"].join(\",\"),\n      timezone: \"auto\",\n      temperature_unit: unit === \"F\" ? \"fahrenheit\" : \"celsius\",\n      wind_speed_unit: \"kmh\",\n    })\n\n    const url = `https://api.open-meteo.com/v1/forecast?${params.toString()}`\n    const res = await fetch(url)\n    if (!res.ok) throw new Error(`Weather API failed: ${res.status}`)\n    const data = (await res.json()) as ForecastResponse\n\n    const current = data?.current\n    const daily = data?.daily\n    if (!current || !daily) throw new Error(\"Malformed weather API response\")\n\n    const weatherCode = Number(current.weather_code)\n    const mapped = mapWeatherCode(weatherCode)\n\n    const result: GetWeatherResult = {\n      location: name,\n      unit,\n      temperature: Math.round(Number(current.temperature_2m)),\n      condition: mapped.condition,\n      high: Math.round(Number(daily.temperature_2m_max?.[0])),\n      low: Math.round(Number(daily.temperature_2m_min?.[0])),\n      humidity: Math.max(\n        0,\n        Math.min(1, Number(current.relative_humidity_2m) / 100)\n      ),\n      windKph: Math.round(Number(current.wind_speed_10m)),\n      icon: mapped.icon,\n    }\n\n    return result\n  },\n})\n\n// API response types (from Open-Meteo)\ninterface GeocodeItem {\n  id: number\n  name: string\n  latitude: number\n  longitude: number\n  elevation?: number\n  country_code?: string\n  admin1?: string\n  timezone?: string\n}\n\ninterface GeocodeResponse {\n  results?: GeocodeItem[]\n}\n\ninterface ForecastCurrent {\n  time: string\n  interval: number\n  temperature_2m: number\n  relative_humidity_2m: number\n  wind_speed_10m: number\n  weather_code: number\n}\n\ninterface ForecastDaily {\n  time: string[]\n  temperature_2m_max: number[]\n  temperature_2m_min: number[]\n}\n\ninterface ForecastResponse {\n  current: ForecastCurrent\n  daily: ForecastDaily\n}\n\n// Helper functions (hoisted)\nasync function geocodeLocation(location: string): Promise<{\n  latitude: number\n  longitude: number\n  name: string\n}> {\n  // Allow \"lat,lon\" inputs without geocoding\n  const coordMatch = location\n    .trim()\n    .match(/^\\s*(-?\\d+(?:\\.\\d+)?)\\s*,\\s*(-?\\d+(?:\\.\\d+)?)\\s*$/)\n  if (coordMatch) {\n    const latitude = parseFloat(coordMatch[1])\n    const longitude = parseFloat(coordMatch[2])\n    return {\n      latitude,\n      longitude,\n      name: `${latitude.toFixed(3)}, ${longitude.toFixed(3)}`,\n    }\n  }\n\n  const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(\n    location\n  )}&count=1&language=en&format=json`\n  const res = await fetch(url)\n  if (!res.ok) throw new Error(`Geocoding failed: ${res.status}`)\n  const data = (await res.json()) as GeocodeResponse\n  const first = data?.results?.[0]\n  if (!first) throw new Error(`Location not found: ${location}`)\n  const nameParts = [first.name, first.admin1, first.country_code].filter(\n    Boolean\n  )\n  return {\n    latitude: first.latitude,\n    longitude: first.longitude,\n    name: nameParts.join(\", \"),\n  }\n}\n\nfunction mapWeatherCode(code: number): { condition: string; icon?: string } {\n  switch (code) {\n    case 0:\n      return { condition: \"Clear sky\", icon: \"weather-sun\" }\n    case 1:\n      return { condition: \"Mainly clear\", icon: \"weather-sun\" }\n    case 2:\n      return { condition: \"Partly cloudy\", icon: \"weather-partly\" }\n    case 3:\n      return { condition: \"Overcast\", icon: \"weather-cloud\" }\n    case 45:\n    case 48:\n      return { condition: \"Fog\", icon: \"weather-fog\" }\n    case 51:\n    case 53:\n    case 55:\n    case 56:\n    case 57:\n      return { condition: \"Drizzle\", icon: \"weather-drizzle\" }\n    case 61:\n    case 63:\n    case 65:\n    case 66:\n    case 67:\n      return { condition: \"Rain\", icon: \"weather-rain\" }\n    case 71:\n    case 73:\n    case 75:\n    case 77:\n      return { condition: \"Snow\", icon: \"weather-snow\" }\n    case 80:\n    case 81:\n    case 82:\n      return { condition: \"Showers\", icon: \"weather-showers\" }\n    case 85:\n    case 86:\n      return { condition: \"Snow showers\", icon: \"weather-snow\" }\n    case 95:\n    case 96:\n    case 99:\n      return { condition: \"Thunderstorm\", icon: \"weather-thunder\" }\n    default:\n      return { condition: \"Unknown\" }\n  }\n}\n\nexport type WeatherToolType = UIToolInvocation<typeof getWeatherTool>\n",
      "type": "registry:file",
      "target": "~/ai/tools/weather/tool.ts"
    },
    {
      "path": "registry/ai-tools/tools/weather/component.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport type { WeatherToolType } from \"./tool\"\nimport { Loader } from \"@/registry/ai-elements/loader\"\nimport { CodeBlock } from \"@/registry/ai-elements/code-block\"\nimport { Badge } from \"@/registry/ai-tools/ui/badge\"\nimport { cn } from \"@/lib/utils\"\nimport { Card, CardContent, CardHeader } from \"@/registry/ai-tools/ui/card\"\nimport { Skeleton } from \"@/registry/ai-tools/ui/skeleton\"\n\nexport function WeatherCard({ invocation }: { invocation: WeatherToolType }) {\n  const part = invocation\n  const cardBaseClass =\n    \"not-prose flex w-full flex-col gap-0 overflow-hidden border border-border/50 bg-background/95 py-0 text-foreground shadow-sm\"\n  const headerBaseClass =\n    \"flex flex-col gap-2 border-b border-border/50 px-5 py-4 sm:flex-row sm:items-center sm:justify-between\"\n  const contentBaseClass = \"px-6 py-5\"\n  const renderHeader = (\n    title: React.ReactNode,\n    description?: React.ReactNode,\n    actions?: React.ReactNode\n  ) => {\n    const descriptionNode =\n      typeof description === \"string\" ? (\n        <p className=\"text-xs text-muted-foreground\">{description}</p>\n      ) : (\n        (description ?? null)\n      )\n\n    return (\n      <CardHeader className={headerBaseClass}>\n        {(title || descriptionNode) && (\n          <div className=\"space-y-1\">\n            {title ? (\n              <h3 className=\"text-sm font-semibold leading-none tracking-tight text-foreground\">\n                {title}\n              </h3>\n            ) : null}\n            {descriptionNode}\n          </div>\n        )}\n        {actions ? (\n          <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n            {actions}\n          </div>\n        ) : null}\n      </CardHeader>\n    )\n  }\n  // Handle tool invocation states\n  if (part.state === \"input-streaming\") {\n    return (\n      <Card className={cn(cardBaseClass, \"max-w-xl animate-in fade-in-50\")}>\n        {renderHeader(\"Weather\", \"Waiting for input…\")}\n        <CardContent\n          className={cn(\n            contentBaseClass,\n            \"space-y-4 text-sm text-muted-foreground\"\n          )}\n        >\n          <div className=\"flex items-center gap-2\">\n            <Loader /> Preparing weather request\n          </div>\n          <div className=\"space-y-2\">\n            <Skeleton className=\"h-12 w-3/4 rounded-lg\" />\n            <div className=\"grid gap-3 sm:grid-cols-3\">\n              {Array.from({ length: 3 }).map((_, idx) => (\n                <Skeleton key={idx} className=\"h-20 rounded-xl\" />\n              ))}\n            </div>\n          </div>\n        </CardContent>\n      </Card>\n    )\n  }\n\n  if (part.state === \"input-available\") {\n    return (\n      <Card className={cn(cardBaseClass, \"max-w-xl animate-in fade-in-50\")}>\n        {renderHeader(\"Weather\", \"Fetching data…\")}\n        <CardContent className={cn(contentBaseClass, \"space-y-4\")}>\n          <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n            <Loader /> Running tool\n          </div>\n          <div className=\"space-y-2\">\n            <Skeleton className=\"h-14 w-full rounded-xl\" />\n            <div className=\"grid gap-3 sm:grid-cols-3\">\n              {Array.from({ length: 3 }).map((_, idx) => (\n                <Skeleton key={idx} className=\"h-20 rounded-xl\" />\n              ))}\n            </div>\n          </div>\n          {part.input ? (\n            <div className=\"rounded-md border border-border/40 bg-muted/40\">\n              <CodeBlock\n                code={JSON.stringify(part.input, null, 2)}\n                language=\"json\"\n              />\n            </div>\n          ) : null}\n        </CardContent>\n      </Card>\n    )\n  }\n\n  if (part.state === \"output-error\") {\n    return (\n      <Card className={cn(cardBaseClass, \"max-w-xl animate-in fade-in-50\")}>\n        {renderHeader(\"Weather\", \"Error\")}\n        <CardContent className={contentBaseClass}>\n          <div className=\"rounded-md border border-destructive/30 bg-destructive/10 p-3 text-sm text-destructive\">\n            {part.errorText || \"An error occurred while fetching weather.\"}\n          </div>\n        </CardContent>\n      </Card>\n    )\n  }\n\n  if (part.output === undefined) return null\n\n  const {\n    location,\n    temperature,\n    unit,\n    condition,\n    high,\n    low,\n    humidity,\n    windKph,\n  } = part.output\n  return (\n    <Card className={cn(cardBaseClass, \"max-w-xl animate-in fade-in-50\")}>\n      {renderHeader(\n        \"Weather\",\n        location,\n        part.output.icon ? (\n          <Badge variant=\"secondary\" className=\"h-9 w-9 rounded-full text-lg\">\n            {part.output.icon}\n          </Badge>\n        ) : null\n      )}\n      <CardContent className={cn(contentBaseClass, \"space-y-6 pb-6\")}>\n        <div className=\"flex flex-wrap items-end justify-between gap-4\">\n          <div className=\"space-y-1\">\n            <p className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n              Current conditions\n            </p>\n            <div className=\"text-5xl font-semibold tracking-tight\">\n              {temperature}°{unit}\n            </div>\n            <p className=\"text-sm text-muted-foreground\">{condition}</p>\n          </div>\n          <div className=\"rounded-xl border border-border/40 bg-muted/40 px-4 py-2 text-center text-sm text-muted-foreground\">\n            High {high}°{unit} • Low {low}°{unit}\n          </div>\n        </div>\n        <dl className=\"grid gap-3 text-sm sm:grid-cols-2\">\n          <div className=\"rounded-lg border border-border/40 bg-muted/30 px-4 py-3\">\n            <dt className=\"text-muted-foreground text-xs uppercase tracking-wide\">\n              Humidity\n            </dt>\n            <dd className=\"mt-1 font-medium\">{Math.round(humidity * 100)}%</dd>\n          </div>\n          <div className=\"rounded-lg border border-border/40 bg-muted/30 px-4 py-3\">\n            <dt className=\"text-muted-foreground text-xs uppercase tracking-wide\">\n              Wind\n            </dt>\n            <dd className=\"mt-1 font-medium\">{windKph} kph</dd>\n          </div>\n        </dl>\n      </CardContent>\n    </Card>\n  )\n}\n",
      "type": "registry:file",
      "target": "~/ai/tools/weather/component.tsx"
    },
    {
      "path": "registry/ai-elements/loader.tsx",
      "content": "import { cn } from \"@/lib/utils\"\nimport type { HTMLAttributes } from \"react\"\n\ntype LoaderIconProps = {\n  size?: number\n}\n\nconst LoaderIcon = ({ size = 16 }: LoaderIconProps) => (\n  <svg\n    height={size}\n    strokeLinejoin=\"round\"\n    style={{ color: \"currentcolor\" }}\n    viewBox=\"0 0 16 16\"\n    width={size}\n  >\n    <title>Loader</title>\n    <g clipPath=\"url(#clip0_2393_1490)\">\n      <path d=\"M8 0V4\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n      <path\n        d=\"M8 16V12\"\n        opacity=\"0.5\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M3.29773 1.52783L5.64887 4.7639\"\n        opacity=\"0.9\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M12.7023 1.52783L10.3511 4.7639\"\n        opacity=\"0.1\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M12.7023 14.472L10.3511 11.236\"\n        opacity=\"0.4\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M3.29773 14.472L5.64887 11.236\"\n        opacity=\"0.6\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M15.6085 5.52783L11.8043 6.7639\"\n        opacity=\"0.2\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M0.391602 10.472L4.19583 9.23598\"\n        opacity=\"0.7\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M15.6085 10.4722L11.8043 9.2361\"\n        opacity=\"0.3\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n      <path\n        d=\"M0.391602 5.52783L4.19583 6.7639\"\n        opacity=\"0.8\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n      />\n    </g>\n    <defs>\n      <clipPath id=\"clip0_2393_1490\">\n        <rect fill=\"white\" height=\"16\" width=\"16\" />\n      </clipPath>\n    </defs>\n  </svg>\n)\n\nexport type LoaderProps = HTMLAttributes<HTMLDivElement> & {\n  size?: number\n}\n\nexport const Loader = ({ className, size = 16, ...props }: LoaderProps) => (\n  <div\n    className={cn(\n      \"inline-flex animate-spin items-center justify-center\",\n      className\n    )}\n    {...props}\n  >\n    <LoaderIcon size={size} />\n  </div>\n)\n",
      "type": "registry:component",
      "target": ""
    },
    {
      "path": "registry/ai-elements/code-block.tsx",
      "content": "\"use client\"\n\nimport { Button } from \"@/registry/ai-tools/ui/button\"\nimport { cn } from \"@/lib/utils\"\nimport { CheckIcon, CopyIcon } from \"lucide-react\"\nimport type { ComponentProps, HTMLAttributes, ReactNode } from \"react\"\nimport { createContext, useContext, useState } from \"react\"\nimport { Prism as SyntaxHighlighter } from \"react-syntax-highlighter\"\nimport {\n  oneDark,\n  oneLight,\n} from \"react-syntax-highlighter/dist/esm/styles/prism\"\n\ntype CodeBlockContextType = {\n  code: string\n}\n\nconst CodeBlockContext = createContext<CodeBlockContextType>({\n  code: \"\",\n})\n\nexport type CodeBlockProps = HTMLAttributes<HTMLDivElement> & {\n  code: string\n  language: string\n  showLineNumbers?: boolean\n  children?: ReactNode\n}\n\nexport const CodeBlock = ({\n  code,\n  language,\n  showLineNumbers = false,\n  className,\n  children,\n  ...props\n}: CodeBlockProps) => (\n  <CodeBlockContext.Provider value={{ code }}>\n    <div\n      className={cn(\n        \"relative w-full overflow-hidden rounded-md border bg-background text-foreground\",\n        className\n      )}\n      {...props}\n    >\n      <div className=\"relative\">\n        <SyntaxHighlighter\n          className=\"overflow-hidden dark:hidden\"\n          codeTagProps={{\n            className: \"font-mono text-sm\",\n          }}\n          customStyle={{\n            margin: 0,\n            padding: \"1rem\",\n            fontSize: \"0.875rem\",\n            background: \"hsl(var(--background))\",\n            color: \"hsl(var(--foreground))\",\n          }}\n          language={language}\n          lineNumberStyle={{\n            color: \"hsl(var(--muted-foreground))\",\n            paddingRight: \"1rem\",\n            minWidth: \"2.5rem\",\n          }}\n          showLineNumbers={showLineNumbers}\n          style={oneLight}\n        >\n          {code}\n        </SyntaxHighlighter>\n        <SyntaxHighlighter\n          className=\"hidden overflow-hidden dark:block\"\n          codeTagProps={{\n            className: \"font-mono text-sm\",\n          }}\n          customStyle={{\n            margin: 0,\n            padding: \"1rem\",\n            fontSize: \"0.875rem\",\n            background: \"hsl(var(--background))\",\n            color: \"hsl(var(--foreground))\",\n          }}\n          language={language}\n          lineNumberStyle={{\n            color: \"hsl(var(--muted-foreground))\",\n            paddingRight: \"1rem\",\n            minWidth: \"2.5rem\",\n          }}\n          showLineNumbers={showLineNumbers}\n          style={oneDark}\n        >\n          {code}\n        </SyntaxHighlighter>\n        {children && (\n          <div className=\"absolute top-2 right-2 flex items-center gap-2\">\n            {children}\n          </div>\n        )}\n      </div>\n    </div>\n  </CodeBlockContext.Provider>\n)\n\nexport type CodeBlockCopyButtonProps = ComponentProps<typeof Button> & {\n  onCopy?: () => void\n  onError?: (error: Error) => void\n  timeout?: number\n}\n\nexport const CodeBlockCopyButton = ({\n  onCopy,\n  onError,\n  timeout = 2000,\n  children,\n  className,\n  ...props\n}: CodeBlockCopyButtonProps) => {\n  const [isCopied, setIsCopied] = useState(false)\n  const { code } = useContext(CodeBlockContext)\n\n  const copyToClipboard = async () => {\n    if (typeof window === \"undefined\" || !navigator.clipboard.writeText) {\n      onError?.(new Error(\"Clipboard API not available\"))\n      return\n    }\n\n    try {\n      await navigator.clipboard.writeText(code)\n      setIsCopied(true)\n      onCopy?.()\n      setTimeout(() => setIsCopied(false), timeout)\n    } catch (error) {\n      onError?.(error as Error)\n    }\n  }\n\n  const Icon = isCopied ? CheckIcon : CopyIcon\n\n  return (\n    <Button\n      className={cn(\"shrink-0\", className)}\n      onClick={copyToClipboard}\n      size=\"icon\"\n      variant=\"ghost\"\n      {...props}\n    >\n      {children ?? <Icon size={14} />}\n    </Button>\n  )\n}\n",
      "type": "registry:component",
      "target": ""
    },
    {
      "path": "registry/ai-tools/ui/badge.tsx",
      "content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst badgeVariants = cva(\n  \"inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden\",\n  {\n    variants: {\n      variant: {\n        default:\n          \"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90\",\n        secondary:\n          \"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90\",\n        destructive:\n          \"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n        outline:\n          \"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  }\n)\n\nfunction Badge({\n  className,\n  variant,\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"span\"> &\n  VariantProps<typeof badgeVariants> & { asChild?: boolean }) {\n  const Comp = asChild ? Slot : \"span\"\n\n  return (\n    <Comp\n      data-slot=\"badge\"\n      className={cn(badgeVariants({ variant }), className)}\n      {...props}\n    />\n  )\n}\n\nexport { Badge, badgeVariants }\n",
      "type": "registry:ui",
      "target": ""
    },
    {
      "path": "registry/ai-tools/ui/card.tsx",
      "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Card({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card\"\n      className={cn(\n        \"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-header\"\n      className={cn(\n        \"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-title\"\n      className={cn(\"leading-none font-semibold\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-description\"\n      className={cn(\"text-muted-foreground text-sm\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-action\"\n      className={cn(\n        \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-content\"\n      className={cn(\"px-6\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-footer\"\n      className={cn(\"flex items-center px-6 [.border-t]:pt-6\", className)}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Card,\n  CardHeader,\n  CardFooter,\n  CardTitle,\n  CardAction,\n  CardDescription,\n  CardContent,\n}\n",
      "type": "registry:ui",
      "target": ""
    },
    {
      "path": "registry/ai-tools/ui/skeleton.tsx",
      "content": "import { cn } from \"@/lib/utils\"\n\nfunction Skeleton({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"skeleton\"\n      className={cn(\"bg-accent animate-pulse rounded-md\", className)}\n      {...props}\n    />\n  )\n}\n\nexport { Skeleton }\n",
      "type": "registry:ui",
      "target": ""
    },
    {
      "path": "registry/ai-tools/ui/button.tsx",
      "content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n  \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n  {\n    variants: {\n      variant: {\n        default:\n          \"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90\",\n        destructive:\n          \"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n        outline:\n          \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\n        secondary:\n          \"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80\",\n        ghost:\n          \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n        link: \"text-primary underline-offset-4 hover:underline\",\n      },\n      size: {\n        default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n        sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n        lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n        icon: \"size-9\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n)\n\nfunction Button({\n  className,\n  variant,\n  size,\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean\n  }) {\n  const Comp = asChild ? Slot : \"button\"\n\n  return (\n    <Comp\n      data-slot=\"button\"\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  )\n}\n\nexport { Button, buttonVariants }\n",
      "type": "registry:ui",
      "target": ""
    }
  ]
}
