transform markdown through asset transformer
This commit is contained in:
24
packages/docs/src/asset-builder/transform-markdown.ts
Normal file
24
packages/docs/src/asset-builder/transform-markdown.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import grayMatter from "gray-matter"
|
||||||
|
import MarkdownIt from "markdown-it"
|
||||||
|
import prism from "markdown-it-prism"
|
||||||
|
import { readFile } from "node:fs/promises"
|
||||||
|
import type { AssetTransformer } from "./asset-builder.js"
|
||||||
|
|
||||||
|
const renderer = new MarkdownIt({
|
||||||
|
html: true,
|
||||||
|
linkify: true,
|
||||||
|
}).use(prism)
|
||||||
|
|
||||||
|
export const transformMarkdown: AssetTransformer = {
|
||||||
|
async transform(inputFile) {
|
||||||
|
if (!/\.md$/.test(inputFile)) return
|
||||||
|
|
||||||
|
const { data, content } = grayMatter(await readFile(inputFile, "utf8"))
|
||||||
|
const html = renderer.render(content)
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: html,
|
||||||
|
type: "text/html",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
import { LocalFileAsset } from "../asset-builder/asset.js"
|
||||||
import { AppLink } from "../navigation/app-link"
|
import { AppLink } from "../navigation/app-link"
|
||||||
import { guideLinks } from "../navigation/guide-links"
|
import { guideLinks } from "../navigation/guide-links"
|
||||||
import { MainNavigation } from "../navigation/main-navigation"
|
import { MainNavigation } from "../navigation/main-navigation"
|
||||||
import { docsProseClass, linkClass, maxWidthContainer } from "../ui/components"
|
import { docsProseClass, linkClass, maxWidthContainer } from "../ui/components"
|
||||||
|
|
||||||
export default function GuidePage({ html }: { html: string }) {
|
export function GuidePage({ url }: { url: string }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<header className="bg-slate-700/30 shadow sticky top-0 backdrop-blur-sm transition z-10 flex">
|
<header className="bg-slate-700/30 shadow sticky top-0 backdrop-blur-sm transition z-10 flex">
|
||||||
@@ -24,10 +25,14 @@ export default function GuidePage({ html }: { html: string }) {
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<section
|
<LocalFileAsset from={new URL(`${url}.md`, import.meta.url)}>
|
||||||
className={clsx(docsProseClass, "pb-8 flex-1 min-w-0")}
|
{(asset) => (
|
||||||
dangerouslySetInnerHTML={{ __html: html }}
|
<section
|
||||||
/>
|
className={clsx(docsProseClass, "pb-8 flex-1 min-w-0")}
|
||||||
|
dangerouslySetInnerHTML={{ __html: asset.content }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</LocalFileAsset>
|
||||||
</main>
|
</main>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import packageJson from "reacord/package.json"
|
import packageJson from "reacord/package.json"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { renderMarkdownFile } from "../helpers/markdown"
|
import { LocalFileAsset } from "../asset-builder/asset.js"
|
||||||
import { MainNavigation } from "../navigation/main-navigation"
|
import { MainNavigation } from "../navigation/main-navigation"
|
||||||
import { maxWidthContainer } from "../ui/components"
|
import { maxWidthContainer } from "../ui/components"
|
||||||
|
|
||||||
const landingExample = await renderMarkdownFile(
|
|
||||||
new URL("landing-example.md", import.meta.url).pathname,
|
|
||||||
)
|
|
||||||
|
|
||||||
export function Landing() {
|
export function Landing() {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col min-w-0 min-h-screen text-center">
|
<div className="flex flex-col min-w-0 min-h-screen text-center">
|
||||||
@@ -17,10 +13,14 @@ export function Landing() {
|
|||||||
<div className="px-4 pb-8 flex flex-1">
|
<div className="px-4 pb-8 flex flex-1">
|
||||||
<main className="px-4 py-6 rounded-lg shadow bg-slate-800 space-y-5 m-auto w-full max-w-xl">
|
<main className="px-4 py-6 rounded-lg shadow bg-slate-800 space-y-5 m-auto w-full max-w-xl">
|
||||||
<h1 className="text-6xl font-light">reacord</h1>
|
<h1 className="text-6xl font-light">reacord</h1>
|
||||||
<section
|
<LocalFileAsset from={new URL("landing-example.md", import.meta.url)}>
|
||||||
className="mx-auto text-sm sm:text-base"
|
{(asset) => (
|
||||||
dangerouslySetInnerHTML={{ __html: landingExample.html }}
|
<section
|
||||||
/>
|
className="mx-auto text-sm sm:text-base"
|
||||||
|
dangerouslySetInnerHTML={{ __html: asset.content }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</LocalFileAsset>
|
||||||
<p className="text-2xl font-light">{packageJson.description}</p>
|
<p className="text-2xl font-light">{packageJson.description}</p>
|
||||||
<a
|
<a
|
||||||
href="/guides/getting-started"
|
href="/guides/getting-started"
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ import ssrPrepass from "react-ssr-prepass"
|
|||||||
import { AssetBuilderProvider } from "./asset-builder/asset-builder-context.js"
|
import { AssetBuilderProvider } from "./asset-builder/asset-builder-context.js"
|
||||||
import { AssetBuilder } from "./asset-builder/asset-builder.js"
|
import { AssetBuilder } from "./asset-builder/asset-builder.js"
|
||||||
import { transformEsbuild } from "./asset-builder/transform-esbuild.js"
|
import { transformEsbuild } from "./asset-builder/transform-esbuild.js"
|
||||||
|
import { transformMarkdown } from "./asset-builder/transform-markdown.js"
|
||||||
import { transformPostCss } from "./asset-builder/transform-postcss.js"
|
import { transformPostCss } from "./asset-builder/transform-postcss.js"
|
||||||
import { fromProjectRoot } from "./constants"
|
import { fromProjectRoot } from "./constants"
|
||||||
import GuidePage from "./guides/guide-page"
|
import { GuidePage } from "./guides/guide-page"
|
||||||
import { renderMarkdownFile } from "./helpers/markdown"
|
import { renderMarkdownFile } from "./helpers/markdown"
|
||||||
import { Html } from "./html.js"
|
import { Html } from "./html.js"
|
||||||
import { Landing } from "./landing/landing"
|
import { Landing } from "./landing/landing"
|
||||||
@@ -24,6 +25,7 @@ const port = process.env.PORT || 3000
|
|||||||
const assets = await AssetBuilder.create(fromProjectRoot(".asset-cache"), [
|
const assets = await AssetBuilder.create(fromProjectRoot(".asset-cache"), [
|
||||||
transformEsbuild,
|
transformEsbuild,
|
||||||
transformPostCss,
|
transformPostCss,
|
||||||
|
transformMarkdown,
|
||||||
])
|
])
|
||||||
|
|
||||||
async function render(res: Response, element: React.ReactElement) {
|
async function render(res: Response, element: React.ReactElement) {
|
||||||
@@ -43,14 +45,14 @@ const router = Router()
|
|||||||
.use(assets.middleware())
|
.use(assets.middleware())
|
||||||
|
|
||||||
.get("/guides/*", async (req: Request<{ 0: string }>, res) => {
|
.get("/guides/*", async (req: Request<{ 0: string }>, res) => {
|
||||||
const { html, data } = await renderMarkdownFile(
|
const { data } = await renderMarkdownFile(
|
||||||
new URL(`guides/${req.params[0]}.md`, import.meta.url).pathname,
|
new URL(`guides/${req.params[0]}.md`, import.meta.url).pathname,
|
||||||
)
|
)
|
||||||
await render(
|
await render(
|
||||||
res,
|
res,
|
||||||
<AssetBuilderProvider value={assets}>
|
<AssetBuilderProvider value={assets}>
|
||||||
<Html title={`${data.title} | Reacord`} description={data.description}>
|
<Html title={`${data.title} | Reacord`} description={data.description}>
|
||||||
<GuidePage html={html} />
|
<GuidePage url={req.params[0]} />
|
||||||
</Html>
|
</Html>
|
||||||
</AssetBuilderProvider>,
|
</AssetBuilderProvider>,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user