{open && createPortal(
<>
setOpen(false)} />
{DISPLAY_MODE_OPTIONS.map(opt => {
const OptIcon = DISPLAY_MODE_ICONS[opt.value]
return (
)
})}
>,
document.body
)}
)
}
function toBooleanValue(value: FrontmatterValue): boolean {
if (typeof value === 'boolean') return value
if (typeof value === 'string') return value.toLowerCase() === 'true'
return false
}
function autoDetectFromValue(propKey: string, value: FrontmatterValue): PropertyDisplayMode {
if (canonicalSystemMetadataKey(propKey) === '_icon') return 'text'
if (typeof value === 'boolean') return 'boolean'
if (typeof value === 'string' && isUrlValue(value)) return 'url'
if (typeof value === 'string' && isValidCssColor(value) && value.startsWith('#')) return 'color'
return 'text'
}
type SmartCellProps = {
propKey: string; value: FrontmatterValue; displayMode: PropertyDisplayMode; isEditing: boolean
vaultStatuses: string[]; vaultTags: string[]
onStartEdit: (key: string | null) => void; onSave: (key: string, value: string) => void
onSaveList: (key: string, items: string[]) => void; onUpdate?: (key: string, value: FrontmatterValue) => void
}
interface ScalarEditProps {
value: string
isEditing: boolean
onStartEdit: () => void
onSave: (nextValue: string) => void
onCancel: () => void
}
function createScalarEditProps({
propKey,
value,
isEditing,
onStartEdit,
onSave,
}: {
propKey: string
value: FrontmatterValue
isEditing: boolean
onStartEdit: (key: string | null) => void
onSave: (key: string, value: string) => void
}): ScalarEditProps {
return {
value: String(value ?? ''),
isEditing,
onStartEdit: () => onStartEdit(propKey),
onSave: (nextValue: string) => onSave(propKey, nextValue),
onCancel: () => onStartEdit(null),
}
}
function renderScalarDisplayMode({
propKey,
value,
isEditing,
resolvedMode,
vaultStatuses,
vaultTags,
onSave,
onSaveList,
onStartEdit,
onUpdate,
editProps,
}: SmartCellProps & {
resolvedMode: PropertyDisplayMode
editProps: ScalarEditProps
}) {
switch (resolvedMode) {
case 'status':
return
case 'tags':
return
case 'date':
return (
onSave(propKey, v)}
autoOpen={isEditing}
onCancel={() => onStartEdit(null)}
/>
)
case 'boolean': {
const boolVal = toBooleanValue(value)
return onUpdate?.(propKey, !boolVal)} />
}
case 'url':
return
case 'color':
return
default:
return
}
}
function ScalarValueCell(props: SmartCellProps) {
const { propKey, value, displayMode, isEditing, onStartEdit, onSave } = props
const editProps = createScalarEditProps({
propKey,
value,
isEditing,
onStartEdit,
onSave,
})
if (canonicalSystemMetadataKey(propKey) === '_icon') {
return
}
const resolvedMode = displayMode === 'text' ? autoDetectFromValue(propKey, value) : displayMode
return renderScalarDisplayMode({ ...props, resolvedMode, editProps })
}
export function SmartPropertyValueCell(props: SmartCellProps) {
const { propKey, value, displayMode, isEditing, vaultTags, onSaveList, onStartEdit } = props
if (Array.isArray(value)) {
if (displayMode === 'tags') {
return
}
return onSaveList(propKey, items)} label={propKey} />
}
return
}