Skip to content

Commit

Permalink
fix: support for tabbed changelog (#1065)
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity authored Jun 22, 2024
1 parent ee803cd commit cc0fd80
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 73 deletions.
11 changes: 9 additions & 2 deletions packages/fdr-sdk/src/navigation/NodeCollector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ interface NavigationNodeWithMetadataAndParents {
const NodeCollectorInstances = new WeakMap<NavigationNode, NodeCollector>();

export class NodeCollector {
private static readonly EMPTY = new NodeCollector(undefined);
private idToNode = new Map<FernNavigation.NodeId, NavigationNode>();
private slugToNode: Record<FernNavigation.Slug, NavigationNodeWithMetadataAndParents> = {};
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;
Expand All @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
);
}
18 changes: 13 additions & 5 deletions packages/fdr-sdk/src/navigation/utils/findNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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") ??
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand Down
29 changes: 14 additions & 15 deletions packages/ui/app/src/docs/ChangelogEntryPage.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -11,15 +12,17 @@ export function ChangelogEntryPage({ resolvedPath }: { resolvedPath: ResolvedPat
return (
<div className="flex justify-between px-4 md:px-6 lg:pl-8 lg:pr-16 xl:pr-0">
<div className="w-full min-w-0 pt-8">
<article className="mx-auto w-fit break-words lg:ml-0 xl:mx-auto">
<article className="mx-auto xl:w-fit break-words lg:ml-0 xl:mx-auto">
<section id={resolvedPath.node.date} className="flex items-stretch">
<div className="prose relative mr-6 max-w-content-width flex-1 dark:prose-invert">
<div className="max-xl:hidden w-sidebar-width" />
<div className="relative mr-6 max-w-content-width flex-1 max-xl:mx-auto">
<header className="mb-8">
<div className="space-y-1">
<div className="not-prose">
<FernLink href={`/${resolvedPath.changelogSlug}`}>
<span className="t-accent shrink truncate whitespace-nowrap text-sm font-semibold">
{resolvedPath.changelogTitle}
<span className="t-accent shrink truncate whitespace-nowrap text-sm font-semibold inline-flex gap-1 items-center">
<ArrowLeftIcon className="size-4" />
Back to {resolvedPath.changelogTitle}
</span>
</FernLink>
</div>
Expand All @@ -35,19 +38,15 @@ export function ChangelogEntryPage({ resolvedPath }: { resolvedPath: ResolvedPat
</div>
)}
</header>
<MdxContent mdx={page} />
</div>
<div className="-mt-2 w-72 pl-4 text-right">
{/* <span className="t-muted text-base sticky top-header-height-padded">
{resolvedPath.node.title}
</span> */}
<div className="prose dark:prose-invert">
<MdxContent mdx={page} />
</div>

<BottomNavigationButtons />
</div>
<div className="-mt-2 w-72 pl-4 text-right max-xl:hidden" />
</section>

<div className="max-w-content-width">
<BottomNavigationButtons />
</div>
<div className="h-36" />
<div className="h-48" />
</article>
</div>
</div>
Expand Down
53 changes: 31 additions & 22 deletions packages/ui/app/src/docs/ChangelogPage.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="flex justify-between px-4 md:px-6 lg:pl-8 lg:pr-16 xl:pr-0">
<div className="w-full min-w-0 pt-8">
<article className="mx-auto w-fit break-words lg:ml-0 xl:mx-auto">
<section className="prose dark:prose-invert prose-h1:mt-[1.5em]">
<CustomDocsPageHeader
title={resolvedPath.node.title}
sectionTitleBreadcrumbs={resolvedPath.sectionTitleBreadcrumbs}
excerpt={typeof overview !== "string" ? overview?.frontmatter.excerpt : undefined}
/>
{overview != null && (
<section className="prose w-content-width dark:prose-invert">
<MdxContent mdx={overview} />
</section>
)}
<div className={clsx("w-full min-w-0 pt-8", { "sm:pt-16 lg:pt-32": fullWidth })}>
<article className="mx-auto xl:w-fit break-words lg:ml-0 xl:mx-auto">
<section className="flex">
{fullWidth && <div className="max-xl:hidden w-sidebar-width" />}
<div className="max-w-content-width w-full max-xl:mx-auto">
<CustomDocsPageHeader
title={resolvedPath.node.title}
sectionTitleBreadcrumbs={resolvedPath.sectionTitleBreadcrumbs}
excerpt={typeof overview !== "string" ? overview?.frontmatter.excerpt : undefined}
/>
{overview != null && (
<section className="prose w-content-width dark:prose-invert">
<MdxContent mdx={overview} />
</section>
)}
</div>
</section>

{resolvedPath.node.children.flatMap((year) =>
Expand All @@ -33,11 +40,17 @@ export function ChangelogPage({ resolvedPath }: { resolvedPath: ResolvedPath.Cha
<Fragment key={entry.id}>
<hr className="my-16" />
<section id={entry.date} className="flex items-stretch">
<div className="prose relative mr-6 max-w-content-width flex-1 dark:prose-invert">
{title != null && <h2>{title}</h2>}
<MdxContent mdx={page} />
{fullWidth && <div className="max-xl:hidden w-sidebar-width" />}
<div className="relative mr-6 max-w-content-width flex-1 max-xl:mx-auto">
<div className="t-muted text-base mb-8 xl:hidden">
<FernLink href={`/${entry.slug}`}>{entry.title}</FernLink>
</div>
<div className="prose dark:prose-invert">
{title != null && <h1>{title}</h1>}
<MdxContent mdx={page} />
</div>
</div>
<div className="-mt-2 w-72 pl-4 text-right">
<div className="-mt-2 w-72 pl-4 text-right max-xl:hidden">
<span className="t-muted text-base sticky top-header-height-padded">
<FernLink href={`/${entry.slug}`}>{entry.title}</FernLink>
</span>
Expand All @@ -48,11 +61,7 @@ export function ChangelogPage({ resolvedPath }: { resolvedPath: ResolvedPath.Cha
}),
),
)}

{/* <div className="max-w-content-width">
<BottomNavigationButtons />
</div> */}
<div className="h-36" />
<div className="h-48" />
</article>
</div>
</div>
Expand Down
37 changes: 19 additions & 18 deletions packages/ui/app/src/docs/Docs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const SearchDialog = dynamic(() => import("../search/SearchDialog").then(
});

export const Docs: React.FC<DocsProps> = memo<DocsProps>(function UnmemoizedDocs({ logoHeight, logoHref }) {
const { layout, colors, currentVersionId } = useDocsContext();
const { layout, colors, currentVersionId, sidebar } = useDocsContext();
const openSearchDialog = useOpenSearchDialog();
const { isInlineFeedbackEnabled } = useFeatureFlags();
const { resolvedPath } = useNavigationContext();
Expand Down Expand Up @@ -67,8 +67,10 @@ export const Docs: React.FC<DocsProps> = memo<DocsProps>(function UnmemoizedDocs
)}

<div className="relative mx-auto flex min-h-0 w-full min-w-0 max-w-page-width flex-1">
<style>
{`
{sidebar != null && resolvedPath.type !== "changelog-entry" && (
<>
<style>
{`
.fern-sidebar-container {
border-right-width: ${colors.light?.sidebarBackground == null ? 0 : 1}px;
border-left-width: ${colors.light?.sidebarBackground == null || layout?.pageWidth?.type !== "full" ? 0 : 1}px;
Expand All @@ -79,21 +81,20 @@ export const Docs: React.FC<DocsProps> = memo<DocsProps>(function UnmemoizedDocs
border-left-width: ${colors.dark?.sidebarBackground == null || layout?.pageWidth?.type !== "full" ? 0 : 1}px;
}
`}
</style>
<Sidebar
className={clsx(
layout?.disableHeader !== true
? "fern-sidebar-container bg-sidebar border-concealed sticky top-header-height mt-header-height hidden h-vh-minus-header w-sidebar-width lg:block"
: "fern-sidebar-container bg-sidebar border-concealed fixed hidden h-vh-minus-header w-sidebar-width lg:block",
{
invisible: resolvedPath.type === "changelog-entry",
},
)}
logoHeight={logoHeight}
logoHref={logoHref}
showSearchBar={layout?.disableHeader || layout?.searchbarPlacement !== "HEADER"}
/>
{layout?.disableHeader && <div className="hidden w-sidebar-width lg:block" />}
</style>
<Sidebar
className={clsx(
layout?.disableHeader !== true
? "fern-sidebar-container bg-sidebar border-concealed sticky top-header-height mt-header-height hidden h-vh-minus-header w-sidebar-width lg:block"
: "fern-sidebar-container bg-sidebar border-concealed fixed hidden h-vh-minus-header w-sidebar-width lg:block",
)}
logoHeight={logoHeight}
logoHref={logoHref}
showSearchBar={layout?.disableHeader || layout?.searchbarPlacement !== "HEADER"}
/>
{layout?.disableHeader && <div className="hidden w-sidebar-width lg:block" />}
</>
)}

<main className="fern-main">
{isInlineFeedbackEnabled ? (
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/app/src/next-app/DocsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export declare namespace DocsPage {
tabs: SidebarTab[];
currentVersionId: FernNavigation.VersionId | undefined;
versions: SidebarVersionInfo[];
sidebar: FernNavigation.SidebarRootNode;
sidebar: FernNavigation.SidebarRootNode | undefined;
}

export interface Props {
Expand Down
7 changes: 5 additions & 2 deletions packages/ui/app/src/search/SearchDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,15 @@ export const SearchSidebar: React.FC<PropsWithChildren<SearchSidebar.Props>> = (

function createSearchPlaceholderWithVersion(
activeVersion: SidebarVersionInfo | undefined,
sidebar: FernNavigation.SidebarRootNode,
sidebar: FernNavigation.SidebarRootNode | undefined,
): string {
return `Search ${activeVersion != null ? `across ${activeVersion.id} ` : ""}for ${createSearchPlaceholder(sidebar)}...`;
}

function createSearchPlaceholder(sidebar: FernNavigation.SidebarRootNode): string {
function createSearchPlaceholder(sidebar: FernNavigation.SidebarRootNode | undefined): string {
if (sidebar == null) {
return "guides and endpoints";
}
const hasGuides = checkHasGuides(sidebar);
const hasEndpoints = checkHasEndpoints(sidebar);
if (hasGuides && hasEndpoints) {
Expand Down
13 changes: 9 additions & 4 deletions packages/ui/app/src/sidebar/CollapseSidebarContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ export const CollapseSidebarProvider: FC<
const parentIdMap = new Map<FernNavigation.NodeId, FernNavigation.NodeId[]>();
const parentToChildrenMap = new Map<FernNavigation.NodeId, FernNavigation.NodeId[]>();

if (sidebar == null) {
return { parentIdMap, parentToChildrenMap };
}

FernNavigation.utils.traverseNavigation(sidebar, (node, _index, parents) => {
if (FernNavigation.hasMetadata(node)) {
parentIdMap.set(
Expand Down Expand Up @@ -177,10 +181,11 @@ export const CollapseSidebarProvider: FC<
// If there is only one pageGroup with only one page, hide the sidebar content
// this is useful for tabs that only have one page
if (
sidebar.children.length === 1 &&
sidebar.children[0].type === "sidebarGroup" &&
sidebar.children[0].children.length === 1 &&
sidebar.children[0].children[0].type === "page"
sidebar == null ||
(sidebar.children.length === 1 &&
sidebar.children[0].type === "sidebarGroup" &&
sidebar.children[0].children.length === 1 &&
sidebar.children[0].children[0].type === "page")
) {
return null;
}
Expand Down
Loading

0 comments on commit cc0fd80

Please sign in to comment.