From f92bfcfec6e5cf81167f64c6c5c65f6d1351f50e Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 09:10:00 +0800 Subject: [PATCH] =?UTF-8?q?refactor(PipConfigPanel):=20=E6=8F=90=E5=8F=96?= =?UTF-8?q?=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" && ( +
+ + +
+ )} +
+ ) +}