From 39c4de2dbc93d776952d381889207b0edca5fc41 Mon Sep 17 00:00:00 2001 From: Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com> Date: Tue, 10 Jan 2023 12:25:14 -0500 Subject: [PATCH] refactor(website): extract layouts and use more server components (#9027) Closes https://github.com/discordjs/discord.js/issues/8920 Closes https://github.com/discordjs/discord.js/issues/8997 --- apps/website/package.json | 2 +- apps/website/src/app/docAPI.ts | 26 ++ .../packages/[package]/[...slug]/page.tsx | 382 ------------------ .../[package]/[version]/[item]/head.tsx | 89 ++++ .../[item]}/layout.tsx | 4 +- .../[package]/[version]/[item]/page.tsx | 114 ++++++ .../[item]}/providers.tsx | 0 .../packages/[package]/[version]/layout.tsx | 143 +++++++ .../packages/[package]/[version]/page.tsx | 67 +++ .../app/docs/packages/[package]/layout.tsx | 10 - apps/website/src/app/docs/packages/page.tsx | 19 +- apps/website/src/components/Anchor.tsx | 12 + apps/website/src/components/CodeListing.tsx | 88 ---- apps/website/src/components/DocContainer.tsx | 135 ------- apps/website/src/components/ExcerptText.tsx | 42 ++ .../src/components/HyperlinkedText.tsx | 26 -- .../src/components/InheritanceText.tsx | 17 +- apps/website/src/components/ItemLink.tsx | 42 ++ apps/website/src/components/MethodItem.tsx | 124 ------ apps/website/src/components/MethodList.tsx | 24 -- apps/website/src/components/NameText.tsx | 3 + apps/website/src/components/Nav.tsx | 8 +- apps/website/src/components/Outline.tsx | 23 ++ .../src/components/OverloadSwitcher.tsx | 54 +++ apps/website/src/components/Panel.tsx | 10 + .../website/src/components/ParameterTable.tsx | 18 +- apps/website/src/components/Property.tsx | 69 ++++ apps/website/src/components/PropertyList.tsx | 52 ++- apps/website/src/components/Scrollbars.tsx | 8 + apps/website/src/components/Section.tsx | 16 + apps/website/src/components/Sections.tsx | 99 ----- .../{SidebarItems.tsx => Sidebar.tsx} | 63 +-- apps/website/src/components/SignatureText.tsx | 10 + apps/website/src/components/Table.tsx | 2 - .../src/components/TableOfContentItems.tsx | 115 ++++-- .../website/src/components/TypeParamTable.tsx | 27 +- .../documentation/Documentation.tsx | 8 + .../src/components/documentation/Header.tsx | 36 ++ .../documentation/HierarchyText.tsx | 51 +++ .../MemberContainerDocumentation.tsx | 33 ++ .../src/components/documentation/Members.tsx | 13 + .../components/documentation/ObjectHeader.tsx | 18 + .../section/ConstructorSection.tsx | 30 ++ .../documentation/section/MethodsSection.tsx | 45 +++ .../section/ParametersSection.tsx | 12 + .../section/PropertiesSection.tsx | 12 + .../section/ResponsiveSection.tsx | 24 ++ .../documentation/section/SummarySection.tsx | 16 + .../section/TypeParametersSection.tsx | 12 + .../documentation/tsdoc/BlockComment.tsx | 38 ++ .../components/documentation/tsdoc/TSDoc.tsx | 121 ++++++ .../src/components/documentation/util.ts | 53 +++ apps/website/src/components/model/Class.tsx | 43 +- apps/website/src/components/model/Enum.tsx | 33 -- .../website/src/components/model/Function.tsx | 65 --- .../src/components/model/Interface.tsx | 34 +- .../src/components/model/TypeAlias.tsx | 21 +- .../website/src/components/model/Variable.tsx | 17 +- .../src/components/model/enum/Enum.tsx | 26 ++ .../src/components/model/enum/EnumMember.tsx | 20 + .../components/model/function/Function.tsx | 28 ++ .../model/function/FunctionBody.tsx | 23 ++ .../src/components/model/method/Method.tsx | 39 ++ .../model/method/MethodDocumentation.tsx | 32 ++ .../components/model/method/MethodHeader.tsx | 62 +++ .../src/components/tsdoc/BlockComment.tsx | 58 --- apps/website/src/components/tsdoc/TSDoc.tsx | 129 ------ apps/website/src/util/constants.ts | 4 + apps/website/src/util/members.ts | 37 ++ apps/website/src/util/model.server.ts | 32 +- apps/website/tsconfig.json | 1 + packages/ui/src/lib/components/Section.tsx | 4 +- yarn.lock | 134 +++--- 73 files changed, 1831 insertions(+), 1476 deletions(-) create mode 100644 apps/website/src/app/docAPI.ts delete mode 100644 apps/website/src/app/docs/packages/[package]/[...slug]/page.tsx create mode 100644 apps/website/src/app/docs/packages/[package]/[version]/[item]/head.tsx rename apps/website/src/app/docs/packages/[package]/{[...slug] => [version]/[item]}/layout.tsx (62%) create mode 100644 apps/website/src/app/docs/packages/[package]/[version]/[item]/page.tsx rename apps/website/src/app/docs/packages/[package]/{[...slug] => [version]/[item]}/providers.tsx (100%) create mode 100644 apps/website/src/app/docs/packages/[package]/[version]/layout.tsx create mode 100644 apps/website/src/app/docs/packages/[package]/[version]/page.tsx delete mode 100644 apps/website/src/app/docs/packages/[package]/layout.tsx create mode 100644 apps/website/src/components/Anchor.tsx delete mode 100644 apps/website/src/components/CodeListing.tsx delete mode 100644 apps/website/src/components/DocContainer.tsx create mode 100644 apps/website/src/components/ExcerptText.tsx delete mode 100644 apps/website/src/components/HyperlinkedText.tsx create mode 100644 apps/website/src/components/ItemLink.tsx delete mode 100644 apps/website/src/components/MethodItem.tsx delete mode 100644 apps/website/src/components/MethodList.tsx create mode 100644 apps/website/src/components/NameText.tsx create mode 100644 apps/website/src/components/Outline.tsx create mode 100644 apps/website/src/components/OverloadSwitcher.tsx create mode 100644 apps/website/src/components/Panel.tsx create mode 100644 apps/website/src/components/Property.tsx create mode 100644 apps/website/src/components/Scrollbars.tsx create mode 100644 apps/website/src/components/Section.tsx delete mode 100644 apps/website/src/components/Sections.tsx rename apps/website/src/components/{SidebarItems.tsx => Sidebar.tsx} (69%) create mode 100644 apps/website/src/components/SignatureText.tsx create mode 100644 apps/website/src/components/documentation/Documentation.tsx create mode 100644 apps/website/src/components/documentation/Header.tsx create mode 100644 apps/website/src/components/documentation/HierarchyText.tsx create mode 100644 apps/website/src/components/documentation/MemberContainerDocumentation.tsx create mode 100644 apps/website/src/components/documentation/Members.tsx create mode 100644 apps/website/src/components/documentation/ObjectHeader.tsx create mode 100644 apps/website/src/components/documentation/section/ConstructorSection.tsx create mode 100644 apps/website/src/components/documentation/section/MethodsSection.tsx create mode 100644 apps/website/src/components/documentation/section/ParametersSection.tsx create mode 100644 apps/website/src/components/documentation/section/PropertiesSection.tsx create mode 100644 apps/website/src/components/documentation/section/ResponsiveSection.tsx create mode 100644 apps/website/src/components/documentation/section/SummarySection.tsx create mode 100644 apps/website/src/components/documentation/section/TypeParametersSection.tsx create mode 100644 apps/website/src/components/documentation/tsdoc/BlockComment.tsx create mode 100644 apps/website/src/components/documentation/tsdoc/TSDoc.tsx create mode 100644 apps/website/src/components/documentation/util.ts delete mode 100644 apps/website/src/components/model/Enum.tsx delete mode 100644 apps/website/src/components/model/Function.tsx create mode 100644 apps/website/src/components/model/enum/Enum.tsx create mode 100644 apps/website/src/components/model/enum/EnumMember.tsx create mode 100644 apps/website/src/components/model/function/Function.tsx create mode 100644 apps/website/src/components/model/function/FunctionBody.tsx create mode 100644 apps/website/src/components/model/method/Method.tsx create mode 100644 apps/website/src/components/model/method/MethodDocumentation.tsx create mode 100644 apps/website/src/components/model/method/MethodHeader.tsx delete mode 100644 apps/website/src/components/tsdoc/BlockComment.tsx delete mode 100644 apps/website/src/components/tsdoc/TSDoc.tsx create mode 100644 apps/website/src/util/members.ts diff --git a/apps/website/package.json b/apps/website/package.json index ee4dbbd24..ad202ff1a 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -54,7 +54,7 @@ "ariakit": "^2.0.0-next.41", "cmdk": "^0.1.20", "meilisearch": "^0.30.0", - "next": "^13.0.7-canary.1", + "next": "^13.1.2-canary.4", "next-mdx-remote": "^4.2.0", "next-themes": "npm:@wits/next-themes@latest", "react": "^18.2.0", diff --git a/apps/website/src/app/docAPI.ts b/apps/website/src/app/docAPI.ts new file mode 100644 index 000000000..85f7a0800 --- /dev/null +++ b/apps/website/src/app/docAPI.ts @@ -0,0 +1,26 @@ +import { readFile } from 'node:fs/promises'; +import { join } from 'node:path'; + +export async function fetchVersions(packageName: string): Promise { + const response = await fetch(`https://docs.discordjs.dev/api/info?package=${packageName}`, { + next: { revalidate: 3_600 }, + }); + + return response.json(); +} + +export async function fetchModelJSON(packageName: string, version: string): Promise { + if (process.env.NEXT_PUBLIC_LOCAL_DEV) { + const res = await readFile( + join(process.cwd(), '..', '..', 'packages', packageName, 'docs', 'docs.api.json'), + 'utf8', + ); + return JSON.parse(res); + } + + const response = await fetch(`https://docs.discordjs.dev/docs/${packageName}/${version}.api.json`, { + next: { revalidate: 3_600 }, + }); + + return response.json(); +} diff --git a/apps/website/src/app/docs/packages/[package]/[...slug]/page.tsx b/apps/website/src/app/docs/packages/[package]/[...slug]/page.tsx deleted file mode 100644 index 800bb507b..000000000 --- a/apps/website/src/app/docs/packages/[package]/[...slug]/page.tsx +++ /dev/null @@ -1,382 +0,0 @@ -/* eslint-disable no-case-declarations */ -import { readFile } from 'node:fs/promises'; -import { join } from 'node:path'; -// eslint-disable-next-line n/prefer-global/process -import process, { cwd } from 'node:process'; -import { - findPackage, - getMembers, - type ApiItemJSON, - type ApiClassJSON, - type ApiFunctionJSON, - type ApiInterfaceJSON, - type ApiTypeAliasJSON, - type ApiVariableJSON, - type ApiEnumJSON, -} from '@discordjs/api-extractor-utils'; -import { createApiModel } from '@discordjs/scripts'; -import { ApiFunction, ApiItemKind, type ApiPackage } from '@microsoft/api-extractor-model'; -import Image from 'next/image'; -// import Head from 'next/head'; -import { notFound } from 'next/navigation'; -import { serialize } from 'next-mdx-remote/serialize'; -import rehypeIgnore from 'rehype-ignore'; -import rehypePrettyCode, { type Options } from 'rehype-pretty-code'; -import rehypeRaw from 'rehype-raw'; -import rehypeSlug from 'rehype-slug'; -import remarkGfm from 'remark-gfm'; -import { getHighlighter } from 'shiki'; -import shikiLangJavascript from 'shiki/languages/javascript.tmLanguage.json'; -import shikiLangTypescript from 'shiki/languages/typescript.tmLanguage.json'; -import shikiThemeDarkPlus from 'shiki/themes/dark-plus.json'; -import shikiThemeLightPlus from 'shiki/themes/light-plus.json'; -import vercelLogo from '../../../../../assets/powered-by-vercel.svg'; -import { MDXRemote } from '~/components/MDXRemote'; -import { Nav } from '~/components/Nav'; -import { Class } from '~/components/model/Class'; -import { Enum } from '~/components/model/Enum'; -import { Function } from '~/components/model/Function'; -import { Interface } from '~/components/model/Interface'; -import { TypeAlias } from '~/components/model/TypeAlias'; -import { Variable } from '~/components/model/Variable'; -import { MemberProvider } from '~/contexts/member'; -import { DESCRIPTION, PACKAGES } from '~/util/constants'; -import { findMember, findMemberByKey } from '~/util/model.server'; -import { tryResolveDescription } from '~/util/summary'; - -export async function generateStaticParams({ params }: { params?: { package: string } }) { - const packageName = params?.package ?? 'builders'; - - try { - let data: any[] = []; - let versions: string[] = []; - if (process.env.NEXT_PUBLIC_LOCAL_DEV) { - const res = await readFile(join(cwd(), '..', '..', 'packages', packageName, 'docs', 'docs.api.json'), 'utf8'); - data = JSON.parse(res); - } else { - const response = await fetch(`https://docs.discordjs.dev/api/info?package=${packageName}`, { - next: { revalidate: 3_600 }, - }); - versions = await response.json(); - versions = versions.slice(-2); - - for (const version of versions) { - const res = await fetch(`https://docs.discordjs.dev/docs/${packageName}/${version}.api.json`); - data = [...data, await res.json()]; - } - } - - if (Array.isArray(data)) { - const models = data.map((innerData) => createApiModel(innerData)); - const pkgs = models.map((model) => findPackage(model, packageName)) as ApiPackage[]; - - return [ - ...versions.map((version) => ({ slug: [version] })), - ...pkgs.flatMap((pkg, idx) => - getMembers(pkg, versions[idx] ?? 'main').map((member) => { - if (member.kind === ApiItemKind.Function && member.overloadIndex && member.overloadIndex > 1) { - return { - slug: [versions[idx] ?? 'main', `${member.name}:${member.overloadIndex}:${member.kind}`], - }; - } - - return { - slug: [versions[idx] ?? 'main', `${member.name}:${member.kind}`], - }; - }), - ), - ]; - } - - const model = createApiModel(data); - const pkg = findPackage(model, packageName)!; - - return [ - { slug: ['main'] }, - ...getMembers(pkg, 'main').map((member) => { - if (member.kind === ApiItemKind.Function && member.overloadIndex && member.overloadIndex > 1) { - return { - slug: ['main', `${member.name}:${member.overloadIndex}:${member.kind}`], - }; - } - - return { slug: ['main', `${member.name}:${member.kind}`] }; - }), - ]; - } catch { - return [{ slug: ['main'] }]; - } -} - -async function getData(packageName: string, slug: string[]) { - const [branchName = 'main', member] = slug; - - if (!PACKAGES.includes(packageName)) { - notFound(); - } - - let data; - try { - if (process.env.NEXT_PUBLIC_LOCAL_DEV) { - const res = await readFile(join(cwd(), '..', '..', 'packages', packageName, 'docs', 'docs.api.json'), 'utf8'); - data = JSON.parse(res); - } else { - const res = await fetch(`https://docs.discordjs.dev/docs/${packageName}/${branchName}.api.json`); - data = await res.json(); - } - } catch { - notFound(); - } - - const [memberName, overloadIndex] = member?.split('%3A') ?? []; - - const readme = await readFile(join(cwd(), 'src', 'assets', 'readme', packageName, 'home-README.md'), 'utf8'); - - const mdxSource = await serialize(readme, { - mdxOptions: { - remarkPlugins: [remarkGfm], - remarkRehypeOptions: { allowDangerousHtml: true }, - rehypePlugins: [ - rehypeRaw, - rehypeIgnore, - rehypeSlug, - [ - rehypePrettyCode, - { - theme: { - dark: shikiThemeDarkPlus, - light: shikiThemeLightPlus, - }, - getHighlighter: async (options?: Partial) => - getHighlighter({ - ...options, - langs: [ - // @ts-expect-error: Working as intended - { id: 'javascript', aliases: ['js'], scopeName: 'source.js', grammar: shikiLangJavascript }, - // @ts-expect-error: Working as intended - { id: 'typescript', aliases: ['ts'], scopeName: 'source.ts', grammar: shikiLangTypescript }, - ], - }), - }, - ], - ], - format: 'md', - }, - }); - - const model = createApiModel(data); - const pkg = findPackage(model, packageName); - - // eslint-disable-next-line prefer-const - let { containerKey, name } = findMember(model, packageName, memberName, branchName) ?? {}; - if (name && overloadIndex && !Number.isNaN(Number.parseInt(overloadIndex, 10))) { - containerKey = ApiFunction.getContainerKey(name, Number.parseInt(overloadIndex, 10)); - } - - const members = pkg - ? getMembers(pkg, branchName).filter((item) => item.overloadIndex === null || item.overloadIndex <= 1) - : []; - const foundMember = - memberName && containerKey ? findMemberByKey(model, packageName, containerKey, branchName) ?? null : null; - const description = foundMember ? tryResolveDescription(foundMember) ?? DESCRIPTION : DESCRIPTION; - - return { - packageName, - branchName, - data: { - members, - member: foundMember, - description, - source: mdxSource, - }, - }; -} - -// function resolveMember(packageName?: string | undefined, member?: SidebarLayoutProps['data']['member']) { -// switch (member?.kind) { -// case 'Class': { -// const typedMember = member as ApiClassJSON; -// return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}&methods=${typedMember.methods.length}&props=${typedMember.properties.length}`; -// } - -// case 'Function': { -// const typedMember = member as ApiFunctionJSON; -// return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}`; -// } - -// case 'Interface': { -// const typedMember = member as ApiInterfaceJSON; -// return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}&methods=${typedMember.methods.length}&props=${typedMember.properties.length}`; -// } - -// case 'TypeAlias': { -// const typedMember = member as ApiTypeAliasJSON; -// return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}`; -// } - -// case 'Variable': { -// const typedMember = member as ApiVariableJSON; -// return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}`; -// } - -// case 'Enum': { -// const typedMember = member as ApiEnumJSON; -// return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}&members=${typedMember.members.length}`; -// } - -// default: { -// return `?pkg=${packageName}&kind=${member?.kind}&name=${member?.name}`; -// } -// } -// } - -function member(props?: ApiItemJSON | undefined) { - switch (props?.kind) { - case 'Class': - return ; - case 'Function': - return ; - case 'Interface': - return ; - case 'TypeAlias': - return ; - case 'Variable': - return ; - case 'Enum': - return ; - default: - return
Cannot render that item type
; - } -} - -export default async function Page({ params }: { params: { package: string; slug: string[] } }) { - const data = await getData(params.package, params.slug); - - // const name = useMemo( - // () => `discord.js${params.data?.member?.name ? ` | ${params.data.member.name}` : ''}`, - // [params.data?.member?.name], - // ); - // const ogTitle = useMemo( - // () => `${params.packageName ?? 'discord.js'}${params.data?.member?.name ? ` | ${params.data.member.name}` : ''}`, - // [params.packageName, params.data?.member?.name], - // ); - // const ogImage = useMemo( - // () => resolveMember(params.packageName, params.data?.member), - // [params.packageName, params.data?.member], - // ); - - // Just in case - // return ; - - return ( - -