mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-13 10:03:31 +01:00
refactor: website facelift (#10823)
This commit is contained in:
@@ -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} />;
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user