From 1be35ee625b9a51b35b0f2c2ee59a8eec8c2c13f Mon Sep 17 00:00:00 2001 From: Tarulata Priya Date: Sun, 18 Oct 2026 22:40:15 +0530 Subject: [PATCH] feat(editor): support text overlays URL query parameter and position presets (#1422) --- src/components/TextControls.tsx | 475 +++++++++++++------------ src/hooks/tests/useVideoEditor.test.ts | 31 ++ src/hooks/useVideoEditor.ts | 90 ++++- src/lib/editorPersistence.ts | 2 +- 4 files changed, 365 insertions(+), 233 deletions(-) diff --git a/src/components/TextControls.tsx b/src/components/TextControls.tsx index 48cbef3b6..9a3a96a40 100644 --- a/src/components/TextControls.tsx +++ b/src/components/TextControls.tsx @@ -1,223 +1,252 @@ -"use client"; - -import { EditRecipe, TextOverlay } from "@/lib/types"; -import { createDefaultTextOverlay } from "@/lib/text-overlay"; -import { Trash2, Plus } from "lucide-react"; -import { useMemo } from "react"; -import FontSelector from "./FontSelector"; -import ColorPicker from "./ColorPicker" -import { useFontManager } from "@/hooks/useFontManager"; - -interface TextControlsProps { - recipe: EditRecipe; - onChange: (patch: Partial) => void; - selectedTextId: string | null; - onSelectText: (id: string | null) => void; -} - -/** - * Controls for managing text overlays on the video. - * Allows users to add, remove, and select text overlays. - */ -export default function TextControls({ - recipe, - onChange, - selectedTextId, - onSelectText, -}: TextControlsProps) { - const { customFonts, addFonts, removeFont, getErrors } = useFontManager(); - - /** - * Always ensures textOverlays is an array, even if recipe is malformed. - */ - const textOverlays = useMemo( - (): TextOverlay[] => { - const overlays = recipe?.textOverlays; - return Array.isArray(overlays) ? overlays : []; - }, - [recipe?.textOverlays] - ); - - /** - * Adds a new text overlay to the recipe. - */ - const handleAddText = () => { - const newOverlay = createDefaultTextOverlay(); - const updatedOverlays = [...textOverlays, newOverlay]; - onChange({ textOverlays: updatedOverlays }); - onSelectText(newOverlay.id); - }; - - /** - * Removes a text overlay from the recipe. - */ - const handleRemoveText = (id: string) => { - const updatedOverlays = textOverlays.filter((overlay) => overlay.id !== id); - onChange({ textOverlays: updatedOverlays }); - if (selectedTextId === id) { - onSelectText(null); - } - }; - - /** - * Updates a text overlay property. - */ - const handleUpdateText = (id: string, updates: Partial) => { - const updatedOverlays = textOverlays.map((overlay) => - overlay.id === id ? { ...overlay, ...updates } : overlay - ); - onChange({ textOverlays: updatedOverlays }); - }; - - /** - * Get the currently selected overlay. - */ - const selectedOverlay = useMemo( - (): TextOverlay | undefined => - textOverlays.find((o) => o.id === selectedTextId), - [textOverlays, selectedTextId] - ); - - return ( -
- {/* Add Text Button */} - - - {/* Text Overlay List */} - {textOverlays.length > 0 && ( -
- {textOverlays.map((overlay, idx) => ( -
- - -
- ))} -
- )} - - {/* Text Editing Controls */} - {selectedOverlay && ( -
- {/* Text Input */} -
- -