"use client"; import clsx from "clsx"; import { AnimatePresence, motion, useIsPresent } from "framer-motion"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useRef } from "react"; import { remToPx } from "@/lib/remToPx"; import { Button } from "./Button"; import { useIsInsideMobileNavigation } from "./MobileNavigation"; import { useSectionStore } from "./SectionProvider"; import { Tag } from "./Tag"; interface NavGroup { title: string; links: Array<{ title: string; href: string; }>; } function useInitialValue(value: T, condition = true) { let initialValue = useRef(value).current; return condition ? initialValue : value; } function TopLevelNavItem({ href, children }: { href: string; children: React.ReactNode }) { return (
  • {children}
  • ); } function NavLink({ href, children, tag, active = false, isAnchorLink = false, }: { href: string; children: React.ReactNode; tag?: string; active?: boolean; isAnchorLink?: boolean; }) { return ( {children} {tag && ( {tag} )} ); } function VisibleSectionHighlight({ group, pathname }: { group: NavGroup; pathname: string }) { let [sections, visibleSections] = useInitialValue( [useSectionStore((s) => s.sections), useSectionStore((s) => s.visibleSections)], useIsInsideMobileNavigation() ); let isPresent = useIsPresent(); let firstVisibleSectionIndex = Math.max( 0, [{ id: "_top" }, ...sections].findIndex((section) => section.id === visibleSections[0]) ); let itemHeight = remToPx(2); let height = isPresent ? Math.max(1, visibleSections.length) * itemHeight : itemHeight; let top = group.links.findIndex((link) => link.href === pathname) * itemHeight + firstVisibleSectionIndex * itemHeight; return ( ); } function ActivePageMarker({ group, pathname }: { group: NavGroup; pathname: string }) { let itemHeight = remToPx(2); let offset = remToPx(0.25); let activePageIndex = group.links.findIndex((link) => link.href === pathname); let top = offset + activePageIndex * itemHeight; return ( ); } function NavigationGroup({ group, className }: { group: NavGroup; className?: string }) { // If this is the mobile navigation then we always render the initial // state, so that the state does not change during the close animation. // The state will still update when we re-open (re-render) the navigation. let isInsideMobileNavigation = useIsInsideMobileNavigation(); let [pathname, sections] = useInitialValue( [usePathname(), useSectionStore((s) => s.sections)], isInsideMobileNavigation ); let isActiveGroup = group.links.findIndex((link) => link.href === pathname) !== -1; return (
  • {group.title}
    {isActiveGroup && } {isActiveGroup && }
      {group.links.map((link) => ( {link.title} {link.href === pathname && sections.length > 0 && ( {sections.map((section) => (
    • {section.title}
    • ))}
      )}
      ))}
  • ); } export const navigation: Array = [ { title: "Introduction", links: [ { title: "What is Formbricks?", href: "/docs/introduction/what-is-formbricks" }, { title: "Why is it better?", href: "/docs/introduction/why-is-it-better" }, { title: "How does it work?", href: "/docs/introduction/how-it-works" }, ], }, { title: "Getting Started", links: [ { title: "Quickstart: In app", href: "/docs/getting-started/quickstart-in-app-survey" }, { title: "Framework Guides", href: "/docs/getting-started/framework-guides" }, { title: "Troubleshooting", href: "/docs/getting-started/troubleshooting" }, ], }, { title: "Attributes", links: [ { title: "Why Attributes?", href: "/docs/attributes/why" }, { title: "Custom Attributes", href: "/docs/attributes/custom-attributes" }, { title: "Identify users", href: "/docs/attributes/identify-users" }, ], }, { title: "Actions", links: [ { title: "Why Actions?", href: "/docs/actions/why" }, { title: "No-Code Actions", href: "/docs/actions/no-code" }, { title: "Code Actions", href: "/docs/actions/code" }, ], }, { title: "Link Surveys", links: [ { title: "Data Prefilling", href: "/docs/link-surveys/data-prefilling" }, { title: "Identify Users", href: "/docs/link-surveys/user-identification" }, { title: "Single Use Links", href: "/docs/link-surveys/single-use-links" }, ], }, { title: "Best Practices", links: [ { title: "Learn from Churn", href: "/docs/best-practices/cancel-subscription" }, { title: "Interview Prompt", href: "/docs/best-practices/interview-prompt" }, { title: "Product-Market Fit", href: "/docs/best-practices/pmf-survey" }, { title: "Trial Conversion", href: "/docs/best-practices/improve-trial-cr" }, { title: "Feature Chaser", href: "/docs/best-practices/feature-chaser" }, { title: "Feedback Box", href: "/docs/best-practices/feedback-box" }, { title: "Docs Feedback", href: "/docs/best-practices/docs-feedback" }, ], }, { title: "Integrations", links: [ { title: "Airtable", href: "/docs/integrations/airtable" }, { title: "Google Sheets", href: "/docs/integrations/google-sheets" }, { title: "Make.com", href: "/docs/integrations/make" }, { title: "n8n", href: "/docs/integrations/n8n" }, { title: "Zapier", href: "/docs/integrations/zapier" }, ], }, { title: "Self-hosting", links: [ { title: "Introduction", href: "/docs/self-hosting/deployment" }, { title: "One-Click Setup", href: "/docs/self-hosting/production" }, { title: "Advanced Setup", href: "/docs/self-hosting/docker" }, { title: "Configure", href: "/docs/self-hosting/external-auth-providers" }, { title: "Migration Guide", href: "/docs/self-hosting/migration-guide" }, ], }, { title: "Contributing", links: [ { title: "Introduction", href: "/docs/contributing/introduction" }, { title: "Demo App", href: "/docs/contributing/demo" }, { title: "Setup Dev Environment", href: "/docs/contributing/setup" }, { title: "How we code at Formbricks", href: "/docs/contributing/how-we-code" }, { title: "How to create a service", href: "/docs/contributing/creating-a-service" }, { title: "Troubleshooting", href: "/docs/contributing/troubleshooting" }, { title: "FAQ", href: "/docs/faq" }, ], }, { title: "Client API", links: [ { title: "Overview", href: "/docs/api/client/overview" }, { title: "Actions", href: "/docs/api/client/actions" }, { title: "Displays", href: "/docs/api/client/displays" }, { title: "People", href: "/docs/api/client/people" }, { title: "Responses", href: "/docs/api/client/responses" }, ], }, { title: "Management API", links: [ { title: "API Key Setup", href: "/docs/api/management/api-key-setup" }, { title: "Action Classes", href: "/docs/api/management/action-classes" }, { title: "Attribute Classes", href: "/docs/api/management/attribute-classes" }, { title: "Me", href: "/docs/api/management/me" }, { title: "People", href: "/docs/api/management/people" }, { title: "Surveys", href: "/docs/api/management/surveys" }, { title: "Webhooks", href: "/docs/api/management/webhooks" }, ], }, ]; export function Navigation(props: React.ComponentPropsWithoutRef<"nav">) { return ( ); }