{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "feature-sticky-section",
  "type": "registry:ui",
  "description": "Sticky section with controllable panels and scroll behavior",
  "dependencies": [
    "@radix-ui/react-slot",
    "@radix-ui/react-use-controllable-state"
  ],
  "files": [
    {
      "path": "registry/default/ui/feature-sticky-section.tsx",
      "content": "\"use client\"\n\nimport {\n  createContext,\n  forwardRef,\n  useCallback,\n  useContext,\n  useEffect,\n  useId,\n  useRef,\n  type ComponentPropsWithoutRef,\n  type ForwardedRef,\n  type ReactNode,\n} from \"react\"\nimport NextImage from \"next/image\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* -------------------------------------------------------------------------\n * Context\n * ----------------------------------------------------------------------- */\n\ninterface StickySectionContextValue {\n  activeIndex: number\n  registerPanel: (index: number, el: HTMLElement | null) => void\n  unregisterPanel: (index: number) => void\n  scrollToPanel: (index: number) => void\n}\n\nconst StickySectionContext = createContext<StickySectionContextValue | null>(\n  null\n)\n\nfunction useStickySection() {\n  const ctx = useContext(StickySectionContext)\n  if (!ctx) {\n    throw new Error(\n      \"StickySection components must be used within StickySection.Root\"\n    )\n  }\n  return ctx\n}\n\n/* -------------------------------------------------------------------------\n * Root\n * ----------------------------------------------------------------------- */\n\nexport interface StickySectionRootProps\n  extends Omit<ComponentPropsWithoutRef<\"div\">, \"defaultValue\" | \"onChange\"> {\n  /** Controlled active index */\n  value?: number\n  /** Uncontrolled default active index */\n  defaultValue?: number\n  /** Callback when active index changes */\n  onValueChange?: (value: number) => void\n  /** Merge props onto child element instead of rendering a div */\n  asChild?: boolean\n}\n\nconst Root = ({\n  value: valueProp,\n  defaultValue = 0,\n  onValueChange,\n  asChild = false,\n  children,\n  ...props\n}: StickySectionRootProps) => {\n  const [activeIndex, setActiveIndex] = useControllableState({\n    prop: valueProp,\n    defaultProp: defaultValue,\n    onChange: onValueChange,\n  })\n\n  const panelRefs = useRef<Map<number, HTMLElement>>(new Map())\n  const isClickScrolling = useRef(false)\n  const ratioMap = useRef<Map<number, number>>(new Map())\n\n  const registerPanel = useCallback((index: number, el: HTMLElement | null) => {\n    if (el) {\n      panelRefs.current.set(index, el)\n    } else {\n      panelRefs.current.delete(index)\n    }\n  }, [])\n\n  const unregisterPanel = useCallback((index: number) => {\n    panelRefs.current.delete(index)\n  }, [])\n\n  const scrollToPanel = useCallback(\n    (index: number) => {\n      setActiveIndex(index)\n      isClickScrolling.current = true\n      const target = panelRefs.current.get(index)\n      if (target) {\n        target.scrollIntoView({ behavior: \"smooth\", block: \"start\" })\n        setTimeout(() => {\n          isClickScrolling.current = false\n        }, 800)\n      }\n    },\n    [setActiveIndex]\n  )\n\n  useEffect(() => {\n    const refs = Array.from(panelRefs.current.entries())\n      .sort(([a], [b]) => a - b)\n      .map(([, el]) => el)\n      .filter(Boolean)\n\n    if (refs.length === 0) {\n      return\n    }\n\n    const observer = new IntersectionObserver(\n      (entries) => {\n        if (isClickScrolling.current) {\n          return\n        }\n\n        for (const entry of entries) {\n          const index = Number((entry.target as HTMLElement).dataset.index)\n          if (!Number.isNaN(index)) {\n            ratioMap.current.set(index, entry.intersectionRatio)\n          }\n        }\n\n        let bestIndex = 0\n        let bestRatio = -1\n        for (const [idx, ratio] of ratioMap.current) {\n          if (ratio > bestRatio) {\n            bestRatio = ratio\n            bestIndex = idx\n          }\n        }\n\n        if (bestRatio > 0) {\n          setActiveIndex(bestIndex)\n        }\n      },\n      {\n        threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],\n      }\n    )\n\n    for (const ref of refs) {\n      observer.observe(ref)\n    }\n    return () => observer.disconnect()\n  }, [setActiveIndex])\n\n  const contextValue: StickySectionContextValue = {\n    activeIndex,\n    registerPanel,\n    unregisterPanel,\n    scrollToPanel,\n  }\n\n  const Comp = asChild ? Slot : \"div\"\n\n  return (\n    <StickySectionContext.Provider value={contextValue}>\n      <Comp data-slot=\"sticky-section-root\" {...props}>\n        {children}\n      </Comp>\n    </StickySectionContext.Provider>\n  )\n}\n\n/* -------------------------------------------------------------------------\n * List\n * ----------------------------------------------------------------------- */\n\nexport interface StickySectionListProps extends ComponentPropsWithoutRef<\"ul\"> {\n  asChild?: boolean\n}\n\nconst List = ({\n  asChild = false,\n  children,\n  ...props\n}: StickySectionListProps) => {\n  const Comp = asChild ? Slot : \"ul\"\n  return (\n    <Comp data-slot=\"sticky-section-list\" {...props}>\n      {children}\n    </Comp>\n  )\n}\n\n/* -------------------------------------------------------------------------\n * Item\n * ----------------------------------------------------------------------- */\n\nexport interface StickySectionItemProps extends ComponentPropsWithoutRef<\"li\"> {\n  /** Index of the panel this item corresponds to */\n  index: number\n  asChild?: boolean\n}\n\nconst Item = ({\n  index,\n  asChild = false,\n  children,\n  ...props\n}: StickySectionItemProps) => {\n  const { activeIndex } = useStickySection()\n  const Comp = asChild ? Slot : \"li\"\n\n  return (\n    <Comp\n      data-slot=\"sticky-section-item\"\n      data-state={activeIndex === index ? \"active\" : \"inactive\"}\n      {...props}\n    >\n      {children}\n    </Comp>\n  )\n}\n\n/* -------------------------------------------------------------------------\n * Trigger\n * ----------------------------------------------------------------------- */\n\nexport interface StickySectionTriggerProps\n  extends ComponentPropsWithoutRef<\"button\"> {\n  /** Index of the panel to scroll to when clicked */\n  index: number\n  asChild?: boolean\n}\n\nconst Trigger = (\n  {\n    index,\n    asChild = false,\n    onClick,\n    children,\n    ...props\n  }: StickySectionTriggerProps,\n  ref: ForwardedRef<HTMLButtonElement>\n) => {\n  const { activeIndex, scrollToPanel } = useStickySection()\n\n  const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n    scrollToPanel(index)\n    onClick?.(e)\n  }\n\n  const triggerProps = {\n    \"data-slot\": \"sticky-section-trigger\",\n    \"data-state\": activeIndex === index ? \"active\" : \"inactive\",\n    \"aria-current\": activeIndex === index ? (\"true\" as const) : undefined,\n    type: \"button\" as const,\n    onClick: handleClick,\n  }\n\n  if (asChild) {\n    return (\n      <Slot ref={ref} {...triggerProps} {...props}>\n        {children}\n      </Slot>\n    )\n  }\n\n  return (\n    <button ref={ref} {...triggerProps} {...props}>\n      {children}\n    </button>\n  )\n}\n\nconst TriggerWithRef = forwardRef(Trigger)\n\n/* -------------------------------------------------------------------------\n * Content\n * ----------------------------------------------------------------------- */\n\nexport interface StickySectionContentProps\n  extends ComponentPropsWithoutRef<\"div\"> {\n  asChild?: boolean\n}\n\nconst Content = ({\n  asChild = false,\n  children,\n  ...props\n}: StickySectionContentProps) => {\n  const Comp = asChild ? Slot : \"div\"\n  return (\n    <Comp data-slot=\"sticky-section-content\" {...props}>\n      {children}\n    </Comp>\n  )\n}\n\n/* -------------------------------------------------------------------------\n * Panel\n * ----------------------------------------------------------------------- */\n\nexport interface StickySectionPanelProps\n  extends ComponentPropsWithoutRef<\"div\"> {\n  /** Index of this panel for intersection tracking */\n  index: number\n  asChild?: boolean\n}\n\nconst Panel = (\n  { index, asChild = false, children, ...props }: StickySectionPanelProps,\n  forwardedRef: ForwardedRef<HTMLDivElement>\n) => {\n  const { registerPanel, unregisterPanel } = useStickySection()\n\n  const setRef = useCallback(\n    (el: HTMLDivElement | null) => {\n      registerPanel(index, el)\n      if (typeof forwardedRef === \"function\") {\n        forwardedRef(el)\n      } else if (forwardedRef) {\n        forwardedRef.current = el\n      }\n    },\n    [index, registerPanel, forwardedRef]\n  )\n\n  useEffect(() => {\n    return () => unregisterPanel(index)\n  }, [index, unregisterPanel])\n\n  const Comp = asChild ? Slot : \"div\"\n\n  return (\n    <Comp\n      data-index={index}\n      data-slot=\"sticky-section-panel\"\n      ref={setRef}\n      {...props}\n    >\n      {children}\n    </Comp>\n  )\n}\n\nconst PanelWithRef = forwardRef(Panel)\n\n/* -------------------------------------------------------------------------\n * Wrapper\n * ----------------------------------------------------------------------- */\n\nexport interface StickySectionWrapperProps\n  extends ComponentPropsWithoutRef<\"div\"> {}\n\nconst Wrapper = ({\n  className,\n  children,\n  ...props\n}: StickySectionWrapperProps) => (\n  <div\n    className={cn(\n      \"relative mx-auto max-w-[calc(-2rem+100vw)] overflow-x-clip border-border border-x\",\n      className\n    )}\n    {...props}\n  >\n    {children}\n  </div>\n)\n\n/* -------------------------------------------------------------------------\n * Namespace export\n * ----------------------------------------------------------------------- */\n\nexport const StickySection = {\n  Root,\n  List,\n  Item,\n  Trigger: TriggerWithRef,\n  Content,\n  Panel: PanelWithRef,\n  Wrapper,\n}\n\n/* -------------------------------------------------------------------------\n * OSSSection - Styled composition example\n * ----------------------------------------------------------------------- */\n\nexport interface OSSProject {\n  id: string\n  name: string\n  tagline: string\n  description: string\n  stars: string\n  contributors: string\n  exploreUrl: string\n  image: string\n  icon: ReactNode\n}\n\nexport interface OSSSectionProps {\n  /** Project items to display. Defaults to Vite, Vitest, Rolldown, Oxc. */\n  projects?: OSSProject[]\n}\n\nfunction ViteIcon({ className }: { className?: string }) {\n  const baseId = useId().replaceAll(\":\", \"\")\n  const gradientAId = `${baseId}-vite-a`\n  const gradientBId = `${baseId}-vite-b`\n\n  return (\n    <svg aria-hidden className={className} fill=\"none\" viewBox=\"0 0 24 24\">\n      <title>Vite</title>\n      <path\n        d=\"M21.805 2.472L12.36 21.1a.4.4 0 01-.72.002L2.197 2.474a.4.4 0 01.44-.575l9.28 1.8a.4.4 0 00.153 0l9.293-1.8a.4.4 0 01.442.573z\"\n        fill={`url(#${gradientAId})`}\n      />\n      <path\n        d=\"M16.326.06L9.3 1.43a.2.2 0 00-.16.186l-.895 9.94a.2.2 0 00.243.213l2.73-.595a.2.2 0 01.24.246l-.81 3.97a.2.2 0 00.248.24l1.687-.435a.2.2 0 01.248.24l-1.29 6.3c-.046.222.249.334.37.14L12.148 22l5.98-12.12a.2.2 0 00-.214-.283l-2.8.55a.2.2 0 01-.233-.258l1.68-7.6a.2.2 0 00-.234-.258z\"\n        fill={`url(#${gradientBId})`}\n      />\n      <defs>\n        <linearGradient\n          gradientUnits=\"userSpaceOnUse\"\n          id={gradientAId}\n          x1=\"1.646\"\n          x2=\"13.337\"\n          y1=\"1.384\"\n          y2=\"18.28\"\n        >\n          <stop stopColor=\"#41D1FF\" />\n          <stop offset=\"1\" stopColor=\"#BD34FE\" />\n        </linearGradient>\n        <linearGradient\n          gradientUnits=\"userSpaceOnUse\"\n          id={gradientBId}\n          x1=\"10.146\"\n          x2=\"13.146\"\n          y1=\"0\"\n          y2=\"15.18\"\n        >\n          <stop stopColor=\"#FFBD4F\" />\n          <stop offset=\"1\" stopColor=\"#FF9922\" />\n        </linearGradient>\n      </defs>\n    </svg>\n  )\n}\n\nfunction VitestIcon({ className }: { className?: string }) {\n  const baseId = useId().replaceAll(\":\", \"\")\n  const gradientAId = `${baseId}-vitest-a`\n\n  return (\n    <svg aria-hidden className={className} fill=\"none\" viewBox=\"0 0 24 24\">\n      <title>Vitest</title>\n      <path d=\"M5.4 18.6L12 22.8l6.6-4.2L12 3 5.4 18.6z\" fill=\"#FCC72B\" />\n      <path\n        d=\"M12 3l6.6 15.6L12 22.8 5.4 18.6 12 3z\"\n        fill={`url(#${gradientAId})`}\n      />\n      <path d=\"M6 17.4l4.2-8.1 3 5.1-1.5 2.1L6 17.4z\" fill=\"#22c55e\" />\n      <path\n        d=\"M18 17.4l-4.2-8.1-3 5.1 1.5 2.1L18 17.4z\"\n        fill=\"#22c55e\"\n        opacity=\"0.7\"\n      />\n      <defs>\n        <linearGradient\n          gradientUnits=\"userSpaceOnUse\"\n          id={gradientAId}\n          x1=\"5.4\"\n          x2=\"18.6\"\n          y1=\"3\"\n          y2=\"22.8\"\n        >\n          <stop stopColor=\"#41D1FF\" />\n          <stop offset=\"1\" stopColor=\"#22c55e\" />\n        </linearGradient>\n      </defs>\n    </svg>\n  )\n}\n\nfunction RolldownIcon({ className }: { className?: string }) {\n  return (\n    <svg aria-hidden className={className} fill=\"none\" viewBox=\"0 0 24 24\">\n      <title>Rolldown</title>\n      <circle cx=\"12\" cy=\"12\" fill=\"#f59e0b\" r=\"10\" />\n      <path\n        d=\"M8 8h8v2H8V8zm0 3h8v2H8v-2zm0 3h5v2H8v-2z\"\n        fill=\"#1a1a1a\"\n        opacity=\"0.8\"\n      />\n    </svg>\n  )\n}\n\nfunction OxcIcon({ className }: { className?: string }) {\n  return (\n    <svg aria-hidden className={className} fill=\"none\" viewBox=\"0 0 24 24\">\n      <title>Oxc</title>\n      <path d=\"M12 2L3 7v10l9 5 9-5V7l-9-5z\" fill=\"#32f3e9\" />\n      <path\n        d=\"M12 4.5L5.5 8v8l6.5 3.5L18.5 16V8L12 4.5z\"\n        fill=\"#1a1a1a\"\n        opacity=\"0.3\"\n      />\n    </svg>\n  )\n}\n\nexport const defaultOSSSectionProjects: OSSProject[] = [\n  {\n    id: \"vite\",\n    name: \"Vite\",\n    tagline: \"The build tool for the web\",\n    description:\n      \"Vite is the default choice for single-page web applications and the foundation for fullstack frameworks like TanStack Start, Nuxt, SvelteKit and more.\",\n    stars: \"78.3k\",\n    contributors: \"1,235\",\n    exploreUrl: \"https://vite.dev\",\n    image: \"/images/vite-terminal.jpg\",\n    icon: <ViteIcon className=\"size-6\" />,\n  },\n  {\n    id: \"vitest\",\n    name: \"Vitest\",\n    tagline: \"The next-generation test runner\",\n    description:\n      \"Vitest is a feature-rich test runner that understands your Vite config, is Jest-compatible, and works out-of-the-box with TypeScript & ESM.\",\n    stars: \"16.0k\",\n    contributors: \"713\",\n    exploreUrl: \"https://vitest.dev\",\n    image: \"/images/vitest-terminal.jpg\",\n    icon: <VitestIcon className=\"size-6\" />,\n  },\n  {\n    id: \"rolldown\",\n    name: \"Rolldown\",\n    tagline: \"The blazing fast JavaScript bundler\",\n    description:\n      \"Rolldown is a Rust-based bundler with Rollup-compatible API, and esbuild-equivalent performance & feature set. It also powers Vite version 8 and above.\",\n    stars: \"12.9k\",\n    contributors: \"152\",\n    exploreUrl: \"https://rolldown.rs\",\n    image: \"/images/rolldown-terminal.jpg\",\n    icon: <RolldownIcon className=\"size-6\" />,\n  },\n  {\n    id: \"oxc\",\n    name: \"Oxc\",\n    tagline: \"The fastest JavaScript language toolchain\",\n    description:\n      \"Oxc is the foundation of our unified toolchain. It includes linter (oxlint), formatter (oxfmt), parser, resolver, transformer, and minifier, all with state-of-the-art performance.\",\n    stars: \"19.1k\",\n    contributors: \"314\",\n    exploreUrl: \"https://oxc.rs\",\n    image: \"/images/oxc-terminal.jpg\",\n    icon: <OxcIcon className=\"size-6\" />,\n  },\n]\n\nfunction GithubIcon({ className }: { className?: string }) {\n  return (\n    <svg\n      aria-hidden\n      className={className}\n      fill=\"currentColor\"\n      viewBox=\"0 0 20 20\"\n    >\n      <title>GitHub</title>\n      <path\n        clipRule=\"evenodd\"\n        d=\"M10 0C4.477 0 0 4.477 0 10c0 4.42 2.865 8.17 6.839 9.49.5.09.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.604-3.369-1.34-3.369-1.34-.454-1.156-1.11-1.462-1.11-1.462-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.831.092-.646.35-1.086.636-1.336-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0110 4.836c.85.004 1.705.115 2.504.337 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.203 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.578.688.48C17.138 18.165 20 14.418 20 10c0-5.523-4.477-10-10-10z\"\n        fillRule=\"evenodd\"\n      />\n    </svg>\n  )\n}\n\nexport interface OSSSectionContainerProps\n  extends ComponentPropsWithoutRef<\"section\"> {}\n\nfunction OSSSectionContainer({\n  className,\n  children,\n  ...props\n}: OSSSectionContainerProps) {\n  return (\n    <section\n      data-slot=\"oss-section-container\"\n      className={cn(\"flex border-border/50 border-t\", className)}\n      {...props}\n    >\n      {children}\n    </section>\n  )\n}\n\nexport interface OSSSectionSidebarProps\n  extends ComponentPropsWithoutRef<\"div\"> {}\n\nfunction OSSSectionSidebar({\n  className,\n  children,\n  ...props\n}: OSSSectionSidebarProps) {\n  return (\n    <div\n      data-slot=\"oss-section-sidebar\"\n      className={cn(\n        \"sticky top-0 hidden w-72 shrink-0 flex-col self-start p-10 md:flex\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </div>\n  )\n}\n\nexport interface OSSSectionSidebarListProps\n  extends ComponentPropsWithoutRef<\"ul\"> {}\n\nfunction OSSSectionSidebarList({\n  className,\n  children,\n  ...props\n}: OSSSectionSidebarListProps) {\n  return (\n    <ul\n      data-slot=\"oss-section-sidebar-list\"\n      className={cn(\"flex flex-col gap-4\", className)}\n      {...props}\n    >\n      {children}\n    </ul>\n  )\n}\n\nexport interface OSSSectionSidebarItemProps\n  extends ComponentPropsWithoutRef<\"li\"> {}\n\nfunction OSSSectionSidebarItem({\n  className,\n  children,\n  ...props\n}: OSSSectionSidebarItemProps) {\n  return (\n    <li\n      data-slot=\"oss-section-sidebar-item\"\n      className={cn(\n        \"transition-all duration-500 ease-out data-[state=active]:opacity-100 data-[state=inactive]:opacity-40 data-[state=inactive]:grayscale\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </li>\n  )\n}\n\nexport interface OSSSectionPanelsProps\n  extends ComponentPropsWithoutRef<\"div\"> {}\n\nfunction OSSSectionPanels({\n  className,\n  children,\n  ...props\n}: OSSSectionPanelsProps) {\n  return (\n    <div\n      data-slot=\"oss-section-panels\"\n      className={cn(\"w-full border-border/50 md:border-l\", className)}\n      {...props}\n    >\n      {children}\n    </div>\n  )\n}\n\nexport interface OSSSectionPanelGridProps\n  extends ComponentPropsWithoutRef<\"div\"> {\n  withBottomBorder?: boolean\n}\n\nfunction OSSSectionPanelGrid({\n  className,\n  withBottomBorder = false,\n  children,\n  ...props\n}: OSSSectionPanelGridProps) {\n  return (\n    <div\n      data-slot=\"oss-section-panel-grid\"\n      className={cn(\n        \"grid w-full lg:grid-cols-2\",\n        withBottomBorder && \"border-border/50 border-b\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </div>\n  )\n}\n\nexport interface OSSSectionPanelContentProps\n  extends ComponentPropsWithoutRef<\"div\"> {}\n\nfunction OSSSectionPanelContent({\n  className,\n  children,\n  ...props\n}: OSSSectionPanelContentProps) {\n  return (\n    <div\n      data-slot=\"oss-section-panel-content\"\n      className={cn(\n        \"flex flex-col justify-between gap-10 p-8 lg:gap-20 lg:p-10\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </div>\n  )\n}\n\nexport interface OSSSectionPanelImageProps\n  extends Omit<ComponentPropsWithoutRef<typeof NextImage>, \"alt\" | \"src\"> {\n  src: string\n  alt: string\n}\n\nfunction OSSSectionPanelImage({\n  className,\n  src,\n  alt,\n  ...props\n}: OSSSectionPanelImageProps) {\n  return (\n    <div\n      data-slot=\"oss-section-panel-image-wrap\"\n      className=\"relative overflow-hidden border-border/50 border-t lg:border-t-0 lg:border-l\"\n    >\n      <NextImage\n        alt={alt}\n        className={cn(\"h-full w-full object-cover\", className)}\n        fill\n        sizes=\"(max-width: 1024px) 100vw, 50vw\"\n        src={src}\n        {...props}\n      />\n    </div>\n  )\n}\n\nexport function OSSSection({\n  projects = defaultOSSSectionProjects,\n}: OSSSectionProps) {\n  return (\n    <StickySection.Root>\n      <OSSSectionContainer>\n        <OSSSectionSidebar>\n          <StickySection.List asChild>\n            <OSSSectionSidebarList>\n              {projects.map((project, i) => (\n                <StickySection.Item asChild index={i} key={project.id}>\n                  <OSSSectionSidebarItem>\n                    <StickySection.Trigger\n                      className=\"flex cursor-pointer items-center gap-4 border-none bg-transparent p-0 text-base text-foreground\"\n                      index={i}\n                    >\n                      {project.icon}\n                      {project.name}\n                    </StickySection.Trigger>\n                  </OSSSectionSidebarItem>\n                </StickySection.Item>\n              ))}\n            </OSSSectionSidebarList>\n          </StickySection.List>\n        </OSSSectionSidebar>\n\n        <StickySection.Content asChild>\n          <OSSSectionPanels>\n            {projects.map((project, i) => (\n              <StickySection.Panel asChild index={i} key={project.id}>\n                <OSSSectionPanelGrid withBottomBorder={i < projects.length - 1}>\n                  <OSSSectionPanelContent>\n                    <div className=\"flex max-w-80 flex-col gap-5\">\n                      <span className=\"font-mono text-grey text-xs uppercase tracking-wide\">\n                        {project.name}\n                      </span>\n                      <h4 className=\"text-pretty font-semibold text-2xl text-foreground lg:text-3xl\">\n                        {project.tagline}\n                      </h4>\n                      <p className=\"max-w-100 text-base text-foreground/70 leading-relaxed\">\n                        {project.description}\n                      </p>\n                      <a\n                        className=\"mt-2 inline-flex w-fit items-center gap-2 rounded-lg border border-border/80 bg-transparent px-5 py-2.5 font-medium text-foreground text-sm transition-colors hover:bg-foreground/5\"\n                        href={project.exploreUrl}\n                        rel=\"noopener noreferrer\"\n                        target=\"_blank\"\n                      >\n                        Explore {project.name}\n                      </a>\n                    </div>\n\n                    <div className=\"flex items-center gap-6 text-sm\">\n                      <div className=\"flex items-center gap-2\">\n                        <GithubIcon className=\"size-5 text-grey\" />\n                        <span className=\"font-semibold text-foreground\">\n                          {project.stars}\n                        </span>\n                        <span className=\"text-grey\">stars</span>\n                      </div>\n                      <div className=\"flex items-center gap-2\">\n                        <span className=\"font-semibold text-foreground\">\n                          {project.contributors}\n                        </span>\n                        <span className=\"text-grey\">contributors</span>\n                      </div>\n                    </div>\n                  </OSSSectionPanelContent>\n\n                  <OSSSectionPanelImage\n                    alt={`${project.name} terminal output`}\n                    src={project.image}\n                  />\n                </OSSSectionPanelGrid>\n              </StickySection.Panel>\n            ))}\n          </OSSSectionPanels>\n        </StickySection.Content>\n      </OSSSectionContainer>\n    </StickySection.Root>\n  )\n}\n\nexport const OSSSectionComponents = {\n  Container: OSSSectionContainer,\n  Sidebar: OSSSectionSidebar,\n  SidebarList: OSSSectionSidebarList,\n  SidebarItem: OSSSectionSidebarItem,\n  Panels: OSSSectionPanels,\n  PanelGrid: OSSSectionPanelGrid,\n  PanelContent: OSSSectionPanelContent,\n  PanelImage: OSSSectionPanelImage,\n}\n",
      "type": "registry:ui"
    }
  ]
}