/** * Shared UI helpers of the decisions screens (registry + fiche) — v2. * Labels that complement app/lexicon.ts locally (short weight forms, chain * kinds, circle-kind iconography) live here; the lexicon stays the single * source for everything it already names. */ import type { ChainKind, CircleKind, Decision, DecisionStatus, VoteSession, Weight, } from '~/types/domain' import { FROZEN_LABEL, STATUS_LABELS } from '~/lexicon' /** Short weight forms — registry pills and card metadata. */ export const WEIGHT_SHORT: Record = { light: 'léger', binding: 'engageant', structural: 'structurant', } /** Chain kinds in plain French (fiche chain block). */ export const CHAIN_LABELS: Record = { ratification: 'ratification', revision: 'révision', revocation: 'révocation', element: 'élément', } /** Circle kind iconography — lieu / thème / équipe (never a right). */ export const KIND_ICONS: Record = { place: 'i-lucide-map-pin', theme: 'i-lucide-tag', team: 'i-lucide-users-round', } export const KIND_LABELS: Record = { place: 'Lieux', theme: 'Thèmes', team: 'Équipes', } /** Advice positions in plain French. */ export const ADVICE_LABELS = { favorable: 'favorable', reserved: 'réservé', unfavorable: 'défavorable', } as const /** Display status: 'frozen' overlays 'voting' when the session is frozen. */ export type DisplayStatus = DecisionStatus | 'frozen' export function displayStatus(decision: Decision, session?: VoteSession): DisplayStatus { if (decision.status === 'voting' && session?.status === 'frozen') return 'frozen' return decision.status } export function displayStatusLabel(status: DisplayStatus): string { return status === 'frozen' ? FROZEN_LABEL : STATUS_LABELS[status as DecisionStatus] } /** Timeline color mapping — the ONE state→color mapping (moods.css tokens). */ export const STATUS_TOKEN: Record = { draft: 'prepa', advice: 'fenetre', objection: 'fenetre', framing: 'prepa', voting: 'vote', frozen: 'fige', adopted: 'vigueur', rejected: 'clos', revoked: 'revoque', transmitted: 'fige', closed: 'clos', } /** Case/accent-insensitive folding — same logic as useSearch. */ export function fold(text: string): string { return text.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase() } /** Short French date (« 12 août 2026 »). */ export function dateFr(iso?: string): string { if (!iso) return '' return new Date(iso).toLocaleDateString('fr-FR', { day: 'numeric', month: 'short', year: 'numeric', }) } /** French date + time for timeline milestones. */ export function dateTimeFr(iso?: string): string { if (!iso) return '' return new Date(iso).toLocaleString('fr-FR', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit', }) }