Skip to content

Commit 1585eb6

Browse files
committed
feat: website
1 parent dcf98e4 commit 1585eb6

File tree

17 files changed

+390
-107
lines changed

17 files changed

+390
-107
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pids
1717
# Dist
1818
dist
1919
dist-docs
20+
packages/discord-api-types
2021

2122
# Miscellaneous
2223
.tmp

apps/website/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"lucide-react": "^0.503.0",
6161
"meilisearch": "^0.49.0",
6262
"motion": "^12.9.2",
63-
"next": "15.4.0-canary.11",
63+
"next": "15.4.0-canary.31",
6464
"next-mdx-remote-client": "^2.1.1",
6565
"next-themes": "^0.4.6",
6666
"nuqs": "^2.4.3",

apps/website/src/app/docs/packages/[packageName]/[version]/layout.tsx renamed to apps/website/src/app/docs/packages/[packageName]/[version]/[[...item]]/layout.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { VscGithubInverted } from '@react-icons/all-files/vsc/VscGithubInverted'
44
import type { Metadata } from 'next';
55
import Link from 'next/link';
66
import { Suspense, type PropsWithChildren } from 'react';
7+
import { EntryPointSelect } from '@/components/EntrypointSelect';
78
import { Footer } from '@/components/Footer';
89
import { Navigation } from '@/components/Navigation';
910
import { Scrollbars } from '@/components/OverlayScrollbars';
@@ -13,14 +14,21 @@ import { ThemeSwitchNoSRR } from '@/components/ThemeSwitch';
1314
import { VersionSelect } from '@/components/VersionSelect';
1415
import { Sidebar, SidebarContent, SidebarHeader, SidebarInset, SidebarTrigger } from '@/components/ui/Sidebar';
1516
import { buttonStyles } from '@/styles/ui/button';
17+
import { PACKAGES_WITH_ENTRY_POINTS } from '@/util/constants';
1618
import { ENV } from '@/util/env';
19+
import { fetchEntryPoints } from '@/util/fetchEntryPoints';
1720
import { fetchVersions } from '@/util/fetchVersions';
21+
import { parseDocsPathParams } from '@/util/parseDocsPathParams';
1822
import { CmdK } from './CmdK';
1923

2024
export async function generateMetadata({
2125
params,
2226
}: {
23-
readonly params: Promise<{ readonly packageName: string; readonly version: string }>;
27+
readonly params: Promise<{
28+
readonly item?: string[] | undefined;
29+
readonly packageName: string;
30+
readonly version: string;
31+
}>;
2432
}): Promise<Metadata> {
2533
const { packageName, version } = await params;
2634

@@ -35,10 +43,20 @@ export async function generateMetadata({
3543
export default async function Layout({
3644
params,
3745
children,
38-
}: PropsWithChildren<{ readonly params: Promise<{ readonly packageName: string; readonly version: string }> }>) {
39-
const { packageName, version } = await params;
46+
}: PropsWithChildren<{
47+
readonly params: Promise<{
48+
readonly item?: string[] | undefined;
49+
readonly packageName: string;
50+
readonly version: string;
51+
}>;
52+
}>) {
53+
const { packageName, version, item } = await params;
4054

4155
const versions = fetchVersions(packageName);
56+
const entryPoints = fetchEntryPoints(packageName, version);
57+
58+
const hasEntryPoints = PACKAGES_WITH_ENTRY_POINTS.includes(packageName);
59+
const { entryPoints: parsedEntrypoints } = parseDocsPathParams(item);
4260

4361
return (
4462
<>
@@ -65,12 +83,13 @@ export default async function Layout({
6583
<PackageSelect />
6684
{/* <h3 className="p-1 text-lg font-semibold">{version}</h3> */}
6785
<VersionSelect versionsPromise={versions} />
86+
{hasEntryPoints ? <EntryPointSelect entryPointsPromise={entryPoints} /> : null}
6887
<SearchButton />
6988
</div>
7089
</SidebarHeader>
7190
<SidebarContent className="bg-[#f3f3f4] p-0 py-4 pl-4 dark:bg-[#121214]">
7291
<Scrollbars>
73-
<Navigation packageName={packageName} version={version} />
92+
<Navigation entryPoint={parsedEntrypoints.join('.')} packageName={packageName} version={version} />
7493
</Scrollbars>
7594
</SidebarContent>
7695
</Sidebar>
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
'use cache';
2+
3+
import { readFile } from 'node:fs/promises';
4+
import { join } from 'node:path';
5+
import rehypeShikiFromHighlighter from '@shikijs/rehype/core';
6+
import type { Metadata } from 'next';
7+
import { MDXRemote } from 'next-mdx-remote-client/rsc';
8+
import remarkGfm from 'remark-gfm';
9+
import { DocItem } from '@/components/DocItem';
10+
import { fetchNode } from '@/util/fetchNode';
11+
import { parseDocsPathParams } from '@/util/parseDocsPathParams';
12+
import { getSingletonHighlighter } from '@/util/shiki.bundle';
13+
14+
export async function generateMetadata({
15+
params,
16+
}: {
17+
readonly params: Promise<{
18+
readonly item?: string[] | undefined;
19+
readonly packageName: string;
20+
readonly version: string;
21+
}>;
22+
}): Promise<Metadata> {
23+
const { item, packageName, version } = await params;
24+
25+
const { foundItem } = parseDocsPathParams(item);
26+
27+
if (!foundItem) {
28+
return {
29+
title: `${packageName} (${version})`,
30+
};
31+
}
32+
33+
const decodedItemName = decodeURIComponent(foundItem);
34+
const titlePart = decodedItemName.split(':')?.[0] ?? decodedItemName;
35+
36+
return {
37+
title: `${titlePart} (${packageName} - ${version})`,
38+
};
39+
}
40+
41+
export default async function Page({
42+
params,
43+
}: {
44+
readonly params: Promise<{
45+
readonly item?: string[] | undefined;
46+
readonly packageName: string;
47+
readonly version: string;
48+
}>;
49+
}) {
50+
const { item, packageName, version } = await params;
51+
52+
const { entryPoints: parsedEntrypoints, foundItem } = parseDocsPathParams(item);
53+
54+
if (!foundItem) {
55+
const fileContent = await readFile(join(process.cwd(), `src/assets/readme/${packageName}/home-README.md`), 'utf8');
56+
57+
return (
58+
<div className="prose prose-neutral dark:prose-invert prose-a:[&>img]:inline-block prose-a:[&>img]:m-0 prose-a:[&>img[height='44']]:h-11 prose-p:my-2 prose-pre:py-3 prose-pre:rounded-sm prose-pre:px-0 prose-pre:border prose-pre:border-[#d4d4d4] dark:prose-pre:border-[#404040] prose-code:font-normal prose-a:text-[#5865F2] prose-a:no-underline prose-a:hover:text-[#3d48c3] dark:prose-a:hover:text-[#7782fa] mx-auto max-w-screen-xl px-6 py-6 [&_code_span:last-of-type:empty]:hidden [&_div[align='center']_p_a+a]:ml-2">
59+
<MDXRemote
60+
options={{
61+
mdxOptions: {
62+
remarkPlugins: [remarkGfm],
63+
rehypePlugins: [
64+
[
65+
rehypeShikiFromHighlighter,
66+
await getSingletonHighlighter({
67+
langs: ['typescript', 'javascript', 'shellscript'],
68+
themes: ['github-light', 'github-dark-dimmed'],
69+
}),
70+
{
71+
themes: {
72+
light: 'github-light',
73+
dark: 'github-dark-dimmed',
74+
},
75+
},
76+
],
77+
],
78+
},
79+
}}
80+
source={fileContent}
81+
/>
82+
</div>
83+
);
84+
}
85+
86+
const entryPointString = parsedEntrypoints.join('.');
87+
const node = await fetchNode({
88+
entryPoint: entryPointString,
89+
item: decodeURIComponent(foundItem),
90+
packageName,
91+
version,
92+
});
93+
94+
return (
95+
<main className="mx-auto flex w-full max-w-screen-xl flex-col gap-8 px-6 py-4">
96+
<DocItem node={node} packageName={packageName} version={version} />
97+
</main>
98+
);
99+
}

apps/website/src/app/docs/packages/[packageName]/[version]/[item]/page.tsx

Lines changed: 0 additions & 44 deletions
This file was deleted.

apps/website/src/app/docs/packages/[packageName]/[version]/page.tsx

Lines changed: 0 additions & 42 deletions
This file was deleted.

apps/website/src/components/DocItem.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
'use cache';
2+
13
import { VscSymbolParameter } from '@react-icons/all-files/vsc/VscSymbolParameter';
24
import { ConstructorNode } from './ConstructorNode';
35
import { DeprecatedNode } from './DeprecatedNode';
@@ -26,8 +28,6 @@ async function OverloadNode({
2628
readonly packageName: string;
2729
readonly version: string;
2830
}) {
29-
'use cache';
30-
3131
return (
3232
<Tabs className="flex flex-col gap-4">
3333
<TabList className="flex flex-wrap gap-2">
@@ -63,8 +63,6 @@ export async function DocItem({
6363
readonly packageName: string;
6464
readonly version: string;
6565
}) {
66-
'use cache';
67-
6866
if (node.overloads?.length) {
6967
return <OverloadNode node={node} packageName={packageName} version={version} />;
7068
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use client';
2+
3+
import { useParams, useRouter } from 'next/navigation';
4+
import { use } from 'react';
5+
import { parseDocsPathParams } from '@/util/parseDocsPathParams';
6+
import { Select, SelectList, SelectOption, SelectTrigger } from './ui/Select';
7+
8+
export function EntryPointSelect({
9+
entryPointsPromise,
10+
}: {
11+
readonly entryPointsPromise: Promise<{ readonly entryPoint: string }[]>;
12+
}) {
13+
const router = useRouter();
14+
const params = useParams();
15+
const entryPoints = use(entryPointsPromise);
16+
17+
const { entryPoints: parsedEntrypoints } = parseDocsPathParams(params.item as string[] | undefined);
18+
19+
return (
20+
<Select
21+
aria-label="Select an entrypoint"
22+
defaultSelectedKey={parsedEntrypoints.length ? parsedEntrypoints.join('/') : 'global'}
23+
>
24+
<SelectTrigger className="bg-[#f3f3f4] dark:bg-[#121214]" />
25+
<SelectList classNames={{ popover: 'bg-[#f3f3f4] dark:bg-[#28282d]' }} items={entryPoints}>
26+
{(item) => (
27+
<SelectOption
28+
className="dark:pressed:bg-[#313135] bg-[#f3f3f4] dark:bg-[#28282d] dark:hover:bg-[#313135]"
29+
href={`/docs/packages/${params.packageName}/${params.version}/${item.entryPoint}`}
30+
id={item.entryPoint || 'global'}
31+
key={item.entryPoint || 'global'}
32+
onHoverStart={() =>
33+
router.prefetch(`/docs/packages/${params.packageName}/${params.version}/${item.entryPoint}`)
34+
}
35+
textValue={item.entryPoint || 'global'}
36+
>
37+
{item.entryPoint || 'global'}
38+
</SelectOption>
39+
)}
40+
</SelectList>
41+
</Select>
42+
);
43+
}

apps/website/src/components/Navigation.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,16 @@ import { resolveNodeKind } from './DocKind';
55
import { NavigationItem } from './NavigationItem';
66
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/Collapsible';
77

8-
export async function Navigation({ packageName, version }: { readonly packageName: string; readonly version: string }) {
9-
const node = await fetchSitemap({ packageName, version });
8+
export async function Navigation({
9+
entryPoint,
10+
packageName,
11+
version,
12+
}: {
13+
readonly entryPoint?: string | undefined;
14+
readonly packageName: string;
15+
readonly version: string;
16+
}) {
17+
const node = await fetchSitemap({ entryPoint, packageName, version });
1018

1119
if (!node) {
1220
notFound();

apps/website/src/util/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ export const PACKAGES = [
1111
{ name: 'util' },
1212
{ name: 'voice' },
1313
{ name: 'ws' },
14+
{ name: 'discord-api-types' },
1415
];
1516

17+
export const PACKAGES_WITH_ENTRY_POINTS = ['discord-api-types'];
18+
1619
export const DESCRIPTION =
1720
"discord.js is a powerful Node.js module that allows you to interact with the Discord API very easily. It takes a much more object-oriented approach than most other JS Discord libraries, making your bot's code significantly tidier and easier to comprehend.";

0 commit comments

Comments
 (0)