import type { FilterOperator } from "./table-properties-types" /** * Semantic cell kind for a column — drives default filter icon, type, and * static option labels when `ColumnDef.filter` is omitted or partial. * * @see `resolveColumnFilter` in `column-filter.ts` * @see `apps/web/docs/table-column-cells-pattern.md` */ export type ColumnCellKind = | "person" | "people-rail" | "status" | "pill" | "tags" | "signal-bars" | "boolean" | "progress" | "rating" | "currency" | "numeric" | "attachment" | "external-link" | "relative-time" | "date" | "text" export type ColumnFilterSelectVariant = "default" | "person" export interface ColumnCellKindFilterPreset { type: "select" | "text" | "date" | "date-range" | "range" icon: string operators?: readonly FilterOperator[] options?: { value: string; label: string }[] selectVariant?: ColumnFilterSelectVariant /** When true and no explicit min/max — bounds come from the hub dataset. */ dataBounds?: boolean rangeMin?: number rangeMax?: number rangeStep?: number /** Suffix in filter UI, e.g. "%" for progress. */ rangeUnit?: string } const SELECT_IS: readonly FilterOperator[] = ["is", "is_not"] const TEXT_CONTAINS: readonly FilterOperator[] = ["contains", "not_contains"] const RATING_OPTIONS = [1, 2, 3, 4, 5].map(n => ({ value: String(n), label: n === 1 ? "1 star" : `${n} stars`, })) const BOOLEAN_OPTIONS = [ { value: "true", label: "Yes" }, { value: "false", label: "No" }, ] const SIGNAL_OPTIONS = [ { value: "1", label: "Low" }, { value: "2", label: "Normal" }, { value: "3", label: "High" }, ] export const COLUMN_CELL_KIND_FILTER_PRESETS: Record< ColumnCellKind, ColumnCellKindFilterPreset > = { person: { type: "select", icon: "fa-user", operators: SELECT_IS, selectVariant: "person", }, "people-rail": { type: "select", icon: "fa-users", operators: SELECT_IS, selectVariant: "person", }, status: { type: "select", icon: "fa-circle-check", operators: SELECT_IS }, pill: { type: "select", icon: "fa-list-check", operators: SELECT_IS }, tags: { type: "text", icon: "fa-tags", operators: TEXT_CONTAINS }, "signal-bars": { type: "select", icon: "fa-signal-bars", operators: SELECT_IS, options: SIGNAL_OPTIONS, }, boolean: { type: "select", icon: "fa-toggle-on", operators: SELECT_IS, options: BOOLEAN_OPTIONS, }, progress: { type: "range", icon: "fa-chart-simple", rangeMin: 0, rangeMax: 100, rangeStep: 1, rangeUnit: "%", }, rating: { type: "select", icon: "fa-star", operators: SELECT_IS, options: RATING_OPTIONS, }, currency: { type: "range", icon: "fa-dollar-sign", dataBounds: true, rangeUnit: "", }, numeric: { type: "range", icon: "fa-hashtag", dataBounds: true, rangeStep: 1, }, attachment: { type: "text", icon: "fa-paperclip", operators: TEXT_CONTAINS }, "external-link": { type: "text", icon: "fa-arrow-up-right-from-square", operators: TEXT_CONTAINS }, "relative-time": { type: "date-range", icon: "fa-clock", operators: SELECT_IS }, date: { type: "date", icon: "fa-calendar-days", operators: SELECT_IS }, text: { type: "text", icon: "fa-font", operators: TEXT_CONTAINS }, } export function filterPresetForCellKind( kind: ColumnCellKind, ): ColumnCellKindFilterPreset { return COLUMN_CELL_KIND_FILTER_PRESETS[kind] }