import { Activity, Archive, Baby, Bell, BookOpen, BookOpenText, Bookmark, Briefcase, Building, Bus, Calendar, CalendarCheck, CalendarDays, Camera, Car, ChartColumn, ChartPie, Church, ClipboardCheck, ClipboardList, Clock, Coffee, Contact, CreditCard, Database, DoorOpen, FileText, Files, Film, Flag, Folder, Gift, Globe, GraduationCap, HandCoins, HandHeart, Handshake, Headphones, Heart, HeartHandshake, House, Image, Images, Inbox, KeyRound, Landmark, LayoutGrid, Library, ListChecks, ListTodo, Mail, Map as MapIcon, MapPin, Megaphone, MessageCircle, MessageSquare, Mic, Monitor, MonitorPlay, Music, Newspaper, Notebook, Package, Palette, PartyPopper, Phone, Presentation, Printer, Projector, Radio, Receipt, School, Send, Shield, ShoppingBag, Sparkles, Star, Sun, TabletSmartphone, Tag, Tent, Ticket, Trophy, Truck, Tv, UserCheck, UserRound, Users, UsersRound, Utensils, Video, Wallet, Wrench, type LucideIcon, } from "lucide-react"; import type { ReactElement } from "react"; import { type DashboardModuleIconName, isDashboardModuleIconName } from "../module-icons.js"; import { ShellIcon } from "./shell-icons.js"; /** * The Lucide components for the icons a module may declare (manifest v9, ADR 0063), by name. * * Each icon is imported by name, so the Dashboard bundles exactly this curated set and never the * whole library. Typed against `DASHBOARD_MODULE_ICON_NAMES`, so the map can neither miss a name * the platform accepts nor carry one it does not; the shell's tests prove each entry is a real Lucide * component. */ export const MODULE_ICON_COMPONENTS: Readonly> = Object.freeze({ activity: Activity, archive: Archive, baby: Baby, bell: Bell, "book-open": BookOpen, "book-open-text": BookOpenText, bookmark: Bookmark, briefcase: Briefcase, building: Building, bus: Bus, calendar: Calendar, "calendar-check": CalendarCheck, "calendar-days": CalendarDays, camera: Camera, car: Car, "chart-column": ChartColumn, "chart-pie": ChartPie, church: Church, "clipboard-check": ClipboardCheck, "clipboard-list": ClipboardList, clock: Clock, coffee: Coffee, contact: Contact, "credit-card": CreditCard, database: Database, "door-open": DoorOpen, "file-text": FileText, files: Files, film: Film, flag: Flag, folder: Folder, gift: Gift, globe: Globe, "graduation-cap": GraduationCap, "hand-coins": HandCoins, "hand-heart": HandHeart, handshake: Handshake, headphones: Headphones, heart: Heart, "heart-handshake": HeartHandshake, house: House, image: Image, images: Images, inbox: Inbox, "key-round": KeyRound, landmark: Landmark, "layout-grid": LayoutGrid, library: Library, "list-checks": ListChecks, "list-todo": ListTodo, mail: Mail, map: MapIcon, "map-pin": MapPin, megaphone: Megaphone, "message-circle": MessageCircle, "message-square": MessageSquare, mic: Mic, monitor: Monitor, "monitor-play": MonitorPlay, music: Music, newspaper: Newspaper, notebook: Notebook, package: Package, palette: Palette, "party-popper": PartyPopper, phone: Phone, presentation: Presentation, printer: Printer, projector: Projector, radio: Radio, receipt: Receipt, school: School, send: Send, shield: Shield, "shopping-bag": ShoppingBag, sparkles: Sparkles, star: Star, sun: Sun, "tablet-smartphone": TabletSmartphone, tag: Tag, tent: Tent, ticket: Ticket, trophy: Trophy, truck: Truck, tv: Tv, "user-check": UserCheck, "user-round": UserRound, users: Users, "users-round": UsersRound, utensils: Utensils, video: Video, wallet: Wallet, wrench: Wrench, }); /** * A module's icon: the Lucide icon it declared, or the generic module icon when it declared none or * one this Dashboard cannot draw. Decorative, like every navigation icon (ADR 0058): the module's * name is always beside it or in its control's accessible name. */ export function ModuleIcon(props: { readonly icon: string | undefined; readonly size?: number; }): ReactElement { if (!isDashboardModuleIconName(props.icon)) { return ; } const Icon = MODULE_ICON_COMPONENTS[props.icon]; return (