mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
refactor: docs design (#8487)
This commit is contained in:
@@ -6,8 +6,8 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"build": "unbuild",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format"
|
||||
},
|
||||
"main": "./dist/index.mjs",
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"build": "unbuild",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format",
|
||||
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
|
||||
"prepack": "yarn lint && yarn test && yarn build",
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"build": "unbuild",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format",
|
||||
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
|
||||
"prepack": "yarn lint && yarn test && yarn build",
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"description": "The docs.json generator for discord.js and its related projects",
|
||||
"scripts": {
|
||||
"build": "unbuild",
|
||||
"lint": "prettier --check . && eslint src --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src --ext mjs,js,ts --fix",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format",
|
||||
"prepack": "yarn format && yarn build",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/docgen/*'",
|
||||
@@ -50,7 +50,7 @@
|
||||
"devDependencies": {
|
||||
"@favware/cliff-jumper": "^1.8.6",
|
||||
"@types/jsdoc-to-markdown": "^7.0.3",
|
||||
"@types/node": "^16.11.47",
|
||||
"@types/node": "^16.11.48",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
||||
"@typescript-eslint/parser": "^5.33.0",
|
||||
"eslint": "^8.22.0",
|
||||
@@ -61,7 +61,7 @@
|
||||
"prettier": "^2.7.1",
|
||||
"rollup-plugin-typescript2": "0.32.1",
|
||||
"typescript": "^4.7.4",
|
||||
"unbuild": "^0.8.4"
|
||||
"unbuild": "^0.8.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"description": "Lightweight HTTP proxy for Discord's API, brought to you as a container 📦",
|
||||
"scripts": {
|
||||
"build": "unbuild",
|
||||
"lint": "prettier --check . && eslint src --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src --ext mjs,js,ts --fix",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format",
|
||||
"prepack": "yarn lint && yarn test && yarn build",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/proxy-container/*'"
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"build": "unbuild",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format",
|
||||
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
|
||||
"prepack": "yarn lint && yarn test && yarn build",
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"build": "unbuild",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format",
|
||||
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
|
||||
"prepack": "yarn lint && yarn test && yarn build",
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"build": "unbuild",
|
||||
"lint": "prettier --check . && eslint src --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src --ext mjs,js,ts --fix",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format"
|
||||
},
|
||||
"main": "./dist/index.cjs",
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"scripts": {
|
||||
"build": "unbuild",
|
||||
"test": "jest --coverage",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format",
|
||||
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
|
||||
"prepack": "yarn lint && yarn test && yarn build",
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
"dev:next": "next dev",
|
||||
"dev:css": "yarn generate:css --watch",
|
||||
"generate:css": "unocss 'src/**/*.tsx' --out-file ./src/styles/unocss.css",
|
||||
"lint": "prettier --check . && eslint src --ext mjs,js,ts,tsx",
|
||||
"format": "prettier --write . && eslint src --ext mjs,js,ts,tsx --fix"
|
||||
"lint": "prettier --check . && TIMING=1 eslint src --ext mjs,js,ts,tsx",
|
||||
"format": "prettier --write . && TIMING=1 eslint src --ext mjs,js,ts,tsx --fix"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
@@ -47,11 +47,17 @@
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.0",
|
||||
"@emotion/server": "^11.10.0",
|
||||
"@mantine/core": "^5.1.6",
|
||||
"@mantine/hooks": "^5.1.6",
|
||||
"@mantine/next": "^5.1.6",
|
||||
"@mantine/nprogress": "^5.1.6",
|
||||
"@mantine/spotlight": "^5.1.6",
|
||||
"@microsoft/api-extractor-model": "^7.23.0",
|
||||
"@microsoft/tsdoc": "0.14.1",
|
||||
"@microsoft/tsdoc-config": "0.16.1",
|
||||
"@vscode/codicons": "^0.0.32",
|
||||
"framer-motion": "^7.1.0",
|
||||
"next": "^12.2.5",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@@ -60,9 +66,6 @@
|
||||
"sharp": "^0.30.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/cypress": "^8.0.3",
|
||||
"@testing-library/dom": "^8.17.1",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.3.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@types/node": "^16.11.48",
|
||||
@@ -85,7 +88,6 @@
|
||||
"eslint-plugin-react": "^7.30.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"happy-dom": "^6.0.4",
|
||||
"msw": "^0.44.2",
|
||||
"prettier": "^2.7.1",
|
||||
"typescript": "^4.7.4",
|
||||
"unocss": "^0.45.6",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Group, Stack, Title } from '@mantine/core';
|
||||
import type { ReactNode } from 'react';
|
||||
import { CommentSection } from './Comment';
|
||||
import { HyperlinkedText } from './HyperlinkedText';
|
||||
@@ -9,36 +10,33 @@ export enum CodeListingSeparatorType {
|
||||
Value = '=',
|
||||
}
|
||||
|
||||
export interface CodeListingProps {
|
||||
export function CodeListing({
|
||||
name,
|
||||
separator = CodeListingSeparatorType.Type,
|
||||
summary,
|
||||
typeTokens,
|
||||
children,
|
||||
}: {
|
||||
name: string;
|
||||
summary?: ReturnType<DocItem['toJSON']>['summary'];
|
||||
typeTokens: TokenDocumentation[];
|
||||
separator?: CodeListingSeparatorType;
|
||||
children?: ReactNode;
|
||||
className?: string | undefined;
|
||||
}
|
||||
|
||||
export function CodeListing({
|
||||
name,
|
||||
className,
|
||||
separator = CodeListingSeparatorType.Type,
|
||||
summary,
|
||||
typeTokens,
|
||||
children,
|
||||
}: CodeListingProps) {
|
||||
}) {
|
||||
return (
|
||||
<div className={className}>
|
||||
<div key={name} className="flex flex-col">
|
||||
<div className="w-full flex flex-row gap-3">
|
||||
<h4 className="font-mono m-0">{`${name}`}</h4>
|
||||
<h4 className="m-0">{separator}</h4>
|
||||
<h4 className="font-mono m-0 break-all">
|
||||
<HyperlinkedText tokens={typeTokens} />
|
||||
</h4>
|
||||
</div>
|
||||
{summary && <CommentSection textClassName="text-dark-100 dark:text-gray-300" node={summary} />}
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
<Stack key={name}>
|
||||
<Group>
|
||||
<Title order={4} className="font-mono">
|
||||
{name}
|
||||
</Title>
|
||||
<Title order={4}>{separator}</Title>
|
||||
<Title order={4} className="font-mono break-all">
|
||||
<HyperlinkedText tokens={typeTokens} />
|
||||
</Title>
|
||||
</Group>
|
||||
{summary && <CommentSection node={summary} />}
|
||||
{children}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
import { Anchor, Box, Text } from '@mantine/core';
|
||||
import Link from 'next/link';
|
||||
import type { ReactNode } from 'react';
|
||||
import { PrismAsyncLight as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||
import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism';
|
||||
import type { CommentNode } from '~/DocModel/comment/CommentNode';
|
||||
import type { CommentNodeContainer } from '~/DocModel/comment/CommentNodeContainer';
|
||||
import type { FencedCodeCommentNode } from '~/DocModel/comment/FencedCodeCommentNode';
|
||||
import type { LinkTagCommentNode } from '~/DocModel/comment/LinkTagCommentNode';
|
||||
import type { PlainTextCommentNode } from '~/DocModel/comment/PlainTextCommentNode';
|
||||
|
||||
export interface RemarksBlockProps {
|
||||
node: ReturnType<CommentNode['toJSON']>;
|
||||
textClassName?: string | undefined;
|
||||
}
|
||||
|
||||
export function CommentSection({ node, textClassName }: RemarksBlockProps): JSX.Element {
|
||||
export function CommentSection({ node }: { node: ReturnType<CommentNode['toJSON']> }): JSX.Element {
|
||||
const createNode = (node: ReturnType<CommentNode['toJSON']>, idx?: number): ReactNode => {
|
||||
switch (node.kind) {
|
||||
case 'PlainText':
|
||||
return <span key={idx}>{(node as ReturnType<PlainTextCommentNode['toJSON']>).text}</span>;
|
||||
return (
|
||||
<Text key={idx} span>
|
||||
{(node as ReturnType<PlainTextCommentNode['toJSON']>).text}
|
||||
</Text>
|
||||
);
|
||||
case 'Paragraph':
|
||||
return (
|
||||
<p key={idx} className={textClassName}>
|
||||
<Text key={idx} inline>
|
||||
{(node as ReturnType<CommentNodeContainer['toJSON']>).nodes.map((node, idx) => createNode(node, idx))}
|
||||
</p>
|
||||
</Text>
|
||||
);
|
||||
case 'SoftBreak':
|
||||
return <br key={idx} />;
|
||||
@@ -29,18 +30,41 @@ export function CommentSection({ node, textClassName }: RemarksBlockProps): JSX.
|
||||
const { codeDestination, urlDestination, text } = node as ReturnType<LinkTagCommentNode['toJSON']>;
|
||||
|
||||
if (codeDestination) {
|
||||
return <Link href={codeDestination.path}>{text ?? codeDestination.name}</Link>;
|
||||
return (
|
||||
<Link key={idx} href={codeDestination.path} passHref>
|
||||
<Anchor component="a" className="font-mono">
|
||||
{text ?? codeDestination.name}
|
||||
</Anchor>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
if (urlDestination) {
|
||||
return <Link href={urlDestination}>{text ?? urlDestination}</Link>;
|
||||
return (
|
||||
<Link key={idx} href={urlDestination} passHref>
|
||||
<Anchor component="a" className="font-mono">
|
||||
{text ?? urlDestination}
|
||||
</Anchor>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
case 'FencedCodeBlock': {
|
||||
const { language, code } = node as ReturnType<FencedCodeCommentNode['toJSON']>;
|
||||
return <SyntaxHighlighter language={language}>{code}</SyntaxHighlighter>;
|
||||
return (
|
||||
<SyntaxHighlighter
|
||||
key={idx}
|
||||
wrapLines
|
||||
wrapLongLines
|
||||
language={language}
|
||||
style={vscDarkPlus}
|
||||
codeTagProps={{ style: { fontFamily: 'JetBrains Mono' } }}
|
||||
>
|
||||
{code}
|
||||
</SyntaxHighlighter>
|
||||
);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
@@ -50,12 +74,12 @@ export function CommentSection({ node, textClassName }: RemarksBlockProps): JSX.
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Box>
|
||||
{node.kind === 'Paragraph' || node.kind === 'Section' ? (
|
||||
<>{(node as CommentNodeContainer).nodes.map((node, idx) => createNode(node, idx))}</>
|
||||
) : (
|
||||
<>{createNode(node)}</>
|
||||
createNode(node)
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Group, Stack, Title, Text, Box } from '@mantine/core';
|
||||
import { useMediaQuery } from '@mantine/hooks';
|
||||
import type { ReactNode } from 'react';
|
||||
import { VscListSelection, VscSymbolParameter } from 'react-icons/vsc';
|
||||
import { PrismAsyncLight as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||
@@ -32,73 +34,73 @@ export function DocContainer({
|
||||
extendsTokens,
|
||||
implementsTokens,
|
||||
}: DocContainerProps) {
|
||||
const matches = useMediaQuery('(max-width: 768px)', true, { getInitialValueInEffect: false });
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-full max-h-full grow">
|
||||
<div className="border-0.5 border-gray px-10 py-2">
|
||||
<h2 className="flex gap-2 items-center break-all m-0 dark:text-white">
|
||||
<Stack>
|
||||
<Title order={2} ml="xs">
|
||||
<Group>
|
||||
{generateIcon(kind)}
|
||||
{name}
|
||||
</h2>
|
||||
</div>
|
||||
</Group>
|
||||
</Title>
|
||||
|
||||
<div className="min-h-full overflow-y-auto overflow-x-clip px-10 pt-5 pb-10">
|
||||
<Section iconElement={<VscListSelection />} title="Summary" className="dark:text-white mb-5">
|
||||
{summary ? (
|
||||
<CommentSection textClassName="text-dark-100 dark:text-gray-300" node={summary} />
|
||||
) : (
|
||||
<p className="text-dark-100 dark:text-gray-300">No summary provided.</p>
|
||||
)}
|
||||
</Section>
|
||||
<div className={extendsTokens?.length ? 'mb-2' : 'mb-10'}>
|
||||
<SyntaxHighlighter
|
||||
wrapLines
|
||||
wrapLongLines
|
||||
language="typescript"
|
||||
style={vscDarkPlus}
|
||||
codeTagProps={{ style: { fontFamily: 'JetBrains Mono' } }}
|
||||
>
|
||||
{excerpt}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
{extendsTokens?.length ? (
|
||||
<div
|
||||
className={`flex flex-row items-center dark:text-white gap-3 ${implementsTokens?.length ? '' : 'mb-10'}`}
|
||||
>
|
||||
<h3 className="m-0">Extends</h3>
|
||||
<h3 className="m-0">{CodeListingSeparatorType.Type}</h3>
|
||||
<p className="font-mono break-all">
|
||||
<HyperlinkedText tokens={extendsTokens} />
|
||||
</p>
|
||||
</div>
|
||||
<Section title="Summary" icon={<VscListSelection />} padded dense={matches}>
|
||||
{summary ? <CommentSection node={summary} /> : <Text>No summary provided.</Text>}
|
||||
</Section>
|
||||
|
||||
<Box px="xs" pb="xs">
|
||||
<SyntaxHighlighter
|
||||
wrapLongLines
|
||||
language="typescript"
|
||||
style={vscDarkPlus}
|
||||
codeTagProps={{ style: { fontFamily: 'JetBrains Mono' } }}
|
||||
>
|
||||
{excerpt}
|
||||
</SyntaxHighlighter>
|
||||
</Box>
|
||||
|
||||
{extendsTokens?.length ? (
|
||||
<Group noWrap>
|
||||
<Title order={3} ml="xs">
|
||||
Extends
|
||||
</Title>
|
||||
<Title order={3} ml="xs">
|
||||
{CodeListingSeparatorType.Type}
|
||||
</Title>
|
||||
<Text className="font-mono break-all">
|
||||
<HyperlinkedText tokens={extendsTokens} />
|
||||
</Text>
|
||||
</Group>
|
||||
) : null}
|
||||
|
||||
{implementsTokens?.length ? (
|
||||
<Group noWrap>
|
||||
<Title order={3} ml="xs">
|
||||
Implements
|
||||
</Title>
|
||||
<Title order={3} ml="xs">
|
||||
{CodeListingSeparatorType.Type}
|
||||
</Title>
|
||||
<Text className="font-mono break-all">
|
||||
{implementsTokens.map((token, idx) => (
|
||||
<>
|
||||
<HyperlinkedText tokens={token} />
|
||||
{idx < implementsTokens.length - 1 ? ', ' : ''}
|
||||
</>
|
||||
))}
|
||||
</Text>
|
||||
</Group>
|
||||
) : null}
|
||||
|
||||
<Stack>
|
||||
{typeParams?.length ? (
|
||||
<Section title="Type Parameters" icon={<VscSymbolParameter />} padded dense={matches} defaultClosed>
|
||||
<TypeParamTable data={typeParams} />
|
||||
</Section>
|
||||
) : null}
|
||||
{implementsTokens?.length ? (
|
||||
<div className={`flex flex-row items-center dark:text-white gap-3 mb-10`}>
|
||||
<h3 className="m-0">Implements</h3>
|
||||
<h3 className="m-0">{CodeListingSeparatorType.Type}</h3>
|
||||
<p className="font-mono break-all">
|
||||
{implementsTokens.map((token, i) => (
|
||||
<>
|
||||
<HyperlinkedText key={i} tokens={token} />
|
||||
{i < implementsTokens.length - 1 ? ', ' : ''}
|
||||
</>
|
||||
))}
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="space-y-10">
|
||||
{typeParams?.length ? (
|
||||
<Section
|
||||
iconElement={<VscSymbolParameter />}
|
||||
title="Type Parameters"
|
||||
className="dark:text-white"
|
||||
defaultClosed
|
||||
>
|
||||
<TypeParamTable data={typeParams} />
|
||||
</Section>
|
||||
) : null}
|
||||
<div className="space-y-10">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Stack>{children}</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { Anchor, Text } from '@mantine/core';
|
||||
import Link from 'next/link';
|
||||
import type { TokenDocumentation } from '~/util/parse.server';
|
||||
|
||||
export interface HyperlinkedTextProps {
|
||||
tokens: TokenDocumentation[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a hyperlinked html node based on token type references
|
||||
*
|
||||
@@ -12,22 +9,24 @@ export interface HyperlinkedTextProps {
|
||||
*
|
||||
* @returns An array of JSX elements and string comprising the hyperlinked text
|
||||
*/
|
||||
export function HyperlinkedText({ tokens }: HyperlinkedTextProps) {
|
||||
export function HyperlinkedText({ tokens }: { tokens: TokenDocumentation[] }) {
|
||||
return (
|
||||
<>
|
||||
{tokens.map((token) => {
|
||||
{tokens.map((token, idx) => {
|
||||
if (token.path) {
|
||||
return (
|
||||
<Link key={token.text} href={token.path}>
|
||||
<a className="text-blue-500 dark:text-blue-300 no-underline">{token.text}</a>
|
||||
<Link key={idx} href={token.path} passHref>
|
||||
<Anchor component="a" inherit>
|
||||
{token.text}
|
||||
</Anchor>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span key={token.text} className="text-blue-500 dark:text-blue-300">
|
||||
<Text key={idx} span unstyled>
|
||||
{token.text}
|
||||
</span>
|
||||
</Text>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { FiMenu } from 'react-icons/fi';
|
||||
import { VscPackage } from 'react-icons/vsc';
|
||||
import { ListSidebar } from './ListSidebar';
|
||||
import type { DocItem } from '~/DocModel/DocItem';
|
||||
import type { getMembers } from '~/util/parse.server';
|
||||
|
||||
export interface ItemListProps {
|
||||
packageName: string;
|
||||
data: {
|
||||
members: ReturnType<typeof getMembers>;
|
||||
};
|
||||
|
||||
selectedMember?: ReturnType<DocItem['toJSON']> | undefined;
|
||||
}
|
||||
|
||||
function onMenuClick() {
|
||||
console.log('menu clicked');
|
||||
// Todo show/hide list
|
||||
}
|
||||
|
||||
export function ItemSidebar({ packageName, data, selectedMember }: ItemListProps) {
|
||||
return (
|
||||
<div className="flex flex-col min-h-full max-h-full grow min-w-[270px] lg:border-r-solid border-0.5 border-gray">
|
||||
<div className="border-b-0.5 border-gray py-2">
|
||||
<h2 className="flex gap-2 items-center m-0 px-2 dark:text-white">
|
||||
<VscPackage />
|
||||
{`${packageName}`}
|
||||
</h2>
|
||||
<button
|
||||
type="button"
|
||||
className="lg:hidden mr-2 bg-transparent border-none cursor-pointer"
|
||||
title="Menu"
|
||||
onClick={onMenuClick}
|
||||
>
|
||||
<FiMenu size={32} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="hidden lg:block lg:min-h-full overflow-y-auto overflow-x-clip py-3 px-4">
|
||||
<ListSidebar members={data.members} title="test" selectedMember={selectedMember} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FiLink } from 'react-icons/fi';
|
||||
import { Group, Stack, Title } from '@mantine/core';
|
||||
import { CommentSection } from './Comment';
|
||||
import { HyperlinkedText } from './HyperlinkedText';
|
||||
import { ParameterTable } from './ParameterTable';
|
||||
@@ -7,10 +7,6 @@ import type { DocMethodSignature } from '~/DocModel/DocMethodSignature';
|
||||
|
||||
type MethodResolvable = ReturnType<DocMethod['toJSON']> | ReturnType<DocMethodSignature['toJSON']>;
|
||||
|
||||
export interface MethodItemProps {
|
||||
data: MethodResolvable;
|
||||
}
|
||||
|
||||
function getShorthandName(data: MethodResolvable) {
|
||||
return `${data.name}(${data.parameters.reduce((prev, cur, index) => {
|
||||
if (index === 0) {
|
||||
@@ -21,37 +17,24 @@ function getShorthandName(data: MethodResolvable) {
|
||||
}, '')})`;
|
||||
}
|
||||
|
||||
function onAnchorClick() {
|
||||
console.log('anchor clicked');
|
||||
// Todo implement jump-to links
|
||||
}
|
||||
|
||||
export function MethodItem({ data }: MethodItemProps) {
|
||||
export function MethodItem({ data }: { data: MethodResolvable }) {
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<div className="flex">
|
||||
<button
|
||||
type="button"
|
||||
className="bg-transparent border-none cursor-pointer dark:text-white"
|
||||
title="Anchor"
|
||||
onClick={onAnchorClick}
|
||||
>
|
||||
<FiLink size={16} />
|
||||
</button>
|
||||
<div className="flex flex-col">
|
||||
<div className="w-full flex flex-row gap-3">
|
||||
<h4 className="font-mono m-0 break-all">{`${getShorthandName(data)}`}</h4>
|
||||
<h4 className="m-0">:</h4>
|
||||
<h4 className="font-mono m-0 break-all">
|
||||
<Stack>
|
||||
<Group>
|
||||
<Stack>
|
||||
<Group>
|
||||
<Title order={5} className="font-mono break-all">{`${getShorthandName(data)}`}</Title>
|
||||
<Title order={5}>:</Title>
|
||||
<Title order={5} className="font-mono break-all">
|
||||
<HyperlinkedText tokens={data.returnTypeTokens} />
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx-7 mb-5">
|
||||
{data.summary && <CommentSection textClassName="text-dark-100 dark:text-gray-300" node={data.summary} />}
|
||||
</Title>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Group>
|
||||
<Group sx={{ display: data.summary || data.parameters.length ? 'block' : 'none' }} mb="lg">
|
||||
{data.summary ? <CommentSection node={data.summary} /> : null}
|
||||
{data.parameters.length ? <ParameterTable data={data.parameters} /> : null}
|
||||
</div>
|
||||
</div>
|
||||
</Group>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { Stack } from '@mantine/core';
|
||||
import { MethodItem } from './MethodItem';
|
||||
import type { DocMethod } from '~/DocModel/DocMethod';
|
||||
import type { DocMethodSignature } from '~/DocModel/DocMethodSignature';
|
||||
|
||||
export interface MethodListProps {
|
||||
export function MethodList({
|
||||
data,
|
||||
}: {
|
||||
data: (ReturnType<DocMethod['toJSON']> | ReturnType<DocMethodSignature['toJSON']>)[];
|
||||
}
|
||||
|
||||
export function MethodList({ data }: MethodListProps) {
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-col gap-5">
|
||||
{data.map((method) => (
|
||||
<MethodItem key={method.name} data={method} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<Stack>
|
||||
{data.map((method) => (
|
||||
<MethodItem key={method.name} data={method} />
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,12 +2,7 @@ import { HyperlinkedText } from './HyperlinkedText';
|
||||
import { Table } from './Table';
|
||||
import type { ParameterDocumentation } from '~/util/parse.server';
|
||||
|
||||
interface ParameterDetailProps {
|
||||
data: ParameterDocumentation[];
|
||||
className?: string | undefined;
|
||||
}
|
||||
|
||||
export function ParameterTable({ data, className }: ParameterDetailProps) {
|
||||
export function ParameterTable({ data }: { data: ParameterDocumentation[] }) {
|
||||
const rows = data.map((param) => ({
|
||||
Name: param.name,
|
||||
Type: <HyperlinkedText tokens={param.tokens} />,
|
||||
@@ -20,12 +15,5 @@ export function ParameterTable({ data, className }: ParameterDetailProps) {
|
||||
Type: 'font-mono',
|
||||
};
|
||||
|
||||
return (
|
||||
<Table
|
||||
className={className}
|
||||
columns={['Name', 'Type', 'Optional', 'Description']}
|
||||
rows={rows}
|
||||
columnStyles={columnStyles}
|
||||
/>
|
||||
);
|
||||
return <Table columns={['Name', 'Type', 'Optional', 'Description']} rows={rows} columnStyles={columnStyles} />;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { Stack } from '@mantine/core';
|
||||
import { CodeListing } from './CodeListing';
|
||||
import type { DocProperty } from '~/DocModel/DocProperty';
|
||||
|
||||
export interface PropertyListProps {
|
||||
data: ReturnType<DocProperty['toJSON']>[];
|
||||
}
|
||||
|
||||
export function PropertyList({ data }: PropertyListProps) {
|
||||
export function PropertyList({ data }: { data: ReturnType<DocProperty['toJSON']>[] }) {
|
||||
return (
|
||||
<div className="flex flex-col gap-5">
|
||||
<Stack>
|
||||
{data.map((prop) => (
|
||||
<CodeListing key={prop.name} name={prop.name} typeTokens={prop.propertyTypeTokens} summary={prop.summary} />
|
||||
))}
|
||||
</div>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
24
packages/website/src/components/RouterTransition.tsx
Normal file
24
packages/website/src/components/RouterTransition.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { startNavigationProgress, resetNavigationProgress, NavigationProgress } from '@mantine/nprogress';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export function RouterTransition() {
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const handleStart = (url: string) => url !== router.asPath && startNavigationProgress();
|
||||
const handleComplete = () => resetNavigationProgress();
|
||||
|
||||
router.events.on('routeChangeStart', handleStart);
|
||||
router.events.on('routeChangeComplete', handleComplete);
|
||||
router.events.on('routeChangeError', handleComplete);
|
||||
|
||||
return () => {
|
||||
router.events.off('routeChangeStart', handleStart);
|
||||
router.events.off('routeChangeComplete', handleComplete);
|
||||
router.events.off('routeChangeError', handleComplete);
|
||||
};
|
||||
}, [router.asPath]);
|
||||
|
||||
return <NavigationProgress />;
|
||||
}
|
||||
@@ -1,72 +1,71 @@
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { createStyles, UnstyledButton, Group, ThemeIcon, Collapse, Box, Text } from '@mantine/core';
|
||||
import { type ReactNode, useState } from 'react';
|
||||
import { VscChevronDown, VscChevronRight } from 'react-icons/vsc';
|
||||
import { Separator } from './Seperator';
|
||||
import { VscChevronDown } from 'react-icons/vsc';
|
||||
|
||||
export interface SectionProps {
|
||||
children: ReactNode;
|
||||
title: string;
|
||||
className?: string | undefined;
|
||||
defaultClosed?: boolean;
|
||||
iconElement?: JSX.Element;
|
||||
showSeparator?: boolean;
|
||||
margin?: boolean;
|
||||
}
|
||||
const useStyles = createStyles((theme, { opened }: { opened: boolean }) => ({
|
||||
control: {
|
||||
display: 'block',
|
||||
width: '100%',
|
||||
padding: `${theme.spacing.xs}px ${theme.spacing.xs}px`,
|
||||
color: theme.colorScheme === 'dark' ? theme.colors.dark![0] : theme.black,
|
||||
fontSize: theme.fontSizes.sm,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark![7] : theme.colors.gray![0],
|
||||
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
|
||||
},
|
||||
},
|
||||
|
||||
icon: {
|
||||
transition: 'transform 150ms ease',
|
||||
transform: opened ? 'rotate(180deg)' : 'rotate(0deg)',
|
||||
},
|
||||
}));
|
||||
|
||||
export function Section({
|
||||
title,
|
||||
icon,
|
||||
padded = false,
|
||||
dense = false,
|
||||
defaultClosed = false,
|
||||
children,
|
||||
className,
|
||||
defaultClosed,
|
||||
iconElement,
|
||||
showSeparator = true,
|
||||
margin = true,
|
||||
}: SectionProps) {
|
||||
const [collapsed, setCollapsed] = useState(defaultClosed ?? false);
|
||||
}: {
|
||||
title: string;
|
||||
icon?: JSX.Element;
|
||||
padded?: boolean;
|
||||
dense?: boolean;
|
||||
defaultClosed?: boolean;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
const [opened, setOpened] = useState(!defaultClosed);
|
||||
const { classes } = useStyles({ opened });
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<h3
|
||||
className="flex gap-2 whitespace-pre-wrap font-semibold dark:text-white cursor-pointer"
|
||||
onClick={() => setCollapsed(!collapsed)}
|
||||
>
|
||||
{collapsed ? <VscChevronRight size={20} /> : <VscChevronDown size={20} />}
|
||||
{iconElement ?? null}
|
||||
{title}
|
||||
</h3>
|
||||
<AnimatePresence initial={false} exitBeforeEnter>
|
||||
{collapsed ? null : (
|
||||
<>
|
||||
<motion.div
|
||||
transition={{ duration: 0.5, ease: [0.04, 0.62, 0.23, 0.98] }}
|
||||
key="content"
|
||||
initial="collapsed"
|
||||
animate="open"
|
||||
exit="collapsed"
|
||||
variants={{
|
||||
open: {
|
||||
opacity: 1,
|
||||
height: 'auto',
|
||||
paddingLeft: '1.75rem',
|
||||
paddingRight: '1.75rem',
|
||||
marginBottom: margin ? '1.25rem' : 0,
|
||||
},
|
||||
collapsed: {
|
||||
opacity: 0,
|
||||
height: 0,
|
||||
paddingLeft: '1.75rem',
|
||||
paddingRight: '1.75rem',
|
||||
paddingBottom: 0,
|
||||
marginBottom: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
{showSeparator && <Separator />}
|
||||
</>
|
||||
<Box className="break-all">
|
||||
<UnstyledButton className={classes.control} onClick={() => setOpened((o) => !o)}>
|
||||
<Group position="apart">
|
||||
<Group>
|
||||
{icon ? (
|
||||
<ThemeIcon variant="outline" size={30}>
|
||||
{icon}
|
||||
</ThemeIcon>
|
||||
) : null}
|
||||
<Text weight={600} size="md">
|
||||
{title}
|
||||
</Text>
|
||||
</Group>
|
||||
<VscChevronDown size={20} className={classes.icon} />
|
||||
</Group>
|
||||
</UnstyledButton>
|
||||
<Collapse in={opened}>
|
||||
{padded ? (
|
||||
<Box py={20} px={dense ? 0 : 31} mx={dense ? 10 : 25}>
|
||||
{children}
|
||||
</Box>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</Collapse>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useMediaQuery } from '@mantine/hooks';
|
||||
import { VscSymbolConstant, VscSymbolMethod, VscSymbolProperty } from 'react-icons/vsc';
|
||||
import { MethodList } from './MethodList';
|
||||
import { ParameterTable } from './ParameterTable';
|
||||
@@ -6,37 +7,31 @@ import { Section } from './Section';
|
||||
import type { DocInterface } from '~/DocModel/DocInterface';
|
||||
import type { ParameterDocumentation } from '~/util/parse.server';
|
||||
|
||||
export interface PropertiesSectionProps {
|
||||
data: ReturnType<DocInterface['toJSON']>['properties'];
|
||||
}
|
||||
export function PropertiesSection({ data }: { data: ReturnType<DocInterface['toJSON']>['properties'] }) {
|
||||
const matches = useMediaQuery('(max-width: 768px)', true, { getInitialValueInEffect: false });
|
||||
|
||||
export function PropertiesSection({ data }: PropertiesSectionProps) {
|
||||
return data.length ? (
|
||||
<Section iconElement={<VscSymbolProperty />} title="Properties" className="dark:text-white">
|
||||
<Section title="Properties" icon={<VscSymbolProperty />} padded dense={matches}>
|
||||
<PropertyList data={data} />
|
||||
</Section>
|
||||
) : null;
|
||||
}
|
||||
|
||||
export interface MethodsSectionProps {
|
||||
data: ReturnType<DocInterface['toJSON']>['methods'];
|
||||
}
|
||||
export function MethodsSection({ data }: { data: ReturnType<DocInterface['toJSON']>['methods'] }) {
|
||||
const matches = useMediaQuery('(max-width: 768px)', true, { getInitialValueInEffect: false });
|
||||
|
||||
export function MethodsSection({ data }: MethodsSectionProps) {
|
||||
return data.length ? (
|
||||
<Section iconElement={<VscSymbolMethod />} title="Methods" className="dark:text-white">
|
||||
<Section title="Methods" icon={<VscSymbolMethod />} padded dense={matches}>
|
||||
<MethodList data={data} />
|
||||
</Section>
|
||||
) : null;
|
||||
}
|
||||
|
||||
export interface ParametersSectionProps {
|
||||
data: ParameterDocumentation[];
|
||||
}
|
||||
export function ParametersSection({ data }: { data: ParameterDocumentation[] }) {
|
||||
const matches = useMediaQuery('(max-width: 768px)', true, { getInitialValueInEffect: false });
|
||||
|
||||
export function ParametersSection({ data }: ParametersSectionProps) {
|
||||
return data.length ? (
|
||||
<Section iconElement={<VscSymbolConstant />} title="Parameters" className="dark:text-white">
|
||||
<Section title="Parameters" icon={<VscSymbolConstant />} padded dense={matches}>
|
||||
<ParameterTable data={data} />
|
||||
</Section>
|
||||
) : null;
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export function Separator() {
|
||||
return <div className="h-[1px] w-full bg-gray-300" />;
|
||||
}
|
||||
@@ -1,32 +1,16 @@
|
||||
import { createStyles, UnstyledButton, Group, Text } from '@mantine/core';
|
||||
import Link from 'next/link';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import {
|
||||
VscSymbolClass,
|
||||
VscSymbolEnum,
|
||||
VscSymbolField,
|
||||
VscSymbolInterface,
|
||||
VscSymbolMethod,
|
||||
VscSymbolField,
|
||||
VscSymbolVariable,
|
||||
VscSymbolMethod,
|
||||
} from 'react-icons/vsc';
|
||||
import type { ItemListProps } from './ItemSidebar';
|
||||
import { Section } from './Section';
|
||||
import type { DocItem } from '~/DocModel/DocItem';
|
||||
|
||||
export type Members = ItemListProps['data']['members'];
|
||||
|
||||
export interface ListSidebarSectionProps {
|
||||
members: Members;
|
||||
selectedMember?: ReturnType<DocItem['toJSON']> | undefined;
|
||||
title: string;
|
||||
}
|
||||
|
||||
interface GroupedMembers {
|
||||
Classes: Members;
|
||||
Functions: Members;
|
||||
Enums: Members;
|
||||
Interfaces: Members;
|
||||
Types: Members;
|
||||
Variables: Members;
|
||||
}
|
||||
import type { GroupedMembers, Members } from './SidebarLayout';
|
||||
|
||||
function groupMembers(members: Members): GroupedMembers {
|
||||
const Classes: Members = [];
|
||||
@@ -81,42 +65,54 @@ function resolveIcon(item: keyof GroupedMembers) {
|
||||
}
|
||||
}
|
||||
|
||||
export function ListSidebar({ members, selectedMember }: ListSidebarSectionProps) {
|
||||
const useStyles = createStyles((theme) => ({
|
||||
link: {
|
||||
fontWeight: 500,
|
||||
display: 'block',
|
||||
padding: 5,
|
||||
paddingLeft: 31,
|
||||
marginLeft: 25,
|
||||
fontSize: theme.fontSizes.sm,
|
||||
color: theme.colorScheme === 'dark' ? theme.colors.dark![0] : theme.colors.gray![7],
|
||||
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],
|
||||
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export function SidebarItems({
|
||||
members,
|
||||
setOpened,
|
||||
}: {
|
||||
members: Members;
|
||||
setOpened: Dispatch<SetStateAction<boolean>>;
|
||||
}) {
|
||||
const { classes } = useStyles();
|
||||
const groupItems = groupMembers(members);
|
||||
|
||||
return (
|
||||
<>
|
||||
{(Object.keys(groupItems) as (keyof GroupedMembers)[])
|
||||
.filter((group) => groupItems[group].length)
|
||||
.map((group, i) => (
|
||||
<Section iconElement={resolveIcon(group)} key={i} title={group} showSeparator={false}>
|
||||
<div className="space-y-2">
|
||||
{groupItems[group].map((member, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex gap-2 whitespace-pre-wrap no-underline break-all justify-between text-blue-500 dark:text-blue-300"
|
||||
>
|
||||
<Link href={member.path}>
|
||||
<a
|
||||
className={`no-underline m-0 text-sm font-semibold ${
|
||||
selectedMember?.containerKey === member.containerKey
|
||||
? 'text-blue-500 dark:text-blue-300'
|
||||
: 'text-gray-500 dark:text-gray-300 hover:text-dark-100 dark:hover:text-white'
|
||||
}`}
|
||||
>
|
||||
{member.name}
|
||||
</a>
|
||||
</Link>
|
||||
<div>
|
||||
.map((group, idx) => (
|
||||
<Section key={idx} title={group} icon={resolveIcon(group)}>
|
||||
{groupItems[group].map((member, i) => (
|
||||
<Link key={i} href={member.path} passHref>
|
||||
<UnstyledButton className={classes.link} component="a" onClick={() => setOpened((o) => !o)}>
|
||||
<Group>
|
||||
<Text>{member.name}</Text>
|
||||
{member.overloadIndex && member.overloadIndex > 1 ? (
|
||||
<div className="flex font-mono w-[15px] h-[15px] items-center justify-center rounded-md border border-2 font-bold text-sm color-gray-500 dark:color-gray-300">
|
||||
<p className="font-semibold">{`${member.overloadIndex}`}</p>
|
||||
</div>
|
||||
<Text size="xs" color="dimmed">
|
||||
{member.overloadIndex}
|
||||
</Text>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Group>
|
||||
</UnstyledButton>
|
||||
</Link>
|
||||
))}
|
||||
</Section>
|
||||
))}
|
||||
</>
|
||||
@@ -1,30 +1,207 @@
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { type ItemListProps, ItemSidebar } from './ItemSidebar';
|
||||
import {
|
||||
useMantineTheme,
|
||||
AppShell,
|
||||
Navbar,
|
||||
MediaQuery,
|
||||
// Aside,
|
||||
Header,
|
||||
Burger,
|
||||
Anchor,
|
||||
Breadcrumbs,
|
||||
ScrollArea,
|
||||
Group,
|
||||
Text,
|
||||
ThemeIcon,
|
||||
Box,
|
||||
UnstyledButton,
|
||||
createStyles,
|
||||
Menu,
|
||||
ActionIcon,
|
||||
useMantineColorScheme,
|
||||
} from '@mantine/core';
|
||||
import { NextLink } from '@mantine/next';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
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 type { DocItem } from '~/DocModel/DocItem';
|
||||
import type { findMember } from '~/util/model.server';
|
||||
import type { getMembers } from '~/util/parse.server';
|
||||
|
||||
export interface SidebarLayoutProps {
|
||||
packageName: string;
|
||||
data: {
|
||||
members: ReturnType<typeof getMembers>;
|
||||
member: ReturnType<typeof findMember>;
|
||||
};
|
||||
|
||||
selectedMember?: ReturnType<DocItem['toJSON']> | undefined;
|
||||
}
|
||||
|
||||
export type Members = SidebarLayoutProps['data']['members'];
|
||||
|
||||
export interface GroupedMembers {
|
||||
Classes: Members;
|
||||
Functions: Members;
|
||||
Enums: Members;
|
||||
Interfaces: Members;
|
||||
Types: Members;
|
||||
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,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark![7] : theme.colors.gray![0],
|
||||
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
|
||||
},
|
||||
},
|
||||
|
||||
icon: {
|
||||
transition: 'transform 150ms ease',
|
||||
transform: opened ? 'rotate(180deg)' : 'rotate(0deg)',
|
||||
},
|
||||
}));
|
||||
|
||||
const libraries = [
|
||||
{ label: 'builders', value: 'builders' },
|
||||
{ label: 'collection', value: 'collection' },
|
||||
{ label: 'discord.js', value: 'discord.js' },
|
||||
{ label: 'proxy', value: 'proxy' },
|
||||
{ label: 'rest', value: 'rest' },
|
||||
{ label: 'voice', value: 'voice' },
|
||||
{ label: 'ws', value: 'ws' },
|
||||
];
|
||||
|
||||
export function SidebarLayout({ packageName, data, children }: PropsWithChildren<Partial<SidebarLayoutProps>>) {
|
||||
const router = useRouter();
|
||||
|
||||
const theme = useMantineTheme();
|
||||
const { colorScheme, toggleColorScheme } = useMantineColorScheme();
|
||||
const dark = colorScheme === 'dark';
|
||||
|
||||
const [opened, setOpened] = useState(false);
|
||||
const [openedPicker, setOpenedPicker] = useState(false);
|
||||
|
||||
const { classes } = useStyles({ opened: openedPicker });
|
||||
|
||||
const libraryMenuItems = libraries.map((item) => (
|
||||
<Menu.Item key={item.label} component={NextLink} href={`/docs/main/packages/${item.value}`}>
|
||||
{item.label}
|
||||
</Menu.Item>
|
||||
));
|
||||
|
||||
const asPathWithoutQuery = router.asPath.split('?')[0];
|
||||
const breadcrumbs = asPathWithoutQuery?.split('/').map((path, idx, original) => (
|
||||
<Link key={idx} href={original.slice(0, idx + 1).join('/')} passHref>
|
||||
<Anchor component="a">{path}</Anchor>
|
||||
</Link>
|
||||
));
|
||||
|
||||
export function SidebarLayout({
|
||||
packageName,
|
||||
data,
|
||||
children,
|
||||
}: PropsWithChildren<Partial<ItemListProps & { data: { member: ReturnType<typeof findMember> } }>>) {
|
||||
return (
|
||||
<div className="flex flex-col max-w-full h-full max-h-full bg-white dark:bg-dark">
|
||||
<div className="flex min-h-[40px] border-0.5 border-b-0 border-gray items-center m-0 px-2 dark:text-white">
|
||||
Breadcrumbs
|
||||
</div>
|
||||
<div className="flex flex-col lg:flex-row overflow-hidden">
|
||||
<div className="h-full w-full lg:max-w-[310px] lg:min-w-[310px]">
|
||||
<AppShell
|
||||
styles={{
|
||||
main: {
|
||||
background: theme.colorScheme === 'dark' ? theme.colors.dark![8] : theme.colors.gray![0],
|
||||
},
|
||||
}}
|
||||
navbarOffsetBreakpoint="sm"
|
||||
asideOffsetBreakpoint="sm"
|
||||
navbar={
|
||||
<Navbar hiddenBreakpoint="sm" hidden={!opened} width={{ sm: 200, lg: 300 }}>
|
||||
{packageName && data ? (
|
||||
<ItemSidebar packageName={packageName} data={data} selectedMember={data.member} />
|
||||
<>
|
||||
<Navbar.Section p="xs">
|
||||
<>
|
||||
<Menu
|
||||
onOpen={() => setOpenedPicker(true)}
|
||||
onClose={() => setOpenedPicker(false)}
|
||||
radius="md"
|
||||
width="target"
|
||||
>
|
||||
<Menu.Target>
|
||||
<UnstyledButton className={classes.control}>
|
||||
<Group position="apart">
|
||||
<Group>
|
||||
<ThemeIcon variant="outline" size={30}>
|
||||
<VscPackage />
|
||||
</ThemeIcon>
|
||||
<Text weight="600" size="md">
|
||||
{packageName}
|
||||
</Text>
|
||||
</Group>
|
||||
<VscChevronDown className={classes.icon} size={20} />
|
||||
</Group>
|
||||
</UnstyledButton>
|
||||
</Menu.Target>
|
||||
<Menu.Dropdown>{libraryMenuItems}</Menu.Dropdown>
|
||||
</Menu>
|
||||
</>
|
||||
</Navbar.Section>
|
||||
|
||||
<Navbar.Section p="xs" grow component={ScrollArea}>
|
||||
<SidebarItems members={data.members} setOpened={setOpened} />
|
||||
</Navbar.Section>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="h-full grow">{children}</div>
|
||||
<div className="h-full w-full lg:max-w-[310px] lg:min-w-[310px]">
|
||||
{packageName && data?.member ? (
|
||||
<ItemSidebar packageName={packageName} data={data} selectedMember={data.member} />
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</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>
|
||||
// ) : (
|
||||
// <></>
|
||||
// )
|
||||
// }
|
||||
// footer={
|
||||
// <Footer height={60} p="md">
|
||||
// Application footer
|
||||
// </Footer>
|
||||
// }
|
||||
header={
|
||||
<Header height={70} p="md">
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', height: '100%' }}>
|
||||
<div>
|
||||
<MediaQuery largerThan="sm" styles={{ display: 'none' }}>
|
||||
<Burger
|
||||
opened={opened}
|
||||
onClick={() => setOpened((o) => !o)}
|
||||
size="sm"
|
||||
color={theme.colors.gray![6]}
|
||||
mr="xl"
|
||||
/>
|
||||
</MediaQuery>
|
||||
|
||||
<MediaQuery smallerThan="sm" styles={{ display: 'none' }}>
|
||||
<Breadcrumbs>{breadcrumbs}</Breadcrumbs>
|
||||
</MediaQuery>
|
||||
</div>
|
||||
<ActionIcon
|
||||
variant="outline"
|
||||
color={dark ? 'yellow' : 'blurple'}
|
||||
onClick={() => toggleColorScheme()}
|
||||
title="Toggle color scheme"
|
||||
>
|
||||
{dark ? <WiDaySunny size={18} /> : <WiNightClear size={18} />}
|
||||
</ActionIcon>
|
||||
</Box>
|
||||
</Header>
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</AppShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,45 +1,37 @@
|
||||
import { Table as MantineTable } from '@mantine/core';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
export interface RowData {
|
||||
monospace?: boolean;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface TableProps {
|
||||
export function Table({
|
||||
rows,
|
||||
columns,
|
||||
columnStyles,
|
||||
}: {
|
||||
columns: string[];
|
||||
columnStyles?: Record<string, string>;
|
||||
rows: Record<string, ReactNode>[];
|
||||
className?: string | undefined;
|
||||
}
|
||||
|
||||
export function Table({ rows, columns, columnStyles, className }: TableProps) {
|
||||
}) {
|
||||
return (
|
||||
<div className={className}>
|
||||
<table className="table-fixed w-full pb-10 border-collapse">
|
||||
<thead>
|
||||
<tr>
|
||||
{columns.map((column) => (
|
||||
<th key={column} className="border-b z-10 text-left text-sm pl-2 border-gray">
|
||||
{column}
|
||||
</th>
|
||||
<MantineTable>
|
||||
<thead>
|
||||
<tr>
|
||||
{columns.map((column) => (
|
||||
<th key={column} className="break-normal">
|
||||
{column}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((row, idx) => (
|
||||
<tr key={idx}>
|
||||
{Object.entries(row).map(([colName, val]) => (
|
||||
<td key={colName} className={columnStyles?.[colName] ?? ''}>
|
||||
{val}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((row, i) => (
|
||||
<tr key={i}>
|
||||
{Object.entries(row).map(([colName, val]) => (
|
||||
<td
|
||||
key={colName}
|
||||
className={`p-2 text-sm border-b text-left border-gray break-all ${columnStyles?.[colName] ?? ''}`}
|
||||
>
|
||||
{val}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
))}
|
||||
</tbody>
|
||||
</MantineTable>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,12 +2,7 @@ import { HyperlinkedText } from './HyperlinkedText';
|
||||
import { Table } from './Table';
|
||||
import type { TypeParameterData } from '~/util/parse.server';
|
||||
|
||||
export interface TableProps {
|
||||
data: TypeParameterData[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function TypeParamTable({ data, className }: TableProps) {
|
||||
export function TypeParamTable({ data }: { data: TypeParameterData[] }) {
|
||||
const rows = data.map((typeParam) => ({
|
||||
Name: typeParam.name,
|
||||
Constraints: <HyperlinkedText tokens={typeParam.constraintTokens} />,
|
||||
@@ -24,7 +19,6 @@ export function TypeParamTable({ data, className }: TableProps) {
|
||||
|
||||
return (
|
||||
<Table
|
||||
className={className}
|
||||
columns={['Name', 'Constraints', 'Optional', 'Default', 'Description']}
|
||||
rows={rows}
|
||||
columnStyles={rowElements}
|
||||
|
||||
@@ -2,11 +2,7 @@ import { DocContainer } from '../DocContainer';
|
||||
import { MethodsSection, PropertiesSection } from '../Sections';
|
||||
import type { DocClass } from '~/DocModel/DocClass';
|
||||
|
||||
export interface ClassProps {
|
||||
data: ReturnType<DocClass['toJSON']>;
|
||||
}
|
||||
|
||||
export function Class({ data }: ClassProps) {
|
||||
export function Class({ data }: { data: ReturnType<DocClass['toJSON']> }) {
|
||||
return (
|
||||
<DocContainer
|
||||
name={data.name}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { Stack } from '@mantine/core';
|
||||
import { useMediaQuery } from '@mantine/hooks';
|
||||
import { VscSymbolEnumMember } from 'react-icons/vsc';
|
||||
import { CodeListing, CodeListingSeparatorType } from '../CodeListing';
|
||||
import { DocContainer } from '../DocContainer';
|
||||
import { Section } from '../Section';
|
||||
import type { DocEnum } from '~/DocModel/DocEnum';
|
||||
|
||||
export interface EnumProps {
|
||||
data: ReturnType<DocEnum['toJSON']>;
|
||||
}
|
||||
export function Enum({ data }: { data: ReturnType<DocEnum['toJSON']> }) {
|
||||
const matches = useMediaQuery('(max-width: 768px)', true, { getInitialValueInEffect: false });
|
||||
|
||||
export function Enum({ data }: EnumProps) {
|
||||
return (
|
||||
<DocContainer name={data.name} kind={data.kind} excerpt={data.excerpt} summary={data.summary}>
|
||||
<Section iconElement={<VscSymbolEnumMember />} title="Members" className="dark:text-white">
|
||||
<div className="flex flex-col gap-5">
|
||||
<Section title="Members" icon={<VscSymbolEnumMember />} padded dense={matches}>
|
||||
<Stack>
|
||||
{data.members.map((member) => (
|
||||
<CodeListing
|
||||
key={member.name}
|
||||
@@ -22,7 +22,7 @@ export function Enum({ data }: EnumProps) {
|
||||
summary={member.summary}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Stack>
|
||||
</Section>
|
||||
</DocContainer>
|
||||
);
|
||||
|
||||
@@ -2,11 +2,7 @@ import { DocContainer } from '../DocContainer';
|
||||
import { ParametersSection } from '../Sections';
|
||||
import type { DocFunction } from '~/DocModel/DocFunction';
|
||||
|
||||
export interface FunctionProps {
|
||||
data: ReturnType<DocFunction['toJSON']>;
|
||||
}
|
||||
|
||||
export function Function({ data }: FunctionProps) {
|
||||
export function Function({ data }: { data: ReturnType<DocFunction['toJSON']> }) {
|
||||
return (
|
||||
<DocContainer
|
||||
name={`${data.name}${data.overloadIndex ? ` (${data.overloadIndex})` : ''}`}
|
||||
|
||||
@@ -2,11 +2,7 @@ import { DocContainer } from '../DocContainer';
|
||||
import { MethodsSection, PropertiesSection } from '../Sections';
|
||||
import type { DocInterface } from '~/DocModel/DocInterface';
|
||||
|
||||
export interface InterfaceProps {
|
||||
data: ReturnType<DocInterface['toJSON']>;
|
||||
}
|
||||
|
||||
export function Interface({ data }: InterfaceProps) {
|
||||
export function Interface({ data }: { data: ReturnType<DocInterface['toJSON']> }) {
|
||||
return (
|
||||
<DocContainer
|
||||
name={data.name}
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { DocContainer } from '../DocContainer';
|
||||
import type { DocTypeAlias } from '~/DocModel/DocTypeAlias';
|
||||
|
||||
export interface TypeAliasProps {
|
||||
data: ReturnType<DocTypeAlias['toJSON']>;
|
||||
}
|
||||
|
||||
export function TypeAlias({ data }: TypeAliasProps) {
|
||||
export function TypeAlias({ data }: { data: ReturnType<DocTypeAlias['toJSON']> }) {
|
||||
return (
|
||||
<DocContainer
|
||||
name={data.name}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { DocContainer } from '../DocContainer';
|
||||
import type { DocVariable } from '~/DocModel/DocVariable';
|
||||
|
||||
export interface VariableProps {
|
||||
data: ReturnType<DocVariable['toJSON']>;
|
||||
}
|
||||
|
||||
export function Variable({ data }: VariableProps) {
|
||||
export function Variable({ data }: { data: ReturnType<DocVariable['toJSON']> }) {
|
||||
return <DocContainer name={data.name} kind={data.kind} excerpt={data.excerpt} summary={data.summary} />;
|
||||
}
|
||||
|
||||
@@ -5,11 +5,10 @@ export type DocItemJSON = ReturnType<DocItem['toJSON']>;
|
||||
|
||||
export const MemberContext = createContext<DocItemJSON | undefined>(undefined);
|
||||
|
||||
export interface MemberProviderProps {
|
||||
export const MemberProvider = ({
|
||||
member,
|
||||
children,
|
||||
}: {
|
||||
member: DocItemJSON | undefined;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const MemberProvider = ({ member, children }: MemberProviderProps) => (
|
||||
<MemberContext.Provider value={member}>{children}</MemberContext.Provider>
|
||||
);
|
||||
}) => <MemberContext.Provider value={member}>{children}</MemberContext.Provider>;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NextResponse } from 'next/server';
|
||||
import type { NextRequest } from 'next/server';
|
||||
|
||||
export default function middleware(request: NextRequest) {
|
||||
return NextResponse.rewrite(new URL('/docs/main/packages/builders', request.url));
|
||||
return NextResponse.redirect(new URL('/docs/main/packages/builders', request.url));
|
||||
}
|
||||
|
||||
export const config = {
|
||||
|
||||
@@ -1,8 +1,57 @@
|
||||
import { ColorScheme, ColorSchemeProvider, MantineProvider } from '@mantine/core';
|
||||
import { useColorScheme } from '@mantine/hooks';
|
||||
import type { AppProps } from 'next/app';
|
||||
import '@unocss/reset/normalize.css';
|
||||
import Head from 'next/head';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { RouterTransition } from '~/components/RouterTransition';
|
||||
import '../styles/unocss.css';
|
||||
import '../styles/main.css';
|
||||
|
||||
export default function MyApp({ Component, pageProps }: AppProps) {
|
||||
return <Component {...pageProps} />;
|
||||
const preferredColorScheme = useColorScheme('dark', { getInitialValueInEffect: true });
|
||||
const [colorScheme, setColorScheme] = useState<ColorScheme>(preferredColorScheme);
|
||||
const toggleColorScheme = (value?: ColorScheme) =>
|
||||
setColorScheme(value ?? (colorScheme === 'dark' ? 'light' : 'dark'));
|
||||
|
||||
useEffect(() => {
|
||||
setColorScheme(preferredColorScheme);
|
||||
}, [preferredColorScheme]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
|
||||
</Head>
|
||||
|
||||
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
|
||||
<MantineProvider
|
||||
theme={{
|
||||
fontFamily: 'Inter',
|
||||
colorScheme,
|
||||
colors: {
|
||||
blurple: [
|
||||
'#5865F2',
|
||||
'#5865F2',
|
||||
'#5865F2',
|
||||
'#5865F2',
|
||||
'#5865F2',
|
||||
'#5865F2',
|
||||
'#5865F2',
|
||||
'#5865F2',
|
||||
'#5865F2',
|
||||
'#5865F2',
|
||||
],
|
||||
},
|
||||
primaryColor: 'blurple',
|
||||
}}
|
||||
withCSSVariables
|
||||
withNormalizeCSS
|
||||
withGlobalStyles
|
||||
>
|
||||
<RouterTransition />
|
||||
<Component {...pageProps} />
|
||||
</MantineProvider>
|
||||
</ColorSchemeProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
import { Html, Head, Main, NextScript } from 'next/document';
|
||||
import { createGetInitialProps } from '@mantine/next';
|
||||
import Document, { Html, Head, Main, NextScript } from 'next/document';
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `(() => {
|
||||
const prefersDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const persistedColorPreference = localStorage.getItem('theme') || 'auto';
|
||||
if (persistedColorPreference === 'dark' || (prefersDarkMode && persistedColorPreference !== 'light')) {
|
||||
document.documentElement.classList.toggle('dark', true);
|
||||
}
|
||||
})();`,
|
||||
}}
|
||||
/>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
const getInitialProps = createGetInitialProps();
|
||||
export default class _Document extends Document {
|
||||
public static override getInitialProps = getInitialProps;
|
||||
|
||||
public override render() {
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-throw-literal */
|
||||
import { Box } from '@mantine/core';
|
||||
import { ApiFunction } from '@microsoft/api-extractor-model';
|
||||
import type { GetStaticPaths, GetStaticProps } from 'next/types';
|
||||
import type { DocClass } from '~/DocModel/DocClass';
|
||||
@@ -7,8 +8,7 @@ import type { DocFunction } from '~/DocModel/DocFunction';
|
||||
import type { DocInterface } from '~/DocModel/DocInterface';
|
||||
import type { DocTypeAlias } from '~/DocModel/DocTypeAlias';
|
||||
import type { DocVariable } from '~/DocModel/DocVariable';
|
||||
import type { ItemListProps } from '~/components/ItemSidebar';
|
||||
import { SidebarLayout } from '~/components/SidebarLayout';
|
||||
import { SidebarLayout, type SidebarLayoutProps } from '~/components/SidebarLayout';
|
||||
import { Class } from '~/components/model/Class';
|
||||
import { Enum } from '~/components/model/Enum';
|
||||
import { Function } from '~/components/model/Function';
|
||||
@@ -26,10 +26,6 @@ export const getStaticPaths: GetStaticPaths = async () => {
|
||||
const pkgs = (
|
||||
await Promise.all(
|
||||
packages.map(async (packageName) => {
|
||||
if (packageName === 'rest') {
|
||||
return { params: { slug: ['main', 'packages', packageName] } };
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`https://docs.discordjs.dev/docs/${packageName}/main.api.json`);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
@@ -40,16 +36,21 @@ export const getStaticPaths: GetStaticPaths = async () => {
|
||||
|
||||
return [
|
||||
{ params: { slug: ['main', 'packages', packageName] } },
|
||||
...getMembers(pkg!).map((member) => {
|
||||
if (member.kind === 'Function' && member.overloadIndex) {
|
||||
return {
|
||||
params: {
|
||||
slug: ['main', 'packages', packageName, `${member.name}:${member.overloadIndex}`],
|
||||
},
|
||||
};
|
||||
}
|
||||
return { params: { slug: ['main', 'packages', packageName, member.name] } };
|
||||
}),
|
||||
...getMembers(pkg!)
|
||||
// Filtering out enum `RESTEvents` because of interface with similar name `RestEvents`
|
||||
// causing next.js export to error
|
||||
.filter((member) => member.name !== 'RESTEvents')
|
||||
.map((member) => {
|
||||
if (member.kind === 'Function' && member.overloadIndex) {
|
||||
return {
|
||||
params: {
|
||||
slug: ['main', 'packages', packageName, `${member.name}:${member.overloadIndex}`],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return { params: { slug: ['main', 'packages', packageName, member.name] } };
|
||||
}),
|
||||
];
|
||||
} catch {
|
||||
return { params: { slug: ['', '', '', ''] } };
|
||||
@@ -77,8 +78,8 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
|
||||
const model = createApiModel(data);
|
||||
const pkg = findPackage(model, packageName);
|
||||
|
||||
let { containerKey, name } = findMember(model, packageName, memberName)!;
|
||||
if (overloadIndex) {
|
||||
let { containerKey, name } = findMember(model, packageName, memberName) ?? {};
|
||||
if (name && overloadIndex) {
|
||||
containerKey = ApiFunction.getContainerKey(name, parseInt(overloadIndex, 10));
|
||||
}
|
||||
|
||||
@@ -87,7 +88,8 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
|
||||
packageName,
|
||||
data: {
|
||||
members: pkg ? getMembers(pkg) : [],
|
||||
member: memberName ? findMemberByKey(model, packageName, containerKey)?.toJSON() ?? null : null,
|
||||
member:
|
||||
memberName && containerKey ? findMemberByKey(model, packageName, containerKey)?.toJSON() ?? null : null,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -116,13 +118,11 @@ const member = (props: any) => {
|
||||
case 'Enum':
|
||||
return <Enum data={props as ReturnType<DocEnum['toJSON']>} />;
|
||||
default:
|
||||
return <div>Cannot render that item type</div>;
|
||||
return <Box>Cannot render that item type</Box>;
|
||||
}
|
||||
};
|
||||
|
||||
export default function Slug(
|
||||
props: Partial<ItemListProps & { error?: string; data: { member: ReturnType<typeof findMember> } }>,
|
||||
) {
|
||||
export default function Slug(props: Partial<SidebarLayoutProps & { error?: string }>) {
|
||||
return props.error ? (
|
||||
<div className="flex max-w-full h-full bg-white dark:bg-dark">{props.error}</div>
|
||||
) : (
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function DocsLanding() {
|
||||
return <div>Documentation</div>;
|
||||
}
|
||||
@@ -1,73 +1,117 @@
|
||||
import { createStyles, Container, Title, Button, Group, Text, Center } from '@mantine/core';
|
||||
import Image from 'next/future/image';
|
||||
import Link from 'next/link';
|
||||
import { forwardRef, MouseEventHandler, Ref } from 'react';
|
||||
import codeSample from '../assets/code-sample.png';
|
||||
import logo from '../assets/djs_logo_rainbow_400x400.png';
|
||||
import vercelLogo from '../assets/powered-by-vercel.svg';
|
||||
import text from '../text.json';
|
||||
|
||||
interface ButtonProps {
|
||||
label: string;
|
||||
href?: string;
|
||||
ref?: Ref<HTMLAnchorElement>;
|
||||
onClick?: MouseEventHandler<HTMLAnchorElement>;
|
||||
}
|
||||
const useStyles = createStyles((theme) => ({
|
||||
inner: {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingTop: theme.spacing.xl * 4,
|
||||
paddingBottom: theme.spacing.xl * 4,
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const LinkButton = forwardRef<HTMLAnchorElement, ButtonProps>(({ label, onClick, href }: ButtonProps, ref) => (
|
||||
<a
|
||||
href={href}
|
||||
onClick={onClick}
|
||||
ref={ref}
|
||||
className="no-underline max-h-[70px] bg-blurple px-3 py-4 rounded-lg font-semibold text-white"
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
));
|
||||
[theme.fn.smallerThan('md')]: {
|
||||
flexDirection: 'column',
|
||||
gap: 50,
|
||||
},
|
||||
},
|
||||
|
||||
content: {
|
||||
maxWidth: 480,
|
||||
marginRight: theme.spacing.xl * 3,
|
||||
|
||||
[theme.fn.smallerThan('md')]: {
|
||||
marginRight: 0,
|
||||
},
|
||||
},
|
||||
|
||||
title: {
|
||||
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
|
||||
fontSize: 44,
|
||||
lineHeight: 1.2,
|
||||
fontWeight: 900,
|
||||
|
||||
[theme.fn.smallerThan('xs')]: {
|
||||
fontSize: 28,
|
||||
},
|
||||
},
|
||||
|
||||
highlight: {
|
||||
position: 'relative',
|
||||
backgroundColor: theme.fn.variant({ variant: 'light', color: theme.primaryColor }).background,
|
||||
borderRadius: theme.radius.sm,
|
||||
padding: '4px 12px',
|
||||
},
|
||||
|
||||
control: {
|
||||
[theme.fn.smallerThan('xs')]: {
|
||||
flex: 1,
|
||||
},
|
||||
},
|
||||
|
||||
image: {
|
||||
flex: 1,
|
||||
height: '100%',
|
||||
maxWidth: 550,
|
||||
|
||||
[theme.fn.smallerThan('xs')]: {
|
||||
maxWidth: 350,
|
||||
},
|
||||
},
|
||||
|
||||
vercel: {
|
||||
height: '100%',
|
||||
maxWidth: 250,
|
||||
paddingBottom: theme.spacing.xl * 4,
|
||||
},
|
||||
}));
|
||||
|
||||
export default function IndexRoute() {
|
||||
const { classes } = useStyles();
|
||||
return (
|
||||
<main className="w-full max-w-full max-h-full h-full flex-col bg-white dark:bg-dark overflow-y-auto">
|
||||
<div className="flex h-[65px] sticky top-0 border-b border-gray justify-center px-10 bg-white dark:bg-dark">
|
||||
<div className="flex items-center w-full max-w-[1100px] justify-between">
|
||||
<div className="h-[50px] w-[50px] rounded-lg overflow-hidden">
|
||||
<Image className="h-[50px] w-[50px]" src={logo} />
|
||||
</div>
|
||||
<div className="flex flex-row space-x-8">
|
||||
<Link href="/docs" passHref>
|
||||
<a className="no-underline text-blurple font-semibold">Docs</a>
|
||||
</Link>
|
||||
<a className="text-blurple font-semibold">Guide</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="xl:flex xl:flex-col xl:justify-center w-full max-w-full box-border p-10">
|
||||
<div className="flex flex-col xl:flex-row grow max-w-[1100px] pb-10 space-y-10 xl:space-x-20 place-items-center place-self-center">
|
||||
<div className="flex flex-col max-w-[800px] lt-xl:items-center">
|
||||
<h1 className="font-bold text-6xl text-blurple my-2">{text.heroTitle}</h1>
|
||||
<p className="text-xl text-dark-100 dark:text-gray-300">{text.heroDescription}</p>
|
||||
<div className="flex flew-row space-x-4">
|
||||
<LinkButton label="Read the guide" />
|
||||
<div>
|
||||
<Container size="lg">
|
||||
<div className={classes.inner}>
|
||||
<div className={classes.content}>
|
||||
<Title className={classes.title}>
|
||||
The <span className={classes.highlight}>most popular</span> way to build Discord <br /> bots.
|
||||
</Title>
|
||||
<Text color="dimmed" mt="md">
|
||||
discord.js is a powerful Node.js module that allows you to interact with the Discord API very easily. It
|
||||
takes a much more object-oriented approach than most other JS Discord libraries, making your bot's
|
||||
code significantly tidier and easier to comprehend.
|
||||
</Text>
|
||||
|
||||
<Group mt={30}>
|
||||
<Link href="/docs" passHref>
|
||||
<LinkButton label="Check out the docs" />
|
||||
<Button component="a" radius="xl" size="md" className={classes.control}>
|
||||
Docs
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sm:flex sm:grow sm:shrink h-full xl:items-center hidden">
|
||||
<Image src={codeSample} className="max-w-[600px] h-full rounded-xl shadow-md overflow-hidden" />
|
||||
<Link href="https://discordjs.guide" passHref>
|
||||
<Button component="a" variant="default" radius="xl" size="md" className={classes.control}>
|
||||
Guide
|
||||
</Button>
|
||||
</Link>
|
||||
</Group>
|
||||
</div>
|
||||
<Image src={codeSample} className={classes.image} />
|
||||
</div>
|
||||
<div className="flex place-content-center">
|
||||
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss" title="Vercel">
|
||||
<Image
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
src={vercelLogo}
|
||||
alt="Vercel"
|
||||
className="max-w-[250px] shadow-md overflow-hidden"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<Center>
|
||||
<Link href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss" passHref>
|
||||
<a title="Vercel">
|
||||
<Image
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
src={vercelLogo}
|
||||
alt="Vercel"
|
||||
className={classes.vercel}
|
||||
/>
|
||||
</a>
|
||||
</Link>
|
||||
</Center>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"heroTitle": "The most popular way to build Discord bots.",
|
||||
"heroDescription": "discord.js is a powerful Node.js module that allows you to interact with the Discord API very easily. It takes a much more object-oriented approach than most other JS Discord libraries, making your bot's code significantly tidier and easier to comprehend."
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"build": "unbuild",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"docs": "docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
|
||||
"prepack": "yarn build && yarn lint",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/ws/*'",
|
||||
|
||||
10
turbo.json
10
turbo.json
@@ -3,11 +3,15 @@
|
||||
"pipeline": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["**/dist/**"]
|
||||
"outputs": ["dist/**"]
|
||||
},
|
||||
"@discordjs/website#build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": [".next/**"]
|
||||
},
|
||||
"test": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["**/coverage/**"]
|
||||
"outputs": []
|
||||
},
|
||||
"lint": {
|
||||
"dependsOn": ["^build"],
|
||||
@@ -19,7 +23,7 @@
|
||||
},
|
||||
"docs": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["**/docs/docs.json", "**/docs/docs.api.json"]
|
||||
"outputs": ["docs/docs.json", "docs/docs.api.json"]
|
||||
},
|
||||
"changelog": {
|
||||
"dependsOn": ["^build"],
|
||||
|
||||
Reference in New Issue
Block a user