Skip to content

Commit

Permalink
Unify markdown renderers (#12)
Browse files Browse the repository at this point in the history
* Don't distinguish between md and mdx when rendering server-side

* Init base components

* Start reusing base components between Markdown and MdxContent

* Reuse code blocks between renderers

* Add P to base components

* Fully unify the styles of both renderers
  • Loading branch information
kafkas authored Jul 31, 2023
1 parent 99b0b1a commit fd39a2e
Show file tree
Hide file tree
Showing 15 changed files with 237 additions and 256 deletions.
8 changes: 0 additions & 8 deletions packages/ui/app/src/ResolvedUrlPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { MDXRemoteSerializeResult } from "next-mdx-remote";

export type ResolvedUrlPath =
| ResolvedUrlPath.Section
| ResolvedUrlPath.MarkdownPage
| ResolvedUrlPath.MdxPage
| ResolvedUrlPath.Api
| ResolvedUrlPath.ClientLibraries
Expand All @@ -19,13 +18,6 @@ export declare namespace ResolvedUrlPath {
slug: string;
}

export interface MarkdownPage {
type: "markdown-page";
page: FernRegistryDocsRead.PageMetadata;
slug: string;
markdownContent: string;
}

export interface MdxPage {
type: "mdx-page";
page: FernRegistryDocsRead.PageMetadata;
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/app/src/api-page/endpoints/EndpointContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const EndpointContent = React.memo<EndpointContent.Props>(function Endpoi
</div>
{endpoint.description != null && (
<div className="mt-6">
<Markdown type="api">{endpoint.description}</Markdown>
<Markdown>{endpoint.description}</Markdown>
</div>
)}
<div className="mt-8 flex">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const EndpointParameter: React.FC<EndpointParameter.Props> = ({ name, des
<TypeShorthand type={type} plural={false} />
</div>
</div>
{description != null && <Markdown type="api">{description}</Markdown>}
{description != null && <Markdown>{description}</Markdown>}
<TypeReferenceDefinitions type={type} isCollapsible />
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/app/src/api-page/endpoints/EndpointSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const EndpointSection: React.FC<EndpointSection.Props> = ({ title, descri
</div>
{description != null && (
<div className="mb-2">
<Markdown type="api">{description}</Markdown>
<Markdown>{description}</Markdown>
</div>
)}
<div className="flex flex-col">{children}</div>
Expand Down
149 changes: 39 additions & 110 deletions packages/ui/app/src/api-page/markdown/Markdown.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
import { Code } from "@blueprintjs/core";
import classNames from "classnames";
import React from "react";
import ReactMarkdown from "react-markdown";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { vscDarkPlus } from "react-syntax-highlighter/dist/cjs/styles/prism";
import rehypeRaw from "rehype-raw";
import remarkGfm from "remark-gfm";
import {
A,
H1,
H2,
H3,
H4,
H5,
H6,
InlineCode,
Li,
Ol,
P,
Table,
Td,
Th,
Thead,
Tr,
Ul,
} from "../../mdx/base-components";
import styles from "./Markdown.module.scss";

export declare namespace Markdown {
export interface Props {
/**
* - `"markdown"`: Markdown pages.
* - `"api"`: API reference pages.
*/
type: "markdown" | "api";
children: string;
className?: string;
}
Expand All @@ -23,119 +34,37 @@ export declare namespace Markdown {
const REMARK_PLUGINS = [remarkGfm];
const REHYPE_PLUGINS = [rehypeRaw];

const PRISM_CLASSNAME_REGEX = /language-(\w+)/;
// TODO: Rename this component to ApiMarkdown

export const Markdown = React.memo<Markdown.Props>(function Markdown({ type, children, className }) {
export const Markdown = React.memo<Markdown.Props>(function Markdown({ children, className }) {
return (
<ReactMarkdown
className={classNames(className, styles.container, "prose prose-sm dark:prose-invert max-w-none")}
remarkPlugins={REMARK_PLUGINS}
rehypePlugins={REHYPE_PLUGINS}
components={{
pre({ className, ...props }) {
return <pre className={classNames(className, "border border-border/60")} {...props} />;
},
code({ node, inline = false, className, children, ...props }) {
if (!inline && className != null) {
const match = PRISM_CLASSNAME_REGEX.exec(className);
if (match != null) {
return (
<SyntaxHighlighter
{...props}
style={vscDarkPlus}
customStyle={{
backgroundColor: "transparent",
padding: 0,
fontSize: "0.9rem",
}}
language={match[1]}
PreTag="div"
>
{String(children)}
</SyntaxHighlighter>
);
}
return null;
}
return (
<Code
{...props}
className={classNames(
className,
"border border-border/60 !bg-neutral-900/50 !text-white !py-0.5 !px-1"
)}
>
{children}
</Code>
);
},
table({ node, ...props }) {
return <table {...props} className={classNames(props.className, "block overflow-x-auto")} />;
},
th({ node, ...props }) {
return (
<th
{...props}
className={classNames(props.className, "text-sm font-normal text-text-stark leading-7")}
/>
);
},
td({ node, ...props }) {
return (
<td
{...props}
className={classNames(props.className, "text-base font-light text-text-default leading-7")}
/>
);
return <InlineCode {...props}>{children}</InlineCode>;
},
h1: ({ node, ...props }) => (
<h1 {...props} className={classNames(props.className, "text-2xl font-semibold mt-10 mb-3")} />
),
h2: ({ node, ...props }) => (
<h2 {...props} className={classNames(props.className, "text-xl font-semibold mt-10 mb-3")} />
),
h3: ({ node, ...props }) => (
<h3 {...props} className={classNames(props.className, "text-lg font-semibold mt-10 mb-3")} />
),
h4: ({ node, ...props }) => (
<h4 {...props} className={classNames(props.className, "text-lg font-semibold mt-10 mb-3")} />
),
h5: ({ node, ...props }) => (
<h5 {...props} className={classNames(props.className, "text-lg font-semibold mt-10 mb-3")} />
),
h6: ({ node, ...props }) => (
<h6 {...props} className={classNames(props.className, "text-lg font-semibold mt-10 mb-3")} />
),
p: ({ node, ...props }) => (
<p
{...props}
className={classNames(
"mb-3",
{
"text-base font-light text-text-default leading-7": type === "markdown",
"text-sm text-text-default leading-6": type === "api",
},
props.className
)}
/>
),
ul: ({ node, ...props }) => (
<ul {...props} className={classNames("list-image-dash", props.className)} />
),
li: ({ node, ...props }) => (
<li
{...props}
className={classNames("text-base font-light text-text-default leading-7", props.className)}
/>
),
a: ({ node, ...props }) => (
<a
{...props}
className={classNames(
"transition !text-white hover:!text-accentPrimary !no-underline !border-b hover:!border-b-2 !border-b-accentPrimary hover:border-b-accentPrimary hover:no-underline font-medium",
props.className
)}
/>
),
table: (props) => <Table {...props} />,
thead: (props) => <Thead {...props} />,
tr: (props) => <Tr {...props} />,
th: (props) => <Th {...props} />,
td: (props) => <Td {...props} />,
h1: (props) => <H1 {...props} />,
h2: (props) => <H2 {...props} />,
h3: (props) => <H3 {...props} />,
h4: (props) => <H4 {...props} />,
h5: (props) => <H5 {...props} />,
h6: (props) => <H6 {...props} />,
p: ({ node, ...props }) => <P variant="sm" {...props} />,
ol: (props) => <Ol {...props} />,
ul: (props) => <Ul {...props} />,
li: (props) => <Li {...props} />,
a: (props) => <A {...props} />,
}}
>
{children}
Expand Down
4 changes: 1 addition & 3 deletions packages/ui/app/src/api-page/subpackages/ApiSubpackage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ export const ApiSubpackage: React.FC<ApiSubpackage.Props> = ({ subpackageId, slu
</div>
{subpackage.description != null && (
<div className="flex flex-col items-start space-y-5 pt-10 md:flex-row md:space-x-[5vw] md:space-y-0">
<Markdown type="api" className="flex-1">
{subpackage.description}
</Markdown>
<Markdown className="flex-1">{subpackage.description}</Markdown>
<div className="flex-1" />
</div>
)}
Expand Down
6 changes: 1 addition & 5 deletions packages/ui/app/src/api-page/types/Description.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,5 @@ export const Description: React.FC<Description.Props> = ({ description }) => {
return null;
}

return (
<Markdown type="api" className="prose-p:text-[#A7A7B0] mt-3">
{description}
</Markdown>
);
return <Markdown className="prose-p:text-[#A7A7B0] mt-3">{description}</Markdown>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ export const BottomNavigationButton: React.FC<BottomNavigationButton.Props> = ({
switch (path.type) {
case "section":
return path.section.title;
case "markdown-page":
case "mdx-page":
return path.page.title;
case "api":
Expand Down
13 changes: 2 additions & 11 deletions packages/ui/app/src/custom-docs-page/CustomDocsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { assertNever } from "@fern-api/core-utils";
import classNames from "classnames";
import { useMemo } from "react";
import { Markdown } from "../api-page/markdown/Markdown";
import { BottomNavigationButtons } from "../bottom-navigation-buttons/BottomNavigationButtons";
import { useDocsContext } from "../docs-context/useDocsContext";
import { MdxContent } from "../mdx/MdxContent";
Expand All @@ -10,7 +8,7 @@ import { TableOfContents } from "./TableOfContents";

export declare namespace CustomDocsPage {
export interface Props {
path: ResolvedUrlPath.MarkdownPage | ResolvedUrlPath.MdxPage;
path: ResolvedUrlPath.MdxPage;
}
}

Expand All @@ -20,14 +18,7 @@ export const CustomDocsPage: React.FC<CustomDocsPage.Props> = ({ path }) => {
const page = useMemo(() => resolvePage(path.page.id), [path.page.id, resolvePage]);

const content = useMemo(() => {
switch (path.type) {
case "markdown-page":
return <Markdown type="markdown">{path.markdownContent}</Markdown>;
case "mdx-page":
return <MdxContent mdx={path.serializedMdxContent} />;
default:
assertNever(path);
}
return <MdxContent mdx={path.serializedMdxContent} />;
}, [path]);

return (
Expand Down
1 change: 0 additions & 1 deletion packages/ui/app/src/docs-context/DocsContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export const DocsContextProvider: React.FC<DocsContextProvider.Props> = ({
switch (resolvedUrlPath.type) {
case "clientLibraries":
case "endpoint":
case "markdown-page":
case "mdx-page":
case "topLevelEndpoint":
case "apiSubpackage":
Expand Down
1 change: 0 additions & 1 deletion packages/ui/app/src/docs/DocsMainContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export const DocsMainContent: React.FC = () => {
const { resolvedPathFromUrl } = useDocsContext();

switch (resolvedPathFromUrl.type) {
case "markdown-page":
case "mdx-page":
return <CustomDocsPage path={resolvedPathFromUrl} />;
case "api":
Expand Down
Loading

0 comments on commit fd39a2e

Please sign in to comment.