Skip to content

Commit

Permalink
Fix missing eyebrow headers in markdown pages (#211)
Browse files Browse the repository at this point in the history
* Add a reference to section from page node

* Add sectionTitle to resolved path
  • Loading branch information
kafkas authored Oct 16, 2023
1 parent 964a562 commit 4e496a2
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const DEFINITION_VERSIONED_UNTABBED: DocsDefinitionSummary = {
items: [
{
type: "section",
title: "Introduction",
title: "Welcome",
urlSlug: "introduction",
skipUrlSlug: false,
collapsed: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { PathResolver } from "../../PathResolver";
import { expectDocsSection, expectPageNode } from "../util";
import { DEFINITION_UNVERSIONED_TABBED } from "./mock-definitions/unversioned-tabbed";
import { DEFINITION_UNVERSIONED_UNTABBED } from "./mock-definitions/unversioned-untabbed";
import { DEFINITION_VERSIONED_TABBED } from "./mock-definitions/versioned-tabbed";
import { DEFINITION_VERSIONED_UNTABBED } from "./mock-definitions/versioned-untabbed";

describe("resolveNavigatable", () => {
describe("correctly gets the section associated with page", () => {
it("with unversioned and untabbed docs", () => {
const resolver = new PathResolver({
definition: DEFINITION_UNVERSIONED_UNTABBED,
});
const node = resolver.rootNavigatable;
expectPageNode(node);
expectDocsSection(node.section);
expect(node.section.title).toBe("Introduction");
});

it("with unversioned and tabbed docs", () => {
const resolver = new PathResolver({
definition: DEFINITION_UNVERSIONED_TABBED,
});
const node = resolver.resolveNavigatable("welcome/advanced-concepts/sharding");
expectPageNode(node);
expectDocsSection(node.section);
expect(node.section.title).toBe("Advanced Concepts");
});

it("with versioned and untabbed docs", () => {
const resolver = new PathResolver({
definition: DEFINITION_VERSIONED_UNTABBED,
});
const node = resolver.resolveNavigatable("v1-2/introduction/authentication");
expectPageNode(node);
expectDocsSection(node.section);
expect(node.section.title).toBe("Welcome");
});

it("with versioned and tabbed docs", () => {
const resolver = new PathResolver({
definition: DEFINITION_VERSIONED_TABBED,
});
const node = resolver.resolveNavigatable("help-center/documents/uploading-documents");
expectPageNode(node);
expectDocsSection(node.section);
expect(node.section.title).toBe("Documents");
});
});
});
9 changes: 9 additions & 0 deletions packages/commons/app-utils/src/path-resolver/__test__/util.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type * as FernRegistryDocsRead from "@fern-fern/registry-browser/api/resources/docs/resources/v1/resources/read";
import type { DocsNode, DocsNodeType } from "../types";

export function expectDocsSectionNode(node: DocsNode | undefined): asserts node is DocsNode.DocsSection {
Expand All @@ -16,6 +17,14 @@ export function expectPageNode(node: DocsNode | undefined): asserts node is Docs
expectNode(node).toBeOfType("page");
}

export function expectDocsSection(
section: FernRegistryDocsRead.DocsSection | null
): asserts section is FernRegistryDocsRead.DocsSection {
if (section == null) {
throw new Error("Expected 'section' to be non-null");
}
}

interface NodeExpectation {
toBeOfType: (type: DocsNodeType | undefined) => void;
}
Expand Down
10 changes: 10 additions & 0 deletions packages/commons/app-utils/src/path-resolver/build-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export function buildDefinitionTree(definition: DocsDefinitionSummary): DocsNode
const children = buildNodesForNavigationItems({
items: navigationConfig.items,
parentSlugs: [],
section: null,
context: {
type: "versioned-untabbed",
root,
Expand Down Expand Up @@ -115,6 +116,7 @@ export function buildDefinitionTree(definition: DocsDefinitionSummary): DocsNode
const children = buildNodesForNavigationItems({
items: rootNavigationConfig.items,
parentSlugs: [],
section: null,
context: {
type: "unversioned-untabbed",
root,
Expand Down Expand Up @@ -169,6 +171,7 @@ function buildNodeForNavigationTab({
const children = buildNodesForNavigationItems({
items: tab.items,
parentSlugs: [...parentSlugs, tab.urlSlug],
section: null,
context:
context.type === "versioned"
? {
Expand All @@ -193,16 +196,19 @@ function buildNodeForNavigationTab({
function buildNodesForNavigationItems({
items,
parentSlugs,
section,
context,
}: {
items: FernRegistryDocsRead.NavigationItem[];
parentSlugs: string[];
section: FernRegistryDocsRead.DocsSection | null;
context: NodeDocsContext;
}): ChildDocsNode[] {
return items.map((childItem) =>
buildNodeForNavigationItem({
item: childItem,
parentSlugs: [...parentSlugs],
section,
context,
})
) as ChildDocsNode[];
Expand All @@ -211,10 +217,12 @@ function buildNodesForNavigationItems({
function buildNodeForNavigationItem({
item,
parentSlugs,
section,
context,
}: {
item: FernRegistryDocsRead.NavigationItem;
parentSlugs: string[];
section: FernRegistryDocsRead.DocsSection | null;
context: NodeDocsContext;
}): DocsNode {
switch (item.type) {
Expand All @@ -224,6 +232,7 @@ function buildNodeForNavigationItem({
slug: page.urlSlug,
leadingSlug: joinUrlSlugs(...parentSlugs, page.urlSlug),
page,
section,
context,
});
}
Expand Down Expand Up @@ -263,6 +272,7 @@ function buildNodeForDocsSection({
const children = buildNodesForNavigationItems({
items: section.items,
parentSlugs: nextSectionParentSlugs(section, parentSlugs),
section,
context,
});
addNodeChildren(sectionNode, children);
Expand Down
3 changes: 3 additions & 0 deletions packages/commons/app-utils/src/path-resolver/node-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,18 +216,21 @@ export class NodeFactory {
slug,
leadingSlug,
page,
section,
context,
}: {
slug: string;
leadingSlug: string;
page: FernRegistryDocsRead.PageMetadata;
section: FernRegistryDocsRead.DocsSection | null;
context: NodeDocsContext;
}): DocsNode.Page {
return {
type: "page",
slug,
leadingSlug,
page,
section,
context,
};
}
Expand Down
1 change: 1 addition & 0 deletions packages/commons/app-utils/src/path-resolver/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ export declare namespace DocsNode {
export interface Page extends BaseNode, NavigatableNode {
type: "page";
page: FernRegistryDocsRead.PageMetadata;
section: FernRegistryDocsRead.DocsSection | null;
context: NodeDocsContext;
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/ui/app/src/ResolvedPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export declare namespace ResolvedPath {
type: "custom-markdown-page";
fullSlug: string;
page: FernRegistryDocsRead.PageMetadata;
sectionTitle: string | null;
serializedMdxContent: SerializedMdxContent;
}

Expand Down
43 changes: 5 additions & 38 deletions packages/ui/app/src/custom-docs-page/CustomDocsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import type * as FernRegistryDocsRead from "@fern-fern/registry-browser/api/resources/docs/resources/v1/resources/read";
import { DocsNode, isUnversionedUntabbedNavigationConfig, SerializedMdxContent } from "@fern-ui/app-utils";
import { useCallback, useMemo } from "react";
import { DocsNode, SerializedMdxContent } from "@fern-ui/app-utils";
import { useMemo } from "react";
import { BottomNavigationButtons } from "../bottom-navigation-buttons/BottomNavigationButtons";
import { HEADER_HEIGHT } from "../constants";
import { useDocsContext } from "../docs-context/useDocsContext";
import { MdxContent } from "../mdx/MdxContent";
import { ResolvedPath } from "../ResolvedPath";
import { useDocsSelectors } from "../selectors/useDocsSelectors";
import { TableOfContents } from "./TableOfContents";

export declare namespace CustomDocsPage {
Expand All @@ -17,52 +15,21 @@ export declare namespace CustomDocsPage {
}
}

export const CustomDocsPage: React.FC<CustomDocsPage.Props> = ({ navigatable, serializedMdxContent, resolvedPath }) => {
export const CustomDocsPage: React.FC<CustomDocsPage.Props> = ({ serializedMdxContent, resolvedPath }) => {
const { resolvePage } = useDocsContext();
const { activeNavigationConfigContext } = useDocsSelectors();

const page = useMemo(() => resolvePage(resolvedPath.page.id), [resolvedPath.page.id, resolvePage]);

const findTitle = useCallback(
(navigationItems: FernRegistryDocsRead.NavigationItem[]) => {
for (const navigationItem of navigationItems) {
if (navigationItem.type !== "section") {
continue;
}
const [sectionSlugInferredFromPath] = navigatable.leadingSlug.split("/");
if (sectionSlugInferredFromPath != null && navigationItem.urlSlug === sectionSlugInferredFromPath) {
return navigationItem.title;
}
}
return undefined;
},
[navigatable.leadingSlug]
);

const sectionTitle = useMemo(() => {
if (isUnversionedUntabbedNavigationConfig(activeNavigationConfigContext.config)) {
return findTitle(activeNavigationConfigContext.config.items);
} else {
for (const tab of activeNavigationConfigContext.config.tabs) {
const title = findTitle(tab.items);
if (title != null) {
return title;
}
}
return undefined;
}
}, [activeNavigationConfigContext, findTitle]);

const content = useMemo(() => {
return serializedMdxContent != null ? <MdxContent mdx={serializedMdxContent} /> : null;
}, [serializedMdxContent]);

return (
<div className="flex space-x-16 px-6 md:px-12">
<div className="w-full min-w-0 max-w-3xl pt-8">
{sectionTitle != null && (
{resolvedPath.sectionTitle != null && (
<div className="text-accent-primary mb-4 text-xs font-semibold uppercase tracking-wider">
{sectionTitle}
{resolvedPath.sectionTitle}
</div>
)}

Expand Down
2 changes: 2 additions & 0 deletions packages/ui/app/src/navigation-context/NavigationContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const NavigationContext = React.createContext<NavigationContextValue>({
title: "",
urlSlug: "",
},
section: null,
context: {
type: "unversioned-untabbed",
root: NodeFactory.createRoot(EMPTY_DEFINITION_SUMMARY),
Expand All @@ -54,6 +55,7 @@ export const NavigationContext = React.createContext<NavigationContextValue>({
title: "",
urlSlug: "",
},
sectionTitle: "",
serializedMdxContent: { compiledSource: "", frontmatter: {}, scope: {} },
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export async function convertNavigatableToResolvedPath({
type: "custom-markdown-page",
fullSlug,
page: serializedNavigatable.page,
sectionTitle: serializedNavigatable.section?.title ?? null,
serializedMdxContent: serializedNavigatable.serializedMdxContent,
};
case "endpoint":
Expand Down

1 comment on commit 4e496a2

@vercel
Copy link

@vercel vercel bot commented on 4e496a2 Oct 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

fern-dev – ./packages/ui/fe-bundle

fern-dev-git-main-buildwithfern.vercel.app
fern-dev-buildwithfern.vercel.app
app-dev.buildwithfern.com
devtest.buildwithfern.com

Please sign in to comment.