feat(website): add detailed property and method documentation (#8252)

Co-authored-by: Noel <buechler.noel@outlook.com>
This commit is contained in:
Suneet Tipirneni
2022-07-08 16:03:18 -04:00
committed by GitHub
parent feb3bdda0a
commit 33ae7df000
18 changed files with 241 additions and 104 deletions

View File

@@ -74,6 +74,7 @@
"@typescript-eslint/eslint-plugin": "^5.30.5",
"@typescript-eslint/parser": "^5.30.5",
"@unocss/cli": "^0.43.2",
"@unocss/reset": "^0.43.2",
"@vitejs/plugin-react": "^1.3.2",
"c8": "^7.11.3",
"concurrently": "^7.2.2",

View File

@@ -1,5 +1,6 @@
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { vs } from 'react-syntax-highlighter/dist/cjs/styles/prism';
import { Separator } from './Seperator';
import { TypeParamTable } from './TypeParamTable';
import { generateIcon } from '~/util/icon';
import type { TypeParameterData } from '~/util/parse.server';
@@ -9,38 +10,43 @@ export interface DocContainerProps {
kind: string;
excerpt: string;
summary?: string | null;
children?: JSX.Element;
children?: JSX.Element | JSX.Element[];
typeParams?: TypeParameterData[];
}
export function DocContainer({ name, kind, excerpt, summary, typeParams, children }: DocContainerProps) {
return (
<div className="px-10">
<h1 className="font-mono flex items-center content-center break-all">
{generateIcon(kind, 'mr-2')}
{name}
</h1>
<h3>Code declaration:</h3>
<div>
<SyntaxHighlighter
wrapLines
wrapLongLines
language="typescript"
style={vs}
codeTagProps={{ style: { fontFamily: 'JetBrains Mono' } }}
>
{excerpt}
</SyntaxHighlighter>
<>
<div className="bg-white border-b-solid border-gray border-width-0.5 sticky top-0 px-10 py-5">
<h1 className="font-mono break-all m-0">
{generateIcon(kind, 'mr-2')}
{name}
</h1>
</div>
{typeParams?.length ? (
<>
<h3>Type Parameters</h3>
<TypeParamTable data={typeParams} />
</>
) : null}
<h3>Summary</h3>
<p>{summary ?? 'No summary provided.'}</p>
{children}
</div>
<div className="p-10">
<div>
<SyntaxHighlighter
wrapLines
wrapLongLines
language="typescript"
style={vs}
codeTagProps={{ style: { fontFamily: 'JetBrains Mono' } }}
>
{excerpt}
</SyntaxHighlighter>
</div>
<h2>Summary</h2>
<p className="color-slate-500">{summary ?? 'No summary provided.'}</p>
<Separator />
{typeParams?.length ? (
<>
<h2>Type Parameters</h2>
<TypeParamTable data={typeParams} className="mb-5 p-3" />
<Separator />
</>
) : null}
<div>{children}</div>
</div>
</>
);
}

View File

@@ -1,4 +1,4 @@
import { AiOutlineMenu } from 'react-icons/ai';
import { FiMenu } from 'react-icons/fi';
import { VscPackage } from 'react-icons/vsc';
import { generateIcon } from '~/util/icon';
import type { getMembers } from '~/util/parse.server';
@@ -17,14 +17,14 @@ function onMenuClick() {
export function ItemSidebar({ packageName, data }: ItemListProps) {
return (
<div className="flex flex-col max-h-full min-w-[270px] border-r-solid border-b-solid border-gray border-width-0.5">
<div className="flex flex-col max-h-full min-w-[270px] lg:border-r-solid border-b-solid border-gray border-width-0.5">
<div className="flex justify-between content-center items-center border-b-solid border-gray border-width-0.5">
<h1 className="px-2 font-mono flex items-center content-center">
<VscPackage className="px-1" />
{`${packageName}`}
</h1>
<button className="lg:hidden mr-2 bg-transparent border-none" onClick={onMenuClick}>
<AiOutlineMenu size={32} />
<button className="lg:hidden mr-2 bg-transparent border-none cursor-pointer" onClick={onMenuClick}>
<FiMenu size={32} />
</button>
</div>
<div className="hidden lg:block overflow-y-scroll overflow-x-clip p-7">

View File

@@ -0,0 +1,51 @@
import { FiLink } from 'react-icons/fi';
import { ParameterTable } from './ParameterTable';
import type { DocMethod } from '~/DocModel/DocMethod';
import type { DocMethodSignature } from '~/DocModel/DocMethodSignature';
import { constructHyperlinkedText } from '~/util/util';
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) {
return `${prev}${cur.name}`;
}
return `${prev}, ${cur.name}`;
}, '')})`;
}
function onAnchorClick() {
console.log('anchor clicked');
// Todo implement jump-to links
}
export function MethodItem({ data }: MethodItemProps) {
return (
<div className="flex flex-col">
<div className="flex content-center">
<button className="bg-transparent border-none cursor-pointer" onClick={onAnchorClick}>
<FiLink size={16} />
</button>
<div className="flex flex-col ml-3">
<div className="w-full flex flex-row">
<h4 className="font-mono my-0 break-all">{`${getShorthandName(data)}`}</h4>
<h4 className="mx-3 my-0">:</h4>
<h4 className="font-mono color-blue-800 my-0 break-all ">
{constructHyperlinkedText(data.returnTypeTokens)}
</h4>
</div>
</div>
</div>
<div className="mx-10">
{data.summary && <p className="color-slate-500 mt-2">{data.summary}</p>}
{data.parameters.length ? <ParameterTable className="mb-10 mx-5" data={data.parameters} /> : null}
</div>
</div>
);
}

View File

@@ -1,3 +1,4 @@
import { MethodItem } from './MethodItem';
import type { DocMethod } from '~/DocModel/DocMethod';
import type { DocMethodSignature } from '~/DocModel/DocMethodSignature';
@@ -8,12 +9,12 @@ export interface MethodListProps {
export function MethodList({ data }: MethodListProps) {
return (
<div>
<h3>Methods</h3>
<ul>
<h2>Methods</h2>
<div className="flex flex-col">
{data.map((method) => (
<li key={method.name}>{method.name}</li>
<MethodItem key={method.name} data={method} />
))}
</ul>
</div>
</div>
);
}

View File

@@ -1,35 +1,31 @@
import { Table } from './Table';
import { constructHyperlinkedText } from '../util/util';
import type { ParameterDocumentation } from '~/util/parse.server';
interface ParameterDetailProps {
data: ParameterDocumentation[];
className?: string | undefined;
}
export function ParameterTable({ data }: ParameterDetailProps) {
export function ParameterTable({ data, className }: ParameterDetailProps) {
const rows = data.map((param) => ({
Name: param.name,
Type: constructHyperlinkedText(param.tokens),
Optional: param.isOptional ? 'Yes' : 'No',
Description: 'None',
}));
const columnStyles = {
Name: 'font-mono',
Type: 'font-mono',
};
return (
<div className="p-10 border border-gray-200 solid rounded-md">
<table className="w-full text-sm text-left text-black-500 dark:text-gray-400">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{data.map((parameter) => (
<tr key={parameter.name} className="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
<th className="py-4 font-normal text-gray-900 dark:text-white whitespace-nowrap">{parameter.name}</th>
<th>
<code>{constructHyperlinkedText(parameter.tokens)}</code>
</th>
<th>{parameter.isOptional ? 'Yes' : 'No'}</th>
<th>None</th>
</tr>
))}
</tbody>
</table>
</div>
<Table
className={className}
columns={['Name', 'Type', 'Optional', 'Description']}
rows={rows}
columnStyles={columnStyles}
/>
);
}

View File

@@ -0,0 +1,19 @@
import type { DocProperty } from '~/DocModel/DocProperty';
import { constructHyperlinkedText } from '~/util/util';
export interface PropertyItemProps {
data: ReturnType<DocProperty['toJSON']>;
}
export function PropertyItem({ data }: PropertyItemProps) {
return (
<div className="flex flex-col mb-2 ml-3">
<div className="w-full flex flex-row">
<h4 className="font-mono my-0">{`${data.name}`}</h4>
<h4 className="mx-3 my-0">:</h4>
<h4 className="font-mono color-blue-800 my-0">{constructHyperlinkedText(data.propertyTypeTokens)}</h4>
</div>
{data.summary && <p className="color-slate-500 mt-2">{data.summary}</p>}
</div>
);
}

View File

@@ -1,3 +1,4 @@
import { PropertyItem } from './PropertyItem';
import type { DocProperty } from '~/DocModel/DocProperty';
export interface PropertyListProps {
@@ -6,13 +7,11 @@ export interface PropertyListProps {
export function PropertyList({ data }: PropertyListProps) {
return (
<div>
<h3>Properties</h3>
<ul>
{data.map((prop) => (
<li key={prop.name}>{prop.name}</li>
))}
</ul>
<div className="flex flex-col">
<h2>Properties</h2>
{data.map((prop) => (
<PropertyItem key={prop.name} data={prop} />
))}
</div>
);
}

View File

@@ -0,0 +1,3 @@
export function Separator() {
return <div className="h-[1px] w-full bg-gray-300 mb-3" />;
}

View File

@@ -0,0 +1,49 @@
export interface RowData {
monospace?: boolean;
content: string;
}
export interface TableProps {
columns: string[];
columnStyles?: Record<string, string>;
rows: Record<string, string | (string | JSX.Element)[]>[];
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-slate-400">
{column}
</th>
))}
</tr>
</thead>
<tbody>
{rows.map((row, i) => (
<tr key={i}>
{Object.entries(row).map(([colName, val]) => {
console.log(colName);
console.log(columnStyles?.[colName]);
return (
<td
key={colName}
className={`p-2 text-sm border-b text-left border-slate-300 break-all ${
columnStyles?.[colName] ?? ''
}`}
>
{val}
</td>
);
})}
</tr>
))}
</tbody>
</table>
</div>
);
}

View File

@@ -1,39 +1,33 @@
import { Table } from './Table';
import type { TypeParameterData } from '~/util/parse.server';
import { constructHyperlinkedText } from '~/util/util';
export interface TableProps {
data: TypeParameterData[];
className?: string;
}
export function TypeParamTable({ data }: TableProps) {
export function TypeParamTable({ data, className }: TableProps) {
const rows = data.map((typeParam) => ({
Name: typeParam.name,
Constraints: constructHyperlinkedText(typeParam.constraintTokens),
Optional: typeParam.optional ? 'Yes' : 'No',
Default: constructHyperlinkedText(typeParam.defaultTokens),
Description: 'None',
}));
const rowElements = {
Name: 'font-mono',
Constraints: 'font-mono',
Default: 'font-mono',
};
return (
<div className="p-10 border border-gray-200 solid rounded-md">
<table className="w-full text-sm text-left text-black-500 dark:text-gray-400">
<thead>
<tr>
<th>Name</th>
<th>Constraint</th>
<th>Optional</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{data.map((parameter) => (
<tr key={parameter.name} className="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
<th className="py-4 font-normal text-gray-900 dark:text-white whitespace-nowrap">{parameter.name}</th>
<th>
<code>{constructHyperlinkedText(parameter.constraintTokens)}</code>
</th>
<th>{parameter.optional ? 'Yes' : 'No'}</th>
<th>
<code>{constructHyperlinkedText(parameter.defaultTokens)}</code>
</th>
<th>None</th>
</tr>
))}
</tbody>
</table>
</div>
<Table
className={className}
columns={['Name', 'Constraints', 'Optional', 'Default', 'Description']}
rows={rows}
columnStyles={rowElements}
/>
);
}

View File

@@ -1,6 +1,7 @@
import { DocContainer } from '../DocContainer';
import { MethodList } from '../MethodList';
import { PropertyList } from '../PropertyList';
import { Separator } from '../Seperator';
import type { DocClass } from '~/DocModel/DocClass';
export interface ClassProps {
@@ -17,8 +18,19 @@ export function Class({ data }: ClassProps) {
typeParams={data.typeParameterData}
>
<>
{data.properties.length ? <PropertyList data={data.properties} /> : null}
{data.methods.length ? <MethodList data={data.methods} /> : null}
{data.properties.length ? (
<>
<PropertyList data={data.properties} />
<Separator />
</>
) : null}
{data.methods.length ? (
<>
<MethodList data={data.methods} />
<Separator />
</>
) : null}
</>
</DocContainer>
);

View File

@@ -15,6 +15,7 @@ export function Function({ data }: FunctionProps) {
summary={data.summary}
typeParams={data.typeParameterData}
>
<h2>Parameters</h2>
<ParameterTable data={data.parameters} />
</DocContainer>
);

View File

@@ -13,8 +13,6 @@ export function TypeAlias({ data }: TypeAliasProps) {
excerpt={data.excerpt}
summary={data.summary}
typeParams={data.typeParameterData}
>
<div>WIP</div>
</DocContainer>
/>
);
}

View File

@@ -39,11 +39,11 @@ export default function Package() {
const { packageName } = useParams();
return (
<div className="flex flex-col lg:flex-row overflow-none max-w-full h-full">
<div className="flex flex-col lg:flex-row overflow-hidden max-w-full h-full">
<div className="w-full lg:min-w-1/4 lg:max-w-1/4">
<ItemSidebar packageName={packageName!} data={data} />
</div>
<div>
<div className="max-h-full grow overflow-auto">
<Outlet />
</div>
</div>

View File

@@ -1,3 +1,4 @@
@import '@unocss/reset/tailwind.css';
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800&display=swap');
html,

View File

@@ -143,6 +143,11 @@ export function genReference(item: ApiItem) {
}
export function genToken(model: ApiModel, token: ExcerptToken) {
if (token.canonicalReference) {
// @ts-expect-error
token.canonicalReference._navigation = '.';
}
const item = token.canonicalReference
? model.resolveDeclarationReference(token.canonicalReference, undefined).resolvedApiItem ?? null
: null;

View File

@@ -3079,6 +3079,7 @@ __metadata:
"@typescript-eslint/eslint-plugin": ^5.30.5
"@typescript-eslint/parser": ^5.30.5
"@unocss/cli": ^0.43.2
"@unocss/reset": ^0.43.2
"@vitejs/plugin-react": ^1.3.2
"@vscode/codicons": ^0.0.31
c8: ^7.11.3
@@ -5089,7 +5090,7 @@ __metadata:
languageName: node
linkType: hard
"@unocss/reset@npm:0.43.2":
"@unocss/reset@npm:0.43.2, @unocss/reset@npm:^0.43.2":
version: 0.43.2
resolution: "@unocss/reset@npm:0.43.2"
checksum: ea9a47d09b179f9b0ee2ff96e5f1617b8f6f3e790f809f9c8e2824e2bb048f0c5b0f653f50f2501f2b1e46e604f344981c94054e70deb1728b34cd440b119be3