Add support for all column types (#81)

* Support files and content ref

* Display all column types

* Pass width

* Format
This commit is contained in:
Samy Pessé
2024-01-02 10:43:52 +01:00
committed by GitHub
parent 66ba1c244f
commit 22eeaca92c
6 changed files with 135 additions and 35 deletions
+3 -9
View File
@@ -1,5 +1,6 @@
import { DocumentInlineMention } from '@gitbook/api';
import NextLink from 'next/link';
import { Link } from '@/components/primitives';
import { InlineProps } from './Inline';
@@ -12,12 +13,5 @@ export async function Mention(props: InlineProps<DocumentInlineMention>) {
return null;
}
return (
<NextLink
href={resolved.href}
className="underline underline-offset-2 text-primary hover:text-primary-700 transition-colors "
>
{resolved.text}
</NextLink>
);
return <Link href={resolved.href}>{resolved.text}</Link>;
}
@@ -1,8 +1,11 @@
import { DocumentBlockTable } from '@gitbook/api';
import IconStar from '@geist-ui/icons/star';
import { ContentRef, DocumentBlockTable } from '@gitbook/api';
import assertNever from 'assert-never';
import { Checkbox } from '@/components/primitives';
import { Checkbox, Link } from '@/components/primitives';
import { getNodeFragmentByName } from '@/lib/document';
import { tcls } from '@/lib/tailwind';
import { filterOutNullable } from '@/lib/typescript';
import { TableRecordKV } from './Table';
import { BlockProps } from '../Block';
@@ -28,25 +31,6 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
}
switch (definition.type) {
/* case 'content-ref':
// @ts-ignore
const target = await resolveContentRef(value, context);
if (!target) {
return <Tag className={tcls(['w-full'])}>{''}</Tag>;
}
return (
<Link
className={tcls(
'whitespace-nowrap',
'text-sm',
'text-primary-400',
'hover:text-primary-500',
)}
href={target.href}
>
{target.text}
</Link>
); */
case 'checkbox':
return (
<Checkbox
@@ -56,9 +40,24 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
/>
);
case 'rating':
const rating = value as number;
return (
<Tag className={tcls('text-base', 'tabular-nums', 'tracking-tighter')}>
{`${value}`}
<Tag className={tcls('text-primary')}>
{value ? (
<span
role="meter"
aria-label={definition.title ?? ''}
aria-valuenow={rating}
aria-valuemin={1}
aria-valuemax={definition.max}
className={tcls('inline-flex', 'gap-1')}
>
{Array.from({ length: rating }).map((_, i) => (
<IconStar key={i} className={tcls('size-4')} />
))}
</span>
) : null}
</Tag>
);
case 'number':
@@ -85,7 +84,87 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
blockStyle={['w-full', 'max-w-[unset]']}
/>
);
case 'files':
const files = await Promise.all(
(value as string[]).map((fileId) =>
context.resolveContentRef({
kind: 'file',
file: fileId,
}),
),
);
return (
<Tag className={tcls('text-base')}>
{files.filter(filterOutNullable).map((file, index) => (
<Link key={index} href={file.href}>
{file.text}
</Link>
))}
</Tag>
);
case 'content-ref': {
const resolved = value ? await context.resolveContentRef(value as ContentRef) : null;
return (
<Tag className={tcls('text-base')}>
{resolved ? <Link href={resolved.href}>{resolved.text}</Link> : null}
</Tag>
);
}
case 'users': {
const resolved = await Promise.all(
(value as string[]).map((userId) =>
context.resolveContentRef({
kind: 'user',
user: userId,
}),
),
);
return (
<Tag className={tcls('text-base')}>
{resolved.filter(filterOutNullable).map((file, index) => (
<Link key={index} href={file.href}>
{file.text}
</Link>
))}
</Tag>
);
}
case 'select': {
return (
<Tag className={tcls()}>
<span className={tcls('inline-flex', 'gap-2')}>
{(value as string[]).map((selectId) => {
const option = definition.options.find(
(option) => option.value === selectId,
);
if (!option) {
return null;
}
return (
<span
key={option.value}
className={tcls(
'text-sm',
'rounded',
'py-1',
'px-2',
'bg-primary-100',
'text-primary-800',
)}
>
{option.label}
</span>
);
})}
</span>
</Tag>
);
}
default:
return null;
assertNever(definition);
}
}
@@ -143,6 +143,8 @@ export function ViewGrid(props: TableViewProps<DocumentTableViewGrid>) {
<thead>
<tr className={tcls(tableTR)}>
{view.columns.map((column) => {
const columnWidth = view.columnWidths?.[column];
return (
<th
key={column}
@@ -158,6 +160,7 @@ export function ViewGrid(props: TableViewProps<DocumentTableViewGrid>) {
'dark:border-l-light/2',
'dark:border-b-light/4',
)}
style={columnWidth ? { width: columnWidth } : undefined}
>
{block.data.definition[column].title}
</th>
+2 -2
View File
@@ -65,13 +65,13 @@ export function SearchAskAnswer(props: { spaceId: string; query: string }) {
});
},
);
}, [spaceId, query, setSearchState]);
}, [spaceId, query, setSearchState, setState]);
React.useEffect(() => {
return () => {
setState(null);
};
}, []);
}, [setState]);
return (
<div
+23
View File
@@ -0,0 +1,23 @@
import NextLink, { LinkProps } from 'next/link';
import { tcls } from '@/lib/tailwind';
/**
* Styled version of Next.js Link component.
*/
export function Link(props: LinkProps & { children: React.ReactNode }) {
return (
<NextLink
{...props}
className={tcls(
'underline',
'underline-offset-2',
'text-primary',
'hover:text-primary-700',
'transition-colors',
)}
>
{props.children}
</NextLink>
);
}
+1
View File
@@ -3,3 +3,4 @@ export * from './Button';
export * from './Loading';
export * from './Card';
export * from './Skeleton';
export * from './Link';