import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet'; import { Textarea } from '@/components/ui/textarea'; import { useMitt } from '@/plugins/MittContext'; import useMediaStore from '@/stores/MediaStore'; import useVideoEditorStore from '@/stores/VideoEditorStore'; import { Bold, Italic, Minus, Plus, Type } from 'lucide-react'; import { useEffect, useState } from 'react'; // Import centralized font management import { DEFAULT_TEXT_CONFIG, getAvailableFonts, loadFonts } from '@/modules/editor/fonts'; export default function TextSidebar({ isOpen, onClose }) { const { selectedTextElement } = useVideoEditorStore(); const { updateCurrentCaption } = useMediaStore(); const emitter = useMitt(); const [textValue, setTextValue] = useState(''); const [fontSize, setFontSize] = useState(24); const [isBold, setIsBold] = useState(true); const [isItalic, setIsItalic] = useState(false); const [fontFamily, setFontFamily] = useState('Montserrat'); const [fillColor, setFillColor] = useState('#ffffff'); const [strokeColor, setStrokeColor] = useState('#000000'); const [strokeWidth, setStrokeWidth] = useState(2); // Font size constraints const MIN_FONT_SIZE = 8; const MAX_FONT_SIZE = 120; const FONT_SIZE_STEP = 2; // Stroke width constraints const MIN_STROKE_WIDTH = 0; const MAX_STROKE_WIDTH = 3; const STROKE_WIDTH_STEP = 1; // Get available fonts from centralized source const availableFonts = getAvailableFonts(); // Load fonts for preview useEffect(() => { const loadPreviewFonts = async () => { if (fontFamily) { try { await loadFonts([ { fontFamily, fontWeight: isBold ? 700 : 400, fontStyle: isItalic ? 'italic' : 'normal', fontSize: 16, }, ]); } catch (error) { console.warn('Failed to load preview font:', error); } } }; loadPreviewFonts(); }, [fontFamily, isBold, isItalic]); // Update state when selected element changes - THIS KEEPS SIDEBAR IN SYNC WITH TRANSFORMER useEffect(() => { if (selectedTextElement) { setTextValue(selectedTextElement.text || ''); setFontSize(selectedTextElement.fontSize || DEFAULT_TEXT_CONFIG.fontSize); setIsBold(selectedTextElement.fontWeight === 'bold' || selectedTextElement.fontWeight === 700 || true); setIsItalic(selectedTextElement.fontStyle === 'italic' || false); setFontFamily(selectedTextElement.fontFamily || DEFAULT_TEXT_CONFIG.fontFamily); setFillColor(selectedTextElement.fill || DEFAULT_TEXT_CONFIG.fill); setStrokeColor(selectedTextElement.stroke || DEFAULT_TEXT_CONFIG.stroke); setStrokeWidth(selectedTextElement.strokeWidth || DEFAULT_TEXT_CONFIG.strokeWidth); } }, [selectedTextElement]); // Handle text changes const handleTextChange = (e) => { const newText = e.target.value; setTextValue(newText); if (selectedTextElement) { // Update the timeline element emitter.emit('text-update', { elementId: selectedTextElement.id, updates: { text: newText }, }); // Update MediaStore to maintain single source of truth updateCurrentCaption(newText); } }; // Handle font size changes - CLAMP AND UPDATE const handleFontSizeChange = (newSize) => { const clampedSize = Math.max(MIN_FONT_SIZE, Math.min(MAX_FONT_SIZE, newSize)); setFontSize(clampedSize); if (selectedTextElement) { emitter.emit('text-update', { elementId: selectedTextElement.id, updates: { fontSize: clampedSize }, }); } }; // Handle stroke width changes const handleStrokeWidthChange = (newWidth) => { const clampedWidth = Math.max(MIN_STROKE_WIDTH, Math.min(MAX_STROKE_WIDTH, newWidth)); setStrokeWidth(clampedWidth); if (selectedTextElement) { emitter.emit('text-update', { elementId: selectedTextElement.id, updates: { strokeWidth: clampedWidth }, }); } }; // Handle fill color changes const handleFillColorChange = (e) => { const newColor = e.target.value; setFillColor(newColor); if (selectedTextElement) { emitter.emit('text-update', { elementId: selectedTextElement.id, updates: { fill: newColor }, }); } }; // Handle stroke color changes const handleStrokeColorChange = (e) => { const newColor = e.target.value; setStrokeColor(newColor); if (selectedTextElement) { emitter.emit('text-update', { elementId: selectedTextElement.id, updates: { stroke: newColor }, }); } }; // Handle font family changes const handleFontFamilyChange = (newFontFamily) => { setFontFamily(newFontFamily); if (selectedTextElement) { emitter.emit('text-update', { elementId: selectedTextElement.id, updates: { fontFamily: newFontFamily }, }); } }; // Handle bold toggle const handleBoldToggle = () => { const newBoldState = !isBold; setIsBold(newBoldState); if (selectedTextElement) { emitter.emit('text-update', { elementId: selectedTextElement.id, updates: { fontWeight: newBoldState ? 'bold' : 'normal' }, }); } }; // Handle italic toggle const handleItalicToggle = () => { const newItalicState = !isItalic; setIsItalic(newItalicState); if (selectedTextElement) { emitter.emit('text-update', { elementId: selectedTextElement.id, updates: { fontStyle: newItalicState ? 'italic' : 'normal' }, }); } }; // Increase font size const increaseFontSize = () => { handleFontSizeChange(fontSize + FONT_SIZE_STEP); }; // Decrease font size const decreaseFontSize = () => { handleFontSizeChange(fontSize - FONT_SIZE_STEP); }; // Increase stroke width const increaseStrokeWidth = () => { handleStrokeWidthChange(strokeWidth + STROKE_WIDTH_STEP); }; // Decrease stroke width const decreaseStrokeWidth = () => { handleStrokeWidthChange(strokeWidth - STROKE_WIDTH_STEP); }; return ( !open && onClose()}> Edit Text
{selectedTextElement ? ( <> {/* Text Content */}