Show definition title when visible in cards (#2476)

This commit is contained in:
Samy Pessé
2024-09-22 19:04:23 +02:00
committed by GitHub
parent 0bf985af61
commit 0f990c772a
4 changed files with 54 additions and 10 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': patch
---
Show definition title when visible in cards
@@ -16,7 +16,7 @@ export function Blocks<T extends DocumentBlock, Tag extends React.ElementType =
/** Ancestors of the blocks */
ancestorBlocks: DocumentBlock[];
/** HTML tag to use */
/** HTML tag to use for the wrapper */
tag?: Tag;
/** Style passed to the wrapper */
@@ -24,12 +24,15 @@ export function Blocks<T extends DocumentBlock, Tag extends React.ElementType =
/** Style passed to all blocks */
blockStyle?: ClassValue;
/** Props to pass to the wrapper element */
wrapperProps?: React.ComponentProps<Tag>;
},
) {
const { nodes, tag: Tag = 'div', style, blockStyle, ...contextProps } = props;
const { nodes, tag: Tag = 'div', style, blockStyle, wrapperProps, ...contextProps } = props;
return (
<Tag className={tcls(style)}>
<Tag {...wrapperProps} className={tcls(style)}>
{nodes.map((node, index) => (
<Block
key={node.key}
@@ -1,4 +1,5 @@
import { ContentRef, DocumentTableViewCards } from '@gitbook/api';
import React from 'react';
import { Image } from '@/components/utils';
import { ClassValue, tcls } from '@/lib/tailwind';
@@ -12,7 +13,7 @@ export async function RecordCard(
record: TableRecordKV;
},
) {
const { view, record, context, isOffscreen } = props;
const { view, record, context, block, isOffscreen } = props;
const coverFile = view.coverDefinition
? getRecordValue<string[]>(record[1], view.coverDefinition)?.[0]
@@ -99,6 +100,31 @@ export async function RecordCard(
)}
>
{view.columns.map((column) => {
const definition = block.data.definition[column];
if (!definition) {
return null;
}
if (!view.hideColumnTitle && definition.title) {
const ariaLabelledBy = `${block.key}-${column}-title`;
return (
<div key={column} className="flex flex-col gap-1">
<div
id={ariaLabelledBy}
className="text-sm text-dark/8 dark:text-light/8"
>
{definition.title}
</div>
<RecordColumnValue
{...props}
column={column}
ariaLabelledBy={ariaLabelledBy}
/>
</div>
);
}
return <RecordColumnValue key={column} {...props} column={column} />;
})}
</div>
@@ -22,11 +22,12 @@ import { FileIcon } from '../FileIcon';
export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
props: BlockProps<DocumentBlockTable> & {
tag?: Tag;
ariaLabelledBy?: string;
record: TableRecordKV;
column: string;
},
) {
const { tag: Tag = 'div', block, document, record, column, context } = props;
const { tag: Tag = 'div', ariaLabelledBy, block, document, record, column, context } = props;
const definition = block.data.definition[column];
const value = record[1].values[column];
@@ -42,6 +43,7 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
className={tcls('w-5', 'h-5')}
checked={value as boolean}
disabled={true}
aria-labelledby={ariaLabelledBy}
/>
);
case 'rating':
@@ -67,7 +69,8 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
</span>
<span
role="meter"
aria-label={definition.title ?? ''}
aria-label={ariaLabelledBy ? undefined : (definition.title ?? '')}
aria-labelledby={ariaLabelledBy}
aria-valuenow={rating}
aria-valuemin={1}
aria-valuemax={definition.max}
@@ -89,6 +92,7 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
return (
<Tag
className={tcls('text-base', 'tabular-nums', 'tracking-tighter')}
aria-labelledby={ariaLabelledBy}
>{`${value}`}</Tag>
);
case 'text':
@@ -116,6 +120,9 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
]}
context={context}
blockStyle={['w-full', 'max-w-[unset]']}
wrapperProps={{
'aria-labelledby': ariaLabelledBy,
}}
/>
);
case 'files':
@@ -129,7 +136,7 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
);
return (
<Tag className={tcls('text-base')}>
<Tag className={tcls('text-base')} aria-labelledby={ariaLabelledBy}>
{files.filter(filterOutNullable).map((ref, index) => {
const contentType = ref.file
? getSimplifiedContentType(ref.file.contentType)
@@ -178,7 +185,10 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
})
: null;
return (
<Tag className={tcls('text-base', 'text-balance', 'flex', 'items-center')}>
<Tag
className={tcls('text-base', 'text-balance', 'flex', 'items-center')}
aria-labelledby={ariaLabelledBy}
>
{resolved?.icon ?? null}
{resolved ? (
<StyledLink href={resolved.href}>{resolved.text}</StyledLink>
@@ -197,7 +207,7 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
);
return (
<Tag className={tcls('text-base')}>
<Tag className={tcls('text-base')} aria-labelledby={ariaLabelledBy}>
{resolved.filter(filterOutNullable).map((file, index) => (
<StyledLink key={index} href={file.href}>
{file.text}
@@ -208,7 +218,7 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
}
case 'select': {
return (
<Tag className={tcls()}>
<Tag aria-labelledby={ariaLabelledBy}>
<span className={tcls('inline-flex', 'gap-2', 'flex-wrap')}>
{(value as string[]).map((selectId) => {
const option = definition.options.find(