diff --git a/packages/keystatic/src/app/CollectionPage.tsx b/packages/keystatic/src/app/CollectionPage.tsx index 2d086dd03..8cfbbe0a8 100644 --- a/packages/keystatic/src/app/CollectionPage.tsx +++ b/packages/keystatic/src/app/CollectionPage.tsx @@ -565,17 +565,42 @@ function CollectionTable( ...(hideStatusColumn ? [] : [statusCell]), nameCell, ...collection.columns.map(column => { - let val; - val = item.data?.[column]; + const raw = item.data?.[column]; + const field = collection.schema[column]; + const FieldCell = + field && + 'kind' in field && + field.kind === 'form' && + 'Cell' in field && + field.Cell; + + if (raw == null) { + return ( + + {undefined} + + ); + } - if (val == null) { - val = undefined; - } else { - val = val + ''; + const strVal = raw + ''; + + if (FieldCell) { + return ( + + + + ); } + return ( - - {val} + + {strVal} ); }), @@ -597,6 +622,7 @@ function CollectionTable( ); } + function getItemPath( basePath: string, collection: string, diff --git a/packages/keystatic/src/form/api.tsx b/packages/keystatic/src/form/api.tsx index 4b87714cf..cfa876f03 100644 --- a/packages/keystatic/src/form/api.tsx +++ b/packages/keystatic/src/form/api.tsx @@ -1,4 +1,4 @@ -import { ReactElement, ReactNode } from 'react'; +import { ReactElement, ReactNode, ComponentType } from 'react'; import { Glob } from '../config'; import { ChildField } from './fields/child'; @@ -48,6 +48,7 @@ export type BasicFormField< parse(value: FormFieldStoredValue): ReaderValue; }; label?: string; + Cell?: ComponentType<{ value: any }>; }; export type SlugFormField< @@ -85,6 +86,7 @@ export type SlugFormField< ): ReaderValueAsSlugField; }; label?: string; + Cell?: ComponentType<{ value: any }>; }; export type AssetFormField< @@ -127,6 +129,7 @@ export type AssetFormField< parse(value: FormFieldStoredValue): ReaderValue; }; label?: string; + Cell?: ComponentType<{ value: any }>; }; export type AssetsFormField< diff --git a/packages/keystatic/src/form/fields/empty-field-ui.tsx b/packages/keystatic/src/form/fields/empty-field-ui.tsx index 0289efad7..7b9caf710 100644 --- a/packages/keystatic/src/form/fields/empty-field-ui.tsx +++ b/packages/keystatic/src/form/fields/empty-field-ui.tsx @@ -19,6 +19,7 @@ export let SlugFieldInput = empty, IntegerFieldInput = empty, NumberFieldInput = empty, ImageFieldInput = empty, + ImageCell = empty, FileFieldInput = empty, DatetimeFieldInput = empty, DateFieldInput = empty, diff --git a/packages/keystatic/src/form/fields/image/index.tsx b/packages/keystatic/src/form/fields/image/index.tsx index 759e534f2..2c8bb43dc 100644 --- a/packages/keystatic/src/form/fields/image/index.tsx +++ b/packages/keystatic/src/form/fields/image/index.tsx @@ -3,7 +3,7 @@ import { AssetFormField } from '../../api'; import { FieldDataError } from '../error'; import { RequiredValidation, assertRequired } from '../utils'; import { getSrcPrefix } from './getSrcPrefix'; -import { ImageFieldInput } from '#field-ui/image'; +import { ImageFieldInput, ImageCell } from '#field-ui/image'; export function image({ label, @@ -34,6 +34,7 @@ export function image({ kind: 'form', formKind: 'asset', label, + Cell: ImageCell, Input(props) { return ( ); } + +export function ImageCell({ value }: { value: string | null }) { + const [errored, setErrored] = useState(false); + if (!value) return null; + if (errored) { + return ( + + {value} + + ); + } + return ( + setErrored(true)} + className={css({ + width: tokenSchema.size.scale[400], + height: tokenSchema.size.scale[400], + objectFit: 'cover', + borderRadius: tokenSchema.size.radius.small, + flexShrink: 0, + })} + /> + ); +}