diff --git a/packages/website/package.json b/packages/website/package.json
index a0cded536..464b5c93d 100644
--- a/packages/website/package.json
+++ b/packages/website/package.json
@@ -70,7 +70,8 @@
"rehype-raw": "^6.1.1",
"rehype-slug": "^5.0.1",
"remark-gfm": "^3.0.1",
- "sharp": "^0.30.7"
+ "sharp": "^0.30.7",
+ "swr": "^1.3.0"
},
"devDependencies": {
"@testing-library/react": "^13.3.0",
diff --git a/packages/website/src/components/RouterTransition.tsx b/packages/website/src/components/RouterTransition.tsx
index bd8652337..2fa6dd979 100644
--- a/packages/website/src/components/RouterTransition.tsx
+++ b/packages/website/src/components/RouterTransition.tsx
@@ -18,6 +18,7 @@ export function RouterTransition() {
router.events.off('routeChangeComplete', handleComplete);
router.events.off('routeChangeError', handleComplete);
};
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [router.asPath]);
return ;
diff --git a/packages/website/src/components/SidebarLayout.tsx b/packages/website/src/components/SidebarLayout.tsx
index 4c14345b9..14e566288 100644
--- a/packages/website/src/components/SidebarLayout.tsx
+++ b/packages/website/src/components/SidebarLayout.tsx
@@ -18,6 +18,7 @@ import {
ActionIcon,
useMantineColorScheme,
Center,
+ Stack,
} from '@mantine/core';
import { NextLink } from '@mantine/next';
import type { MDXRemoteSerializeResult } from 'next-mdx-remote';
@@ -25,15 +26,19 @@ import Image from 'next/future/image';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { type PropsWithChildren, useState } from 'react';
-import { VscChevronDown, VscPackage } from 'react-icons/vsc';
+import { VscChevronDown, VscPackage, VscVersions } from 'react-icons/vsc';
import { WiDaySunny, WiNightClear } from 'react-icons/wi';
+import useSWR from 'swr';
import { SidebarItems } from './SidebarItems';
import type { ApiItemJSON } from '~/DocModel/ApiNodeJSONEncoder';
import type { findMember } from '~/util/model.server';
import type { getMembers } from '~/util/parse.server';
+const fetcher = (url: string) => fetch(url).then((res) => res.json());
+
export interface SidebarLayoutProps {
packageName: string;
+ branchName: string;
data: {
members: ReturnType;
member: ReturnType;
@@ -54,24 +59,31 @@ export interface GroupedMembers {
Variables: Members;
}
-const useStyles = createStyles((theme, { opened }: { opened: boolean }) => ({
- control: {
- display: 'block',
- width: '100%',
- padding: theme.spacing.xs,
- color: theme.colorScheme === 'dark' ? theme.colors.dark![0] : theme.black,
+const useStyles = createStyles(
+ (theme, { openedLib, openedVersion }: { openedLib: boolean; openedVersion: boolean }) => ({
+ control: {
+ display: 'block',
+ width: '100%',
+ padding: theme.spacing.xs,
+ color: theme.colorScheme === 'dark' ? theme.colors.dark![0] : theme.black,
- '&:hover': {
- backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark![6] : theme.colors.gray![0],
- color: theme.colorScheme === 'dark' ? theme.white : theme.black,
+ '&:hover': {
+ backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark![6] : theme.colors.gray![0],
+ color: theme.colorScheme === 'dark' ? theme.white : theme.black,
+ },
},
- },
- icon: {
- transition: 'transform 150ms ease',
- transform: opened ? 'rotate(180deg)' : 'rotate(0deg)',
- },
-}));
+ iconLib: {
+ transition: 'transform 150ms ease',
+ transform: openedLib ? 'rotate(180deg)' : 'rotate(0deg)',
+ },
+
+ iconVersion: {
+ transition: 'transform 150ms ease',
+ transform: openedVersion ? 'rotate(180deg)' : 'rotate(0deg)',
+ },
+ }),
+);
const libraries = [
{ label: 'builders', value: 'builders' },
@@ -83,17 +95,26 @@ const libraries = [
{ label: 'ws', value: 'ws' },
];
-export function SidebarLayout({ packageName, data, children }: PropsWithChildren>) {
+export function SidebarLayout({
+ packageName,
+ branchName,
+ data,
+ children,
+}: PropsWithChildren>) {
const router = useRouter();
-
+ const { data: versions } = useSWR(
+ `https://docs.discordjs.dev/api/info?package=${packageName ?? 'builders'}`,
+ fetcher,
+ );
const theme = useMantineTheme();
const { colorScheme, toggleColorScheme } = useMantineColorScheme();
const dark = colorScheme === 'dark';
const [opened, setOpened] = useState(false);
- const [openedPicker, setOpenedPicker] = useState(false);
+ const [openedLibPicker, setOpenedLibPicker] = useState(false);
+ const [openedVersionPicker, setOpenedVersionPicker] = useState(false);
- const { classes } = useStyles({ opened: openedPicker });
+ const { classes } = useStyles({ openedLib: openedLibPicker, openedVersion: openedVersionPicker });
const libraryMenuItems = libraries.map((item) => (
@@ -101,6 +122,13 @@ export function SidebarLayout({ packageName, data, children }: PropsWithChildren
));
+ const versionMenuItems =
+ versions?.map((item) => (
+
+ {item}
+
+ )) ?? [];
+
const asPathWithoutQuery = router.asPath.split('?')[0]?.split('#')[0];
const breadcrumbs = asPathWithoutQuery?.split('/').map((path, idx, original) => (
@@ -124,10 +152,10 @@ export function SidebarLayout({ packageName, data, children }: PropsWithChildren
{packageName && data ? (
<>
- <>
+
- >
+
+
+
-
+
>
diff --git a/packages/website/src/contexts/member.tsx b/packages/website/src/contexts/member.tsx
index d45059596..f45fd071b 100644
--- a/packages/website/src/contexts/member.tsx
+++ b/packages/website/src/contexts/member.tsx
@@ -1,12 +1,12 @@
-import { createContext } from 'react';
+import { createContext, useContext, type ReactNode } from 'react';
import type { ApiItemJSON } from '~/DocModel/ApiNodeJSONEncoder';
export const MemberContext = createContext(undefined);
-export const MemberProvider = ({
- member,
- children,
-}: {
- member: ApiItemJSON | undefined;
- children: React.ReactNode;
-}) => {children};
+export const MemberProvider = ({ member, children }: { member: ApiItemJSON | undefined; children: ReactNode }) => (
+ {children}
+);
+
+export function useMember() {
+ return useContext(MemberContext);
+}
diff --git a/packages/website/src/pages/docs/[...slug].tsx b/packages/website/src/pages/docs/[...slug].tsx
index 045f5965a..d241743af 100644
--- a/packages/website/src/pages/docs/[...slug].tsx
+++ b/packages/website/src/pages/docs/[...slug].tsx
@@ -1,11 +1,13 @@
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
-import { Box } from '@mantine/core';
+import { Affix, Box, Button, Transition } from '@mantine/core';
+import { useMediaQuery, useWindowScroll } from '@mantine/hooks';
import { ApiFunction, ApiPackage } from '@microsoft/api-extractor-model';
import { MDXRemote } from 'next-mdx-remote';
import { serialize } from 'next-mdx-remote/serialize';
import Head from 'next/head';
import type { GetStaticPaths, GetStaticProps } from 'next/types';
+import { VscChevronUp } from 'react-icons/vsc';
import rehypeHighlight from 'rehype-highlight';
import rehypeIgnore from 'rehype-ignore';
import rehypeRaw from 'rehype-raw';
@@ -165,6 +167,7 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
return {
props: {
packageName,
+ branchName,
data: {
members: pkg ? getMembers(pkg, branchName) : [],
member:
@@ -202,6 +205,9 @@ const member = (props?: ApiItemJSON | undefined) => {
};
export default function Slug(props: Partial) {
+ const [scroll, scrollTo] = useWindowScroll();
+ const matches = useMediaQuery('(max-width: 1200px)', true, { getInitialValueInEffect: false });
+
return props.error ? (
{props.error}
) : (
@@ -213,6 +219,19 @@ export default function Slug(props: Partialdiscord.js | {props.data.member.name}
{member(props.data.member)}
+
+ 250}>
+ {(transitionStyles) => (
+ }
+ style={transitionStyles}
+ onClick={() => scrollTo({ y: 0 })}
+ >
+ Scroll to top
+
+ )}
+
+
>
) : props.data?.source ? (
diff --git a/yarn.lock b/yarn.lock
index c78c4ae79..c865c4e27 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2052,6 +2052,7 @@ __metadata:
rehype-slug: ^5.0.1
remark-gfm: ^3.0.1
sharp: ^0.30.7
+ swr: ^1.3.0
typescript: ^4.7.4
unocss: ^0.45.12
vercel: ^28.1.0
@@ -15633,6 +15634,15 @@ __metadata:
languageName: node
linkType: hard
+"swr@npm:^1.3.0":
+ version: 1.3.0
+ resolution: "swr@npm:1.3.0"
+ peerDependencies:
+ react: ^16.11.0 || ^17.0.0 || ^18.0.0
+ checksum: e7a184f0d560e9c8be85c023cc8e65e56a88a6ed46f9394b301b07f838edca23d2e303685319a4fcd620b81d447a7bcb489c7fa0a752c259f91764903c690cdb
+ languageName: node
+ linkType: hard
+
"sync-request@npm:^6.1.0":
version: 6.1.0
resolution: "sync-request@npm:6.1.0"