setIsMenuOpen(false)}
+ />
+
>
);
}
+
+function MobileMenuLinks({
+ isProductOpen,
+ setIsProductOpen,
+ setIsMenuOpen,
+}: {
+ isProductOpen: boolean;
+ setIsProductOpen: (open: boolean) => void;
+ setIsMenuOpen: (open: boolean) => void;
+}) {
+ return (
+
+
+ setIsMenuOpen(false)}
+ className="block text-base text-neutral-700 hover:text-neutral-900 transition-colors"
+ >
+ Docs
+
+ setIsMenuOpen(false)}
+ className="block text-base text-neutral-700 hover:text-neutral-900 transition-colors"
+ >
+ Blog
+
+ setIsMenuOpen(false)}
+ className="block text-base text-neutral-700 hover:text-neutral-900 transition-colors"
+ >
+ Pricing
+
+ setIsMenuOpen(false)}
+ className="block text-base text-neutral-700 hover:text-neutral-900 transition-colors"
+ >
+ Enterprise
+
+
+ );
+}
+
+function MobileProductSection({
+ isProductOpen,
+ setIsProductOpen,
+ setIsMenuOpen,
+}: {
+ isProductOpen: boolean;
+ setIsProductOpen: (open: boolean) => void;
+ setIsMenuOpen: (open: boolean) => void;
+}) {
+ return (
+
+
+ {isProductOpen && (
+
+
+
+
+ )}
+
+ );
+}
+
+function MobileProductsList({
+ setIsMenuOpen,
+}: {
+ setIsMenuOpen: (open: boolean) => void;
+}) {
+ return (
+
+
+ Products
+
+ {productsList.map((link) => (
+
setIsMenuOpen(false)}
+ className="text-sm text-neutral-600 hover:text-neutral-900 transition-colors flex items-center justify-between py-1"
+ >
+
{link.label}
+ {link.badge && (
+
+ {link.badge}
+
+ )}
+
+ ))}
+
+ );
+}
+
+function MobileFeaturesList({
+ setIsMenuOpen,
+}: {
+ setIsMenuOpen: (open: boolean) => void;
+}) {
+ return (
+
+
+ Features
+
+ {featuresList.map((link) => (
+
setIsMenuOpen(false)}
+ className="text-sm text-neutral-600 hover:text-neutral-900 transition-colors flex items-center justify-between py-1"
+ >
+
{link.label}
+ {link.badge && (
+
+ {link.badge}
+
+ )}
+
+ ))}
+
+ );
+}
+
+function MobileMenuCTAs({
+ platform,
+ platformCTA,
+ setIsMenuOpen,
+}: {
+ platform: string;
+ platformCTA: ReturnType
;
+ setIsMenuOpen: (open: boolean) => void;
+}) {
+ return (
+
+ );
+}
diff --git a/apps/web/src/components/sidebar-navigation.tsx b/apps/web/src/components/sidebar-navigation.tsx
new file mode 100644
index 0000000000..593c3ade7b
--- /dev/null
+++ b/apps/web/src/components/sidebar-navigation.tsx
@@ -0,0 +1,71 @@
+import { Link } from "@tanstack/react-router";
+import { useEffect, useRef } from "react";
+
+export function SidebarNavigation({
+ sections,
+ currentSlug,
+ onLinkClick,
+ scrollContainerRef,
+ linkTo,
+}: {
+ sections: { title: string; docs: T[] }[];
+ currentSlug: string | undefined;
+ onLinkClick?: () => void;
+ scrollContainerRef?: React.RefObject;
+ linkTo: string;
+}) {
+ const activeLinkRef = useRef(null);
+
+ useEffect(() => {
+ if (activeLinkRef.current && scrollContainerRef?.current) {
+ const container = scrollContainerRef.current;
+ const activeLink = activeLinkRef.current;
+
+ requestAnimationFrame(() => {
+ const containerRect = container.getBoundingClientRect();
+ const linkRect = activeLink.getBoundingClientRect();
+
+ const scrollTop =
+ activeLink.offsetTop -
+ container.offsetTop -
+ containerRect.height / 2 +
+ linkRect.height / 2;
+
+ container.scrollTop = scrollTop;
+ });
+ }
+ }, [currentSlug, scrollContainerRef]);
+
+ return (
+
+ );
+}
diff --git a/apps/web/src/hooks/use-handbook-drawer.ts b/apps/web/src/hooks/use-handbook-drawer.ts
new file mode 100644
index 0000000000..eb0540a1c0
--- /dev/null
+++ b/apps/web/src/hooks/use-handbook-drawer.ts
@@ -0,0 +1,13 @@
+import { createContext, useContext } from "react";
+
+interface HandbookDrawerContextType {
+ isOpen: boolean;
+ setIsOpen: (open: boolean) => void;
+}
+
+export const HandbookDrawerContext =
+ createContext(null);
+
+export function useHandbookDrawer() {
+ return useContext(HandbookDrawerContext);
+}
diff --git a/apps/web/src/routeTree.gen.ts b/apps/web/src/routeTree.gen.ts
index 0dd2a7b37c..5fd76a3fa6 100644
--- a/apps/web/src/routeTree.gen.ts
+++ b/apps/web/src/routeTree.gen.ts
@@ -31,7 +31,6 @@ import { Route as ViewOssFriendsRouteImport } from './routes/_view/oss-friends'
import { Route as ViewOpensourceRouteImport } from './routes/_view/opensource'
import { Route as ViewFreeRouteImport } from './routes/_view/free'
import { Route as ViewFileTranscriptionRouteImport } from './routes/_view/file-transcription'
-import { Route as ViewFaqRouteImport } from './routes/_view/faq'
import { Route as ViewEnterpriseRouteImport } from './routes/_view/enterprise'
import { Route as ViewBrandRouteImport } from './routes/_view/brand'
import { Route as ViewAboutRouteImport } from './routes/_view/about'
@@ -199,11 +198,6 @@ const ViewFileTranscriptionRoute = ViewFileTranscriptionRouteImport.update({
path: '/file-transcription',
getParentRoute: () => ViewRouteRoute,
} as any)
-const ViewFaqRoute = ViewFaqRouteImport.update({
- id: '/faq',
- path: '/faq',
- getParentRoute: () => ViewRouteRoute,
-} as any)
const ViewEnterpriseRoute = ViewEnterpriseRouteImport.update({
id: '/enterprise',
path: '/enterprise',
@@ -514,7 +508,6 @@ export interface FileRoutesByFullPath {
'/about': typeof ViewAboutRoute
'/brand': typeof ViewBrandRoute
'/enterprise': typeof ViewEnterpriseRoute
- '/faq': typeof ViewFaqRoute
'/file-transcription': typeof ViewFileTranscriptionRoute
'/free': typeof ViewFreeRoute
'/opensource': typeof ViewOpensourceRoute
@@ -592,7 +585,6 @@ export interface FileRoutesByTo {
'/about': typeof ViewAboutRoute
'/brand': typeof ViewBrandRoute
'/enterprise': typeof ViewEnterpriseRoute
- '/faq': typeof ViewFaqRoute
'/file-transcription': typeof ViewFileTranscriptionRoute
'/free': typeof ViewFreeRoute
'/opensource': typeof ViewOpensourceRoute
@@ -675,7 +667,6 @@ export interface FileRoutesById {
'/_view/about': typeof ViewAboutRoute
'/_view/brand': typeof ViewBrandRoute
'/_view/enterprise': typeof ViewEnterpriseRoute
- '/_view/faq': typeof ViewFaqRoute
'/_view/file-transcription': typeof ViewFileTranscriptionRoute
'/_view/free': typeof ViewFreeRoute
'/_view/opensource': typeof ViewOpensourceRoute
@@ -758,7 +749,6 @@ export interface FileRouteTypes {
| '/about'
| '/brand'
| '/enterprise'
- | '/faq'
| '/file-transcription'
| '/free'
| '/opensource'
@@ -836,7 +826,6 @@ export interface FileRouteTypes {
| '/about'
| '/brand'
| '/enterprise'
- | '/faq'
| '/file-transcription'
| '/free'
| '/opensource'
@@ -918,7 +907,6 @@ export interface FileRouteTypes {
| '/_view/about'
| '/_view/brand'
| '/_view/enterprise'
- | '/_view/faq'
| '/_view/file-transcription'
| '/_view/free'
| '/_view/opensource'
@@ -1158,13 +1146,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ViewFileTranscriptionRouteImport
parentRoute: typeof ViewRouteRoute
}
- '/_view/faq': {
- id: '/_view/faq'
- path: '/faq'
- fullPath: '/faq'
- preLoaderRoute: typeof ViewFaqRouteImport
- parentRoute: typeof ViewRouteRoute
- }
'/_view/enterprise': {
id: '/_view/enterprise'
path: '/enterprise'
@@ -1636,7 +1617,6 @@ interface ViewRouteRouteChildren {
ViewAboutRoute: typeof ViewAboutRoute
ViewBrandRoute: typeof ViewBrandRoute
ViewEnterpriseRoute: typeof ViewEnterpriseRoute
- ViewFaqRoute: typeof ViewFaqRoute
ViewFileTranscriptionRoute: typeof ViewFileTranscriptionRoute
ViewFreeRoute: typeof ViewFreeRoute
ViewOpensourceRoute: typeof ViewOpensourceRoute
@@ -1694,7 +1674,6 @@ const ViewRouteRouteChildren: ViewRouteRouteChildren = {
ViewAboutRoute: ViewAboutRoute,
ViewBrandRoute: ViewBrandRoute,
ViewEnterpriseRoute: ViewEnterpriseRoute,
- ViewFaqRoute: ViewFaqRoute,
ViewFileTranscriptionRoute: ViewFileTranscriptionRoute,
ViewFreeRoute: ViewFreeRoute,
ViewOpensourceRoute: ViewOpensourceRoute,
diff --git a/apps/web/src/routes/_view/company-handbook/route.tsx b/apps/web/src/routes/_view/company-handbook/route.tsx
index 36ef19c14c..f6c71b0fc1 100644
--- a/apps/web/src/routes/_view/company-handbook/route.tsx
+++ b/apps/web/src/routes/_view/company-handbook/route.tsx
@@ -1,11 +1,8 @@
-import {
- createFileRoute,
- Link,
- Outlet,
- useMatchRoute,
-} from "@tanstack/react-router";
+import { createFileRoute, Outlet, useMatchRoute } from "@tanstack/react-router";
import { allHandbooks } from "content-collections";
-import { useMemo } from "react";
+import { useMemo, useRef } from "react";
+
+import { SidebarNavigation } from "@/components/sidebar-navigation";
import { handbookStructure } from "./-structure";
@@ -72,34 +69,20 @@ function LeftSidebar() {
return { sections };
}, []);
+ const scrollContainerRef = useRef(null);
+
return (