mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-16 19:43:29 +01:00
refactor(website): consolidate badge logic (#9417)
Co-authored-by: Noel <buechler.noel@outlook.com>
This commit is contained in:
37
apps/website/src/components/Badges.tsx
Normal file
37
apps/website/src/components/Badges.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import type { ApiDocumentedItem } from '@microsoft/api-extractor-model';
|
||||||
|
import { ApiAbstractMixin, ApiProtectedMixin, ApiReadonlyMixin, ApiStaticMixin } from '@microsoft/api-extractor-model';
|
||||||
|
import type { PropsWithChildren } from 'react';
|
||||||
|
|
||||||
|
export enum BadgeColor {
|
||||||
|
Danger = 'bg-red-500',
|
||||||
|
Primary = 'bg-blurple',
|
||||||
|
Warning = 'bg-yellow-500',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Badge({ children, color = BadgeColor.Primary }: PropsWithChildren<{ color?: BadgeColor | undefined }>) {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={`h-5 flex flex-row place-content-center place-items-center rounded-full px-3 text-center text-xs font-semibold uppercase text-white ${color}`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Badges({ item }: { item: ApiDocumentedItem }) {
|
||||||
|
const isStatic = ApiStaticMixin.isBaseClassOf(item) && item.isStatic;
|
||||||
|
const isProtected = ApiProtectedMixin.isBaseClassOf(item) && item.isProtected;
|
||||||
|
const isReadonly = ApiReadonlyMixin.isBaseClassOf(item) && item.isReadonly;
|
||||||
|
const isAbstract = ApiAbstractMixin.isBaseClassOf(item) && item.isAbstract;
|
||||||
|
const isDeprecated = Boolean(item.tsdocComment?.deprecatedBlock);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-row gap-1 md:ml-7">
|
||||||
|
{isDeprecated ? <Badge color={BadgeColor.Danger}>Deprecated</Badge> : null}
|
||||||
|
{isProtected ? <Badge>Protected</Badge> : null}
|
||||||
|
{isStatic ? <Badge>Static</Badge> : null}
|
||||||
|
{isAbstract ? <Badge>Abstract</Badge> : null}
|
||||||
|
{isReadonly ? <Badge>Readonly</Badge> : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ export interface ExcerptTextProps {
|
|||||||
*/
|
*/
|
||||||
export function ExcerptText({ model, excerpt }: ExcerptTextProps) {
|
export function ExcerptText({ model, excerpt }: ExcerptTextProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<span>
|
||||||
{excerpt.spannedTokens.map((token, idx) => {
|
{excerpt.spannedTokens.map((token, idx) => {
|
||||||
if (token.kind === ExcerptTokenKind.Reference) {
|
if (token.kind === ExcerptTokenKind.Reference) {
|
||||||
const source = token.canonicalReference?.source;
|
const source = token.canonicalReference?.source;
|
||||||
@@ -59,6 +59,6 @@ export function ExcerptText({ model, excerpt }: ExcerptTextProps) {
|
|||||||
|
|
||||||
return token.text;
|
return token.text;
|
||||||
})}
|
})}
|
||||||
</>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,59 +5,29 @@ import type {
|
|||||||
ApiPropertySignature,
|
ApiPropertySignature,
|
||||||
} from '@microsoft/api-extractor-model';
|
} from '@microsoft/api-extractor-model';
|
||||||
import type { PropsWithChildren } from 'react';
|
import type { PropsWithChildren } from 'react';
|
||||||
|
import { Badges } from './Badges';
|
||||||
import { CodeHeading } from './CodeHeading';
|
import { CodeHeading } from './CodeHeading';
|
||||||
import { ExcerptText } from './ExcerptText';
|
import { ExcerptText } from './ExcerptText';
|
||||||
import { InheritanceText } from './InheritanceText';
|
import { InheritanceText } from './InheritanceText';
|
||||||
import { TSDoc } from './documentation/tsdoc/TSDoc';
|
import { TSDoc } from './documentation/tsdoc/TSDoc';
|
||||||
|
|
||||||
export enum PropertySeparatorType {
|
|
||||||
Type = ':',
|
|
||||||
Value = '=',
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Property({
|
export function Property({
|
||||||
item,
|
item,
|
||||||
children,
|
children,
|
||||||
separator,
|
|
||||||
inheritedFrom,
|
inheritedFrom,
|
||||||
}: PropsWithChildren<{
|
}: PropsWithChildren<{
|
||||||
inheritedFrom?: (ApiDeclaredItem & ApiItemContainerMixin) | undefined;
|
inheritedFrom?: (ApiDeclaredItem & ApiItemContainerMixin) | undefined;
|
||||||
item: ApiProperty | ApiPropertySignature;
|
item: ApiProperty | ApiPropertySignature;
|
||||||
separator?: PropertySeparatorType;
|
|
||||||
}>) {
|
}>) {
|
||||||
const isDeprecated = Boolean(item.tsdocComment?.deprecatedBlock);
|
|
||||||
const hasSummary = Boolean(item.tsdocComment?.summarySection);
|
const hasSummary = Boolean(item.tsdocComment?.summarySection);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col scroll-mt-30 gap-4" id={item.displayName}>
|
<div className="flex flex-col scroll-mt-30 gap-4" id={item.displayName}>
|
||||||
<div className="flex flex-col gap-2 md:-ml-9">
|
<div className="flex flex-col gap-2 md:-ml-9">
|
||||||
{isDeprecated || item.isReadonly || item.isOptional || (item as ApiProperty).isStatic ? (
|
<Badges item={item} />
|
||||||
<div className="flex flex-row gap-1 md:ml-7">
|
|
||||||
{isDeprecated ? (
|
|
||||||
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-red-500 px-3 text-center text-xs font-semibold uppercase text-white">
|
|
||||||
Deprecated
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{(item as ApiProperty).isStatic ? (
|
|
||||||
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-blurple px-3 text-center text-xs font-semibold uppercase text-white">
|
|
||||||
Static
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{item.isReadonly ? (
|
|
||||||
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-blurple px-3 text-center text-xs font-semibold uppercase text-white">
|
|
||||||
Readonly
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{item.isOptional ? (
|
|
||||||
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-blurple px-3 text-center text-xs font-semibold uppercase text-white">
|
|
||||||
Optional
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<CodeHeading href={`#${item.displayName}`}>
|
<CodeHeading href={`#${item.displayName}`}>
|
||||||
{`${item.displayName}${item.isOptional ? '?' : ''}`}
|
{`${item.displayName}${item.isOptional ? '?' : ''}`}
|
||||||
<span>{separator}</span>
|
<span>:</span>
|
||||||
{item.propertyTypeExcerpt.text ? (
|
{item.propertyTypeExcerpt.text ? (
|
||||||
<ExcerptText excerpt={item.propertyTypeExcerpt} model={item.getAssociatedModel()!} />
|
<ExcerptText excerpt={item.propertyTypeExcerpt} model={item.getAssociatedModel()!} />
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import type {
|
|||||||
} from '@microsoft/api-extractor-model';
|
} from '@microsoft/api-extractor-model';
|
||||||
import { ApiItemKind } from '@microsoft/api-extractor-model';
|
import { ApiItemKind } from '@microsoft/api-extractor-model';
|
||||||
import { Fragment, useMemo } from 'react';
|
import { Fragment, useMemo } from 'react';
|
||||||
import { Property, PropertySeparatorType } from './Property';
|
import { Property } from './Property';
|
||||||
import { resolveMembers } from '~/util/members';
|
import { resolveMembers } from '~/util/members';
|
||||||
|
|
||||||
export function isPropertyLike(item: ApiItem): item is ApiProperty | ApiPropertySignature {
|
export function isPropertyLike(item: ApiItem): item is ApiProperty | ApiPropertySignature {
|
||||||
@@ -25,7 +25,6 @@ export function PropertyList({ item }: { item: ApiItemContainerMixin }) {
|
|||||||
<Property
|
<Property
|
||||||
inheritedFrom={prop.inherited as ApiDeclaredItem & ApiItemContainerMixin}
|
inheritedFrom={prop.inherited as ApiDeclaredItem & ApiItemContainerMixin}
|
||||||
item={prop.item as ApiProperty}
|
item={prop.item as ApiProperty}
|
||||||
separator={PropertySeparatorType.Type}
|
|
||||||
/>
|
/>
|
||||||
<div className="border-t-2 border-light-900 dark:border-dark-100" />
|
<div className="border-t-2 border-light-900 dark:border-dark-100" />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export function Header({
|
|||||||
{name}
|
{name}
|
||||||
</span>
|
</span>
|
||||||
{sourceURL ? (
|
{sourceURL ? (
|
||||||
<a className="text-blurple" href={sourceURL}>
|
<a className="text-blurple" href={sourceURL} rel="external noopener noreferrer" target="_blank">
|
||||||
<VscFileCode />
|
<VscFileCode />
|
||||||
</a>
|
</a>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
import type { ApiDeclaredItem, ApiItemContainerMixin, ApiTypeParameterListMixin } from '@microsoft/api-extractor-model';
|
|
||||||
import type { ReactNode } from 'react';
|
|
||||||
// import { Outline } from '../Outline';
|
|
||||||
import { SyntaxHighlighter } from '../SyntaxHighlighter';
|
|
||||||
import { Documentation } from './Documentation';
|
|
||||||
import { MethodsSection } from './section/MethodsSection';
|
|
||||||
import { PropertiesSection } from './section/PropertiesSection';
|
|
||||||
import { SummarySection } from './section/SummarySection';
|
|
||||||
import { TypeParameterSection } from './section/TypeParametersSection';
|
|
||||||
import { hasProperties, hasMethods /* , serializeMembers */ } from './util';
|
|
||||||
|
|
||||||
export function MemberContainerDocumentation({
|
|
||||||
item,
|
|
||||||
subheading,
|
|
||||||
}: {
|
|
||||||
item: ApiDeclaredItem & ApiItemContainerMixin & ApiTypeParameterListMixin;
|
|
||||||
subheading?: ReactNode;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<Documentation>
|
|
||||||
{subheading}
|
|
||||||
{/* @ts-expect-error async component */}
|
|
||||||
<SyntaxHighlighter code={item.excerpt.text} />
|
|
||||||
<SummarySection item={item} />
|
|
||||||
{item.typeParameters.length ? <TypeParameterSection item={item} /> : null}
|
|
||||||
{hasProperties(item) ? <PropertiesSection item={item} /> : null}
|
|
||||||
{hasMethods(item) ? <MethodsSection item={item} /> : null}
|
|
||||||
|
|
||||||
{/* <Outline members={serializeMembers(item)} /> */}
|
|
||||||
</Documentation>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -2,23 +2,15 @@ import type { ApiConstructor } from '@microsoft/api-extractor-model';
|
|||||||
import { VscSymbolMethod } from '@react-icons/all-files/vsc/VscSymbolMethod';
|
import { VscSymbolMethod } from '@react-icons/all-files/vsc/VscSymbolMethod';
|
||||||
import { ParameterTable } from '../../ParameterTable';
|
import { ParameterTable } from '../../ParameterTable';
|
||||||
import { TSDoc } from '../tsdoc/TSDoc';
|
import { TSDoc } from '../tsdoc/TSDoc';
|
||||||
|
import { parametersString } from '../util';
|
||||||
import { DocumentationSection } from './DocumentationSection';
|
import { DocumentationSection } from './DocumentationSection';
|
||||||
|
import { CodeHeading } from '~/components/CodeHeading';
|
||||||
function getShorthandName(ctor: ApiConstructor) {
|
|
||||||
return `constructor(${ctor.parameters.reduce((prev, cur, index) => {
|
|
||||||
if (index === 0) {
|
|
||||||
return `${prev}${cur.isOptional ? `${cur.name}?` : cur.name}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${prev}, ${cur.isOptional ? `${cur.name}?` : cur.name}`;
|
|
||||||
}, '')})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ConstructorSection({ item }: { item: ApiConstructor }) {
|
export function ConstructorSection({ item }: { item: ApiConstructor }) {
|
||||||
return (
|
return (
|
||||||
<DocumentationSection icon={<VscSymbolMethod size={20} />} padded title="Constructor">
|
<DocumentationSection icon={<VscSymbolMethod size={20} />} padded title="Constructor">
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<h4 className="break-all font-mono text-lg font-bold">{getShorthandName(item)}</h4>
|
<CodeHeading>{`constructor(${parametersString(item)})`}</CodeHeading>
|
||||||
{item.tsdocComment ? <TSDoc item={item} tsdoc={item.tsdocComment} /> : null}
|
{item.tsdocComment ? <TSDoc item={item} tsdoc={item.tsdocComment} /> : null}
|
||||||
<ParameterTable item={item} />
|
<ParameterTable item={item} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,10 +6,13 @@ import type {
|
|||||||
ApiMethodSignature,
|
ApiMethodSignature,
|
||||||
ApiProperty,
|
ApiProperty,
|
||||||
ApiPropertySignature,
|
ApiPropertySignature,
|
||||||
|
ApiDocumentedItem,
|
||||||
|
ApiParameterListMixin,
|
||||||
} from '@microsoft/api-extractor-model';
|
} from '@microsoft/api-extractor-model';
|
||||||
import type { TableOfContentsSerialized } from '../TableOfContentItems';
|
import type { TableOfContentsSerialized } from '../TableOfContentItems';
|
||||||
import { METHOD_SEPARATOR, OVERLOAD_SEPARATOR } from '~/util/constants';
|
import { METHOD_SEPARATOR, OVERLOAD_SEPARATOR } from '~/util/constants';
|
||||||
import { resolveMembers } from '~/util/members';
|
import { resolveMembers } from '~/util/members';
|
||||||
|
import { resolveParameters } from '~/util/model';
|
||||||
|
|
||||||
export function hasProperties(item: ApiItemContainerMixin) {
|
export function hasProperties(item: ApiItemContainerMixin) {
|
||||||
return resolveMembers(item, memberPredicate).some(
|
return resolveMembers(item, memberPredicate).some(
|
||||||
@@ -56,3 +59,13 @@ export function serializeMembers(clazz: ApiItemContainerMixin): TableOfContentsS
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parametersString(item: ApiDocumentedItem & ApiParameterListMixin) {
|
||||||
|
return resolveParameters(item).reduce((prev, cur, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
return `${prev}${cur.isOptional ? `${cur.name}?` : cur.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${prev}, ${cur.isOptional ? `${cur.name}?` : cur.name}`;
|
||||||
|
}, '');
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { ApiClass, ApiConstructor } from '@microsoft/api-extractor-model';
|
import type { ApiClass, ApiConstructor } from '@microsoft/api-extractor-model';
|
||||||
import { ApiItemKind } from '@microsoft/api-extractor-model';
|
import { ApiItemKind } from '@microsoft/api-extractor-model';
|
||||||
// import { Outline } from '../Outline';
|
// import { Outline } from '../Outline';
|
||||||
|
import { Badges } from '../Badges';
|
||||||
import { Documentation } from '../documentation/Documentation';
|
import { Documentation } from '../documentation/Documentation';
|
||||||
import { HierarchyText } from '../documentation/HierarchyText';
|
import { HierarchyText } from '../documentation/HierarchyText';
|
||||||
import { Members } from '../documentation/Members';
|
import { Members } from '../documentation/Members';
|
||||||
@@ -16,6 +17,7 @@ export function Class({ clazz }: { clazz: ApiClass }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Documentation>
|
<Documentation>
|
||||||
|
<Badges item={clazz} />
|
||||||
<ObjectHeader item={clazz} />
|
<ObjectHeader item={clazz} />
|
||||||
<HierarchyText item={clazz} type="Extends" />
|
<HierarchyText item={clazz} type="Extends" />
|
||||||
<HierarchyText item={clazz} type="Implements" />
|
<HierarchyText item={clazz} type="Implements" />
|
||||||
|
|||||||
@@ -1,25 +1,11 @@
|
|||||||
import type { ApiMethod, ApiMethodSignature } from '@microsoft/api-extractor-model';
|
import type { ApiMethod, ApiMethodSignature } from '@microsoft/api-extractor-model';
|
||||||
import { ApiItemKind } from '@microsoft/api-extractor-model';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import { Badges } from '~/components/Badges';
|
||||||
import { CodeHeading } from '~/components/CodeHeading';
|
import { CodeHeading } from '~/components/CodeHeading';
|
||||||
import { ExcerptText } from '~/components/ExcerptText';
|
import { ExcerptText } from '~/components/ExcerptText';
|
||||||
import { resolveParameters } from '~/util/model';
|
import { parametersString } from '~/components/documentation/util';
|
||||||
|
|
||||||
function getShorthandName(method: ApiMethod | ApiMethodSignature) {
|
|
||||||
const params = resolveParameters(method);
|
|
||||||
|
|
||||||
return `${method.name}${method.isOptional ? '?' : ''}(${params.reduce((prev, cur, index) => {
|
|
||||||
if (index === 0) {
|
|
||||||
return `${prev}${cur.isOptional ? `${cur.name}?` : cur.name}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${prev}, ${cur.isOptional ? `${cur.name}?` : cur.name}`;
|
|
||||||
}, '')})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function MethodHeader({ method }: { method: ApiMethod | ApiMethodSignature }) {
|
export function MethodHeader({ method }: { method: ApiMethod | ApiMethodSignature }) {
|
||||||
const isDeprecated = Boolean(method.tsdocComment?.deprecatedBlock);
|
|
||||||
|
|
||||||
const key = useMemo(
|
const key = useMemo(
|
||||||
() => `${method.displayName}${method.overloadIndex && method.overloadIndex > 1 ? `:${method.overloadIndex}` : ''}`,
|
() => `${method.displayName}${method.overloadIndex && method.overloadIndex > 1 ? `:${method.overloadIndex}` : ''}`,
|
||||||
[method.displayName, method.overloadIndex],
|
[method.displayName, method.overloadIndex],
|
||||||
@@ -28,29 +14,9 @@ export function MethodHeader({ method }: { method: ApiMethod | ApiMethodSignatur
|
|||||||
return (
|
return (
|
||||||
<div className="flex flex-col scroll-mt-30" id={key}>
|
<div className="flex flex-col scroll-mt-30" id={key}>
|
||||||
<div className="flex flex-col gap-2 md:-ml-9">
|
<div className="flex flex-col gap-2 md:-ml-9">
|
||||||
{isDeprecated ||
|
<Badges item={method} />
|
||||||
(method.kind === ApiItemKind.Method && (method as ApiMethod).isProtected) ||
|
|
||||||
(method.kind === ApiItemKind.Method && (method as ApiMethod).isStatic) ? (
|
|
||||||
<div className="flex flex-row gap-1 md:ml-7">
|
|
||||||
{isDeprecated ? (
|
|
||||||
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-red-500 px-3 text-center text-xs font-semibold uppercase text-white">
|
|
||||||
Deprecated
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{method.kind === ApiItemKind.Method && (method as ApiMethod).isProtected ? (
|
|
||||||
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-blurple px-3 text-center text-xs font-semibold uppercase text-white">
|
|
||||||
Protected
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{method.kind === ApiItemKind.Method && (method as ApiMethod).isStatic ? (
|
|
||||||
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-blurple px-3 text-center text-xs font-semibold uppercase text-white">
|
|
||||||
Static
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<CodeHeading href={`#${key}`}>
|
<CodeHeading href={`#${key}`}>
|
||||||
{getShorthandName(method)}
|
{`${method.name}(${parametersString(method)})`}
|
||||||
<span>:</span>
|
<span>:</span>
|
||||||
<ExcerptText excerpt={method.returnTypeExcerpt} model={method.getAssociatedModel()!} />
|
<ExcerptText excerpt={method.returnTypeExcerpt} model={method.getAssociatedModel()!} />
|
||||||
</CodeHeading>
|
</CodeHeading>
|
||||||
|
|||||||
Reference in New Issue
Block a user