wip custom reference page
This commit is contained in:
5
packages/website/.gitignore
vendored
5
packages/website/.gitignore
vendored
@@ -4,7 +4,10 @@ node_modules
|
||||
/build
|
||||
/public/build
|
||||
.env
|
||||
/public/api
|
||||
cypress/videos
|
||||
cypress/screenshots
|
||||
*.out.css
|
||||
|
||||
# typedoc output
|
||||
/public/api
|
||||
/app/assets/api.json
|
||||
|
||||
8
packages/website/app/modules/api/api-data.server.ts
Normal file
8
packages/website/app/modules/api/api-data.server.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { JSONOutput } from "typedoc"
|
||||
|
||||
export type ApiData = JSONOutput.ContainerReflection
|
||||
|
||||
export async function loadApiData(): Promise<ApiData> {
|
||||
const data = await import("~/assets/api.json")
|
||||
return data as ApiData
|
||||
}
|
||||
13
packages/website/app/modules/helpers/promise-all-object.ts
Normal file
13
packages/website/app/modules/helpers/promise-all-object.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export async function promiseAllObject<Input extends object>(
|
||||
input: Input,
|
||||
): Promise<{
|
||||
[K in keyof Input]: Awaited<Input[K]>
|
||||
}> {
|
||||
const result: any = {}
|
||||
await Promise.all(
|
||||
Object.entries(input).map(async ([key, promise]) => {
|
||||
result[key] = await promise
|
||||
}),
|
||||
)
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
export async function renderMarkdown(
|
||||
markdown: string,
|
||||
): Promise<{ __html: string }> {
|
||||
const rehypePrism = import("rehype-prism-plus").then(
|
||||
(module) => module.default,
|
||||
)
|
||||
const rehypeStringify = import("rehype-stringify").then(
|
||||
(module) => module.default,
|
||||
)
|
||||
const remarkParse = import("remark-parse").then((module) => module.default)
|
||||
const remarkRehype = import("remark-rehype").then((module) => module.default)
|
||||
const { unified } = await import("unified")
|
||||
|
||||
const processor = unified()
|
||||
.use(await remarkParse)
|
||||
.use(await remarkRehype)
|
||||
.use(await rehypeStringify)
|
||||
.use(await rehypePrism)
|
||||
|
||||
const result = await processor.process(markdown)
|
||||
|
||||
return { __html: result.toString() }
|
||||
}
|
||||
82
packages/website/app/routes/api.tsx
Normal file
82
packages/website/app/routes/api.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import clsx from "clsx"
|
||||
import { Fragment } from "react"
|
||||
import type { LoaderFunction } from "remix"
|
||||
import { Outlet, useLoaderData } from "remix"
|
||||
import { loadApiData } from "~/modules/api/api-data.server"
|
||||
import { ActiveLink } from "~/modules/navigation/active-link"
|
||||
import type { AppLinkProps } from "~/modules/navigation/app-link"
|
||||
import { AppLink } from "~/modules/navigation/app-link"
|
||||
import { MainNavigation } from "~/modules/navigation/main-navigation"
|
||||
import {
|
||||
docsProseClass,
|
||||
linkClass,
|
||||
maxWidthContainer,
|
||||
} from "~/modules/ui/components"
|
||||
|
||||
type LoaderData = {
|
||||
categorySections: Array<{
|
||||
title: string
|
||||
links: AppLinkProps[]
|
||||
}>
|
||||
// [key: string]: unknown
|
||||
}
|
||||
|
||||
export const loader: LoaderFunction = async () => {
|
||||
const apiData = await loadApiData()
|
||||
|
||||
const childrenById = Object.fromEntries(
|
||||
apiData.children.map((child) => [child.id, { name: child.name }]),
|
||||
)
|
||||
|
||||
const data: LoaderData = {
|
||||
categorySections: apiData.categories.map((category) => ({
|
||||
title: category.title,
|
||||
links: category.children
|
||||
.map((childId) => childrenById[childId])
|
||||
.flatMap<AppLinkProps>((child) =>
|
||||
child
|
||||
? { to: `/api/${child.name}`, type: "router", children: child.name }
|
||||
: [],
|
||||
),
|
||||
})),
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
export default function ApiReferencePage() {
|
||||
const data = useLoaderData<LoaderData>()
|
||||
return (
|
||||
<div className="isolate">
|
||||
<header className="bg-slate-700/30 shadow sticky top-0 backdrop-blur-sm transition z-10 flex">
|
||||
<div className={maxWidthContainer}>
|
||||
<MainNavigation />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className={clsx(maxWidthContainer, "mt-8 flex items-start gap-4")}>
|
||||
<nav className="w-48 sticky top-24 hidden md:block">
|
||||
{data.categorySections.map((category) => (
|
||||
<Fragment key={category.title}>
|
||||
<h2 className="text-2xl">{category.title}</h2>
|
||||
<ul className="mt-3 mb-6 flex flex-col gap-2 items-start">
|
||||
{category.links.map((link) => (
|
||||
<li key={link.to}>
|
||||
<ActiveLink to={link.to}>
|
||||
{({ active }) => (
|
||||
<AppLink {...link} className={linkClass({ active })} />
|
||||
)}
|
||||
</ActiveLink>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Fragment>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
<main className={clsx(docsProseClass, "pb-8 flex-1 min-w-0")}>
|
||||
<Outlet />
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
51
packages/website/app/routes/api/$name.tsx
Normal file
51
packages/website/app/routes/api/$name.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import type { LoaderFunction } from "remix"
|
||||
import { useLoaderData } from "remix"
|
||||
import { inspect } from "node:util"
|
||||
import { loadApiData } from "~/modules/api/api-data.server"
|
||||
import { renderMarkdown } from "~/modules/markdown/render-markdown.server"
|
||||
|
||||
type LoaderData = {
|
||||
title: string
|
||||
description?: { __html: string }
|
||||
}
|
||||
|
||||
export const loader: LoaderFunction = async ({ params }) => {
|
||||
const apiData = await loadApiData()
|
||||
|
||||
const entityName = params.name!
|
||||
|
||||
const info = apiData.children?.find((child) => child.name === entityName)
|
||||
console.log(inspect(info, { depth: Number.POSITIVE_INFINITY }))
|
||||
|
||||
const description = [
|
||||
info?.comment?.shortText,
|
||||
info?.comment?.text,
|
||||
info?.signatures?.[0]?.comment?.shortText,
|
||||
info?.signatures?.[0]?.comment?.text,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n\n")
|
||||
|
||||
const data: LoaderData = {
|
||||
title: entityName,
|
||||
description: description ? await renderMarkdown(description) : undefined,
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
export default function ApiDetailPage() {
|
||||
const data = useLoaderData<LoaderData>()
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>{data.title}</h1>
|
||||
{data.description ? (
|
||||
<section dangerouslySetInnerHTML={data.description} />
|
||||
) : undefined}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function addDefined<Value extends number | string>(
|
||||
...values: Array<Value | undefined>
|
||||
): Value | undefined {}
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "website",
|
||||
"scripts": {
|
||||
"prepare": "remix setup node",
|
||||
"dev": "concurrently 'typedoc --watch' 'pnpm tailwind -- --watch' 'remix dev'",
|
||||
"dev": "NODE_OPTIONS=--enable-source-maps concurrently 'typedoc --watch' 'pnpm tailwind -- --watch' 'remix dev'",
|
||||
"test": "node ./scripts/test.js",
|
||||
"test-dev": "pnpm dev & wait-on http-get://localhost:3000 && cypress open",
|
||||
"build": "typedoc && pnpm tailwind -- --minify && remix build",
|
||||
@@ -27,7 +27,12 @@
|
||||
"react-focus-on": "^3.5.4",
|
||||
"react-router": "^6.2.1",
|
||||
"react-router-dom": "^6.2.1",
|
||||
"remix": "^1.1.1"
|
||||
"rehype-stringify": "^9.0.2",
|
||||
"remark-parse": "^10.0.1",
|
||||
"rehype-prism-plus": "^1.3.1",
|
||||
"remark-rehype": "^10.1.0",
|
||||
"remix": "^1.1.1",
|
||||
"unified": "^10.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@remix-run/dev": "^1.1.1",
|
||||
@@ -43,7 +48,6 @@
|
||||
"cypress": "^9.2.1",
|
||||
"execa": "^6.0.0",
|
||||
"postcss": "^8.4.5",
|
||||
"rehype-prism-plus": "^1.3.1",
|
||||
"tailwindcss": "^3.0.13",
|
||||
"typedoc": "^0.22.10",
|
||||
"typescript": "^4.5.4",
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"$schema": "https://typedoc.org/schema.json",
|
||||
"entryPoints": ["../reacord/library/main.ts"],
|
||||
"out": ["public/api"],
|
||||
"tsconfig": "../reacord/tsconfig.json",
|
||||
"json": "./app/assets/api.json",
|
||||
"excludeInternal": true,
|
||||
"excludePrivate": true,
|
||||
"excludeProtected": true,
|
||||
|
||||
Reference in New Issue
Block a user