{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tour2",
  "type": "registry:block",
  "title": "Tour2",
  "description": "Tour2",
  "files": [
    {
      "path": "components/usages/tour2usage.tsx",
      "content": "import { useTour } from \"@/registry/open-source/tour2\"\nimport { Button } from \"../ui/button\"\n\nexport default function Tour2Usage() {\n    const tour = useTour()\n\n    return (\n        <div>\n\n            <Button size=\"lg\" onClick={() => tour.start(\"main\")}>\n                Start Tour\n            </Button>\n\n            <div data-tour-step-id=\"step1\">step 1 in the tour wooooot</div>\n            <div data-tour-step-id=\"step2\">step 2 in the tour wooooot</div>\n        </div>\n\n    )\n}",
      "type": "registry:block",
      "target": "~/example.tsx"
    },
    {
      "path": "components/usages/tour2usage.tsx",
      "content": "import { useTour } from \"@/registry/open-source/tour2\"\nimport { Button } from \"../ui/button\"\n\nexport default function Tour2Usage() {\n    const tour = useTour()\n\n    return (\n        <div>\n\n            <Button size=\"lg\" onClick={() => tour.start(\"main\")}>\n                Start Tour\n            </Button>\n\n            <div data-tour-step-id=\"step1\">step 1 in the tour wooooot</div>\n            <div data-tour-step-id=\"step2\">step 2 in the tour wooooot</div>\n        </div>\n\n    )\n}",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/tour2.tsx",
      "content": "\"use client\"\n\nimport { Button } from \"@/components/ui/button\"\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from \"@/components/ui/card\"\nimport { Popover, PopoverAnchor, PopoverContent } from \"@/components/ui/popover\"\nimport { cn } from \"@/registry/utilities/cn\"\nimport type { Content } from \"@radix-ui/react-popover\"\nimport { XIcon } from \"lucide-react\"\nimport Link from \"next/link\"\nimport * as React from \"react\"\nimport { createPortal } from \"react-dom\"\n\n// Credit:\n// https://onboarding-tour.vercel.app/\n\nconst TourContext = React.createContext<{\n    start: (tourId: string) => void\n    close: () => void\n} | null>(null)\n\nfunction useTour() {\n    const context = React.useContext(TourContext)\n    if (!context) {\n        throw new Error(\"useTour must be used within a TourProvider\")\n    }\n    return context\n}\n\ninterface Step {\n    id: string\n    title: React.ReactNode\n    content: React.ReactNode\n    nextRoute?: string\n    previousRoute?: string\n    nextLabel?: React.ReactNode\n    previousLabel?: React.ReactNode\n    side?: React.ComponentProps<typeof Content>[\"side\"]\n    sideOffset?: React.ComponentProps<typeof Content>[\"sideOffset\"]\n    align?: React.ComponentProps<typeof Content>[\"align\"]\n    alignOffset?: React.ComponentProps<typeof Content>[\"alignOffset\"]\n    className?: string\n}\n\ninterface Tour {\n    id: string\n    steps: Step[]\n}\n\nfunction TourProvider({\n    tours,\n    children,\n}: {\n    tours: Tour[]\n    children: React.ReactNode\n}) {\n    const [isOpen, setIsOpen] = React.useState(false)\n    const [activeTourId, setActiveTourId] = React.useState<string | null>(null)\n    const [currentStepIndex, setCurrentStepIndex] = React.useState(0)\n\n    const activeTour = tours.find((tour) => tour.id === activeTourId)\n    const steps = activeTour?.steps || []\n\n    function next() {\n        if (currentStepIndex < steps.length - 1) {\n            setCurrentStepIndex((prev) => prev + 1)\n        } else {\n            setIsOpen(false)\n            setCurrentStepIndex(0)\n            setActiveTourId(null)\n        }\n    }\n\n    function previous() {\n        if (currentStepIndex > 0) {\n            setCurrentStepIndex((prev) => prev - 1)\n        }\n    }\n\n    function close() {\n        setIsOpen(false)\n        setCurrentStepIndex(0)\n        setActiveTourId(null)\n    }\n\n    function start(tourId: string) {\n        const tour = tours.find((tour) => tour.id === tourId)\n        if (tour) {\n            if (tour.steps.length > 0) {\n                setActiveTourId(tourId)\n                setIsOpen(true)\n                setCurrentStepIndex(0)\n            } else {\n                console.error(`Tour with id '${tourId}' has no steps.`)\n            }\n        } else {\n            console.error(`Tour with id '${tourId}' not found.`)\n        }\n    }\n\n    return (\n        <TourContext.Provider\n            value={{\n                start,\n                close,\n            }}>\n            {children}\n            {isOpen && activeTour && steps.length > 0 && (\n                <TourOverlay\n                    step={steps[currentStepIndex]}\n                    currentStepIndex={currentStepIndex}\n                    totalSteps={steps.length}\n                    onNext={next}\n                    onPrevious={previous}\n                    onClose={close}\n                />\n            )}\n        </TourContext.Provider>\n    )\n}\n\nfunction TourOverlay({\n    step,\n    currentStepIndex,\n    totalSteps,\n    onNext,\n    onPrevious,\n    onClose,\n}: {\n    step: Step\n    currentStepIndex: number\n    totalSteps: number\n    onNext: () => void\n    onPrevious: () => void\n    onClose: () => void\n}) {\n    const [targets, setTargets] = React.useState<\n        { rect: DOMRect; radius: number }[]\n    >([])\n\n    React.useEffect(() => {\n        let needsScroll = true\n\n        function updatePosition() {\n            const elements = document.querySelectorAll(\n                `[data-tour-step-id*='${step.id}']`\n            )\n\n            if (elements.length > 0) {\n                const validElements: {\n                    rect: {\n                        width: number\n                        height: number\n                        x: number\n                        y: number\n                        left: number\n                        top: number\n                        right: number\n                        bottom: number\n                        toJSON: () => void\n                    }\n                    radius: number\n                    element: Element\n                }[] = []\n\n                Array.from(elements).forEach((element) => {\n                    const rect = element.getBoundingClientRect()\n                    if (rect.width === 0 && rect.height === 0) return\n\n                    const style = window.getComputedStyle(element)\n                    const radius = Number(style.borderRadius) || 4\n\n                    validElements.push({\n                        rect: {\n                            width: rect.width,\n                            height: rect.height,\n                            x: rect.left,\n                            y: rect.top,\n                            left: rect.left,\n                            top: rect.top,\n                            right: rect.right,\n                            bottom: rect.bottom,\n                            toJSON: () => { },\n                        },\n                        radius,\n                        element,\n                    })\n                })\n\n                setTargets(\n                    validElements.map(({ rect, radius }) => ({ rect, radius }))\n                )\n\n                if (validElements.length > 0 && needsScroll) {\n                    validElements[0].element.scrollIntoView({\n                        behavior: \"smooth\",\n                        block: \"center\",\n                    })\n                    needsScroll = false\n                }\n            } else {\n                setTargets([])\n            }\n        }\n\n        updatePosition()\n        const handleResizeOrScroll = () => updatePosition()\n\n        window.addEventListener(\"resize\", handleResizeOrScroll)\n        window.addEventListener(\"scroll\", handleResizeOrScroll, true)\n\n        const observer = new MutationObserver(() => updatePosition())\n        observer.observe(document.body, {\n            attributes: true,\n            childList: true,\n            subtree: true,\n        })\n\n        const resizeObserver = new ResizeObserver(() => updatePosition())\n        resizeObserver.observe(document.body)\n\n        return () => {\n            window.removeEventListener(\"resize\", handleResizeOrScroll)\n            window.removeEventListener(\"scroll\", handleResizeOrScroll, true)\n            observer.disconnect()\n            resizeObserver.disconnect()\n        }\n    }, [step])\n\n    React.useEffect(() => {\n        document.body.style.overflow = \"hidden\"\n        return () => {\n            document.body.style.overflow = \"\"\n        }\n    }, [])\n\n    if (!document) return null\n    if (targets.length === 0) return null\n\n    return createPortal(\n        <div className=\"fixed inset-0 z-50\">\n            <svg className=\"absolute inset-0 size-full\">\n                <defs>\n                    <mask id=\"tour-mask\">\n                        <rect\n                            x=\"0\"\n                            y=\"0\"\n                            width=\"100%\"\n                            height=\"100%\"\n                            fill=\"white\"\n                        />\n                        {targets.map((target, i) => (\n                            <rect\n                                key={i}\n                                x={target.rect.left}\n                                y={target.rect.top}\n                                width={target.rect.width}\n                                height={target.rect.height}\n                                rx={target.radius}\n                                fill=\"black\"\n                            />\n                        ))}\n                    </mask>\n                </defs>\n                <rect\n                    width=\"100%\"\n                    height=\"100%\"\n                    mask=\"url(#tour-mask)\"\n                    className=\"fill-black opacity-20\"\n                />\n                {targets.map((target, i) => {\n                    return (\n                        <rect\n                            key={i}\n                            x={target.rect.left}\n                            y={target.rect.top}\n                            width={target.rect.width}\n                            height={target.rect.height}\n                            rx={target.radius}\n                            className=\"stroke-primary fill-none stroke-2\"\n                        />\n                    )\n                })}\n            </svg>\n            {targets.length > 0 && (\n                <Popover key={step.id} open={true} modal={true}>\n                    <PopoverAnchor\n                        virtualRef={{\n                            current: {\n                                getBoundingClientRect: () =>\n                                    targets[0]?.rect || {\n                                        top: 0,\n                                        left: 0,\n                                        width: 0,\n                                        height: 0,\n                                        bottom: 0,\n                                        right: 0,\n                                        x: 0,\n                                        y: 0,\n                                        toJSON: () => { },\n                                    },\n                            },\n                        }}\n                    />\n                    <PopoverContent\n                        className={cn(\"px-0 z-999\", step.className)}\n                        side={step.side}\n                        sideOffset={step.sideOffset}\n                        align={step.align}\n                        alignOffset={step.alignOffset}\n                        onOpenAutoFocus={(e) => e.preventDefault()}\n                        onCloseAutoFocus={(e) => e.preventDefault()}\n                        asChild>\n                        <Card>\n                            <CardHeader>\n                                <CardTitle>{step.title}</CardTitle>\n                                <CardDescription>\n                                    Step {currentStepIndex + 1} of {totalSteps}\n                                </CardDescription>\n                                <Button\n                                    variant=\"ghost\"\n                                    size=\"icon\"\n                                    onClick={onClose}>\n                                    <XIcon />\n                                </Button>\n                            </CardHeader>\n                            <CardContent>{step.content}</CardContent>\n                            <CardFooter className=\"justify-between\">\n                                {currentStepIndex > 0 &&\n                                    (step.previousRoute ? (\n                                        <Button\n                                            variant=\"outline\"\n                                            onClick={onPrevious}\n                                            asChild>\n                                            <Link href={step.previousRoute}>\n                                                {step.previousLabel ??\n                                                    \"Previous\"}\n                                            </Link>\n                                        </Button>\n                                    ) : (\n                                        <Button\n                                            variant=\"outline\"\n                                            onClick={onPrevious}>\n                                            {step.previousLabel ?? \"Previous\"}\n                                        </Button>\n                                    ))}\n                                {step.nextRoute ? (\n                                    <Button\n                                        className=\"ml-auto\"\n                                        onClick={onNext}\n                                        asChild>\n                                        <Link href={step.nextRoute}>\n                                            {step.nextLabel ??\n                                                (currentStepIndex ===\n                                                    totalSteps - 1\n                                                    ? \"Finish\"\n                                                    : \"Next\")}\n                                        </Link>\n                                    </Button>\n                                ) : (\n                                    <Button\n                                        className=\"ml-auto\"\n                                        onClick={onNext}>\n                                        {step.nextLabel ??\n                                            (currentStepIndex === totalSteps - 1\n                                                ? \"Finish\"\n                                                : \"Next\")}\n                                    </Button>\n                                )}\n                            </CardFooter>\n                        </Card>\n                    </PopoverContent>\n                </Popover>\n            )\n            }\n        </div >,\n        document.body\n    )\n}\n\nexport { TourProvider, useTour, type Step, type Tour }",
      "type": "registry:ui"
    },
    {
      "path": "components/ui/button.tsx",
      "content": "import * as React from \"react\";\r\n\r\nimport { cn } from \"@/registry/utilities/cn\";\r\nimport { Slot } from \"@radix-ui/react-slot\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\n\r\nconst buttonVariants = cva(\r\n\t\"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm text-white hover:text-gray-400 font-medium ring-offset-background transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\r\n\t{\r\n\t\tvariants: {\r\n\t\t\tvariant: {\r\n\t\t\t\tsimple:\r\n\t\t\t\t\t\"bg-secondary relative z-10 bg-transparent hover:border-secondary hover:bg-secondary/50  border border-transparent dark:text-white text-sm md:text-sm transition font-medium duration-200  rounded-md px-4 py-2  flex items-center justify-center\",\r\n\t\t\t\tdefault: \"bg-primary text-primary-foreground hover:bg-primary/90\",\r\n\t\t\t\tdestructive:\r\n\t\t\t\t\t\"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\r\n\t\t\t\toutline:\r\n\t\t\t\t\t\"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\r\n\t\t\t\tsecondary:\r\n\t\t\t\t\t\"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\r\n\t\t\t\tghost: \"hover:bg-accent hover:text-black hover:stroke-black dark:text-white text-black\",\r\n\t\t\t\tlink: \"text-primary underline-offset-4 hover:underline\",\r\n\t\t\t},\r\n\t\t\tsize: {\r\n\t\t\t\tdefault: \"h-10 px-4 py-2\",\r\n\t\t\t\tsm: \"h-9 rounded-md px-3\",\r\n\t\t\t\tlg: \"h-11 rounded-md px-8\",\r\n\t\t\t\ticon: \"h-10 w-10\",\r\n\t\t\t},\r\n\t\t},\r\n\t\tdefaultVariants: {\r\n\t\t\tvariant: \"default\",\r\n\t\t\tsize: \"default\",\r\n\t\t},\r\n\t}\r\n);\r\n\r\nexport interface ButtonProps\r\n\textends React.ButtonHTMLAttributes<HTMLButtonElement>,\r\n\t\tVariantProps<typeof buttonVariants> {\r\n\tasChild?: boolean;\r\n}\r\n\r\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\r\n\t({ className, variant, size, asChild = false, ...props }, ref) => {\r\n\t\tconst Comp = asChild ? Slot : \"button\";\r\n\t\treturn (\r\n\t\t\t<Comp\r\n\t\t\t\tclassName={cn(buttonVariants({ variant, size, className }))}\r\n\t\t\t\tref={ref}\r\n\t\t\t\t{...props}\r\n\t\t\t/>\r\n\t\t);\r\n\t}\r\n);\r\nButton.displayName = \"Button\";\r\n\r\nexport { Button, buttonVariants };\r\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/utilities/cn.ts",
      "content": "import { ClassValue, clsx } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n\treturn twMerge(clsx(inputs));\r\n}\r\n",
      "type": "registry:ui"
    },
    {
      "path": "components/ui/card.tsx",
      "content": "import React from \"react\";\r\n\r\nimport { cn } from \"@/registry/utilities/cn\";\r\n\r\nconst Card = React.forwardRef<\r\n\tHTMLDivElement,\r\n\tReact.HTMLAttributes<HTMLDivElement>\r\n>(({ className, ...props }, ref) => (\r\n\t<div\r\n\t\tref={ref}\r\n\t\tclassName={cn(\r\n\t\t\t\"rounded-lg border bg-card text-card-foreground shadow-xs\",\r\n\t\t\tclassName\r\n\t\t)}\r\n\t\t{...props}\r\n\t/>\r\n));\r\nCard.displayName = \"Card\";\r\n\r\nconst CardHeader = React.forwardRef<\r\n\tHTMLDivElement,\r\n\tReact.HTMLAttributes<HTMLDivElement>\r\n>(({ className, ...props }, ref) => (\r\n\t<div\r\n\t\tref={ref}\r\n\t\tclassName={cn(\"flex flex-col space-y-1.5 p-6\", className)}\r\n\t\t{...props}\r\n\t/>\r\n));\r\nCardHeader.displayName = \"CardHeader\";\r\n\r\nconst CardTitle = React.forwardRef<\r\n\tHTMLParagraphElement,\r\n\tReact.HTMLAttributes<HTMLHeadingElement>\r\n>(({ className, ...props }, ref) => (\r\n\t<h3\r\n\t\tref={ref}\r\n\t\tclassName={cn(\r\n\t\t\t\"text-2xl font-semibold leading-none tracking-tight\",\r\n\t\t\tclassName\r\n\t\t)}\r\n\t\t{...props}\r\n\t/>\r\n));\r\nCardTitle.displayName = \"CardTitle\";\r\n\r\nconst CardDescription = React.forwardRef<\r\n\tHTMLParagraphElement,\r\n\tReact.HTMLAttributes<HTMLParagraphElement>\r\n>(({ className, ...props }, ref) => (\r\n\t<p\r\n\t\tref={ref}\r\n\t\tclassName={cn(\"text-sm text-muted-foreground\", className)}\r\n\t\t{...props}\r\n\t/>\r\n));\r\nCardDescription.displayName = \"CardDescription\";\r\n\r\nconst CardContent = React.forwardRef<\r\n\tHTMLDivElement,\r\n\tReact.HTMLAttributes<HTMLDivElement>\r\n>(({ className, ...props }, ref) => (\r\n\t<div ref={ref} className={cn(\"p-6 pt-0\", className)} {...props} />\r\n));\r\nCardContent.displayName = \"CardContent\";\r\n\r\nconst CardFooter = React.forwardRef<\r\n\tHTMLDivElement,\r\n\tReact.HTMLAttributes<HTMLDivElement>\r\n>(({ className, ...props }, ref) => (\r\n\t<div\r\n\t\tref={ref}\r\n\t\tclassName={cn(\"flex items-center p-6 pt-0\", className)}\r\n\t\t{...props}\r\n\t/>\r\n));\r\nCardFooter.displayName = \"CardFooter\";\r\n\r\nexport {\r\n\tCard,\r\n\tCardHeader,\r\n\tCardFooter,\r\n\tCardTitle,\r\n\tCardDescription,\r\n\tCardContent,\r\n};\r\n",
      "type": "registry:ui"
    },
    {
      "path": "components/ui/popover.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { cn } from \"@/registry/utilities/cn\";\nimport { Popover as PopoverPrimitive } from \"radix-ui\";\n\nfunction Popover({\n\t...props\n}: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n\treturn <PopoverPrimitive.Root data-slot=\"popover\" {...props} />;\n}\n\nfunction PopoverTrigger({\n\t...props\n}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n\treturn <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />;\n}\n\nfunction PopoverContent({\n\tclassName,\n\talign = \"center\",\n\tsideOffset = 4,\n\tshowArrow = false,\n\t...props\n}: React.ComponentProps<typeof PopoverPrimitive.Content> & {\n\tshowArrow?: boolean;\n}) {\n\treturn (\n\t\t<PopoverPrimitive.Portal>\n\t\t\t<PopoverPrimitive.Content\n\t\t\t\tdata-slot=\"popover-content\"\n\t\t\t\talign={align}\n\t\t\t\tsideOffset={sideOffset}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-hidden\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t<>\n\t\t\t\t\t{props.children}\n\t\t\t\t\t{showArrow && (\n\t\t\t\t\t\t<PopoverPrimitive.Arrow className=\"fill-popover -my-px drop-shadow-[0_1px_0_var(--border)]\" />\n\t\t\t\t\t)}\n\t\t\t\t</>\n\t\t\t</PopoverPrimitive.Content>\n\t\t</PopoverPrimitive.Portal>\n\t);\n}\n\nfunction PopoverAnchor({\n\t...props\n}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n\treturn <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />;\n}\n\nexport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };\n",
      "type": "registry:ui"
    }
  ]
}