"use client"; import { useState } from "react"; import { FieldType } from "@planarchy/shared"; import type { FieldOption } from "@planarchy/shared"; import type { CatalogField } from "~/lib/blueprint-field-catalog.js"; // --------------------------------------------------------------------------- // Type icons // --------------------------------------------------------------------------- const TYPE_ICONS: Record = { [FieldType.TEXT]: "Aa", [FieldType.TEXTAREA]: "Aa", [FieldType.NUMBER]: "#", [FieldType.BOOLEAN]: "\u2611", [FieldType.DATE]: "\u{1F4C5}", [FieldType.SELECT]: "\u25BC", [FieldType.MULTI_SELECT]: "\u25BC\u25BC", [FieldType.URL]: "\u{1F517}", [FieldType.EMAIL]: "@", }; const TYPE_LABELS: Record = { [FieldType.TEXT]: "Text", [FieldType.TEXTAREA]: "Textarea", [FieldType.NUMBER]: "Number", [FieldType.BOOLEAN]: "Boolean", [FieldType.DATE]: "Date", [FieldType.SELECT]: "Select", [FieldType.MULTI_SELECT]: "Multi-Select", [FieldType.URL]: "URL", [FieldType.EMAIL]: "Email", }; // --------------------------------------------------------------------------- // Field overrides that the user can set per-field // --------------------------------------------------------------------------- export interface FieldOverrides { enabled: boolean; required: boolean; showInList: boolean; defaultValue: unknown; description: string; } // --------------------------------------------------------------------------- // Props // --------------------------------------------------------------------------- interface FieldCardProps { field: CatalogField; overrides: FieldOverrides; onChange: (overrides: FieldOverrides) => void; } // --------------------------------------------------------------------------- // Component // --------------------------------------------------------------------------- const INPUT_CLS = "px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-500 text-sm"; export function FieldCard({ field, overrides, onChange }: FieldCardProps) { const [expanded, setExpanded] = useState(false); function update(patch: Partial) { onChange({ ...overrides, ...patch }); } function handleToggle() { const next = !overrides.enabled; update({ enabled: next }); if (!next) { setExpanded(false); } } const isActive = overrides.enabled; return (
{/* Header row */}
{ if (isActive) setExpanded((v) => !v); else handleToggle(); }} > {/* Type icon */} {TYPE_ICONS[field.type]} {/* Label + description */}
{field.label} {field.key}

{field.description}

{/* Toggle switch */}
{/* Expanded settings */} {isActive && expanded && (
{/* Default value input */}
update({ defaultValue: val })} />
{/* Toggles row */}
{/* Description override */}
update({ description: e.target.value })} placeholder={field.description} className={INPUT_CLS} />
)}
); } // --------------------------------------------------------------------------- // Type-appropriate default value input // --------------------------------------------------------------------------- function DefaultValueInput({ type, options, value, onChange, }: { type: FieldType; options?: FieldOption[]; value: unknown; onChange: (val: unknown) => void; }) { switch (type) { case FieldType.BOOLEAN: return ( ); case FieldType.NUMBER: return ( onChange(e.target.value === "" ? undefined : Number(e.target.value)) } placeholder="No default" className={INPUT_CLS} /> ); case FieldType.DATE: return ( onChange(e.target.value === "" ? undefined : e.target.value) } className={INPUT_CLS} /> ); case FieldType.SELECT: return ( ); case FieldType.MULTI_SELECT: return ( ); case FieldType.URL: return ( onChange(e.target.value === "" ? undefined : e.target.value) } placeholder="https://..." className={INPUT_CLS} /> ); case FieldType.EMAIL: return ( onChange(e.target.value === "" ? undefined : e.target.value) } placeholder="name@example.com" className={INPUT_CLS} /> ); case FieldType.TEXTAREA: return (