import { useEffect, useState } from "react"; import { ChevronDown, GripVertical, Pencil, Trash2 } from "lucide-react"; import { cn } from "@/lib/utils"; import { t } from "@/i18n"; import { useItemDnd, useSectionDnd } from "@/board/dnd"; import { useBoard } from "@/board/store"; import { IconImg, ItemAnchor, hostOf } from "@/board/primitives"; import { WidgetContent } from "@/widgets"; import type { BoardViewProps, ItemViewProps, RendererViews, SectionViewProps, } from "@/renderers/types"; // Index — editorial/list renderer. Serif masthead + section heads, numbered // full-width rows, stat strip. Ported from mockups/e-editorial.html. function BoardView({ children }: BoardViewProps) { const board = useBoard(); const [now, setNow] = useState(() => new Date()); useEffect(() => { const t = setInterval(() => setNow(new Date()), 1000); return () => clearInterval(t); }, []); const services = board.sections.flatMap((s) => s.items).filter((i) => i.kind !== "widget"); const widgets = board.sections.flatMap((s) => s.items).filter((i) => i.kind === "widget"); const up = services.filter((i) => board.statuses[i.id]?.status === "up").length; const down = services.filter((i) => board.statuses[i.id]?.status === "down").length; const time = new Intl.DateTimeFormat(undefined, { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false, }).format(now); const date = new Intl.DateTimeFormat(undefined, { weekday: "long", day: "numeric", month: "long", year: "numeric", }).format(now); const cells: [string, string, string][] = [ [t("renderer.localTime"), time, date.split(",")[0] ?? ""], ["Services", String(services.length), `${board.sections.length} sections`], ["Up", String(up), "responding"], [t("renderer.down"), String(down), down === 0 ? t("renderer.allGreen") : t("renderer.offline")], ["Widgets", String(widgets.length), "registered"], ]; return (

Dash.

{date}
{cells.map(([k, v, s]) => (
{k}
{v}
{s}
))}
{children}
); } function SectionView({ section, index, onToggle, onDelete, children }: SectionViewProps) { const dnd = useSectionDnd(section.id); return (
{!section.collapsed && children}
); } function ItemView({ item, index, sectionId, status, onEdit }: ItemViewProps) { const dnd = useItemDnd(sectionId, item.id); const host = item.urls[0] ? hostOf(item.urls[0].url) : ""; const state = status?.status; return ( {(open) => (
{String(index + 1).padStart(2, "0")} {item.name} {host ? {host} : null} {host} {item.urls.slice(0, 2).map((u) => u.label ? ( {u.label} ) : null)} {item.urls.length > 0 ? ( {state ?? "…"} ) : } →
)}
); } function WidgetView({ item, index, sectionId, onEdit }: ItemViewProps) { const dnd = useItemDnd(sectionId, item.id); return (
{String(index + 1).padStart(2, "0")} {item.name}
); } export const editorial: RendererViews = { BoardView, SectionView, ItemView, WidgetView, itemsGridClass: "flex flex-col", };