/** * 贴纸配置面板 * 贴纸素材库(emoji / 图片)+ 文字花字 + 位置大小调整 */ import React, { useCallback, useState } from "react"; import { Drawer, Switch } from "antd"; import type { StickerConfig, StickerItem, StickerType, TextStickerPreset, } from "../types"; import { DEFAULT_STICKER_CONFIG, DEFAULT_STICKER_ITEM, TEXT_STICKER_PRESET_LABELS, } from "../types"; interface StickerPanelProps { open: boolean; onClose: () => void; config: StickerConfig; onChange: (config: StickerConfig) => void; totalDuration: number; } /** 常用 emoji 素材 */ const EMOJI_LIST = [ "😀", "😂", "🥰", "😎", "🤩", "😱", "🤔", "😴", "🥳", "😍", "❤️", "🔥", "⭐", "✨", "💯", "👍", "👏", "🎉", "🎵", "💪", "📌", "💡", "🎯", "✅", "❌", "⬆️", "⬇️", "➡️", "⭕", "🔔", ]; /** 文字花字预设对应的 CSS 样式预览 */ const TEXT_PRESET_STYLES: Record = { normal: { color: "#fff", textShadow: "none" }, highlight: { color: "#FFD700", textShadow: "0 0 8px rgba(255,215,0,0.6)" }, bubble: { color: "#fff", background: "rgba(0,0,0,0.5)", borderRadius: 8 }, neon: { color: "#0ff", textShadow: "0 0 6px #0ff, 0 0 12px #0ff" }, shadow: { color: "#fff", textShadow: "2px 2px 4px rgba(0,0,0,0.8)" }, outline: { color: "#fff", WebkitTextStroke: "1px #000" }, gradient: { color: "transparent", background: "linear-gradient(90deg,#f093fb,#f5576c)", WebkitBackgroundClip: "text", }, handwrite: { color: "#333", fontStyle: "italic", fontFamily: "cursive" }, }; /** 生成唯一 ID */ const genId = () => `sticker_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`; const StickerPanel: React.FC = ({ open, onClose, config, onChange, totalDuration, }) => { const [selectedId, setSelectedId] = useState(null); const [activeTab, setActiveTab] = useState("emoji"); const selectedSticker = config.items.find((s) => s.id === selectedId) ?? null; /** 更新单个贴纸 */ const updateItem = useCallback( (id: string, partial: Partial) => { onChange({ ...config, items: config.items.map((s) => s.id === id ? { ...s, ...partial } : s, ), }); }, [config, onChange], ); /** 添加贴纸 */ const addSticker = useCallback( (type: StickerType, content: string) => { const newItem: StickerItem = { ...DEFAULT_STICKER_ITEM, id: genId(), type, content, duration: totalDuration > 0 ? totalDuration : 5, z_index: config.items.length + 1, }; onChange({ ...config, enabled: true, items: [...config.items, newItem], }); setSelectedId(newItem.id); }, [config, onChange, totalDuration], ); /** 删除贴纸 */ const removeSticker = useCallback( (id: string) => { onChange({ ...config, items: config.items.filter((s) => s.id !== id), }); if (selectedId === id) setSelectedId(null); }, [config, onChange, selectedId], ); /** 重置所有 */ const handleReset = useCallback(() => { onChange({ ...DEFAULT_STICKER_CONFIG, enabled: config.enabled }); setSelectedId(null); }, [config.enabled, onChange]); /** 文字花字输入 */ const [textInput, setTextInput] = useState(""); return ( {/* 顶部开关 */}
启用贴纸 onChange({ ...config, enabled: checked })} />
{/* 类型 Tab */}
{(["emoji", "image", "text"] as StickerType[]).map((t) => ( ))}
{/* Tab 内容区 */}
{/* Emoji 素材库 */} {activeTab === "emoji" && (
{EMOJI_LIST.map((emoji) => ( ))}
)} {/* 图片贴纸 */} {activeTab === "image" && (
{ if (e.key === "Enter" && e.currentTarget.value.trim()) { addSticker("image", e.currentTarget.value.trim()); e.currentTarget.value = ""; } }} />
)} {/* 文字花字 */} {activeTab === "text" && (
setTextInput(e.target.value)} />
花字预设预览
{( Object.keys(TEXT_STICKER_PRESET_LABELS) as TextStickerPreset[] ).map((p) => (
示例
{TEXT_STICKER_PRESET_LABELS[p]}
))}
)}
{/* 已添加贴纸列表 */} {config.items.length > 0 && (
已添加贴纸 ({config.items.length})
{config.items.map((item) => (
setSelectedId(item.id)} > {item.type === "emoji" ? item.content : item.type === "text" ? "T" : "🖼"} {item.type === "text" ? item.content.slice(0, 10) : item.type === "emoji" ? "表情贴纸" : "图片贴纸"}
))}
)} {/* 选中贴纸的属性编辑 */} {selectedSticker && (
属性调整
{/* 位置 */}
位置 X updateItem(selectedSticker.id, { x: Number(e.target.value) }) } /> {selectedSticker.x}%
位置 Y updateItem(selectedSticker.id, { y: Number(e.target.value) }) } /> {selectedSticker.y}%
{/* 尺寸 */}
大小 updateItem(selectedSticker.id, { width: Number(e.target.value), height: Number(e.target.value), }) } /> {selectedSticker.width}%
{/* 旋转 */}
旋转 updateItem(selectedSticker.id, { rotation: Number(e.target.value), }) } /> {selectedSticker.rotation}°
{/* 透明度 */}
透明度 updateItem(selectedSticker.id, { opacity: Number(e.target.value), }) } /> {selectedSticker.opacity}%
{/* 时间 */}
开始 updateItem(selectedSticker.id, { start_time: Number(e.target.value), }) } /> 时长 updateItem(selectedSticker.id, { duration: Number(e.target.value), }) } />
{/* 文字贴纸特有属性 */} {selectedSticker.type === "text" && ( <>
花字
字号 updateItem(selectedSticker.id, { font_size: Number(e.target.value), }) } /> {selectedSticker.font_size}px
颜色 updateItem(selectedSticker.id, { text_color: e.target.value, }) } />
)} {/* 预览 */}
{selectedSticker.type === "emoji" && selectedSticker.content} {selectedSticker.type === "text" && selectedSticker.content} {selectedSticker.type === "image" && ( sticker )}
)} {/* 底部重置 */}
); }; export default StickerPanel;