Files
xiaoxia-saas/apps/web/src/pages/editing-planner/components/StickerPanel/hooks/useStickerPanel.ts
T
xiaoxia 223bb530dd
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m20s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m28s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m21s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m49s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m18s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 5m41s
CI/CD Pipeline / Integration Tests (push) Successful in 2m25s
CI/CD Pipeline / Unit Tests (push) Failing after 10m1s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 12m34s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 30s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 33s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m37s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Failing after 5m1s
refactor(StickerPanel): 贴纸面板目录化拆分(516→103行, -80%) (#1191)
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-07-30 12:16:12 +08:00

86 lines
2.3 KiB
TypeScript

import { useState, useCallback, useMemo } from "react"
import type { StickerConfig, StickerItem, StickerType } from "../../../types"
import { DEFAULT_STICKER_CONFIG, DEFAULT_STICKER_ITEM } from "../../../types"
import { genStickerId } from "../constants"
interface UseStickerPanelOptions {
config: StickerConfig
onChange: (config: StickerConfig) => void
totalDuration: number
}
export const useStickerPanel = ({ config, onChange, totalDuration }: UseStickerPanelOptions) => {
const [selectedId, setSelectedId] = useState<string | null>(null)
const [activeTab, setActiveTab] = useState<StickerType>("emoji")
const [textInput, setTextInput] = useState("")
const selectedSticker = useMemo(
() => config.items.find((s) => s.id === selectedId) ?? null,
[config.items, selectedId],
)
/** 更新单个贴纸 */
const updateItem = useCallback(
(id: string, partial: Partial<StickerItem>) => {
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: genStickerId(),
type,
content,
duration: totalDuration > 0 ? totalDuration : 5,
z_index: config.items.length > 0 ? Math.max(...config.items.map((i) => i.z_index)) + 1 : 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])
return {
selectedId,
setSelectedId,
selectedSticker,
activeTab,
setActiveTab,
textInput,
setTextInput,
updateItem,
addSticker,
removeSticker,
handleReset,
}
}