b1d448a627
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 26s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m59s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m59s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m51s
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 50s
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m44s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m32s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m26s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m31s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 4m31s
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
AI Code Review / AI Code Review (pull_request) Successful in 5m6s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 12s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 12s
86 lines
2.3 KiB
TypeScript
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,
|
|
}
|
|
}
|