mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +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) {
|
||||
return (
|
||||
<>
|
||||
<span>
|
||||
{excerpt.spannedTokens.map((token, idx) => {
|
||||
if (token.kind === ExcerptTokenKind.Reference) {
|
||||
const source = token.canonicalReference?.source;
|
||||
@@ -59,6 +59,6 @@ export function ExcerptText({ model, excerpt }: ExcerptTextProps) {
|
||||
|
||||
return token.text;
|
||||
})}
|
||||
</>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,59 +5,29 @@ import type {
|
||||
ApiPropertySignature,
|
||||
} from '@microsoft/api-extractor-model';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { Badges } from './Badges';
|
||||
import { CodeHeading } from './CodeHeading';
|
||||
import { ExcerptText } from './ExcerptText';
|
||||
import { InheritanceText } from './InheritanceText';
|
||||
import { TSDoc } from './documentation/tsdoc/TSDoc';
|
||||
|
||||
export enum PropertySeparatorType {
|
||||
Type = ':',
|
||||
Value = '=',
|
||||
}
|
||||
|
||||
export function Property({
|
||||
item,
|
||||
children,
|
||||
separator,
|
||||
inheritedFrom,
|
||||
}: PropsWithChildren<{
|
||||
inheritedFrom?: (ApiDeclaredItem & ApiItemContainerMixin) | undefined;
|
||||
item: ApiProperty | ApiPropertySignature;
|
||||
separator?: PropertySeparatorType;
|
||||
}>) {
|
||||
const isDeprecated = Boolean(item.tsdocComment?.deprecatedBlock);
|
||||
const hasSummary = Boolean(item.tsdocComment?.summarySection);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col scroll-mt-30 gap-4" id={item.displayName}>
|
||||
<div className="flex flex-col gap-2 md:-ml-9">
|
||||
{isDeprecated || item.isReadonly || item.isOptional || (item as ApiProperty).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}
|
||||
{(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}
|
||||
<Badges item={item} />
|
||||
<CodeHeading href={`#${item.displayName}`}>
|
||||
{`${item.displayName}${item.isOptional ? '?' : ''}`}
|
||||
<span>{separator}</span>
|
||||
<span>:</span>
|
||||
{item.propertyTypeExcerpt.text ? (
|
||||
<ExcerptText excerpt={item.propertyTypeExcerpt} model={item.getAssociatedModel()!} />
|
||||
) : null}
|
||||
|
||||
@@ -7,7 +7,7 @@ import type {
|
||||
} from '@microsoft/api-extractor-model';
|
||||
import { ApiItemKind } from '@microsoft/api-extractor-model';
|
||||
import { Fragment, useMemo } from 'react';
|
||||
import { Property, PropertySeparatorType } from './Property';
|
||||
import { Property } from './Property';
|
||||
import { resolveMembers } from '~/util/members';
|
||||
|
||||
export function isPropertyLike(item: ApiItem): item is ApiProperty | ApiPropertySignature {
|
||||
@@ -25,7 +25,6 @@ export function PropertyList({ item }: { item: ApiItemContainerMixin }) {
|
||||
<Property
|
||||
inheritedFrom={prop.inherited as ApiDeclaredItem & ApiItemContainerMixin}
|
||||
item={prop.item as ApiProperty}
|
||||
separator={PropertySeparatorType.Type}
|
||||
/>
|
||||
<div className="border-t-2 border-light-900 dark:border-dark-100" />
|
||||
</Fragment>
|
||||
|
||||
@@ -38,7 +38,7 @@ export function Header({
|
||||
{name}
|
||||
</span>
|
||||
{sourceURL ? (
|
||||
<a className="text-blurple" href={sourceURL}>
|
||||
<a className="text-blurple" href={sourceURL} rel="external noopener noreferrer" target="_blank">
|
||||
<VscFileCode />
|
||||
</a>
|
||||
) : 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 { ParameterTable } from '../../ParameterTable';
|
||||
import { TSDoc } from '../tsdoc/TSDoc';
|
||||
import { parametersString } from '../util';
|
||||
import { DocumentationSection } from './DocumentationSection';
|
||||
|
||||
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}`;
|
||||
}, '')})`;
|
||||
}
|
||||
import { CodeHeading } from '~/components/CodeHeading';
|
||||
|
||||
export function ConstructorSection({ item }: { item: ApiConstructor }) {
|
||||
return (
|
||||
<DocumentationSection icon={<VscSymbolMethod size={20} />} padded title="Constructor">
|
||||
<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}
|
||||
<ParameterTable item={item} />
|
||||
</div>
|
||||
|
||||
@@ -6,10 +6,13 @@ import type {
|
||||
ApiMethodSignature,
|
||||
ApiProperty,
|
||||
ApiPropertySignature,
|
||||
ApiDocumentedItem,
|
||||
ApiParameterListMixin,
|
||||
} from '@microsoft/api-extractor-model';
|
||||
import type { TableOfContentsSerialized } from '../TableOfContentItems';
|
||||
import { METHOD_SEPARATOR, OVERLOAD_SEPARATOR } from '~/util/constants';
|
||||
import { resolveMembers } from '~/util/members';
|
||||
import { resolveParameters } from '~/util/model';
|
||||
|
||||
export function hasProperties(item: ApiItemContainerMixin) {
|
||||
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 { ApiItemKind } from '@microsoft/api-extractor-model';
|
||||
// import { Outline } from '../Outline';
|
||||
import { Badges } from '../Badges';
|
||||
import { Documentation } from '../documentation/Documentation';
|
||||
import { HierarchyText } from '../documentation/HierarchyText';
|
||||
import { Members } from '../documentation/Members';
|
||||
@@ -16,6 +17,7 @@ export function Class({ clazz }: { clazz: ApiClass }) {
|
||||
|
||||
return (
|
||||
<Documentation>
|
||||
<Badges item={clazz} />
|
||||
<ObjectHeader item={clazz} />
|
||||
<HierarchyText item={clazz} type="Extends" />
|
||||
<HierarchyText item={clazz} type="Implements" />
|
||||
|
||||
@@ -1,25 +1,11 @@
|
||||
import type { ApiMethod, ApiMethodSignature } from '@microsoft/api-extractor-model';
|
||||
import { ApiItemKind } from '@microsoft/api-extractor-model';
|
||||
import { useMemo } from 'react';
|
||||
import { Badges } from '~/components/Badges';
|
||||
import { CodeHeading } from '~/components/CodeHeading';
|
||||
import { ExcerptText } from '~/components/ExcerptText';
|
||||
import { resolveParameters } from '~/util/model';
|
||||
|
||||
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}`;
|
||||
}, '')})`;
|
||||
}
|
||||
import { parametersString } from '~/components/documentation/util';
|
||||
|
||||
export function MethodHeader({ method }: { method: ApiMethod | ApiMethodSignature }) {
|
||||
const isDeprecated = Boolean(method.tsdocComment?.deprecatedBlock);
|
||||
|
||||
const key = useMemo(
|
||||
() => `${method.displayName}${method.overloadIndex && method.overloadIndex > 1 ? `:${method.overloadIndex}` : ''}`,
|
||||
[method.displayName, method.overloadIndex],
|
||||
@@ -28,29 +14,9 @@ export function MethodHeader({ method }: { method: ApiMethod | ApiMethodSignatur
|
||||
return (
|
||||
<div className="flex flex-col scroll-mt-30" id={key}>
|
||||
<div className="flex flex-col gap-2 md:-ml-9">
|
||||
{isDeprecated ||
|
||||
(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}
|
||||
<Badges item={method} />
|
||||
<CodeHeading href={`#${key}`}>
|
||||
{getShorthandName(method)}
|
||||
{`${method.name}(${parametersString(method)})`}
|
||||
<span>:</span>
|
||||
<ExcerptText excerpt={method.returnTypeExcerpt} model={method.getAssociatedModel()!} />
|
||||
</CodeHeading>
|
||||
|
||||
Reference in New Issue
Block a user