mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-24 03:16:40 +00:00
Show definition title when visible in cards (#2476)
This commit is contained in:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user