actually generate doc index for real this time
This commit is contained in:
39
packages/docs/app/create-index.server.ts
Normal file
39
packages/docs/app/create-index.server.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import glob from "fast-glob"
|
||||
import matter from "gray-matter"
|
||||
import { readFile } from "node:fs/promises"
|
||||
import { join, parse, posix } from "node:path"
|
||||
|
||||
export type ContentIndexEntry = {
|
||||
title: string
|
||||
route: string
|
||||
order: number
|
||||
}
|
||||
|
||||
export async function createContentIndex(
|
||||
contentFolderPath: string,
|
||||
): Promise<ContentIndexEntry[]> {
|
||||
const contentFiles = await glob(["**/*.mdx", "**/*.md"], {
|
||||
cwd: contentFolderPath,
|
||||
absolute: true,
|
||||
})
|
||||
|
||||
const entries = await Promise.all(contentFiles.map(getIndexInfo))
|
||||
|
||||
return entries.sort((a, b) => a.order - b.order)
|
||||
}
|
||||
|
||||
async function getIndexInfo(filePath: string): Promise<ContentIndexEntry> {
|
||||
const { dir, name } = parse(filePath)
|
||||
const route = "/" + posix.relative("app/routes", join(dir, name))
|
||||
|
||||
const { data } = matter(await readFile(filePath, "utf8"))
|
||||
|
||||
const title = String(data.meta?.title ?? "")
|
||||
|
||||
let order = Number(data.order)
|
||||
if (!Number.isFinite(order)) {
|
||||
order = Number.POSITIVE_INFINITY
|
||||
}
|
||||
|
||||
return { title, route, order }
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import { readFile } from "node:fs/promises"
|
||||
import remarkFrontmatter from "remark-frontmatter"
|
||||
import remarkParse from "remark-parse"
|
||||
import type { LoaderFunction } from "remix"
|
||||
import { Link, Outlet } from "remix"
|
||||
import { unified } from "unified"
|
||||
import { SideNav } from "~/components/side-nav"
|
||||
import { SidebarLayout } from "~/components/sidebar-layout"
|
||||
import { linkClass } from "~/styles"
|
||||
|
||||
export const loader: LoaderFunction = async () => {
|
||||
const glob = await import("fast-glob")
|
||||
|
||||
const contentFiles = await glob.default(["**/*.mdx", "**/*.md"], {
|
||||
cwd: "content",
|
||||
absolute: true,
|
||||
})
|
||||
|
||||
const contentModules = await Promise.all(
|
||||
contentFiles.map(async (filePath) => {
|
||||
const content = await readFile(filePath, "utf8")
|
||||
const result = await unified()
|
||||
.use(remarkParse)
|
||||
.use(remarkFrontmatter)
|
||||
.process(content)
|
||||
|
||||
return { filePath, result: result.toString() }
|
||||
}),
|
||||
)
|
||||
|
||||
console.log(contentModules)
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
export default function Docs() {
|
||||
return (
|
||||
<SidebarLayout
|
||||
sidebar={
|
||||
<SideNav heading="Guides">
|
||||
<Link className={linkClass} to="getting-started">
|
||||
Getting Started
|
||||
</Link>
|
||||
<Link className={linkClass} to="embeds">
|
||||
Embeds
|
||||
</Link>
|
||||
<Link className={linkClass} to="buttons">
|
||||
Buttons
|
||||
</Link>
|
||||
<Link className={linkClass} to="select-menus">
|
||||
Select Menus
|
||||
</Link>
|
||||
</SideNav>
|
||||
}
|
||||
body={
|
||||
<section className="prose max-w-none prose-invert prose-h1:font-light flex-1 prose-h1:mb-4 prose-p:my-4 prose-pre:text-[15px] prose-pre:font-monospace prose-h2:font-light h-[200vh]">
|
||||
<Outlet />
|
||||
</section>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -48,34 +48,7 @@ export default function App() {
|
||||
<Links />
|
||||
</head>
|
||||
<body>
|
||||
<HeaderLayout
|
||||
header={
|
||||
<nav className="flex justify-between items-center">
|
||||
<Link to="/">
|
||||
<h1 className="text-3xl font-light">
|
||||
reacord{" "}
|
||||
<CodeIcon className="inline w-8 align-sub opacity-50" />
|
||||
</h1>
|
||||
</Link>
|
||||
<div className="flex gap-4">
|
||||
<Link className={linkClass} to="/docs/getting-started">
|
||||
<DocumentTextIcon className="inline align-sub w-5" /> Guides
|
||||
</Link>
|
||||
<Link className={linkClass} to="/api">
|
||||
<DatabaseIcon className="inline align-sub w-5" /> API
|
||||
Reference
|
||||
</Link>
|
||||
<ExternalLink
|
||||
className={linkClass}
|
||||
href="https://github.com/itsMapleLeaf/reacord"
|
||||
>
|
||||
<ExternalLinkIcon className="inline align-sub w-5" /> GitHub
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</nav>
|
||||
}
|
||||
body={<Outlet />}
|
||||
/>
|
||||
<HeaderLayout header={<HeaderNav />} body={<Outlet />} />
|
||||
<ScrollRestoration />
|
||||
<Scripts />
|
||||
{process.env.NODE_ENV === "development" && <LiveReload />}
|
||||
@@ -83,3 +56,29 @@ export default function App() {
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
||||
function HeaderNav() {
|
||||
return (
|
||||
<nav className="flex justify-between items-center">
|
||||
<Link to="/">
|
||||
<h1 className="text-3xl font-light">
|
||||
reacord <CodeIcon className="inline w-8 align-sub opacity-50" />
|
||||
</h1>
|
||||
</Link>
|
||||
<div className="flex gap-4">
|
||||
<Link className={linkClass} to="/docs/guides/getting-started">
|
||||
<DocumentTextIcon className="inline align-sub w-5" /> Guides
|
||||
</Link>
|
||||
<Link className={linkClass} to="/docs/api">
|
||||
<DatabaseIcon className="inline align-sub w-5" /> API Reference
|
||||
</Link>
|
||||
<ExternalLink
|
||||
className={linkClass}
|
||||
href="https://github.com/itsMapleLeaf/reacord"
|
||||
>
|
||||
<ExternalLinkIcon className="inline align-sub w-5" /> GitHub
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
36
packages/docs/app/routes/docs.tsx
Normal file
36
packages/docs/app/routes/docs.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import type { LoaderFunction } from "remix"
|
||||
import { Link, Outlet, useLoaderData } from "remix"
|
||||
import { SideNav } from "~/components/side-nav"
|
||||
import { SidebarLayout } from "~/components/sidebar-layout"
|
||||
import type { ContentIndexEntry } from "~/create-index.server"
|
||||
import { createContentIndex } from "~/create-index.server"
|
||||
import { linkClass } from "~/styles"
|
||||
|
||||
type LoaderData = ContentIndexEntry[]
|
||||
|
||||
export const loader: LoaderFunction = async () => {
|
||||
const data: LoaderData = await createContentIndex("app/routes/docs/guides")
|
||||
return data
|
||||
}
|
||||
|
||||
export default function Docs() {
|
||||
const data: LoaderData = useLoaderData()
|
||||
return (
|
||||
<SidebarLayout
|
||||
sidebar={
|
||||
<SideNav heading="Guides">
|
||||
{data.map(({ title, route }) => (
|
||||
<Link className={linkClass} key={route} to={route}>
|
||||
{title}
|
||||
</Link>
|
||||
))}
|
||||
</SideNav>
|
||||
}
|
||||
body={
|
||||
<section className="prose max-w-none prose-invert prose-h1:font-light flex-1 prose-h1:mb-4 prose-p:my-4 prose-pre:text-[15px] prose-pre:font-monospace prose-h2:font-light h-[200vh]">
|
||||
<Outlet />
|
||||
</section>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
order: 0
|
||||
meta:
|
||||
title: Getting Started
|
||||
description: Learn how to get started with Reacord.
|
||||
@@ -1,17 +1,10 @@
|
||||
import type { LoaderFunction } from "remix"
|
||||
import { useLoaderData } from "remix"
|
||||
import type { DocsJson } from "~/docs.server"
|
||||
import { loadDocs } from "~/docs.server"
|
||||
|
||||
export const loader: LoaderFunction = () => loadDocs()
|
||||
|
||||
export default function Index() {
|
||||
const data: DocsJson = useLoaderData()
|
||||
return (
|
||||
<main>
|
||||
<pre className="w-full overflow-x-auto">
|
||||
{JSON.stringify(data, undefined, 2)}
|
||||
</pre>
|
||||
<h1>Reacord</h1>
|
||||
<pre>code snippet here</pre>
|
||||
<p>Create interactive Discord messages using React and JSX.</p>
|
||||
<button>Get Started</button>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"@tailwindcss/typography": "^0.5.0",
|
||||
"autoprefixer": "^10.4.1",
|
||||
"clsx": "^1.1.1",
|
||||
"gray-matter": "^4.0.3",
|
||||
"postcss": "^8.4.5",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/* eslint-disable unicorn/prefer-module */
|
||||
const glob = require("fast-glob")
|
||||
const { join, relative, normalize, parse } = require("path/posix")
|
||||
|
||||
/**
|
||||
* @type {import('@remix-run/dev/config').AppConfig}
|
||||
*/
|
||||
module.exports = {
|
||||
appDirectory: "app",
|
||||
assetsBuildDirectory: "public/build",
|
||||
publicPath: "/build/",
|
||||
serverBuildDirectory: "build",
|
||||
devServerPort: 8002,
|
||||
ignoredRouteFiles: [".*"],
|
||||
serverModuleFormat: "esm",
|
||||
|
||||
routes: async (defineRoutes) => {
|
||||
const contentFolder = join(__dirname, "content")
|
||||
|
||||
const contentFiles = await glob("**/*.{md,mdx}", {
|
||||
cwd: contentFolder,
|
||||
absolute: true,
|
||||
})
|
||||
|
||||
return defineRoutes((route) => {
|
||||
route("docs", "docs.tsx", () => {
|
||||
for (const filePath of contentFiles) {
|
||||
const localFilePath = relative(contentFolder, filePath)
|
||||
const { dir, name } = parse(localFilePath)
|
||||
const routePath = join(dir, name)
|
||||
route(routePath, filePath, { index: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
mdx: async (filename) => {
|
||||
const highlight = await import("rehype-prism-plus").then(
|
||||
(mod) => mod.default,
|
||||
)
|
||||
return {
|
||||
rehypePlugins: [highlight],
|
||||
}
|
||||
},
|
||||
}
|
||||
24
packages/docs/remix.config.js
Normal file
24
packages/docs/remix.config.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/* eslint-disable unicorn/prefer-module */
|
||||
const glob = require("fast-glob")
|
||||
const { join, relative, normalize, parse } = require("path/posix")
|
||||
|
||||
/**
|
||||
* @type {import('@remix-run/dev/config').AppConfig}
|
||||
*/
|
||||
module.exports = {
|
||||
appDirectory: "app",
|
||||
assetsBuildDirectory: "public/build",
|
||||
publicPath: "/build/",
|
||||
serverBuildDirectory: "build",
|
||||
devServerPort: 8002,
|
||||
ignoredRouteFiles: [".*"],
|
||||
|
||||
mdx: async (filename) => {
|
||||
const highlight = await import("rehype-prism-plus").then(
|
||||
(mod) => mod.default,
|
||||
)
|
||||
return {
|
||||
rehypePlugins: [highlight],
|
||||
}
|
||||
},
|
||||
}
|
||||
32
pnpm-lock.yaml
generated
32
pnpm-lock.yaml
generated
@@ -48,6 +48,7 @@ importers:
|
||||
clsx: ^1.1.1
|
||||
concurrently: ^6.5.1
|
||||
fast-glob: ^3.2.7
|
||||
gray-matter: ^4.0.3
|
||||
postcss: ^8.4.5
|
||||
prettier: ^2.5.1
|
||||
react: ^17.0.2
|
||||
@@ -72,6 +73,7 @@ importers:
|
||||
'@tailwindcss/typography': 0.5.0_tailwindcss@3.0.8
|
||||
autoprefixer: 10.4.1_postcss@8.4.5
|
||||
clsx: 1.1.1
|
||||
gray-matter: 4.0.3
|
||||
postcss: 8.4.5
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
@@ -1603,7 +1605,6 @@ packages:
|
||||
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
||||
dependencies:
|
||||
sprintf-js: 1.0.3
|
||||
dev: true
|
||||
|
||||
/argparse/2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
@@ -3784,7 +3785,6 @@ packages:
|
||||
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/esquery/1.4.0:
|
||||
resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==}
|
||||
@@ -3986,7 +3986,6 @@ packages:
|
||||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
is-extendable: 0.1.1
|
||||
dev: true
|
||||
|
||||
/extend-shallow/3.0.2:
|
||||
resolution: {integrity: sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=}
|
||||
@@ -4423,6 +4422,16 @@ packages:
|
||||
/graceful-fs/4.2.8:
|
||||
resolution: {integrity: sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==}
|
||||
|
||||
/gray-matter/4.0.3:
|
||||
resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
|
||||
engines: {node: '>=6.0'}
|
||||
dependencies:
|
||||
js-yaml: 3.14.1
|
||||
kind-of: 6.0.3
|
||||
section-matter: 1.0.0
|
||||
strip-bom-string: 1.0.0
|
||||
dev: false
|
||||
|
||||
/hard-rejection/2.1.0:
|
||||
resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -4923,7 +4932,6 @@ packages:
|
||||
/is-extendable/0.1.1:
|
||||
resolution: {integrity: sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/is-extendable/1.0.1:
|
||||
resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==}
|
||||
@@ -5748,7 +5756,6 @@ packages:
|
||||
dependencies:
|
||||
argparse: 1.0.10
|
||||
esprima: 4.0.1
|
||||
dev: true
|
||||
|
||||
/js-yaml/4.1.0:
|
||||
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
|
||||
@@ -5901,7 +5908,6 @@ packages:
|
||||
/kind-of/6.0.3:
|
||||
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/kleur/3.0.3:
|
||||
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
|
||||
@@ -7937,6 +7943,14 @@ packages:
|
||||
object-assign: 4.1.1
|
||||
dev: false
|
||||
|
||||
/section-matter/1.0.0:
|
||||
resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
extend-shallow: 2.0.1
|
||||
kind-of: 6.0.3
|
||||
dev: false
|
||||
|
||||
/semver-diff/3.1.1:
|
||||
resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -8174,7 +8188,6 @@ packages:
|
||||
|
||||
/sprintf-js/1.0.3:
|
||||
resolution: {integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=}
|
||||
dev: true
|
||||
|
||||
/ssri/8.0.1:
|
||||
resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==}
|
||||
@@ -8276,6 +8289,11 @@ packages:
|
||||
ansi-regex: 6.0.1
|
||||
dev: true
|
||||
|
||||
/strip-bom-string/1.0.0:
|
||||
resolution: {integrity: sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/strip-bom/3.0.0:
|
||||
resolution: {integrity: sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"exclude": [
|
||||
"**/node_modules/**",
|
||||
"**/coverage/**",
|
||||
"**/build/**",
|
||||
"**/dist/**",
|
||||
"**/.cache/**",
|
||||
"**/api/_build/**",
|
||||
|
||||
Reference in New Issue
Block a user