mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-10 00:23:30 +01:00
feat: table of contents / method visibility / property modifiers
This commit is contained in:
@@ -1,10 +1,8 @@
|
||||
import { Group, Stack, Title } from '@mantine/core';
|
||||
import { Badge, Group, Stack, Title } from '@mantine/core';
|
||||
import type { ReactNode } from 'react';
|
||||
import { HyperlinkedText } from './HyperlinkedText';
|
||||
import { TSDoc } from './tsdoc/TSDoc';
|
||||
import type { DocItem } from '~/DocModel/DocItem';
|
||||
import type { AnyDocNodeJSON } from '~/DocModel/comment/CommentNode';
|
||||
import type { TokenDocumentation } from '~/util/parse.server';
|
||||
import type { DocProperty } from '~/DocModel/DocProperty';
|
||||
|
||||
export enum CodeListingSeparatorType {
|
||||
Type = ':',
|
||||
@@ -12,35 +10,30 @@ export enum CodeListingSeparatorType {
|
||||
}
|
||||
|
||||
export function CodeListing({
|
||||
name,
|
||||
prop,
|
||||
separator = CodeListingSeparatorType.Type,
|
||||
summary,
|
||||
typeTokens,
|
||||
children,
|
||||
comment,
|
||||
}: {
|
||||
name: string;
|
||||
summary?: ReturnType<DocItem['toJSON']>['summary'];
|
||||
typeTokens: TokenDocumentation[];
|
||||
prop: ReturnType<DocProperty['toJSON']>;
|
||||
separator?: CodeListingSeparatorType;
|
||||
children?: ReactNode;
|
||||
className?: string | undefined;
|
||||
comment?: AnyDocNodeJSON | null;
|
||||
}) {
|
||||
return (
|
||||
<Stack spacing="xs" key={name}>
|
||||
<Stack spacing="xs" key={prop.name}>
|
||||
<Group>
|
||||
{prop.readonly ? <Badge variant="filled">Readonly</Badge> : null}
|
||||
{prop.optional ? <Badge variant="filled">Optional</Badge> : null}
|
||||
<Title order={4} className="font-mono">
|
||||
{name}
|
||||
{prop.name}
|
||||
</Title>
|
||||
<Title order={4}>{separator}</Title>
|
||||
<Title order={4} className="font-mono break-all">
|
||||
<HyperlinkedText tokens={typeTokens} />
|
||||
<HyperlinkedText tokens={prop.propertyTypeTokens} />
|
||||
</Title>
|
||||
</Group>
|
||||
<Group>
|
||||
{summary && <TSDoc node={summary} />}
|
||||
{comment && <TSDoc node={comment} />}
|
||||
{prop.summary && <TSDoc node={prop.summary} />}
|
||||
{prop.comment && <TSDoc node={prop.comment} />}
|
||||
{children}
|
||||
</Group>
|
||||
</Stack>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Group, Stack, Title } from '@mantine/core';
|
||||
import { Badge, Group, Stack, Title } from '@mantine/core';
|
||||
import { HyperlinkedText } from './HyperlinkedText';
|
||||
import { ParameterTable } from './ParameterTable';
|
||||
import { TSDoc } from './tsdoc/TSDoc';
|
||||
import type { DocMethod } from '~/DocModel/DocMethod';
|
||||
import type { DocMethodSignature } from '~/DocModel/DocMethodSignature';
|
||||
import { Visibility } from '~/DocModel/Visibility';
|
||||
|
||||
type MethodResolvable = ReturnType<DocMethod['toJSON']> | ReturnType<DocMethodSignature['toJSON']>;
|
||||
|
||||
@@ -18,11 +19,21 @@ function getShorthandName(data: MethodResolvable) {
|
||||
}
|
||||
|
||||
export function MethodItem({ data }: { data: MethodResolvable }) {
|
||||
const method = data as ReturnType<DocMethod['toJSON']>;
|
||||
|
||||
return (
|
||||
<Stack spacing="xs">
|
||||
<Stack
|
||||
id={`${data.name}${data.overloadIndex && data.overloadIndex > 1 ? `:${data.overloadIndex}` : ''}`}
|
||||
className="scroll-mt-30"
|
||||
spacing="xs"
|
||||
>
|
||||
<Group>
|
||||
<Stack>
|
||||
<Group>
|
||||
{data.kind === 'Method' && method.visibility === Visibility.Protected ? (
|
||||
<Badge variant="filled">Protected</Badge>
|
||||
) : null}
|
||||
{data.kind === 'Method' && method.static ? <Badge variant="filled">Static</Badge> : null}
|
||||
<Title order={4} className="font-mono break-all">{`${getShorthandName(data)}`}</Title>
|
||||
<Title order={4}>:</Title>
|
||||
<Title order={4} className="font-mono break-all">
|
||||
|
||||
@@ -12,7 +12,10 @@ export function MethodList({
|
||||
<Stack>
|
||||
{data.map((method) => (
|
||||
<>
|
||||
<MethodItem key={method.name} data={method} />
|
||||
<MethodItem
|
||||
key={`${method.name}${method.overloadIndex && method.overloadIndex > 1 ? `:${method.overloadIndex}` : ''}`}
|
||||
data={method}
|
||||
/>
|
||||
<Divider className="bg-gray-100" size="md" />
|
||||
</>
|
||||
))}
|
||||
|
||||
@@ -6,13 +6,7 @@ export function PropertyList({ data }: { data: ReturnType<DocProperty['toJSON']>
|
||||
return (
|
||||
<Stack>
|
||||
{data.map((prop) => (
|
||||
<CodeListing
|
||||
key={prop.name}
|
||||
name={prop.name}
|
||||
typeTokens={prop.propertyTypeTokens}
|
||||
summary={prop.summary}
|
||||
comment={prop.comment}
|
||||
/>
|
||||
<CodeListing key={prop.name} prop={prop} />
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -11,7 +11,7 @@ const useStyles = createStyles((theme, { opened }: { opened: boolean }) => ({
|
||||
fontSize: theme.fontSizes.sm,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark![7] : theme.colors.gray![0],
|
||||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark![6] : theme.colors.gray![0],
|
||||
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -4,10 +4,15 @@ import { MethodList } from './MethodList';
|
||||
import { ParameterTable } from './ParameterTable';
|
||||
import { PropertyList } from './PropertyList';
|
||||
import { Section } from './Section';
|
||||
import type { DocClass } from '~/DocModel/DocClass';
|
||||
import type { DocInterface } from '~/DocModel/DocInterface';
|
||||
import type { ParameterDocumentation } from '~/util/parse.server';
|
||||
|
||||
export function PropertiesSection({ data }: { data: ReturnType<DocInterface['toJSON']>['properties'] }) {
|
||||
export function PropertiesSection({
|
||||
data,
|
||||
}: {
|
||||
data: ReturnType<DocClass['toJSON']>['properties'] | ReturnType<DocInterface['toJSON']>['properties'];
|
||||
}) {
|
||||
const matches = useMediaQuery('(max-width: 768px)', true, { getInitialValueInEffect: false });
|
||||
|
||||
return data.length ? (
|
||||
@@ -17,7 +22,11 @@ export function PropertiesSection({ data }: { data: ReturnType<DocInterface['toJ
|
||||
) : null;
|
||||
}
|
||||
|
||||
export function MethodsSection({ data }: { data: ReturnType<DocInterface['toJSON']>['methods'] }) {
|
||||
export function MethodsSection({
|
||||
data,
|
||||
}: {
|
||||
data: ReturnType<DocClass['toJSON']>['methods'] | ReturnType<DocInterface['toJSON']>['methods'];
|
||||
}) {
|
||||
const matches = useMediaQuery('(max-width: 768px)', true, { getInitialValueInEffect: false });
|
||||
|
||||
return data.length ? (
|
||||
|
||||
@@ -77,7 +77,7 @@ const useStyles = createStyles((theme) => ({
|
||||
borderLeft: `1px solid ${theme.colorScheme === 'dark' ? theme.colors.dark![4] : theme.colors.gray![3]}`,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark![7] : theme.colors.gray![0],
|
||||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark![6] : theme.colors.gray![0],
|
||||
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
AppShell,
|
||||
Navbar,
|
||||
MediaQuery,
|
||||
// Aside,
|
||||
Aside,
|
||||
Header,
|
||||
Burger,
|
||||
Anchor,
|
||||
@@ -26,6 +26,8 @@ import { type PropsWithChildren, useState } from 'react';
|
||||
import { VscChevronDown, VscPackage } from 'react-icons/vsc';
|
||||
import { WiDaySunny, WiNightClear } from 'react-icons/wi';
|
||||
import { SidebarItems } from './SidebarItems';
|
||||
import { TableOfContentsItems } from './TableOfContentsItems';
|
||||
import type { DocClass } from '~/DocModel/DocClass';
|
||||
import type { DocItem } from '~/DocModel/DocItem';
|
||||
import type { findMember } from '~/util/model.server';
|
||||
import type { getMembers } from '~/util/parse.server';
|
||||
@@ -59,7 +61,7 @@ const useStyles = createStyles((theme, { opened }: { opened: boolean }) => ({
|
||||
color: theme.colorScheme === 'dark' ? theme.colors.dark![0] : theme.black,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark![7] : theme.colors.gray![0],
|
||||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark![6] : theme.colors.gray![0],
|
||||
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
|
||||
},
|
||||
},
|
||||
@@ -153,19 +155,21 @@ export function SidebarLayout({ packageName, data, children }: PropsWithChildren
|
||||
) : null}
|
||||
</Navbar>
|
||||
}
|
||||
// aside={
|
||||
// packageName && data?.member ? (
|
||||
// <MediaQuery smallerThan="sm" styles={{ display: 'none' }}>
|
||||
// <Aside hiddenBreakpoint="sm" width={{ sm: 200, lg: 300 }}>
|
||||
// <ScrollArea p="xs">
|
||||
// <SidebarItems members={data.members} />
|
||||
// </ScrollArea>
|
||||
// </Aside>
|
||||
// </MediaQuery>
|
||||
// ) : (
|
||||
// <></>
|
||||
// )
|
||||
// }
|
||||
aside={
|
||||
packageName && data?.member && data.member.kind === 'Class' ? (
|
||||
<MediaQuery smallerThan="sm" styles={{ display: 'none' }}>
|
||||
<Aside hiddenBreakpoint="sm" width={{ sm: 200, lg: 300 }}>
|
||||
<ScrollArea p="xs">
|
||||
<TableOfContentsItems
|
||||
members={(data.member as unknown as ReturnType<DocClass['toJSON']>).methods}
|
||||
></TableOfContentsItems>
|
||||
</ScrollArea>
|
||||
</Aside>
|
||||
</MediaQuery>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
// footer={
|
||||
// <Footer height={60} p="md">
|
||||
// Application footer
|
||||
@@ -195,7 +199,7 @@ export function SidebarLayout({ packageName, data, children }: PropsWithChildren
|
||||
onClick={() => toggleColorScheme()}
|
||||
title="Toggle color scheme"
|
||||
>
|
||||
{dark ? <WiDaySunny size={18} /> : <WiNightClear size={18} />}
|
||||
{dark ? <WiDaySunny size={20} /> : <WiNightClear size={20} />}
|
||||
</ActionIcon>
|
||||
</Box>
|
||||
</Header>
|
||||
|
||||
61
packages/website/src/components/TableOfContentsItems.tsx
Normal file
61
packages/website/src/components/TableOfContentsItems.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import { createStyles, Group, Text, Box } from '@mantine/core';
|
||||
import { VscListSelection } from 'react-icons/vsc';
|
||||
import type { DocClass } from '~/DocModel/DocClass';
|
||||
import type { DocInterface } from '~/DocModel/DocInterface';
|
||||
|
||||
const useStyles = createStyles((theme) => ({
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
link: {
|
||||
...theme.fn.focusStyles(),
|
||||
display: 'block',
|
||||
textDecoration: 'none',
|
||||
color: theme.colorScheme === 'dark' ? theme.colors.dark![0] : theme.black,
|
||||
lineHeight: 1.2,
|
||||
fontSize: theme.fontSizes.sm,
|
||||
padding: theme.spacing.xs,
|
||||
paddingLeft: theme.spacing.md,
|
||||
marginLeft: 8,
|
||||
borderTopRightRadius: theme.radius.sm,
|
||||
borderBottomRightRadius: theme.radius.sm,
|
||||
borderLeft: `1px solid ${theme.colorScheme === 'dark' ? theme.colors.dark![4] : theme.colors.gray![3]}`,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark![6] : theme.colors.gray![0],
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export function TableOfContentsItems({
|
||||
members,
|
||||
}: {
|
||||
members: ReturnType<DocClass['toJSON']>['methods'] | ReturnType<DocInterface['toJSON']>['methods'];
|
||||
}) {
|
||||
const { classes } = useStyles();
|
||||
|
||||
const items = members.map((member) => {
|
||||
const key = `${member.name}${member.overloadIndex && member.overloadIndex > 1 ? `:${member.overloadIndex}` : ''}`;
|
||||
|
||||
return (
|
||||
<Box<'a'> key={key} href={`#${key}`} component="a" className={classes.link}>
|
||||
<Group>
|
||||
<Text className="line-clamp-1 text-ellipsis overflow-hidden">{member.name}</Text>
|
||||
{member.overloadIndex && member.overloadIndex > 1 ? (
|
||||
<Text size="xs" color="dimmed">
|
||||
{member.overloadIndex}
|
||||
</Text>
|
||||
) : null}
|
||||
</Group>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Group mb="md">
|
||||
<VscListSelection size={20} />
|
||||
<Text>Table of contents</Text>
|
||||
</Group>
|
||||
{items}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import type { DocFunction } from '~/DocModel/DocFunction';
|
||||
export function Function({ data }: { data: ReturnType<DocFunction['toJSON']> }) {
|
||||
return (
|
||||
<DocContainer
|
||||
name={`${data.name}${data.overloadIndex ? ` (${data.overloadIndex})` : ''}`}
|
||||
name={`${data.name}${data.overloadIndex && data.overloadIndex > 1 ? ` (${data.overloadIndex})` : ''}`}
|
||||
kind={data.kind}
|
||||
excerpt={data.excerpt}
|
||||
summary={data.summary}
|
||||
|
||||
@@ -53,7 +53,7 @@ export const getStaticPaths: GetStaticPaths = async () => {
|
||||
// causing next.js export to error
|
||||
.filter((member) => member.name !== 'RESTEvents')
|
||||
.map((member) => {
|
||||
if (member.kind === 'Function' && member.overloadIndex) {
|
||||
if (member.kind === 'Function' && member.overloadIndex && member.overloadIndex > 1) {
|
||||
return {
|
||||
params: {
|
||||
slug: ['main', 'packages', packageName, `${member.name}:${member.overloadIndex}`],
|
||||
|
||||
@@ -34,7 +34,11 @@ export function generatePath(items: readonly ApiItem[]) {
|
||||
path += `${item.displayName}/`;
|
||||
break;
|
||||
case ApiItemKind.Function:
|
||||
path += `${item.displayName}:${(item as ApiFunction).overloadIndex}/`;
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
const functionItem = item as ApiFunction;
|
||||
path += `${functionItem.displayName}${
|
||||
functionItem.overloadIndex && functionItem.overloadIndex > 1 ? `:${functionItem.overloadIndex}` : ''
|
||||
}:/`;
|
||||
break;
|
||||
default:
|
||||
path += `${item.displayName}/`;
|
||||
|
||||
Reference in New Issue
Block a user