import { useEffect, useLayoutEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { getAllWidgetTypes } from "../widgets/WidgetRegistry"; import type { ContextMenuState, WidgetTypeId } from "@/types/homepage-types"; interface AddWidgetMenuProps { state: ContextMenuState; onAdd: (typeId: WidgetTypeId, canvasX: number, canvasY: number) => void; onClose: () => void; } const CATEGORY_ORDER = ["links", "info", "system", "monitoring"] as const; const MARGIN = 8; export function AddWidgetMenu({ state, onAdd, onClose }: AddWidgetMenuProps) { const { t } = useTranslation(); const menuRef = useRef(null); const allTypes = getAllWidgetTypes(); const [pos, setPos] = useState({ left: state.screenX, top: state.screenY }); const [selectedCat, setSelectedCat] = useState< (typeof CATEGORY_ORDER)[number] >(CATEGORY_ORDER[0]); const categoryLabels: Record<(typeof CATEGORY_ORDER)[number], string> = { links: t("homepage.categoryLinks"), info: t("homepage.categoryInfo"), system: t("homepage.categorySystem"), monitoring: t("homepage.categoryMonitoring"), }; useLayoutEffect(() => { if (!state.visible || !menuRef.current) return; const rect = menuRef.current.getBoundingClientRect(); const vw = window.innerWidth; const vh = window.innerHeight; let left = state.screenX; let top = state.screenY; if (state.anchorRect) { left = state.anchorRect.right - rect.width; top = state.anchorRect.top - rect.height - MARGIN; } if (left + rect.width > vw - MARGIN) left = vw - rect.width - MARGIN; if (left < MARGIN) left = MARGIN; if (top < MARGIN) { top = state.anchorRect ? state.anchorRect.bottom + MARGIN : state.screenY + MARGIN; } if (top + rect.height > vh - MARGIN) top = vh - rect.height - MARGIN; if (top < MARGIN) top = MARGIN; setPos({ left, top }); }, [state.visible, state.screenX, state.screenY, state.anchorRect]); useEffect(() => { const handler = (e: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(e.target as Node)) { onClose(); } }; document.addEventListener("mousedown", handler); return () => document.removeEventListener("mousedown", handler); }, [onClose]); useEffect(() => { const handler = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); }; document.addEventListener("keydown", handler); return () => document.removeEventListener("keydown", handler); }, [onClose]); const visibleCategories = CATEGORY_ORDER.filter((cat) => allTypes.some((type) => type.category === cat), ); const selectedTypes = allTypes.filter( (type) => type.category === selectedCat, ); return (
e.stopPropagation()} onWheel={(e) => e.stopPropagation()} > {/* Header */}
{t("homepage.addWidget")}
{/* Category tabs */}
{visibleCategories.map((cat) => ( ))}
{/* Widget list */}
{selectedTypes.length === 0 ? (
No widgets in this category
) : ( selectedTypes.map((type) => ( )) )}
); }