Skip to content

Commit

Permalink
feature: frontmatter description meta tags (#414)
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity authored Jan 30, 2024
1 parent 014b5fa commit 4a5f7ed
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 7 deletions.
11 changes: 9 additions & 2 deletions packages/commons/app-utils/src/mdx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@ import remarkGfm from "remark-gfm";

const REMARK_PLUGINS = [remarkGfm];

export interface FernDocsFrontmatter {
title?: string;
description?: string;
editThisPageUrl?: string;
image?: string;
}

export interface TableOfContentsItem {
// heading: marked.Tokens.Heading | undefined;
simpleString: string;
children: TableOfContentsItem[];
}

export type SerializedMdxContent = MDXRemoteSerializeResult<Record<string, unknown>, Record<string, unknown>>;
export type SerializedMdxContent = MDXRemoteSerializeResult<Record<string, unknown>, FernDocsFrontmatter>;

/**
* Should only be invoked server-side.
Expand All @@ -27,6 +34,6 @@ export async function serializeMdxContent(content: string): Promise<SerializedMd
*/
development: process.env.NODE_ENV !== "production",
},
parseFrontmatter: false,
parseFrontmatter: true,
});
}
5 changes: 3 additions & 2 deletions packages/ui/app/src/custom-docs-page/CustomDocsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const CustomDocsPageHeader = ({ resolvedPath }: Pick<CustomDocsPage.Props
};

export const CustomDocsPage: React.FC<CustomDocsPage.Props> = ({ resolvedPath }) => {
const editThisPage = resolvedPath.serializedMdxContent.frontmatter.editThisPageUrl ?? resolvedPath?.editThisPageUrl;
return (
<div className="flex justify-between px-6 sm:px-8 lg:pl-12 lg:pr-20 xl:pr-0">
<div className="w-full min-w-0 lg:pr-6">
Expand All @@ -43,9 +44,9 @@ export const CustomDocsPage: React.FC<CustomDocsPage.Props> = ({ resolvedPath })
</div>
<aside className="scroll-contain smooth-scroll hide-scrollbar sticky top-16 hidden max-h-[calc(100vh-86px)] w-[19rem] shrink-0 overflow-auto overflow-x-hidden px-8 pb-12 pt-8 xl:block">
<TableOfContents tableOfContents={resolvedPath.tableOfContents} />
{resolvedPath?.editThisPageUrl != null && (
{editThisPage != null && (
<Link
href={resolvedPath.editThisPageUrl}
href={editThisPage}
target="_blank"
rel="noreferrer noopener"
className="t-muted hover:dark:text-text-primary-dark hover:text-text-primary-light my-3 block hyphens-auto break-words py-1.5 text-sm leading-5 no-underline transition hover:no-underline"
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/app/src/mdx/MdxContent.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MDXRemote, MDXRemoteProps, MDXRemoteSerializeResult } from "@fern-ui/app-utils";
import { MDXRemote, MDXRemoteProps, SerializedMdxContent } from "@fern-ui/app-utils";
import React, { HTMLAttributes, useCallback } from "react";
import { ErrorBoundary } from "react-error-boundary";
import { CodeBlockWithClipboardButton } from "../commons/CodeBlockWithClipboardButton";
Expand Down Expand Up @@ -33,7 +33,7 @@ import { MdxErrorBoundaryContent } from "./MdxErrorBoundaryContent";

export declare namespace MdxContent {
export interface Props {
mdx: MDXRemoteSerializeResult;
mdx: SerializedMdxContent;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { getFullSlugForNavigatable, type ResolvedPath } from "@fern-ui/app-utils";
import { NavigatableDocsNode } from "@fern-api/fdr-sdk";
import { FernDocsFrontmatter, getFullSlugForNavigatable, type ResolvedPath } from "@fern-ui/app-utils";
import { visitDiscriminatedUnion } from "@fern-ui/core-utils";
import { useBooleanState, useEventCallback } from "@fern-ui/react-commons";
import { debounce } from "lodash-es";
import Head from "next/head";
import { useRouter } from "next/router";
import { PropsWithChildren, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useDocsContext } from "../docs-context/useDocsContext";
Expand Down Expand Up @@ -184,6 +187,10 @@ export const NavigationContextProvider: React.FC<NavigationContextProvider.Props
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const frontmatter = getFrontmatter(resolvedPath);
const activeTitle = convertToTitle(activeNavigatable, frontmatter);
const activeDescription = convertToDescription(activeNavigatable, frontmatter);

return (
<NavigationContext.Provider
value={{
Expand All @@ -200,7 +207,47 @@ export const NavigationContextProvider: React.FC<NavigationContextProvider.Props
hydrated: hydrated.value,
}}
>
<Head>
{activeTitle != null && <title>{activeTitle}</title>}
{activeDescription != null && <meta name="description" content={activeDescription} />}
{frontmatter?.image != null && <meta property="og:image" content={frontmatter.image} />}
</Head>
{children}
</NavigationContext.Provider>
);
};

function getFrontmatter(resolvedPath: ResolvedPath): FernDocsFrontmatter | undefined {
if (resolvedPath.type === "custom-markdown-page") {
return resolvedPath.serializedMdxContent.frontmatter;
}
return undefined;
}

function convertToTitle(
navigatable: NavigatableDocsNode,
frontmatter: FernDocsFrontmatter | undefined
): string | undefined {
return visitDiscriminatedUnion(navigatable, "type")._visit({
page: (page) => frontmatter?.title ?? page.page.title,
"top-level-endpoint": (endpoint) => endpoint.endpoint.name,
"top-level-webhook": (webhook) => webhook.webhook.name,
webhook: (webhook) => webhook.webhook.name,
endpoint: (endpoint) => endpoint.endpoint.name,
_other: () => undefined,
});
}

function convertToDescription(
navigatable: NavigatableDocsNode,
frontmatter: FernDocsFrontmatter | undefined
): string | undefined {
return visitDiscriminatedUnion(navigatable, "type")._visit({
page: () => frontmatter?.description,
"top-level-endpoint": (endpoint) => endpoint.endpoint.description,
"top-level-webhook": (webhook) => webhook.webhook.description,
webhook: (webhook) => webhook.webhook.description,
endpoint: (endpoint) => endpoint.endpoint.description,
_other: () => undefined,
});
}

0 comments on commit 4a5f7ed

Please sign in to comment.