refactor: website facelift (#10823)

This commit is contained in:
Noel
2025-04-10 22:02:37 +02:00
committed by GitHub
parent 1fe53c7ca2
commit 2e3bc69602
80 changed files with 6136 additions and 2529 deletions

View File

@@ -0,0 +1,14 @@
import { CmdKNoSRR } from '@/components/CmdK';
import { fetchDependencies } from '@/util/fetchDependencies';
export async function CmdK({
params,
}: {
readonly params: Promise<{ readonly packageName: string; readonly version: string }>;
}) {
const { packageName, version } = await params;
const dependencies = await fetchDependencies({ packageName, version });
return <CmdKNoSRR dependencies={dependencies} />;
}

View File

@@ -1,7 +1,7 @@
/* eslint-disable react/no-unknown-property */
import { ImageResponse } from 'next/og';
import { resolveKind } from '~/util/resolveNodeKind';
import { resolveKind } from '@/util/resolveNodeKind';
export const runtime = 'edge';
@@ -15,14 +15,24 @@ export const contentType = 'image/png';
export default async function Image({
params,
}: {
readonly params: { readonly item: string; readonly packageName: string; readonly version: string };
readonly params: Promise<{ readonly item: string; readonly packageName: string; readonly version: string }>;
}) {
const normalizeItem = params.item.split(encodeURIComponent(':')).join('.').toLowerCase();
const { item, packageName, version } = await params;
const isMainVersion = params.version === 'main';
const [fontDataBold, fontDataBlack] = await Promise.all([
fetch(new URL('../../../../../../assets/Geist-Bold.ttf', import.meta.url), {
next: { revalidate: 604_800 },
}).then(async (res) => res.arrayBuffer()),
fetch(new URL('../../../../../../assets/Geist-Black.ttf', import.meta.url), {
next: { revalidate: 604_800 },
}).then(async (res) => res.arrayBuffer()),
]);
const normalizeItem = item.split(encodeURIComponent(':')).join('.').toLowerCase();
const isMain = version === 'main';
const fileContent = await fetch(
`${process.env.BLOB_STORAGE_URL}/rewrite/${params.packageName}/${params.version}.${normalizeItem}.api.json`,
{ next: isMainVersion ? { revalidate: 0 } : { revalidate: 604_800 } },
`${process.env.BLOB_STORAGE_URL}/rewrite/${packageName}/${version}.${normalizeItem}.api.json`,
{ next: { revalidate: isMain ? 0 : 604_800 } },
);
const node = await fileContent.json();
@@ -30,7 +40,7 @@ export default async function Image({
(
<div tw="flex bg-[#121212] h-full w-full p-14">
<div tw="flex flex-col mx-auto h-full text-white">
<div tw="flex text-4xl text-gray-400">{params.packageName}</div>
<div tw="flex text-4xl text-gray-400">{packageName}</div>
<div tw="flex flex-col justify-between h-full w-full pt-14">
<div tw="flex items-center max-w-full">
<span tw="mr-6">{resolveKind(node.kind, 94)}</span>
@@ -40,7 +50,7 @@ export default async function Image({
whiteSpace: 'nowrap',
overflow: 'hidden',
}}
tw="text-[5.5rem] font-bold w-full"
tw="text-[5.5rem] font-bold w-full"
>
{node.displayName}
</h2>
@@ -94,6 +104,20 @@ export default async function Image({
),
{
...size,
fonts: [
{
name: 'Geist',
data: fontDataBold,
weight: 700,
style: 'normal',
},
{
name: 'Geist',
data: fontDataBlack,
weight: 900,
style: 'normal',
},
],
},
);
}

View File

@@ -1,38 +1,44 @@
'use cache';
import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { DocItem } from '~/components/DocItem';
import { fetchNode } from '~/util/fetchNode';
import { DocItem } from '@/components/DocItem';
import { fetchNode } from '@/util/fetchNode';
export async function generateMetadata({
params,
}: {
readonly params: {
readonly params: Promise<{
readonly item: string;
readonly packageName: string;
readonly version: string;
};
}>;
}): Promise<Metadata> {
const normalizeItem = params.item.split(encodeURIComponent(':'))[0];
const { item, packageName, version } = await params;
const normalizeItem = item.split(encodeURIComponent(':'))[0];
return {
title: `${normalizeItem} (${params.packageName} - ${params.version})`,
title: `${normalizeItem} (${packageName} - ${version})`,
};
}
export default async function Page({
params,
}: {
readonly params: { readonly item: string; readonly packageName: string; readonly version: string };
readonly params: Promise<{ readonly item: string; readonly packageName: string; readonly version: string }>;
}) {
const node = await fetchNode({ item: params.item, packageName: params.packageName, version: params.version });
const { item, packageName, version } = await params;
const node = await fetchNode({ item, packageName, version });
if (!node) {
notFound();
}
return (
<main className="flex w-full flex-col gap-8 pb-12 md:pb-0">
<DocItem node={node} packageName={params.packageName} version={params.version} />
<main className="mx-auto flex w-full max-w-screen-xl flex-col gap-8 px-6 py-4">
<DocItem node={node} packageName={packageName} version={version} />
</main>
);
}

View File

@@ -1,24 +1,33 @@
import type { Metadata } from 'next';
import dynamic from 'next/dynamic';
import type { PropsWithChildren } from 'react';
import { Navigation } from '~/components/Navigation';
import { OverlayScrollbarsComponent } from '~/components/OverlayScrollbars';
import { Drawer } from '~/components/ui/Drawer';
import { Footer } from '~/components/ui/Footer';
import { fetchDependencies } from '~/util/fetchDependencies';
'use cache';
// eslint-disable-next-line promise/prefer-await-to-then
const CmdK = dynamic(async () => import('~/components/ui/CmdK').then((mod) => mod.CmdK), { ssr: false });
import { VscGithubInverted } from '@react-icons/all-files/vsc/VscGithubInverted';
import type { Metadata } from 'next';
import Link from 'next/link';
import { Suspense, type PropsWithChildren } from 'react';
import { Footer } from '@/components/Footer';
import { Navigation } from '@/components/Navigation';
import { Scrollbars } from '@/components/OverlayScrollbars';
import { PackageSelect } from '@/components/PackageSelect';
import { SearchButton } from '@/components/SearchButton';
import { ThemeSwitchNoSRR } from '@/components/ThemeSwitch';
import { VersionSelect } from '@/components/VersionSelect';
import { Sidebar, SidebarContent, SidebarHeader, SidebarInset, SidebarTrigger } from '@/components/ui/Sidebar';
import { buttonStyles } from '@/styles/ui/button';
import { ENV } from '@/util/env';
import { fetchVersions } from '@/util/fetchVersions';
import { CmdK } from './CmdK';
export async function generateMetadata({
params,
}: {
readonly params: { readonly packageName: string; readonly version: string };
readonly params: Promise<{ readonly packageName: string; readonly version: string }>;
}): Promise<Metadata> {
const { packageName, version } = await params;
return {
title: {
template: '%s | discord.js',
default: `${params.packageName} (${params.version})`,
default: `${packageName} (${version})`,
},
};
}
@@ -26,44 +35,74 @@ export async function generateMetadata({
export default async function Layout({
params,
children,
}: PropsWithChildren<{ readonly params: { readonly packageName: string; readonly version: string } }>) {
const dependencies = await fetchDependencies({ packageName: params.packageName, version: params.version });
}: PropsWithChildren<{ readonly params: Promise<{ readonly packageName: string; readonly version: string }> }>) {
const { packageName, version } = await params;
const versions = fetchVersions(packageName);
return (
// eslint-disable-next-line react/no-unknown-property
<div className="mx-auto flex max-w-screen-2xl flex-col gap-12 p-6 md:flex-row" vaul-drawer-wrapper="">
<div className="sticky top-6 hidden flex-shrink-0 self-start md:block">
<OverlayScrollbarsComponent
className="max-h-[calc(100dvh-48px)]"
defer
options={{
overflow: { x: 'hidden' },
scrollbars: {
autoHide: 'scroll',
autoHideDelay: 500,
autoHideSuspend: true,
clickScroll: true,
},
}}
>
<Navigation className="pr-4" packageName={params.packageName} version={params.version} />
</OverlayScrollbarsComponent>
</div>
<div className="pb-12">
{children}
<Footer />
</div>
<div className="fixed bottom-0 left-0 right-0 md:hidden">
<Drawer>
<Navigation
className="max-w-none overflow-auto p-0 lg:max-w-none"
drawer
packageName={params.packageName}
version={params.version}
/>
</Drawer>
</div>
<CmdK dependencies={dependencies} />
</div>
<>
<Sidebar closeButton={false} intent="inset">
<SidebarHeader className="bg-[#f3f3f4] p-4 dark:bg-[#121214]">
<div className="flex flex-col gap-2">
<div className="flex place-content-between place-items-center p-1">
<Link className="text-xl font-bold" href={`/docs/packages/${packageName}/${version}`}>
{packageName}
</Link>
<div className="flex place-items-center gap-2">
<Link
aria-label="GitHub"
className={buttonStyles({ variant: 'filled', size: 'icon-sm' })}
href="https://github.com/discordjs/discord.js"
rel="external noopener noreferrer"
target="_blank"
>
<VscGithubInverted aria-hidden data-slot="icon" size={18} />
</Link>
<ThemeSwitchNoSRR />
</div>
</div>
<PackageSelect />
{/* <h3 className="p-1 text-lg font-semibold">{version}</h3> */}
<VersionSelect versionsPromise={versions} />
<SearchButton />
</div>
</SidebarHeader>
<SidebarContent className="bg-[#f3f3f4] p-0 py-4 pl-4 dark:bg-[#121214]">
<Scrollbars>
<Navigation packageName={packageName} version={version} />
</Scrollbars>
</SidebarContent>
</Sidebar>
<SidebarInset>
{ENV.IS_LOCAL_DEV ? (
<div className="sticky top-0 z-10 flex place-content-center place-items-center border border-red-400/35 bg-red-500/65 p-2 px-4 text-center text-base text-white shadow-md backdrop-blur">
Local test environment
</div>
) : null}
{ENV.IS_PREVIEW ? (
<div className="sticky top-0 z-10 flex place-content-center place-items-center border border-red-400/35 bg-red-500/65 p-2 px-4 text-center text-base text-white shadow-md backdrop-blur">
Preview environment
</div>
) : null}
<div className="bg-[#fbfbfb] pb-12 dark:bg-[#1a1a1e]">
<div className="relative px-6 pt-6 md:hidden">
<div className="fixed top-5 left-6 z-20 md:hidden">
<SidebarTrigger aria-label="Navigation" size="icon" variant="filled" />
</div>
<div className="flex place-content-end">
<Link className="text-xl font-bold" href={`/docs/packages/${packageName}/${version}`}>
{packageName}
</Link>
</div>
</div>
{children}
<Footer />
</div>
</SidebarInset>
<Suspense>
<CmdK params={params} />
</Suspense>
</>
);
}

View File

@@ -1,29 +1,19 @@
'use cache';
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
import rehypeShikiFromHighlighter from '@shikijs/rehype/core';
import { MDXRemote } from 'next-mdx-remote-client/rsc';
import remarkGfm from 'remark-gfm';
import { getHighlighterCore } from 'shiki/core';
import getWasm from 'shiki/wasm';
import { getSingletonHighlighter } from '@/util/shiki.bundle';
const highlighter = await getHighlighterCore({
themes: [import('shiki/themes/github-light.mjs'), import('shiki/themes/github-dark-dimmed.mjs')],
langs: [
import('shiki/langs/typescript.mjs'),
import('shiki/langs/javascript.mjs'),
import('shiki/langs/shellscript.mjs'),
],
loadWasm: getWasm,
});
export default async function Page({ params }: { readonly params: Promise<{ readonly packageName: string }> }) {
const { packageName } = await params;
export default async function Page({ params }: { readonly params: { readonly packageName: string } }) {
const fileContent = await readFile(
join(process.cwd(), `src/assets/readme/${params.packageName}/home-README.md`),
'utf8',
);
const fileContent = await readFile(join(process.cwd(), `src/assets/readme/${packageName}/home-README.md`), 'utf8');
return (
<div className="prose prose-neutral mx-auto max-w-screen-xl dark:prose-invert">
<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">
<MDXRemote
options={{
mdxOptions: {
@@ -31,7 +21,10 @@ export default async function Page({ params }: { readonly params: { readonly pac
rehypePlugins: [
[
rehypeShikiFromHighlighter,
highlighter,
await getSingletonHighlighter({
langs: ['typescript', 'javascript', 'shellscript'],
themes: ['github-light', 'github-dark-dimmed'],
}),
{
themes: {
light: 'github-light',