From cc0fd80c0e5545a86b0c62a08dcfaf4082658bf4 Mon Sep 17 00:00:00 2001 From: Andrew Jiang Date: Fri, 21 Jun 2024 20:11:30 -0400 Subject: [PATCH] fix: support for tabbed changelog (#1065) --- .../fdr-sdk/src/navigation/NodeCollector.ts | 11 +++- .../types/NavigationNodeNeighbor.ts | 9 +++- .../fdr-sdk/src/navigation/utils/findNode.ts | 18 +++++-- .../PlaygroundEndpointSelectorContent.tsx | 5 +- .../ui/app/src/docs/ChangelogEntryPage.tsx | 29 +++++----- packages/ui/app/src/docs/ChangelogPage.tsx | 53 +++++++++++-------- packages/ui/app/src/docs/Docs.tsx | 37 ++++++------- packages/ui/app/src/next-app/DocsPage.tsx | 2 +- packages/ui/app/src/search/SearchDialog.tsx | 7 ++- .../src/sidebar/CollapseSidebarContext.tsx | 13 +++-- .../app/src/sidebar/nodes/SidebarRootNode.tsx | 4 +- 11 files changed, 115 insertions(+), 73 deletions(-) diff --git a/packages/fdr-sdk/src/navigation/NodeCollector.ts b/packages/fdr-sdk/src/navigation/NodeCollector.ts index 6ad1342d4c..5bc81ab2a3 100644 --- a/packages/fdr-sdk/src/navigation/NodeCollector.ts +++ b/packages/fdr-sdk/src/navigation/NodeCollector.ts @@ -22,11 +22,15 @@ interface NavigationNodeWithMetadataAndParents { const NodeCollectorInstances = new WeakMap(); export class NodeCollector { + private static readonly EMPTY = new NodeCollector(undefined); private idToNode = new Map(); private slugToNode: Record = {}; private orphanedNodes: NavigationNodeWithMetadata[] = []; - public static collect(rootNode: NavigationNode): NodeCollector { + public static collect(rootNode: NavigationNode | undefined): NodeCollector { + if (rootNode == null) { + return NodeCollector.EMPTY; + } const existing = NodeCollectorInstances.get(rootNode); if (existing != null) { return existing; @@ -52,7 +56,10 @@ export class NodeCollector { } private defaultVersion: FernNavigation.VersionNode | undefined; - constructor(rootNode: NavigationNode) { + constructor(rootNode: NavigationNode | undefined) { + if (rootNode == null) { + return; + } traverseNavigation(rootNode, (node, _index, parents) => { this.idToNode.set(node.id, node); diff --git a/packages/fdr-sdk/src/navigation/types/NavigationNodeNeighbor.ts b/packages/fdr-sdk/src/navigation/types/NavigationNodeNeighbor.ts index 1b7cfa469b..964128fe41 100644 --- a/packages/fdr-sdk/src/navigation/types/NavigationNodeNeighbor.ts +++ b/packages/fdr-sdk/src/navigation/types/NavigationNodeNeighbor.ts @@ -7,8 +7,15 @@ export type NavigationNodeNeighbor = | NavigationNodeApiLeaf | FernNavigation.PageNode | FernNavigation.ChangelogNode + | FernNavigation.ChangelogEntryNode | NavigationNodeSectionOverview; export function isNeighbor(node: NavigationNode): node is NavigationNodeNeighbor { - return isApiLeaf(node) || node.type === "page" || node.type === "changelog" || isSectionOverview(node); + return ( + isApiLeaf(node) || + node.type === "page" || + node.type === "changelog" || + node.type === "changelogEntry" || + isSectionOverview(node) + ); } diff --git a/packages/fdr-sdk/src/navigation/utils/findNode.ts b/packages/fdr-sdk/src/navigation/utils/findNode.ts index 6057be7f5e..350fd98309 100644 --- a/packages/fdr-sdk/src/navigation/utils/findNode.ts +++ b/packages/fdr-sdk/src/navigation/utils/findNode.ts @@ -17,9 +17,9 @@ export declare namespace Node { root: FernNavigation.RootNode; versions: FernNavigation.VersionNode[]; currentVersion: FernNavigation.VersionNode | undefined; - currentTab: FernNavigation.TabNode | undefined; + currentTab: FernNavigation.TabNode | FernNavigation.ChangelogNode | undefined; tabs: FernNavigation.TabChild[]; - sidebar: FernNavigation.SidebarRootNode; + sidebar: FernNavigation.SidebarRootNode | undefined; apiReference: FernNavigation.ApiReferenceNode | undefined; next: NavigationNodeNeighbor | undefined; prev: NavigationNodeNeighbor | undefined; @@ -55,8 +55,14 @@ export function findNode(root: FernNavigation.RootNode, slug: string[]): Node { const sidebar = found.parents.find((node): node is FernNavigation.SidebarRootNode => node.type === "sidebarRoot"); const currentVersion = found.parents.find((node): node is FernNavigation.VersionNode => node.type === "version"); - if (isPage(found.node) && sidebar != null) { + if (isPage(found.node)) { const rootChild = (currentVersion ?? root).child; + const parentsAndNode = [...found.parents, found.node]; + const tabs = rootChild.type === "tabbed" ? rootChild.children : []; + const tabbedNodeIndex = parentsAndNode.findIndex( + (node): node is FernNavigation.TabbedNode => node.type === "tabbed", + ); + const currentTab = tabbedNodeIndex !== -1 ? parentsAndNode[tabbedNodeIndex + 1] : undefined; return { type: "found", node: found.node, @@ -75,9 +81,9 @@ export function findNode(root: FernNavigation.RootNode, slug: string[]): Node { } return node; }), - tabs: rootChild.type === "tabbed" ? rootChild.children : [], + tabs, currentVersion, - currentTab: found.parents.findLast((node): node is FernNavigation.TabNode => node.type === "tab"), + currentTab: currentTab?.type === "tab" || currentTab?.type === "changelog" ? currentTab : undefined, sidebar, apiReference: found.parents.find((node): node is FernNavigation.ApiReferenceNode => node.type === "apiReference") ?? @@ -92,6 +98,8 @@ export function findNode(root: FernNavigation.RootNode, slug: string[]): Node { return { type: "redirect", redirect: root.pointsTo }; } + console.log(found.node); + const redirect = hasRedirect(found.node) ? found.node.pointsTo : currentVersion?.pointsTo ?? root.pointsTo; if (redirect == null || redirect === slugToFind) { diff --git a/packages/ui/app/src/api-playground/PlaygroundEndpointSelectorContent.tsx b/packages/ui/app/src/api-playground/PlaygroundEndpointSelectorContent.tsx index e9e5bdddf5..4a4b84f109 100644 --- a/packages/ui/app/src/api-playground/PlaygroundEndpointSelectorContent.tsx +++ b/packages/ui/app/src/api-playground/PlaygroundEndpointSelectorContent.tsx @@ -27,7 +27,10 @@ export interface ApiGroup { items: FernNavigation.NavigationNodeApiLeaf[]; } -export function flattenApiSection(root: FernNavigation.SidebarRootNode): ApiGroup[] { +export function flattenApiSection(root: FernNavigation.SidebarRootNode | undefined): ApiGroup[] { + if (root == null) { + return []; + } const result: ApiGroup[] = []; FernNavigation.utils.traverseNavigation(root, (node, _, parents) => { if (node.type === "changelog") { diff --git a/packages/ui/app/src/docs/ChangelogEntryPage.tsx b/packages/ui/app/src/docs/ChangelogEntryPage.tsx index 278a55b81b..e0dd1233e6 100644 --- a/packages/ui/app/src/docs/ChangelogEntryPage.tsx +++ b/packages/ui/app/src/docs/ChangelogEntryPage.tsx @@ -1,3 +1,4 @@ +import { ArrowLeftIcon } from "@radix-ui/react-icons"; import { ReactElement } from "react"; import { BottomNavigationButtons } from "../components/BottomNavigationButtons"; import { FernLink } from "../components/FernLink"; @@ -11,15 +12,17 @@ export function ChangelogEntryPage({ resolvedPath }: { resolvedPath: ResolvedPat return (
-
+
-
+
+
- - {resolvedPath.changelogTitle} + + + Back to {resolvedPath.changelogTitle}
@@ -35,19 +38,15 @@ export function ChangelogEntryPage({ resolvedPath }: { resolvedPath: ResolvedPat
)}
- -
-
- {/* - {resolvedPath.node.title} - */} +
+ +
+ +
+
- -
- -
-
+
diff --git a/packages/ui/app/src/docs/ChangelogPage.tsx b/packages/ui/app/src/docs/ChangelogPage.tsx index c83124c39d..ce02d5c051 100644 --- a/packages/ui/app/src/docs/ChangelogPage.tsx +++ b/packages/ui/app/src/docs/ChangelogPage.tsx @@ -1,27 +1,34 @@ +import clsx from "clsx"; import { Fragment, ReactElement } from "react"; import { FernLink } from "../components/FernLink"; +import { useDocsContext } from "../contexts/docs-context/useDocsContext"; import { CustomDocsPageHeader } from "../custom-docs-page/CustomDocsPage"; import { MdxContent } from "../mdx/MdxContent"; import { ResolvedPath } from "../resolver/ResolvedPath"; export function ChangelogPage({ resolvedPath }: { resolvedPath: ResolvedPath.ChangelogPage }): ReactElement { + const { sidebar } = useDocsContext(); + const fullWidth = sidebar == null; const overview = resolvedPath.node.overviewPageId != null ? resolvedPath.pages[resolvedPath.node.overviewPageId] : undefined; return (
-
-
-
- - {overview != null && ( -
- -
- )} +
+
+
+ {fullWidth &&
} +
+ + {overview != null && ( +
+ +
+ )} +
{resolvedPath.node.children.flatMap((year) => @@ -33,11 +40,17 @@ export function ChangelogPage({ resolvedPath }: { resolvedPath: ResolvedPath.Cha
-
- {title != null &&

{title}

} - + {fullWidth &&
} +
+
+ {entry.title} +
+
+ {title != null &&

{title}

} + +
-
+
{entry.title} @@ -48,11 +61,7 @@ export function ChangelogPage({ resolvedPath }: { resolvedPath: ResolvedPath.Cha }), ), )} - - {/*
- -
*/} -
+
diff --git a/packages/ui/app/src/docs/Docs.tsx b/packages/ui/app/src/docs/Docs.tsx index abcca30e99..d5d6e01612 100644 --- a/packages/ui/app/src/docs/Docs.tsx +++ b/packages/ui/app/src/docs/Docs.tsx @@ -28,7 +28,7 @@ export const SearchDialog = dynamic(() => import("../search/SearchDialog").then( }); export const Docs: React.FC = memo(function UnmemoizedDocs({ logoHeight, logoHref }) { - const { layout, colors, currentVersionId } = useDocsContext(); + const { layout, colors, currentVersionId, sidebar } = useDocsContext(); const openSearchDialog = useOpenSearchDialog(); const { isInlineFeedbackEnabled } = useFeatureFlags(); const { resolvedPath } = useNavigationContext(); @@ -67,8 +67,10 @@ export const Docs: React.FC = memo(function UnmemoizedDocs )}
- -