import Block from "@uiw/react-color-block"; import { AlignCenter, AlignLeft, AlignRight, Bold, ChevronDown, Image as ImageIcon, Info, Italic, Trash2, Type, Underline, Upload, } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Slider } from "@/components/ui/slider"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { useScopedT } from "@/contexts/I18nContext"; import { type CustomFont, getCustomFonts } from "@/lib/customFonts"; import { cn } from "@/lib/utils"; import { AddCustomFontDialog } from "./AddCustomFontDialog"; import { getArrowComponent } from "./ArrowSvgs"; import type { AnnotationRegion, AnnotationType, ArrowDirection, FigureData } from "./types"; interface AnnotationSettingsPanelProps { annotation: AnnotationRegion; onContentChange: (content: string) => void; onTypeChange: (type: AnnotationType) => void; onStyleChange: (style: Partial) => void; onFigureDataChange?: (figureData: FigureData) => void; onDelete: () => void; } const FONT_FAMILIES = [ { value: "system-ui, -apple-system, sans-serif", labelKey: "classic" }, { value: "Georgia, serif", labelKey: "editor" }, { value: "Impact, Arial Black, sans-serif", labelKey: "strong" }, { value: "Courier New, monospace", labelKey: "typewriter" }, { value: "Brush Script MT, cursive", labelKey: "deco" }, { value: "Arial, sans-serif", labelKey: "simple" }, { value: "Verdana, sans-serif", labelKey: "modern" }, { value: "Trebuchet MS, sans-serif", labelKey: "clean" }, ]; const FONT_SIZES = [12, 14, 16, 18, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 80, 96, 128]; export function AnnotationSettingsPanel({ annotation, onContentChange, onTypeChange, onStyleChange, onFigureDataChange, onDelete, }: AnnotationSettingsPanelProps) { const t = useScopedT("settings"); const fileInputRef = useRef(null); const [customFonts, setCustomFonts] = useState([]); const fontStyleLabels: Record = { classic: t("fontStyles.classic"), editor: t("fontStyles.editor"), strong: t("fontStyles.strong"), typewriter: t("fontStyles.typewriter"), deco: t("fontStyles.deco"), simple: t("fontStyles.simple"), modern: t("fontStyles.modern"), clean: t("fontStyles.clean"), }; // Load custom fonts on mount useEffect(() => { setCustomFonts(getCustomFonts()); }, []); const colorPalette = [ "#FF0000", // Red "#FFD700", // Yellow/Gold "#00FF00", // Green "#FFFFFF", // White "#0000FF", // Blue "#FF6B00", // Orange "#9B59B6", // Purple "#E91E63", // Pink "#00BCD4", // Cyan "#FF5722", // Deep Orange "#8BC34A", // Light Green "#FFC107", // Amber "#34B27B", // Brand Green "#000000", // Black "#607D8B", // Blue Grey "#795548", // Brown ]; const handleImageUpload = (event: React.ChangeEvent) => { const files = event.target.files; if (!files || files.length === 0) return; const file = files[0]; // Validate file type const validTypes = ["image/jpeg", "image/jpg", "image/png", "image/gif", "image/webp"]; if (!validTypes.includes(file.type)) { toast.error(t("annotation.invalidImageType"), { description: t("annotation.imageFormatsOnly"), }); event.target.value = ""; return; } const reader = new FileReader(); reader.onload = (e) => { const dataUrl = e.target?.result as string; if (dataUrl) { onContentChange(dataUrl); toast.success(t("annotation.imageUploadSuccess")); } }; reader.onerror = () => { toast.error(t("annotation.failedImageUpload"), { description: "There was an error reading the file.", }); }; reader.readAsDataURL(file); event.target.value = ""; }; return (
{t("annotation.title")} {t("annotation.active")}
{/* Type Selector */} onTypeChange(value as AnnotationType)} className="mb-6" > {t("annotation.typeText")} {t("annotation.typeImage")} {t("annotation.typeArrow")} {/* Text Content */}