Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
627 changes: 331 additions & 296 deletions apps/web/src/components/footer.tsx

Large diffs are not rendered by default.

860 changes: 560 additions & 300 deletions apps/web/src/components/header.tsx

Large diffs are not rendered by default.

71 changes: 71 additions & 0 deletions apps/web/src/components/sidebar-navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Link } from "@tanstack/react-router";
import { useEffect, useRef } from "react";

export function SidebarNavigation<T extends { slug: string; title: string }>({
sections,
currentSlug,
onLinkClick,
scrollContainerRef,
linkTo,
}: {
sections: { title: string; docs: T[] }[];
currentSlug: string | undefined;
onLinkClick?: () => void;
scrollContainerRef?: React.RefObject<HTMLDivElement | null>;
linkTo: string;
}) {
const activeLinkRef = useRef<HTMLAnchorElement>(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 (
<nav className="space-y-4">
{sections.map((section) => (
<div key={section.title}>
<h3 className="px-3 text-sm font-semibold text-neutral-700 mb-2">
{section.title}
</h3>
<div className="space-y-0.5">
{section.docs.map((doc) => {
const isActive = currentSlug === doc.slug;
return (
<Link
key={doc.slug}
to={linkTo}
params={{ _splat: doc.slug }}
onClick={onLinkClick}
ref={isActive ? activeLinkRef : undefined}
className={`block pl-5 pr-3 py-1.5 text-sm rounded-sm transition-colors ${
isActive
? "bg-neutral-100 text-stone-600 font-medium"
: "text-neutral-600 hover:text-stone-600 hover:bg-neutral-50"
}`}
>
{doc.title}
</Link>
);
})}
</div>
</div>
))}
</nav>
);
}
13 changes: 13 additions & 0 deletions apps/web/src/hooks/use-handbook-drawer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { createContext, useContext } from "react";

interface HandbookDrawerContextType {
isOpen: boolean;
setIsOpen: (open: boolean) => void;
}

export const HandbookDrawerContext =
createContext<HandbookDrawerContextType | null>(null);

export function useHandbookDrawer() {
return useContext(HandbookDrawerContext);
}
21 changes: 0 additions & 21 deletions apps/web/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -758,7 +749,6 @@ export interface FileRouteTypes {
| '/about'
| '/brand'
| '/enterprise'
| '/faq'
| '/file-transcription'
| '/free'
| '/opensource'
Expand Down Expand Up @@ -836,7 +826,6 @@ export interface FileRouteTypes {
| '/about'
| '/brand'
| '/enterprise'
| '/faq'
| '/file-transcription'
| '/free'
| '/opensource'
Expand Down Expand Up @@ -918,7 +907,6 @@ export interface FileRouteTypes {
| '/_view/about'
| '/_view/brand'
| '/_view/enterprise'
| '/_view/faq'
| '/_view/file-transcription'
| '/_view/free'
| '/_view/opensource'
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1694,7 +1674,6 @@ const ViewRouteRouteChildren: ViewRouteRouteChildren = {
ViewAboutRoute: ViewAboutRoute,
ViewBrandRoute: ViewBrandRoute,
ViewEnterpriseRoute: ViewEnterpriseRoute,
ViewFaqRoute: ViewFaqRoute,
ViewFileTranscriptionRoute: ViewFileTranscriptionRoute,
ViewFreeRoute: ViewFreeRoute,
ViewOpensourceRoute: ViewOpensourceRoute,
Expand Down
49 changes: 16 additions & 33 deletions apps/web/src/routes/_view/company-handbook/route.tsx
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -72,34 +69,20 @@ function LeftSidebar() {
return { sections };
}, []);

const scrollContainerRef = useRef<HTMLDivElement>(null);

return (
<aside className="hidden md:block w-64 shrink-0">
<div className="sticky top-[69px] max-h-[calc(100vh-69px)] overflow-y-auto scrollbar-hide space-y-6 px-4 py-6">
<nav className="space-y-4">
{handbooksBySection.sections.map((section) => (
<div key={section.title}>
<h3 className="px-3 text-sm font-semibold text-neutral-700 mb-2">
{section.title}
</h3>
<div className="space-y-0.5">
{section.docs.map((doc) => (
<Link
key={doc.slug}
to="/company-handbook/$"
params={{ _splat: doc.slug }}
className={`block pl-5 pr-3 py-1.5 text-sm rounded-sm transition-colors ${
currentSlug === doc.slug
? "bg-neutral-100 text-stone-600 font-medium"
: "text-neutral-600 hover:text-stone-600 hover:bg-neutral-50"
}`}
>
{doc.title}
</Link>
))}
</div>
</div>
))}
</nav>
<div
ref={scrollContainerRef}
className="sticky top-[69px] max-h-[calc(100vh-69px)] overflow-y-auto scrollbar-hide space-y-6 px-4 py-6"
>
<SidebarNavigation
sections={handbooksBySection.sections}
currentSlug={currentSlug}
scrollContainerRef={scrollContainerRef}
linkTo="/company-handbook/$"
/>
</div>
</aside>
);
Expand Down
43 changes: 43 additions & 0 deletions apps/web/src/routes/_view/docs/-structure.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { allDocs } from "content-collections";

export const docsStructure = {
sections: ["about", "developers", "pro", "faq"],
defaultPages: {
Expand All @@ -7,3 +9,44 @@ export const docsStructure = {
faq: "faq/general",
} as Record<string, string>,
};

export function getDocsBySection() {
const sectionGroups: Record<
string,
{ title: string; docs: (typeof allDocs)[0][] }
> = {};

allDocs.forEach((doc) => {
if (doc.slug === "index" || doc.isIndex) {
return;
}

const sectionName = doc.section;

if (!sectionGroups[sectionName]) {
sectionGroups[sectionName] = {
title: sectionName,
docs: [],
};
}

sectionGroups[sectionName].docs.push(doc);
});

Object.keys(sectionGroups).forEach((sectionName) => {
sectionGroups[sectionName].docs.sort((a, b) => a.order - b.order);
});

const sections = docsStructure.sections
.map((sectionId) => {
return Object.values(sectionGroups).find(
(group) => group.title.toLowerCase() === sectionId.toLowerCase(),
);
})
.filter(
(section): section is NonNullable<typeof section> =>
section !== undefined,
);

return { sections };
}
Loading