From 291291a1de41d7f0443fb31c74e0d7a4f74a2469 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:09:58 +0800 Subject: [PATCH 01/35] =?UTF-8?q?refactor(PipConfigPanel):=20=E6=8F=90?= =?UTF-8?q?=E5=8F=96=E5=B8=B8=E9=87=8F=E5=92=8C=E5=B7=A5=E5=85=B7=E5=87=BD?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/PipConfigPanel/constants.ts | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 apps/web/src/pages/editing-planner/components/PipConfigPanel/constants.ts diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/constants.ts b/apps/web/src/pages/editing-planner/components/PipConfigPanel/constants.ts new file mode 100644 index 000000000..d78eeb2b2 --- /dev/null +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/constants.ts @@ -0,0 +1,55 @@ +import type { PipGridPosition, PipAnimType, PipSlideDirection } from "../types" + +/** 九宫格位置 → 百分比坐标映射 */ +export const GRID_POSITION_MAP: Record = { + top_left: { x: 5, y: 5 }, + top_center: { x: 37.5, y: 5 }, + top_right: { x: 70, y: 5 }, + center_left: { x: 5, y: 37.5 }, + center: { x: 37.5, y: 37.5 }, + center_right: { x: 70, y: 37.5 }, + bottom_left: { x: 5, y: 70 }, + bottom_center: { x: 37.5, y: 70 }, + bottom_right: { x: 70, y: 70 }, +} + +/** 九宫格位置选项 */ +export const GRID_POSITIONS: PipGridPosition[] = [ + "top_left", + "top_center", + "top_right", + "center_left", + "center", + "center_right", + "bottom_left", + "bottom_center", + "bottom_right", +] + +/** 入场动画选项 */ +export const ANIM_OPTIONS: { value: PipAnimType; label: string }[] = [ + { value: "none", label: "无" }, + { value: "fade_in", label: "淡入" }, + { value: "slide_in", label: "滑入" }, +] + +/** 滑入方向选项 */ +export const SLIDE_DIR_OPTIONS: { value: PipSlideDirection; label: string }[] = [ + { value: "left", label: "← 左" }, + { value: "right", label: "→ 右" }, + { value: "up", label: "↑ 上" }, + { value: "down", label: "↓ 下" }, +] + +/** 预览图层颜色池 */ +export const LAYER_COLORS = [ + "rgba(22,119,255,0.5)", + "rgba(82,196,26,0.5)", + "rgba(250,173,20,0.5)", + "rgba(255,77,79,0.5)", + "rgba(114,46,209,0.5)", + "rgba(19,194,194,0.5)", +] + +let layerIdCounter = 0 +export const genLayerId = () => `pip_layer_${Date.now()}_${++layerIdCounter}` -- 2.54.0 From 4d92df05a4e2c04a05094d03cdb148abaf5e16f0 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:09:59 +0800 Subject: [PATCH 02/35] =?UTF-8?q?refactor(PipConfigPanel):=20=E6=8F=90?= =?UTF-8?q?=E5=8F=96=E6=A0=B8=E5=BF=83=E9=80=BB=E8=BE=91Hook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PipConfigPanel/hooks/usePipConfigPanel.ts | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts b/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts new file mode 100644 index 000000000..ac230681a --- /dev/null +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts @@ -0,0 +1,123 @@ +import { useState, useCallback, useMemo } from "react" +import type { PipConfig, PipLayer, PipGridPosition } from "../types" +import { DEFAULT_PIP_LAYER, DEFAULT_PIP_CONFIG } from "../types" +import { GRID_POSITION_MAP, genLayerId } from "../constants" + +interface UsePipConfigPanelOptions { + config: PipConfig + onChange: (config: PipConfig) => void +} + +export const usePipConfigPanel = ({ config, onChange }: UsePipConfigPanelOptions) => { + const [selectedId, setSelectedId] = useState("") + + const selectedLayer = useMemo( + () => config.layers.find((l) => l.id === selectedId) ?? null, + [config.layers, selectedId], + ) + + /* ── 添加图层 ── */ + const handleAddLayer = useCallback(() => { + const newLayer: PipLayer = { + ...DEFAULT_PIP_LAYER, + id: genLayerId(), + name: `图层 ${config.layers.length + 1}`, + z_index: config.layers.length + 1, + } + onChange({ + ...config, + layers: [...config.layers, newLayer], + }) + setSelectedId(newLayer.id) + }, [config, onChange]) + + /* ── 删除图层 ── */ + const handleDeleteLayer = useCallback( + (id: string) => { + const newLayers = config.layers.filter((l) => l.id !== id) + onChange({ ...config, layers: newLayers }) + if (selectedId === id) { + setSelectedId(newLayers.length > 0 ? newLayers[0].id : "") + } + }, + [config, onChange, selectedId], + ) + + /* ── 更新图层 ── */ + const updateLayer = useCallback( + (id: string, partial: Partial) => { + onChange({ + ...config, + layers: config.layers.map((l) => (l.id === id ? { ...l, ...partial } : l)), + }) + }, + [config, onChange], + ) + + /* ── 切换启用 ── */ + const handleEnableToggle = useCallback( + (checked: boolean) => { + onChange({ ...config, enabled: checked }) + }, + [config, onChange], + ) + + /* ── 重置 ── */ + const handleReset = useCallback(() => { + onChange({ ...DEFAULT_PIP_CONFIG }) + setSelectedId("") + }, [onChange]) + + /* ── 九宫格点击 ── */ + const handleGridClick = useCallback( + (pos: PipGridPosition) => { + if (!selectedLayer) return + const coords = GRID_POSITION_MAP[pos] + updateLayer(selectedLayer.id, { + grid_position: pos, + x: coords.x, + y: coords.y, + }) + }, + [selectedLayer, updateLayer], + ) + + /* ── 宽高变化 ── */ + const handleWidthChange = useCallback( + (val: number) => { + if (!selectedLayer) return + const partial: Partial = { width: val } + if (selectedLayer.aspect_lock) { + partial.height = val + } + updateLayer(selectedLayer.id, partial) + }, + [selectedLayer, updateLayer], + ) + + const handleHeightChange = useCallback( + (val: number) => { + if (!selectedLayer) return + const partial: Partial = { height: val } + if (selectedLayer.aspect_lock) { + partial.width = val + } + updateLayer(selectedLayer.id, partial) + }, + [selectedLayer, updateLayer], + ) + + return { + selectedId, + setSelectedId, + selectedLayer, + handleAddLayer, + handleDeleteLayer, + updateLayer, + handleEnableToggle, + handleReset, + handleGridClick, + handleWidthChange, + handleHeightChange, + } +} -- 2.54.0 From 14c75f33ac0bc017328cb623bdd74e0d573c45ea Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:09:59 +0800 Subject: [PATCH 03/35] =?UTF-8?q?refactor(PipConfigPanel):=20=E6=8F=90?= =?UTF-8?q?=E5=8F=96=E5=9B=BE=E5=B1=82=E5=88=97=E8=A1=A8=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PipConfigPanel/components/LayerList.tsx | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx new file mode 100644 index 000000000..a535e5ba2 --- /dev/null +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx @@ -0,0 +1,58 @@ +import React from "react" +import type { PipLayer } from "../types" +import { LAYER_COLORS } from "../constants" + +export interface LayerListProps { + layers: PipLayer[] + selectedId: string + onSelect: (id: string) => void + onDelete: (id: string) => void +} + +export const LayerList: React.FC = ({ layers, selectedId, onSelect, onDelete }) => { + if (layers.length === 0) { + return ( +
+
暂无图层,点击上方添加
+
+ ) + } + + return ( +
+ {layers.map((layer, idx) => ( +
onSelect(layer.id)} + > + {layer.thumbnail_url || layer.material_url ? ( + {layer.name} + ) : ( +
+ )} + {layer.name} + +
+ ))} +
+ ) +} -- 2.54.0 From a6aa59a5eaadba105d75951712d00bb705706571 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:10:00 +0800 Subject: [PATCH 04/35] =?UTF-8?q?refactor(PipConfigPanel):=20=E6=8F=90?= =?UTF-8?q?=E5=8F=96=E9=A2=84=E8=A7=88=E5=8C=BA=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PipConfigPanel/components/PipPreview.tsx | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx new file mode 100644 index 000000000..9d03d0536 --- /dev/null +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx @@ -0,0 +1,32 @@ +import React from "react" +import type { PipLayer } from "../types" +import { LAYER_COLORS } from "../constants" + +export interface PipPreviewProps { + layers: PipLayer[] + selectedId: string +} + +export const PipPreview: React.FC = ({ layers, selectedId }) => { + return ( +
+ {layers.map((layer, idx) => ( +
+ {layer.name} +
+ ))} +
+ ) +} -- 2.54.0 From f92bfcfec6e5cf81167f64c6c5c65f6d1351f50e Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:10:00 +0800 Subject: [PATCH 05/35] =?UTF-8?q?refactor(PipConfigPanel):=20=E6=8F=90?= =?UTF-8?q?=E5=8F=96=E5=9B=BE=E5=B1=82=E9=85=8D=E7=BD=AE=E9=9D=A2=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PipConfigPanel/components/LayerConfig.tsx | 242 ++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx new file mode 100644 index 000000000..e37c3bd47 --- /dev/null +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx @@ -0,0 +1,242 @@ +import React from "react" +import type { PipLayer, PipGridPosition, PipAnimType, PipSlideDirection } from "../types" +import { GRID_POSITIONS, ANIM_OPTIONS, SLIDE_DIR_OPTIONS } from "../constants" + +export interface LayerConfigProps { + layer: PipLayer + totalDuration: number + onUpdate: (id: string, partial: Partial) => void + onGridClick: (pos: PipGridPosition) => void + onWidthChange: (val: number) => void + onHeightChange: (val: number) => void +} + +export const LayerConfig: React.FC = ({ + layer, + totalDuration, + onUpdate, + onGridClick, + onWidthChange, + onHeightChange, +}) => { + return ( +
+ {/* ── 素材类型 ── */} +
+ +
+ + +
+
+ + {/* ── 素材 URL ── */} +
+ + onUpdate(layer.id, { material_url: e.target.value })} + /> +
+ + {/* ── 位置:九宫格 + 坐标 ── */} +
+ +
+
+ {GRID_POSITIONS.map((pos) => ( + + ))} +
+
+
+ + onUpdate(layer.id, { x: Number(e.target.value) })} + /> +
+
+ + onUpdate(layer.id, { y: Number(e.target.value) })} + /> +
+
+
+
+ + {/* ── 尺寸 ── */} +
+ +
+ + onWidthChange(Number(e.target.value))} + /> + {layer.width}% +
+
+ + onHeightChange(Number(e.target.value))} + /> + {layer.height}% +
+
onUpdate(layer.id, { aspect_lock: !layer.aspect_lock })} + > + {layer.aspect_lock ? "🔒" : "🔓"} + {layer.aspect_lock ? "已锁定比例" : "锁定宽高比"} +
+
+ + {/* ── 圆角 ── */} +
+ +
+ onUpdate(layer.id, { border_radius: Number(e.target.value) })} + /> + {layer.border_radius}% +
+
+ + {/* ── 透明度 ── */} +
+ +
+ onUpdate(layer.id, { opacity: Number(e.target.value) })} + /> + {layer.opacity}% +
+
+ + {/* ── 时间 ── */} +
+ +
+
+ + onUpdate(layer.id, { start_time: Number(e.target.value) })} + /> +
+
+ + onUpdate(layer.id, { duration: Number(e.target.value) })} + /> +
+
+
+ + {/* ── 入场动画 ── */} +
+ + +
+ + {/* 滑入方向(仅 slide_in 时显示) */} + {layer.animation === "slide_in" && ( +
+ + +
+ )} +
+ ) +} -- 2.54.0 From f46cf18ae1146c5ea3361ec7b0e5e3cef1a5a3d6 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:10:16 +0800 Subject: [PATCH 06/35] =?UTF-8?q?refactor(PipConfigPanel):=20=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E5=8C=96=E4=B8=BB=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/PipConfigPanel/index.tsx | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx new file mode 100644 index 000000000..118b15a57 --- /dev/null +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx @@ -0,0 +1,106 @@ +/** + * 混剪配置面板 — Drawer 形式 + * 左侧图层列表 + 右侧单图层配置 + 迷你预览区 + */ +import React from "react" +import { Drawer, Switch } from "antd" +import type { PipConfig } from "../types" + +import { usePipConfigPanel } from "./hooks/usePipConfigPanel" +import { LayerList } from "./components/LayerList" +import { PipPreview } from "./components/PipPreview" +import { LayerConfig } from "./components/LayerConfig" + +export interface PipConfigPanelProps { + open: boolean + onClose: () => void + config: PipConfig + onChange: (config: PipConfig) => void + totalDuration: number +} + +const PipConfigPanel: React.FC = ({ + open, + onClose, + config, + onChange, + totalDuration, +}) => { + const { + selectedId, + setSelectedId, + selectedLayer, + handleAddLayer, + handleDeleteLayer, + updateLayer, + handleEnableToggle, + handleReset, + handleGridClick, + handleWidthChange, + handleHeightChange, + } = usePipConfigPanel({ config, onChange }) + + return ( + + {/* ═══ 顶部工具栏 ═══ */} +
+
+ +
+
+ 启用 + +
+
+ + {/* ═══ 主体:图层列表 + 配置区 ═══ */} +
+ {/* 左侧图层列表 */} + + + {/* 右侧配置区 */} + {!selectedLayer ? ( +
+
选择或添加图层以配置
+
+ ) : ( + <> + + + + )} +
+ + {/* ── 底部操作 ── */} +
+ +
+
+ ) +} + +export default PipConfigPanel +export type { PipConfigPanelProps } -- 2.54.0 From cddaf0249c1e7e6c8b8f8ebd4efb154110cc516f Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:10:16 +0800 Subject: [PATCH 07/35] =?UTF-8?q?refactor(PipConfigPanel):=20=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=97=A7=E5=8D=95=E6=96=87=E4=BB=B6=EF=BC=88=E5=B7=B2?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E5=8C=96=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/PipConfigPanel.tsx | 91 ------------------- 1 file changed, 91 deletions(-) delete mode 100644 apps/web/src/pages/editing-planner/components/PipConfigPanel.tsx diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel.tsx deleted file mode 100644 index 0c9240ac6..000000000 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel.tsx +++ /dev/null @@ -1,91 +0,0 @@ -/** - * 混剪配置面板 — Drawer 形式 - * 左侧图层列表 + 右侧单图层配置 + 迷你预览区 - */ -import React from "react" -import { Drawer, Switch } from "antd" -import type { PipConfig } from "@/pages/editing-planner/types" -import LayerList from "./pip-config/LayerList" -import LayerConfig from "./pip-config/LayerConfig" -import { usePipLayers } from "@/pages/editing-planner/hooks/usePipLayers" - -interface PipConfigPanelProps { - open: boolean - onClose: () => void - config: PipConfig - onChange: (config: PipConfig) => void - totalDuration: number -} - -const PipConfigPanel: React.FC = ({ - open, - onClose, - config, - onChange, - totalDuration, -}) => { - const { - selectedId, - setSelectedId, - selectedLayer, - handleAddLayer, - handleDeleteLayer, - updateLayer, - handleEnableToggle, - handleReset, - handleGridClick, - handleWidthChange, - handleHeightChange, - } = usePipLayers({ config, onChange }) - - return ( - - {/* ═══ 顶部工具栏 ═══ */} -
-
- 共 {config.layers.length} 个图层 -
-
- 启用 - -
-
- - {/* ═══ 主体:图层列表 + 配置区 ═══ */} -
- - -
- - {/* ── 底部操作 ── */} -
- -
-
- ) -} - -export default PipConfigPanel -- 2.54.0 From bfa5c89cbb6aff773dfcd6684516d0b12cf85d13 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:22:23 +0800 Subject: [PATCH 08/35] fix: correct types import path --- .../pages/editing-planner/components/PipConfigPanel/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx index 118b15a57..51d94cc65 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx @@ -4,7 +4,7 @@ */ import React from "react" import { Drawer, Switch } from "antd" -import type { PipConfig } from "../types" +import type { PipConfig } from "../../types" import { usePipConfigPanel } from "./hooks/usePipConfigPanel" import { LayerList } from "./components/LayerList" @@ -103,4 +103,4 @@ const PipConfigPanel: React.FC = ({ } export default PipConfigPanel -export type { PipConfigPanelProps } +export type { PipConfigPanelProps } \ No newline at end of file -- 2.54.0 From 59f23c55df33987e8ecd8dd63b18e4006e746c9f Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:22:25 +0800 Subject: [PATCH 09/35] fix: correct types import path --- .../editing-planner/components/PipConfigPanel/constants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/constants.ts b/apps/web/src/pages/editing-planner/components/PipConfigPanel/constants.ts index d78eeb2b2..2b77dbdf8 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/constants.ts +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/constants.ts @@ -1,4 +1,4 @@ -import type { PipGridPosition, PipAnimType, PipSlideDirection } from "../types" +import type { PipGridPosition, PipAnimType, PipSlideDirection } from "../../types" /** 九宫格位置 → 百分比坐标映射 */ export const GRID_POSITION_MAP: Record = { @@ -52,4 +52,4 @@ export const LAYER_COLORS = [ ] let layerIdCounter = 0 -export const genLayerId = () => `pip_layer_${Date.now()}_${++layerIdCounter}` +export const genLayerId = () => `pip_layer_${Date.now()}_${++layerIdCounter}` \ No newline at end of file -- 2.54.0 From ea957cc0e2da71f0035380b3be943f4e96a18568 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:22:30 +0800 Subject: [PATCH 10/35] fix: correct types import path --- .../components/PipConfigPanel/components/LayerConfig.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx index e37c3bd47..1b3e7aa44 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx @@ -1,5 +1,5 @@ import React from "react" -import type { PipLayer, PipGridPosition, PipAnimType, PipSlideDirection } from "../types" +import type { PipLayer, PipGridPosition, PipAnimType, PipSlideDirection } from "../../../types" import { GRID_POSITIONS, ANIM_OPTIONS, SLIDE_DIR_OPTIONS } from "../constants" export interface LayerConfigProps { @@ -239,4 +239,4 @@ export const LayerConfig: React.FC = ({ )}
) -} +} \ No newline at end of file -- 2.54.0 From e74c23e160e96b3a0d881d515c702cc7c6672485 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:22:32 +0800 Subject: [PATCH 11/35] fix: correct types import path --- .../components/PipConfigPanel/components/LayerList.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx index a535e5ba2..162bf938e 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx @@ -1,5 +1,5 @@ import React from "react" -import type { PipLayer } from "../types" +import type { PipLayer } from "../../../types" import { LAYER_COLORS } from "../constants" export interface LayerListProps { @@ -55,4 +55,4 @@ export const LayerList: React.FC = ({ layers, selectedId, onSele ))} ) -} +} \ No newline at end of file -- 2.54.0 From 535f5accf7b064e989e622c3fa0341cb50d06dd1 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:22:35 +0800 Subject: [PATCH 12/35] fix: correct types import path --- .../components/PipConfigPanel/components/PipPreview.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx index 9d03d0536..7bc3938de 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx @@ -1,5 +1,5 @@ import React from "react" -import type { PipLayer } from "../types" +import type { PipLayer } from "../../../types" import { LAYER_COLORS } from "../constants" export interface PipPreviewProps { @@ -29,4 +29,4 @@ export const PipPreview: React.FC = ({ layers, selectedId }) => ))} ) -} +} \ No newline at end of file -- 2.54.0 From fec949f0fb6a378e4df29d476e7a216a678e769b Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:22:37 +0800 Subject: [PATCH 13/35] fix: correct types import path --- .../components/PipConfigPanel/hooks/usePipConfigPanel.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts b/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts index ac230681a..7f9951d0d 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts @@ -1,6 +1,6 @@ import { useState, useCallback, useMemo } from "react" -import type { PipConfig, PipLayer, PipGridPosition } from "../types" -import { DEFAULT_PIP_LAYER, DEFAULT_PIP_CONFIG } from "../types" +import type { PipConfig, PipLayer, PipGridPosition } from "../../../types" +import { DEFAULT_PIP_LAYER, DEFAULT_PIP_CONFIG } from "../../../types" import { GRID_POSITION_MAP, genLayerId } from "../constants" interface UsePipConfigPanelOptions { @@ -120,4 +120,4 @@ export const usePipConfigPanel = ({ config, onChange }: UsePipConfigPanelOptions handleWidthChange, handleHeightChange, } -} +} \ No newline at end of file -- 2.54.0 From 299cd48849b94fc5f7c03eb7248794367f32c80f Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:24:41 +0800 Subject: [PATCH 14/35] test: add smoke test --- .../components/PipConfigPanel/constants.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 apps/web/src/test/pages/editing-planner/components/PipConfigPanel/constants.test.ts diff --git a/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/constants.test.ts b/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/constants.test.ts new file mode 100644 index 000000000..0414e6a2b --- /dev/null +++ b/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/constants.test.ts @@ -0,0 +1,11 @@ +/** + * Smoke test for constants.test + */ +import { describe, it, expect } from "vitest" +import "@/pages/editing-planner/components/PipConfigPanel/constants" + +describe("constants.test smoke", () => { + it("should load module successfully", () => { + expect(true).toBe(true) + }) +}) -- 2.54.0 From 5baac982aed359dcd6b60fdff5b63c6e0bc2e408 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:24:42 +0800 Subject: [PATCH 15/35] test: add smoke test --- .../PipConfigPanel/hooks/usePipConfigPanel.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 apps/web/src/test/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.test.ts diff --git a/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.test.ts b/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.test.ts new file mode 100644 index 000000000..9d515dece --- /dev/null +++ b/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.test.ts @@ -0,0 +1,11 @@ +/** + * Smoke test for usePipConfigPanel.test + */ +import { describe, it, expect } from "vitest" +import "@/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel" + +describe("usePipConfigPanel.test smoke", () => { + it("should load module successfully", () => { + expect(true).toBe(true) + }) +}) -- 2.54.0 From 42718898d5c1461cc1f2e741c429507a6754065b Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:24:44 +0800 Subject: [PATCH 16/35] test: add smoke test --- .../PipConfigPanel/components/LayerConfig.test.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 apps/web/src/test/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.test.tsx diff --git a/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.test.tsx b/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.test.tsx new file mode 100644 index 000000000..145d92f00 --- /dev/null +++ b/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.test.tsx @@ -0,0 +1,11 @@ +/** + * Smoke test for LayerConfig.test + */ +import { describe, it, expect } from "vitest" +import "@/pages/editing-planner/components/PipConfigPanel/components/LayerConfig" + +describe("LayerConfig.test smoke", () => { + it("should load module successfully", () => { + expect(true).toBe(true) + }) +}) -- 2.54.0 From c71cd5eb3e753570af67b4c8c71e05a4ccace661 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:24:45 +0800 Subject: [PATCH 17/35] test: add smoke test --- .../PipConfigPanel/components/LayerList.test.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 apps/web/src/test/pages/editing-planner/components/PipConfigPanel/components/LayerList.test.tsx diff --git a/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/components/LayerList.test.tsx b/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/components/LayerList.test.tsx new file mode 100644 index 000000000..9f8a6f18c --- /dev/null +++ b/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/components/LayerList.test.tsx @@ -0,0 +1,11 @@ +/** + * Smoke test for LayerList.test + */ +import { describe, it, expect } from "vitest" +import "@/pages/editing-planner/components/PipConfigPanel/components/LayerList" + +describe("LayerList.test smoke", () => { + it("should load module successfully", () => { + expect(true).toBe(true) + }) +}) -- 2.54.0 From 5e7134c3ff9220acff86576cb9992632f68dc54a Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:24:48 +0800 Subject: [PATCH 18/35] test: add smoke test --- .../PipConfigPanel/components/PipPreview.test.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 apps/web/src/test/pages/editing-planner/components/PipConfigPanel/components/PipPreview.test.tsx diff --git a/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/components/PipPreview.test.tsx b/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/components/PipPreview.test.tsx new file mode 100644 index 000000000..ac9b4c14d --- /dev/null +++ b/apps/web/src/test/pages/editing-planner/components/PipConfigPanel/components/PipPreview.test.tsx @@ -0,0 +1,11 @@ +/** + * Smoke test for PipPreview.test + */ +import { describe, it, expect } from "vitest" +import "@/pages/editing-planner/components/PipConfigPanel/components/PipPreview" + +describe("PipPreview.test smoke", () => { + it("should load module successfully", () => { + expect(true).toBe(true) + }) +}) -- 2.54.0 From 563ad349a5188007876b6152e010d7ae9b2d44e3 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:47:32 +0800 Subject: [PATCH 19/35] fix: correct aspect ratio lock logic --- .../PipConfigPanel/hooks/usePipConfigPanel.ts | 93 ++++++++++--------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts b/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts index 7f9951d0d..51de3bebe 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts @@ -1,20 +1,23 @@ -import { useState, useCallback, useMemo } from "react" -import type { PipConfig, PipLayer, PipGridPosition } from "../../../types" -import { DEFAULT_PIP_LAYER, DEFAULT_PIP_CONFIG } from "../../../types" -import { GRID_POSITION_MAP, genLayerId } from "../constants" +import { useState, useCallback, useMemo } from "react"; +import type { PipConfig, PipLayer, PipGridPosition } from "../../../types"; +import { DEFAULT_PIP_LAYER, DEFAULT_PIP_CONFIG } from "../../../types"; +import { GRID_POSITION_MAP, genLayerId } from "../constants"; interface UsePipConfigPanelOptions { - config: PipConfig - onChange: (config: PipConfig) => void + config: PipConfig; + onChange: (config: PipConfig) => void; } -export const usePipConfigPanel = ({ config, onChange }: UsePipConfigPanelOptions) => { - const [selectedId, setSelectedId] = useState("") +export const usePipConfigPanel = ({ + config, + onChange, +}: UsePipConfigPanelOptions) => { + const [selectedId, setSelectedId] = useState(""); const selectedLayer = useMemo( () => config.layers.find((l) => l.id === selectedId) ?? null, [config.layers, selectedId], - ) + ); /* ── 添加图层 ── */ const handleAddLayer = useCallback(() => { @@ -23,89 +26,93 @@ export const usePipConfigPanel = ({ config, onChange }: UsePipConfigPanelOptions id: genLayerId(), name: `图层 ${config.layers.length + 1}`, z_index: config.layers.length + 1, - } + }; onChange({ ...config, layers: [...config.layers, newLayer], - }) - setSelectedId(newLayer.id) - }, [config, onChange]) + }); + setSelectedId(newLayer.id); + }, [config, onChange]); /* ── 删除图层 ── */ const handleDeleteLayer = useCallback( (id: string) => { - const newLayers = config.layers.filter((l) => l.id !== id) - onChange({ ...config, layers: newLayers }) + const newLayers = config.layers.filter((l) => l.id !== id); + onChange({ ...config, layers: newLayers }); if (selectedId === id) { - setSelectedId(newLayers.length > 0 ? newLayers[0].id : "") + setSelectedId(newLayers.length > 0 ? newLayers[0].id : ""); } }, [config, onChange, selectedId], - ) + ); /* ── 更新图层 ── */ const updateLayer = useCallback( (id: string, partial: Partial) => { onChange({ ...config, - layers: config.layers.map((l) => (l.id === id ? { ...l, ...partial } : l)), - }) + layers: config.layers.map((l) => + l.id === id ? { ...l, ...partial } : l, + ), + }); }, [config, onChange], - ) + ); /* ── 切换启用 ── */ const handleEnableToggle = useCallback( (checked: boolean) => { - onChange({ ...config, enabled: checked }) + onChange({ ...config, enabled: checked }); }, [config, onChange], - ) + ); /* ── 重置 ── */ const handleReset = useCallback(() => { - onChange({ ...DEFAULT_PIP_CONFIG }) - setSelectedId("") - }, [onChange]) + onChange({ ...DEFAULT_PIP_CONFIG }); + setSelectedId(""); + }, [onChange]); /* ── 九宫格点击 ── */ const handleGridClick = useCallback( (pos: PipGridPosition) => { - if (!selectedLayer) return - const coords = GRID_POSITION_MAP[pos] + if (!selectedLayer) return; + const coords = GRID_POSITION_MAP[pos]; updateLayer(selectedLayer.id, { grid_position: pos, x: coords.x, y: coords.y, - }) + }); }, [selectedLayer, updateLayer], - ) + ); /* ── 宽高变化 ── */ const handleWidthChange = useCallback( (val: number) => { - if (!selectedLayer) return - const partial: Partial = { width: val } - if (selectedLayer.aspect_lock) { - partial.height = val + if (!selectedLayer) return; + const partial: Partial = { width: val }; + if (selectedLayer.aspect_lock && selectedLayer.height > 0) { + const ratio = selectedLayer.width / selectedLayer.height; + partial.height = Math.round(val / ratio); } - updateLayer(selectedLayer.id, partial) + updateLayer(selectedLayer.id, partial); }, [selectedLayer, updateLayer], - ) + ); const handleHeightChange = useCallback( (val: number) => { - if (!selectedLayer) return - const partial: Partial = { height: val } - if (selectedLayer.aspect_lock) { - partial.width = val + if (!selectedLayer) return; + const partial: Partial = { height: val }; + if (selectedLayer.aspect_lock && selectedLayer.width > 0) { + const ratio = selectedLayer.width / selectedLayer.height; + partial.width = Math.round(val * ratio); } - updateLayer(selectedLayer.id, partial) + updateLayer(selectedLayer.id, partial); }, [selectedLayer, updateLayer], - ) + ); return { selectedId, @@ -119,5 +126,5 @@ export const usePipConfigPanel = ({ config, onChange }: UsePipConfigPanelOptions handleGridClick, handleWidthChange, handleHeightChange, - } -} \ No newline at end of file + }; +}; \ No newline at end of file -- 2.54.0 From 279d4ee32f777fc4c6cb1160d98b8edbd1257fac Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:47:53 +0800 Subject: [PATCH 20/35] fix: add zIndex to PipPreview layers --- .../PipConfigPanel/components/PipPreview.tsx | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx index 7bc3938de..e69de29bb 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx @@ -1,32 +0,0 @@ -import React from "react" -import type { PipLayer } from "../../../types" -import { LAYER_COLORS } from "../constants" - -export interface PipPreviewProps { - layers: PipLayer[] - selectedId: string -} - -export const PipPreview: React.FC = ({ layers, selectedId }) => { - return ( -
- {layers.map((layer, idx) => ( -
- {layer.name} -
- ))} -
- ) -} \ No newline at end of file -- 2.54.0 From 4d6b5149906e79b5b3eea32cce8b332075adc218 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:48:43 +0800 Subject: [PATCH 21/35] fix: add zIndex to PipPreview and restore content --- .../PipConfigPanel/components/PipPreview.tsx | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx index e69de29bb..318568566 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import type { PipLayer } from "../../../types"; +import { LAYER_COLORS } from "../constants"; + +export interface PipPreviewProps { + layers: PipLayer[]; + selectedId: string; +} + +export const PipPreview: React.FC = ({ + layers, + selectedId, +}) => { + return ( +
+ {layers.map((layer, idx) => ( +
+ {layer.name} +
+ ))} +
+ ); +}; \ No newline at end of file -- 2.54.0 From 5796d6cf24532983d43b5d8ff0e5e33952a419a4 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 10:03:32 +0800 Subject: [PATCH 22/35] fix: remove semicolons to match prettier config --- .../PipConfigPanel/hooks/usePipConfigPanel.ts | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts b/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts index 51de3bebe..a67bad720 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts @@ -1,23 +1,23 @@ -import { useState, useCallback, useMemo } from "react"; -import type { PipConfig, PipLayer, PipGridPosition } from "../../../types"; -import { DEFAULT_PIP_LAYER, DEFAULT_PIP_CONFIG } from "../../../types"; -import { GRID_POSITION_MAP, genLayerId } from "../constants"; +import { useState, useCallback, useMemo } from "react" +import type { PipConfig, PipLayer, PipGridPosition } from "../../../types" +import { DEFAULT_PIP_LAYER, DEFAULT_PIP_CONFIG } from "../../../types" +import { GRID_POSITION_MAP, genLayerId } from "../constants" interface UsePipConfigPanelOptions { - config: PipConfig; - onChange: (config: PipConfig) => void; + config: PipConfig + onChange: (config: PipConfig) => void } export const usePipConfigPanel = ({ config, onChange, }: UsePipConfigPanelOptions) => { - const [selectedId, setSelectedId] = useState(""); + const [selectedId, setSelectedId] = useState("") const selectedLayer = useMemo( () => config.layers.find((l) => l.id === selectedId) ?? null, [config.layers, selectedId], - ); + ) /* ── 添加图层 ── */ const handleAddLayer = useCallback(() => { @@ -26,25 +26,25 @@ export const usePipConfigPanel = ({ id: genLayerId(), name: `图层 ${config.layers.length + 1}`, z_index: config.layers.length + 1, - }; + } onChange({ ...config, layers: [...config.layers, newLayer], - }); - setSelectedId(newLayer.id); - }, [config, onChange]); + }) + setSelectedId(newLayer.id) + }, [config, onChange]) /* ── 删除图层 ── */ const handleDeleteLayer = useCallback( (id: string) => { - const newLayers = config.layers.filter((l) => l.id !== id); - onChange({ ...config, layers: newLayers }); + const newLayers = config.layers.filter((l) => l.id !== id) + onChange({ ...config, layers: newLayers }) if (selectedId === id) { - setSelectedId(newLayers.length > 0 ? newLayers[0].id : ""); + setSelectedId(newLayers.length > 0 ? newLayers[0].id : "") } }, [config, onChange, selectedId], - ); + ) /* ── 更新图层 ── */ const updateLayer = useCallback( @@ -54,65 +54,65 @@ export const usePipConfigPanel = ({ layers: config.layers.map((l) => l.id === id ? { ...l, ...partial } : l, ), - }); + }) }, [config, onChange], - ); + ) /* ── 切换启用 ── */ const handleEnableToggle = useCallback( (checked: boolean) => { - onChange({ ...config, enabled: checked }); + onChange({ ...config, enabled: checked }) }, [config, onChange], - ); + ) /* ── 重置 ── */ const handleReset = useCallback(() => { - onChange({ ...DEFAULT_PIP_CONFIG }); - setSelectedId(""); - }, [onChange]); + onChange({ ...DEFAULT_PIP_CONFIG }) + setSelectedId("") + }, [onChange]) /* ── 九宫格点击 ── */ const handleGridClick = useCallback( (pos: PipGridPosition) => { - if (!selectedLayer) return; - const coords = GRID_POSITION_MAP[pos]; + if (!selectedLayer) return + const coords = GRID_POSITION_MAP[pos] updateLayer(selectedLayer.id, { grid_position: pos, x: coords.x, y: coords.y, - }); + }) }, [selectedLayer, updateLayer], - ); + ) /* ── 宽高变化 ── */ const handleWidthChange = useCallback( (val: number) => { - if (!selectedLayer) return; - const partial: Partial = { width: val }; + if (!selectedLayer) return + const partial: Partial = { width: val } if (selectedLayer.aspect_lock && selectedLayer.height > 0) { - const ratio = selectedLayer.width / selectedLayer.height; - partial.height = Math.round(val / ratio); + const ratio = selectedLayer.width / selectedLayer.height + partial.height = Math.round(val / ratio) } - updateLayer(selectedLayer.id, partial); + updateLayer(selectedLayer.id, partial) }, [selectedLayer, updateLayer], - ); + ) const handleHeightChange = useCallback( (val: number) => { - if (!selectedLayer) return; - const partial: Partial = { height: val }; + if (!selectedLayer) return + const partial: Partial = { height: val } if (selectedLayer.aspect_lock && selectedLayer.width > 0) { - const ratio = selectedLayer.width / selectedLayer.height; - partial.width = Math.round(val * ratio); + const ratio = selectedLayer.width / selectedLayer.height + partial.width = Math.round(val * ratio) } - updateLayer(selectedLayer.id, partial); + updateLayer(selectedLayer.id, partial) }, [selectedLayer, updateLayer], - ); + ) return { selectedId, @@ -126,5 +126,5 @@ export const usePipConfigPanel = ({ handleGridClick, handleWidthChange, handleHeightChange, - }; -}; \ No newline at end of file + } +} -- 2.54.0 From cc4ed56066287159866245d096e2239bd5b46504 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 10:03:33 +0800 Subject: [PATCH 23/35] fix: remove semicolons to match prettier config --- .../PipConfigPanel/components/PipPreview.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx index 318568566..1c1ee01ee 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx @@ -1,10 +1,10 @@ -import React from "react"; -import type { PipLayer } from "../../../types"; -import { LAYER_COLORS } from "../constants"; +import React from "react" +import type { PipLayer } from "../../../types" +import { LAYER_COLORS } from "../constants" export interface PipPreviewProps { - layers: PipLayer[]; - selectedId: string; + layers: PipLayer[] + selectedId: string } export const PipPreview: React.FC = ({ @@ -32,5 +32,5 @@ export const PipPreview: React.FC = ({ ))} - ); -}; \ No newline at end of file + ) +} -- 2.54.0 From ea192e40b58936671a6e9b631a5cf6fd265c6009 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 10:18:28 +0800 Subject: [PATCH 24/35] fix: prettier formatting (param wrapping, arrow function style) --- .../components/PipConfigPanel/hooks/usePipConfigPanel.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts b/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts index a67bad720..0c6170783 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts @@ -8,10 +8,7 @@ interface UsePipConfigPanelOptions { onChange: (config: PipConfig) => void } -export const usePipConfigPanel = ({ - config, - onChange, -}: UsePipConfigPanelOptions) => { +export const usePipConfigPanel = ({ config, onChange }: UsePipConfigPanelOptions) => { const [selectedId, setSelectedId] = useState("") const selectedLayer = useMemo( @@ -51,9 +48,7 @@ export const usePipConfigPanel = ({ (id: string, partial: Partial) => { onChange({ ...config, - layers: config.layers.map((l) => - l.id === id ? { ...l, ...partial } : l, - ), + layers: config.layers.map((l) => (l.id === id ? { ...l, ...partial } : l)), }) }, [config, onChange], -- 2.54.0 From fd64c4bf51cb5a5c4ef85dc0c7b5cc7f1469e827 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 10:18:28 +0800 Subject: [PATCH 25/35] fix: prettier formatting (param wrapping) --- .../components/PipConfigPanel/components/PipPreview.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx index 1c1ee01ee..e29eb6d2f 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/PipPreview.tsx @@ -7,10 +7,7 @@ export interface PipPreviewProps { selectedId: string } -export const PipPreview: React.FC = ({ - layers, - selectedId, -}) => { +export const PipPreview: React.FC = ({ layers, selectedId }) => { return (
{layers.map((layer, idx) => ( -- 2.54.0 From dfc1c3c7936a90435edc2637126acc3d44b32268 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 10:30:58 +0800 Subject: [PATCH 26/35] =?UTF-8?q?fix:=20=E5=AE=BD=E9=AB=98=E6=AF=94?= =?UTF-8?q?=E9=94=81=E5=AE=9A=E9=99=A4=E9=9B=B6=E9=98=B2=E6=8A=A4+?= =?UTF-8?q?=E8=B6=8A=E7=95=8C=E9=92=B3=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PipConfigPanel/hooks/usePipConfigPanel.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts b/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts index 0c6170783..80378c261 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/hooks/usePipConfigPanel.ts @@ -3,6 +3,9 @@ import type { PipConfig, PipLayer, PipGridPosition } from "../../../types" import { DEFAULT_PIP_LAYER, DEFAULT_PIP_CONFIG } from "../../../types" import { GRID_POSITION_MAP, genLayerId } from "../constants" +const MIN_DIMENSION = 10 +const MAX_DIMENSION = 80 + interface UsePipConfigPanelOptions { config: PipConfig onChange: (config: PipConfig) => void @@ -89,7 +92,8 @@ export const usePipConfigPanel = ({ config, onChange }: UsePipConfigPanelOptions const partial: Partial = { width: val } if (selectedLayer.aspect_lock && selectedLayer.height > 0) { const ratio = selectedLayer.width / selectedLayer.height - partial.height = Math.round(val / ratio) + const newHeight = Math.round(val / ratio) + partial.height = Math.max(MIN_DIMENSION, Math.min(MAX_DIMENSION, newHeight)) } updateLayer(selectedLayer.id, partial) }, @@ -100,9 +104,10 @@ export const usePipConfigPanel = ({ config, onChange }: UsePipConfigPanelOptions (val: number) => { if (!selectedLayer) return const partial: Partial = { height: val } - if (selectedLayer.aspect_lock && selectedLayer.width > 0) { + if (selectedLayer.aspect_lock && selectedLayer.width > 0 && selectedLayer.height > 0) { const ratio = selectedLayer.width / selectedLayer.height - partial.width = Math.round(val * ratio) + const newWidth = Math.round(val * ratio) + partial.width = Math.max(MIN_DIMENSION, Math.min(MAX_DIMENSION, newWidth)) } updateLayer(selectedLayer.id, partial) }, -- 2.54.0 From a6319712b581b24158231dbe739920bb4e93d3f7 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 10:30:59 +0800 Subject: [PATCH 27/35] =?UTF-8?q?fix:=20X/Y=E8=BE=93=E5=85=A5=E6=A1=86NaN?= =?UTF-8?q?=E9=98=B2=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PipConfigPanel/components/LayerConfig.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx index 1b3e7aa44..e7380aa02 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx @@ -82,7 +82,10 @@ export const LayerConfig: React.FC = ({ min={0} max={100} value={layer.x} - onChange={(e) => onUpdate(layer.id, { x: Number(e.target.value) })} + onChange={(e) => { + const val = Number(e.target.value) + if (!isNaN(val)) onUpdate(layer.id, { x: val }) + }} />
@@ -93,7 +96,10 @@ export const LayerConfig: React.FC = ({ min={0} max={100} value={layer.y} - onChange={(e) => onUpdate(layer.id, { y: Number(e.target.value) })} + onChange={(e) => { + const val = Number(e.target.value) + if (!isNaN(val)) onUpdate(layer.id, { y: val }) + }} />
@@ -239,4 +245,4 @@ export const LayerConfig: React.FC = ({ )} ) -} \ No newline at end of file +} -- 2.54.0 From 549bbb3c766d270bc7b09f956e3c7f9e53cf597c Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 10:36:23 +0800 Subject: [PATCH 28/35] =?UTF-8?q?fix:=20Prettier=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../editing-planner/components/PipConfigPanel/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/constants.ts b/apps/web/src/pages/editing-planner/components/PipConfigPanel/constants.ts index 2b77dbdf8..a15bd7589 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/constants.ts +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/constants.ts @@ -52,4 +52,4 @@ export const LAYER_COLORS = [ ] let layerIdCounter = 0 -export const genLayerId = () => `pip_layer_${Date.now()}_${++layerIdCounter}` \ No newline at end of file +export const genLayerId = () => `pip_layer_${Date.now()}_${++layerIdCounter}` -- 2.54.0 From 8f335736ed21d2c7ab15950c0fc7d0fadc474004 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 10:36:24 +0800 Subject: [PATCH 29/35] =?UTF-8?q?fix:=20Prettier=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/editing-planner/components/PipConfigPanel/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx index 51d94cc65..491815f97 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx @@ -103,4 +103,4 @@ const PipConfigPanel: React.FC = ({ } export default PipConfigPanel -export type { PipConfigPanelProps } \ No newline at end of file +export type { PipConfigPanelProps } -- 2.54.0 From 3221c170e930148dcf75143aee9d88db931f911a Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 10:36:26 +0800 Subject: [PATCH 30/35] =?UTF-8?q?fix:=20Prettier=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/PipConfigPanel/components/LayerList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx index 162bf938e..7c7662672 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx @@ -55,4 +55,4 @@ export const LayerList: React.FC = ({ layers, selectedId, onSele ))} ) -} \ No newline at end of file +} -- 2.54.0 From b645e9ceea7e6f83ad934fa207c0a7035e77fbcf Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 10:48:44 +0800 Subject: [PATCH 31/35] =?UTF-8?q?fix:=20=E6=89=80=E6=9C=89=E6=95=B0?= =?UTF-8?q?=E5=80=BC=E8=BE=93=E5=85=A5=E6=A1=86=E6=B7=BB=E5=8A=A0NaN?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C(width/height/border=5Fradius/opacity/start?= =?UTF-8?q?=5Ftime/duration)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PipConfigPanel/components/LayerConfig.tsx | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx index e7380aa02..900111299 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx @@ -117,7 +117,10 @@ export const LayerConfig: React.FC = ({ min={10} max={80} value={layer.width} - onChange={(e) => onWidthChange(Number(e.target.value))} + onChange={(e) => { + const val = Number(e.target.value) + if (!isNaN(val)) onWidthChange(val) + }} /> {layer.width}% @@ -129,7 +132,10 @@ export const LayerConfig: React.FC = ({ min={10} max={80} value={layer.height} - onChange={(e) => onHeightChange(Number(e.target.value))} + onChange={(e) => { + const val = Number(e.target.value) + if (!isNaN(val)) onHeightChange(val) + }} /> {layer.height}% @@ -153,7 +159,10 @@ export const LayerConfig: React.FC = ({ min={0} max={50} value={layer.border_radius} - onChange={(e) => onUpdate(layer.id, { border_radius: Number(e.target.value) })} + onChange={(e) => { + const val = Number(e.target.value) + if (!isNaN(val)) onUpdate(layer.id, { border_radius: val }) + }} /> {layer.border_radius}% @@ -169,7 +178,10 @@ export const LayerConfig: React.FC = ({ min={0} max={100} value={layer.opacity} - onChange={(e) => onUpdate(layer.id, { opacity: Number(e.target.value) })} + onChange={(e) => { + const val = Number(e.target.value) + if (!isNaN(val)) onUpdate(layer.id, { opacity: val }) + }} /> {layer.opacity}% @@ -188,7 +200,10 @@ export const LayerConfig: React.FC = ({ max={totalDuration || 999} step={0.1} value={layer.start_time} - onChange={(e) => onUpdate(layer.id, { start_time: Number(e.target.value) })} + onChange={(e) => { + const val = Number(e.target.value) + if (!isNaN(val)) onUpdate(layer.id, { start_time: val }) + }} />
@@ -200,7 +215,10 @@ export const LayerConfig: React.FC = ({ max={totalDuration || 999} step={0.1} value={layer.duration} - onChange={(e) => onUpdate(layer.id, { duration: Number(e.target.value) })} + onChange={(e) => { + const val = Number(e.target.value) + if (!isNaN(val)) onUpdate(layer.id, { duration: val }) + }} />
-- 2.54.0 From ea6baf274cc8e17de9e1912143370c88db8179bf Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 11:25:07 +0800 Subject: [PATCH 32/35] =?UTF-8?q?fix:=20=E5=9D=90=E6=A0=87=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E5=A2=9E=E5=8A=A0=E8=B4=9F=E6=95=B0=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?(val>=3D0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/PipConfigPanel/components/LayerConfig.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx index 900111299..8f8ac06b1 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx @@ -84,7 +84,7 @@ export const LayerConfig: React.FC = ({ value={layer.x} onChange={(e) => { const val = Number(e.target.value) - if (!isNaN(val)) onUpdate(layer.id, { x: val }) + if (!isNaN(val) && val >= 0) onUpdate(layer.id, { x: val }) }} /> @@ -98,7 +98,7 @@ export const LayerConfig: React.FC = ({ value={layer.y} onChange={(e) => { const val = Number(e.target.value) - if (!isNaN(val)) onUpdate(layer.id, { y: val }) + if (!isNaN(val) && val >= 0) onUpdate(layer.id, { y: val }) }} /> -- 2.54.0 From bc3f107d3d88270540caaeb82dbf571dcfc4c209 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 11:25:07 +0800 Subject: [PATCH 33/35] =?UTF-8?q?fix:=20=E5=9B=BE=E7=89=87src=E7=A9=BA?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=E9=98=B2=E5=BE=A1(||undefined)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/PipConfigPanel/components/LayerList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx index 7c7662672..135d507d6 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerList.tsx @@ -29,7 +29,7 @@ export const LayerList: React.FC = ({ layers, selectedId, onSele {layer.thumbnail_url || layer.material_url ? ( {layer.name} ) : ( -- 2.54.0 From d21e8a2b8d1b7488e73f7aad16a4c02d87a9926e Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 11:55:17 +0800 Subject: [PATCH 34/35] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E7=9A=84PipConfigPanelProps=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=EF=BC=88=E4=B8=8Einterface=E5=A3=B0=E6=98=8E=E5=86=B2=E7=AA=81?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/editing-planner/components/PipConfigPanel/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx index 491815f97..81867fde1 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/index.tsx @@ -103,4 +103,3 @@ const PipConfigPanel: React.FC = ({ } export default PipConfigPanel -export type { PipConfigPanelProps } -- 2.54.0 From df31e3c37f4a8b578982b9a8f6cc7911fc8a9d7e Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 12:02:06 +0800 Subject: [PATCH 35/35] =?UTF-8?q?fix:=20=E5=9D=90=E6=A0=87=E4=B8=8A?= =?UTF-8?q?=E9=99=90100+=E6=97=B6=E9=97=B4=E8=8C=83=E5=9B=B4totalDuration?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=EF=BC=88AI=20Review=E9=98=BB=E5=A1=9E?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PipConfigPanel/components/LayerConfig.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx index 8f8ac06b1..1af03d1e4 100644 --- a/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx +++ b/apps/web/src/pages/editing-planner/components/PipConfigPanel/components/LayerConfig.tsx @@ -84,7 +84,7 @@ export const LayerConfig: React.FC = ({ value={layer.x} onChange={(e) => { const val = Number(e.target.value) - if (!isNaN(val) && val >= 0) onUpdate(layer.id, { x: val }) + if (!isNaN(val) && val >= 0 && val <= 100) onUpdate(layer.id, { x: val }) }} /> @@ -98,7 +98,7 @@ export const LayerConfig: React.FC = ({ value={layer.y} onChange={(e) => { const val = Number(e.target.value) - if (!isNaN(val) && val >= 0) onUpdate(layer.id, { y: val }) + if (!isNaN(val) && val >= 0 && val <= 100) onUpdate(layer.id, { y: val }) }} /> @@ -202,7 +202,8 @@ export const LayerConfig: React.FC = ({ value={layer.start_time} onChange={(e) => { const val = Number(e.target.value) - if (!isNaN(val)) onUpdate(layer.id, { start_time: val }) + if (!isNaN(val) && val >= 0 && val <= totalDuration) + onUpdate(layer.id, { start_time: val }) }} /> @@ -217,7 +218,8 @@ export const LayerConfig: React.FC = ({ value={layer.duration} onChange={(e) => { const val = Number(e.target.value) - if (!isNaN(val)) onUpdate(layer.id, { duration: val }) + if (!isNaN(val) && val > 0 && val <= totalDuration) + onUpdate(layer.id, { duration: val }) }} /> -- 2.54.0