diff --git a/apps/guide/src/components/Nav.tsx b/apps/guide/src/components/Nav.tsx index 3c2f09362..4f01a4376 100644 --- a/apps/guide/src/components/Nav.tsx +++ b/apps/guide/src/components/Nav.tsx @@ -23,7 +23,9 @@ export function Nav() { )} universal > - +
+ +
); diff --git a/apps/guide/src/components/Sidebar.tsx b/apps/guide/src/components/Sidebar.tsx index 16c2938c7..0675c245e 100644 --- a/apps/guide/src/components/Sidebar.tsx +++ b/apps/guide/src/components/Sidebar.tsx @@ -32,7 +32,7 @@ export function Sidebar() { const { setOpened } = useNav(); return ( -
+
{Object.keys(itemsByCategory).map((category, idx) => (
{itemsByCategory[category]?.map((member, index) => ( => { +export const fetchVersions = async (packageName: string): Promise => { if (process.env.NEXT_PUBLIC_LOCAL_DEV || process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview') { return ['main']; } @@ -26,9 +25,9 @@ export const fetchVersions = cache(async (packageName: string): Promise { +export const fetchModelJSON = async (packageName: string, version: string) => { if (process.env.NEXT_PUBLIC_LOCAL_DEV) { try { const res = await readFile( @@ -67,4 +66,4 @@ export const fetchModelJSON = cache(async (packageName: string, version: string) } catch { return null; } -}); +}; diff --git a/apps/website/src/app/docs/packages/[package]/[version]/[item]/page.tsx b/apps/website/src/app/docs/packages/[package]/[version]/[item]/page.tsx index 0507c78b6..cdfceaa50 100644 --- a/apps/website/src/app/docs/packages/[package]/[version]/[item]/page.tsx +++ b/apps/website/src/app/docs/packages/[package]/[version]/[item]/page.tsx @@ -166,7 +166,7 @@ export default async function Page({ params }: { params: ItemRouteParams }) { } return ( -
+
); diff --git a/apps/website/src/app/docs/packages/[package]/[version]/layout.tsx b/apps/website/src/app/docs/packages/[package]/[version]/layout.tsx index dff246e34..3cfa871c9 100644 --- a/apps/website/src/app/docs/packages/[package]/[version]/layout.tsx +++ b/apps/website/src/app/docs/packages/[package]/[version]/layout.tsx @@ -2,10 +2,11 @@ import type { ApiFunction, ApiItem } from '@discordjs/api-extractor-model'; import { ApiModel } from '@discordjs/api-extractor-model'; import dynamic from 'next/dynamic'; import { notFound } from 'next/navigation'; -import { cache, type PropsWithChildren } from 'react'; +import type { PropsWithChildren } from 'react'; import { fetchModelJSON, fetchVersions } from '~/app/docAPI'; import { CmdKDialog } from '~/components/CmdK'; import { Nav } from '~/components/Nav'; +import { Outline } from '~/components/Outline'; import type { SidebarSectionItemData } from '~/components/Sidebar'; import { resolveItemURI } from '~/components/documentation/util'; import { addPackageToModel } from '~/util/addPackageToModel'; @@ -36,14 +37,14 @@ export const generateStaticParams = async () => { return params; }; -const serializeIntoSidebarItemData = cache((item: ApiItem) => { +const serializeIntoSidebarItemData = (item: ApiItem) => { return { kind: item.kind, name: item.displayName, href: resolveItemURI(item), overloadIndex: 'overloadIndex' in item ? (item.overloadIndex as number) : undefined, } as SidebarSectionItemData; -}); +}; export default async function PackageLayout({ children, params }: PropsWithChildren<{ params: VersionRouteParams }>) { const modelJSON = await fetchModelJSON(params.package, params.version); @@ -80,15 +81,17 @@ export default async function PackageLayout({ children, params }: PropsWithChild
-
+
-
+
{children}
+ +
diff --git a/apps/website/src/app/docs/packages/[package]/[version]/providers.tsx b/apps/website/src/app/docs/packages/[package]/[version]/providers.tsx index 27ee38f28..03367f176 100644 --- a/apps/website/src/app/docs/packages/[package]/[version]/providers.tsx +++ b/apps/website/src/app/docs/packages/[package]/[version]/providers.tsx @@ -4,13 +4,16 @@ import type { PropsWithChildren } from 'react'; import { CmdKProvider } from '~/contexts/cmdK'; import { MemberProvider } from '~/contexts/member'; import { NavProvider } from '~/contexts/nav'; +import { OutlineProvider } from '~/contexts/outline'; export function Providers({ children }: PropsWithChildren) { return ( - - {children} - + + + {children} + + ); } diff --git a/apps/website/src/components/Badges.tsx b/apps/website/src/components/Badges.tsx index 206e0ffde..4da25e88e 100644 --- a/apps/website/src/components/Badges.tsx +++ b/apps/website/src/components/Badges.tsx @@ -28,7 +28,9 @@ export function Badges({ item }: { readonly item: ApiDocumentedItem }) { const isAbstract = ApiAbstractMixin.isBaseClassOf(item) && item.isAbstract; const isDeprecated = Boolean(item.tsdocComment?.deprecatedBlock); - return ( + const isAny = isStatic || isProtected || isReadonly || isAbstract || isDeprecated; + + return isAny ? (
{isDeprecated ? Deprecated : null} {isProtected ? Protected : null} @@ -36,5 +38,5 @@ export function Badges({ item }: { readonly item: ApiDocumentedItem }) { {isAbstract ? Abstract : null} {isReadonly ? Readonly : null}
- ); + ) : null; } diff --git a/apps/website/src/components/Nav.tsx b/apps/website/src/components/Nav.tsx index b7366cbd2..dbb08aa2c 100644 --- a/apps/website/src/components/Nav.tsx +++ b/apps/website/src/components/Nav.tsx @@ -35,10 +35,12 @@ export function Nav({ universal >
- - +
+ + +
+
- ); diff --git a/apps/website/src/components/Outline.tsx b/apps/website/src/components/Outline.tsx index fc7e90c82..f40460e92 100644 --- a/apps/website/src/components/Outline.tsx +++ b/apps/website/src/components/Outline.tsx @@ -1,23 +1,32 @@ 'use client'; +import { useOutline } from '~/contexts/outline'; import { Scrollbars } from './Scrollbars'; -import type { TableOfContentsSerialized } from './TableOfContentItems'; import { TableOfContentItems } from './TableOfContentItems'; -export function Outline({ members }: { readonly members: TableOfContentsSerialized[] }) { +export function Outline() { + const { members } = useOutline(); + + if (!members) { + return null; + } + return ( - +
+ +
); } diff --git a/apps/website/src/components/Sidebar.tsx b/apps/website/src/components/Sidebar.tsx index 8167294c2..b81fa250f 100644 --- a/apps/website/src/components/Sidebar.tsx +++ b/apps/website/src/components/Sidebar.tsx @@ -87,7 +87,7 @@ export function Sidebar({ members }: { readonly members: SidebarSectionItemData[ const groupItems = useMemo(() => groupMembers(members), [members]); return ( -
+
{(Object.keys(groupItems) as (keyof GroupedMembers)[]) .filter((group) => groupItems[group].length) .map((group, idx) => ( @@ -99,7 +99,7 @@ export function Sidebar({ members }: { readonly members: SidebarSectionItemData[ > {groupItems[group].map((member, index) => ( {children}
; + return
{children}
; } diff --git a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx index fbddbe3c6..5c70aa7eb 100644 --- a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx +++ b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx @@ -109,7 +109,7 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc: ); return ( -
+
{comment.deprecatedBlock ? ( {createNode(comment.deprecatedBlock.content)} ) : null} diff --git a/apps/website/src/components/model/Class.tsx b/apps/website/src/components/model/Class.tsx index 30c2a028b..af293ccd3 100644 --- a/apps/website/src/components/model/Class.tsx +++ b/apps/website/src/components/model/Class.tsx @@ -1,6 +1,5 @@ import type { ApiClass, ApiConstructor } from '@discordjs/api-extractor-model'; import { ApiItemKind } from '@discordjs/api-extractor-model'; -// import { Outline } from '../Outline'; import { Badges } from '../Badges'; import { Documentation } from '../documentation/Documentation'; import { HierarchyText } from '../documentation/HierarchyText'; @@ -8,13 +7,16 @@ import { Members } from '../documentation/Members'; import { ObjectHeader } from '../documentation/ObjectHeader'; import { ConstructorSection } from '../documentation/section/ConstructorSection'; import { TypeParameterSection } from '../documentation/section/TypeParametersSection'; -// import { serializeMembers } from '../documentation/util'; +import { serializeMembers } from '../documentation/util'; +import { OutlineSetter } from './OutlineSetter'; export function Class({ clazz }: { readonly clazz: ApiClass }) { const constructor = clazz.members.find((member) => member.kind === ApiItemKind.Constructor) as | ApiConstructor | undefined; + const outlineMembers = serializeMembers(clazz); + return ( @@ -24,7 +26,7 @@ export function Class({ clazz }: { readonly clazz: ApiClass }) { {clazz.typeParameters.length ? : null} {constructor ? : null} - {/* */} + ); } diff --git a/apps/website/src/components/model/Interface.tsx b/apps/website/src/components/model/Interface.tsx index 739138a6c..d98148740 100644 --- a/apps/website/src/components/model/Interface.tsx +++ b/apps/website/src/components/model/Interface.tsx @@ -1,20 +1,22 @@ import type { ApiInterface } from '@discordjs/api-extractor-model'; -// import { Outline } from '../Outline'; import { Documentation } from '../documentation/Documentation'; import { HierarchyText } from '../documentation/HierarchyText'; import { Members } from '../documentation/Members'; import { ObjectHeader } from '../documentation/ObjectHeader'; import { TypeParameterSection } from '../documentation/section/TypeParametersSection'; -// import { serializeMembers } from '../documentation/util'; +import { serializeMembers } from '../documentation/util'; +import { OutlineSetter } from './OutlineSetter'; export function Interface({ item }: { readonly item: ApiInterface }) { + const outlineMembers = serializeMembers(item); + return ( {item.typeParameters.length ? : null} - {/* */} + ); } diff --git a/apps/website/src/components/model/OutlineSetter.tsx b/apps/website/src/components/model/OutlineSetter.tsx new file mode 100644 index 000000000..d07aaa127 --- /dev/null +++ b/apps/website/src/components/model/OutlineSetter.tsx @@ -0,0 +1,19 @@ +'use client'; + +import { useEffect, type PropsWithChildren } from 'react'; +import { useOutline } from '~/contexts/outline'; +import type { TableOfContentsSerialized } from '../TableOfContentItems'; + +export function OutlineSetter({ members }: PropsWithChildren<{ readonly members: TableOfContentsSerialized[] }>) { + const { setMembers } = useOutline(); + + useEffect(() => { + setMembers(members); + + return () => { + setMembers(null); + }; + }, [members, setMembers]); + + return null; +} diff --git a/apps/website/src/components/model/function/Function.tsx b/apps/website/src/components/model/function/Function.tsx index 4f15b27a0..6aee8dcbc 100644 --- a/apps/website/src/components/model/function/Function.tsx +++ b/apps/website/src/components/model/function/Function.tsx @@ -1,37 +1,29 @@ import type { ApiFunction } from '@discordjs/api-extractor-model'; import dynamic from 'next/dynamic'; -import { Header } from '../../documentation/Header'; +import { Documentation } from '~/components/documentation/Documentation'; +import { ObjectHeader } from '~/components/documentation/ObjectHeader'; import { FunctionBody } from './FunctionBody'; const OverloadSwitcher = dynamic(async () => import('../../OverloadSwitcher')); export function Function({ item }: { readonly item: ApiFunction }) { - const header = ( -
- ); - if (item.getMergedSiblings().length > 1) { const overloads = item .getMergedSiblings() .map((sibling, idx) => ); return ( -
- {header} + + -
+ ); } return ( -
- {header} + + -
+ ); } diff --git a/apps/website/src/components/model/function/FunctionBody.tsx b/apps/website/src/components/model/function/FunctionBody.tsx index b66165b0a..4b809da03 100644 --- a/apps/website/src/components/model/function/FunctionBody.tsx +++ b/apps/website/src/components/model/function/FunctionBody.tsx @@ -1,8 +1,5 @@ import type { ApiFunction } from '@discordjs/api-extractor-model'; -import { SyntaxHighlighter } from '../../SyntaxHighlighter'; -import { Documentation } from '../../documentation/Documentation'; import { ParameterSection } from '../../documentation/section/ParametersSection'; -import { SummarySection } from '../../documentation/section/SummarySection'; import { TypeParameterSection } from '../../documentation/section/TypeParametersSection'; export interface FunctionBodyProps { @@ -12,12 +9,9 @@ export interface FunctionBodyProps { export function FunctionBody({ item }: { readonly item: ApiFunction }) { return ( - - {/* @ts-expect-error async component */} - - + <> {item.typeParameters.length ? : null} {item.parameters.length ? : null} - + ); } diff --git a/apps/website/src/contexts/outline.tsx b/apps/website/src/contexts/outline.tsx new file mode 100644 index 000000000..fa512d87f --- /dev/null +++ b/apps/website/src/contexts/outline.tsx @@ -0,0 +1,22 @@ +'use client'; + +import { createContext, useContext, useMemo, useState } from 'react'; +import type { PropsWithChildren, Dispatch, SetStateAction } from 'react'; +import type { TableOfContentsSerialized } from '~/components/TableOfContentItems'; + +export const OutlineContext = createContext<{ + members: TableOfContentsSerialized[] | null | undefined; + setMembers: Dispatch>; +}>({ members: undefined, setMembers: (_) => {} }); + +export const OutlineProvider = ({ children }: PropsWithChildren) => { + const [members, setMembers] = useState(undefined); + + const value = useMemo(() => ({ members, setMembers }), [members]); + + return {children}; +}; + +export function useOutline() { + return useContext(OutlineContext); +} diff --git a/apps/website/src/util/addPackageToModel.ts b/apps/website/src/util/addPackageToModel.ts index d3c4f4e0a..bcfb55e58 100644 --- a/apps/website/src/util/addPackageToModel.ts +++ b/apps/website/src/util/addPackageToModel.ts @@ -2,9 +2,8 @@ import type { ApiModel, ApiPackage } from '@discordjs/api-extractor-model'; import { ApiItem } from '@discordjs/api-extractor-model'; import { TSDocConfiguration } from '@microsoft/tsdoc'; import { TSDocConfigFile } from '@microsoft/tsdoc-config'; -import { cache } from 'react'; -export const addPackageToModel = cache((model: ApiModel, data: any) => { +export const addPackageToModel = (model: ApiModel, data: any) => { let apiPackage: ApiPackage; if (data.metadata) { const tsdocConfiguration = new TSDocConfiguration(); @@ -24,4 +23,4 @@ export const addPackageToModel = cache((model: ApiModel, data: any) => { model.addMember(apiPackage); return model; -}); +}; diff --git a/apps/website/src/util/fetchMember.ts b/apps/website/src/util/fetchMember.ts index 1738b90b8..408a937e3 100644 --- a/apps/website/src/util/fetchMember.ts +++ b/apps/website/src/util/fetchMember.ts @@ -1,11 +1,10 @@ import { ApiModel, ApiFunction } from '@discordjs/api-extractor-model'; -import { cache } from 'react'; import { fetchModelJSON } from '~/app/docAPI'; import { addPackageToModel } from './addPackageToModel'; import { OVERLOAD_SEPARATOR, PACKAGES } from './constants'; import { findMember, findMemberByKey } from './model'; -export const fetchMember = cache(async (packageName: string, branchName: string, item?: string) => { +export const fetchMember = async (packageName: string, branchName: string, item?: string) => { if (!PACKAGES.includes(packageName)) { return null; } @@ -33,4 +32,4 @@ export const fetchMember = cache(async (packageName: string, branchName: string, } return memberName && containerKey ? findMemberByKey(model, packageName, containerKey) ?? null : null; -}); +}; diff --git a/apps/website/src/util/model.ts b/apps/website/src/util/model.ts index 4e4d0aa8c..597b875cf 100644 --- a/apps/website/src/util/model.ts +++ b/apps/website/src/util/model.ts @@ -6,21 +6,20 @@ import type { Excerpt, } from '@discordjs/api-extractor-model'; import type { DocSection } from '@microsoft/tsdoc'; -import { cache } from 'react'; -export const findMemberByKey = cache((model: ApiModel, packageName: string, containerKey: string) => { +export const findMemberByKey = (model: ApiModel, packageName: string, containerKey: string) => { const pkg = model.tryGetPackageByName(packageName === 'discord.js' ? packageName : `@discordjs/${packageName}`)!; return (pkg.members[0] as ApiEntryPoint).tryGetMemberByKey(containerKey); -}); +}; -export const findMember = cache((model: ApiModel, packageName: string, memberName: string | undefined) => { +export const findMember = (model: ApiModel, packageName: string, memberName: string | undefined) => { if (!memberName) { return undefined; } const pkg = model.tryGetPackageByName(packageName === 'discord.js' ? packageName : `@discordjs/${packageName}`)!; return pkg.entryPoints[0]?.findMembersByName(memberName)[0]; -}); +}; interface ResolvedParameter { description?: DocSection | undefined;