返回 oh-my-ppt
AnimationPreferenceChips.tsx
根目录 / src / renderer / src / components / session-create / AnimationPreferenceChips.tsx
1 import type { JSX } from 'react'
2 import type { AnimationPreferenceId } from '@shared/generation'
3 import { useToastStore } from '../../store'
4 import { useT, type I18nKey } from '../../i18n'
5
6 const MAX_SELECTED_ANIMATION_PREFERENCES = 3
7
8 const OPTIONS: Array<{ id: AnimationPreferenceId; labelKey: I18nKey }> = [
9 { id: 'fade', labelKey: 'home.animationPreferenceOptions.fade' },
10 { id: 'fade-up', labelKey: 'home.animationPreferenceOptions.fade-up' },
11 { id: 'fade-down', labelKey: 'home.animationPreferenceOptions.fade-down' },
12 { id: 'fade-left', labelKey: 'home.animationPreferenceOptions.fade-left' },
13 { id: 'fade-right', labelKey: 'home.animationPreferenceOptions.fade-right' },
14 { id: 'scale-in', labelKey: 'home.animationPreferenceOptions.scale-in' },
15 { id: 'slide-up', labelKey: 'home.animationPreferenceOptions.slide-up' },
16 { id: 'slide-down', labelKey: 'home.animationPreferenceOptions.slide-down' },
17 { id: 'slide-left', labelKey: 'home.animationPreferenceOptions.slide-left' },
18 { id: 'slide-right', labelKey: 'home.animationPreferenceOptions.slide-right' },
19 { id: 'fly-in', labelKey: 'home.animationPreferenceOptions.fly-in' },
20 { id: 'wipe', labelKey: 'home.animationPreferenceOptions.wipe' },
21 { id: 'zoom-in', labelKey: 'home.animationPreferenceOptions.zoom-in' },
22 { id: 'spin-in', labelKey: 'home.animationPreferenceOptions.spin-in' },
23 { id: 'pulse-soft', labelKey: 'home.animationPreferenceOptions.pulse-soft' },
24 { id: 'pulse', labelKey: 'home.animationPreferenceOptions.pulse' },
25 { id: 'pulse-strong', labelKey: 'home.animationPreferenceOptions.pulse-strong' },
26 { id: 'grow-shrink-soft', labelKey: 'home.animationPreferenceOptions.grow-shrink-soft' },
27 { id: 'grow-shrink', labelKey: 'home.animationPreferenceOptions.grow-shrink' },
28 { id: 'grow-shrink-strong', labelKey: 'home.animationPreferenceOptions.grow-shrink-strong' }
29 ]
30
31 type AnimationPreferenceChipsProps = {
32 selectedIds: AnimationPreferenceId[]
33 onChange: (ids: AnimationPreferenceId[]) => void
34 compact?: boolean
35 }
36
37 export function AnimationPreferenceChips({
38 selectedIds,
39 onChange,
40 compact = false
41 }: AnimationPreferenceChipsProps): JSX.Element {
42 const { warning } = useToastStore()
43 const t = useT()
44 const selectedSet = new Set(selectedIds)
45
46 const togglePreference = (id: AnimationPreferenceId): void => {
47 if (selectedSet.has(id)) {
48 onChange(selectedIds.filter((item) => item !== id))
49 return
50 }
51 if (selectedIds.length >= MAX_SELECTED_ANIMATION_PREFERENCES) {
52 warning(t('home.animationPreferenceLimitReached'))
53 return
54 }
55 onChange([...selectedIds, id])
56 }
57
58 return (
59 <div className={compact ? 'grid grid-cols-2 gap-1.5 xl:grid-cols-3' : 'flex flex-wrap gap-2'}>
60 {OPTIONS.map((option) => {
61 const selected = selectedSet.has(option.id)
62 return (
63 <button
64 key={option.id}
65 type="button"
66 aria-pressed={selected}
67 onClick={() => togglePreference(option.id)}
68 className={`rounded-lg text-xs transition-colors ${
69 compact ? 'px-2 py-1.5 text-[11px] font-medium' : 'border px-3 py-1.5 font-semibold'
70 } ${
71 selected
72 ? compact
73 ? 'bg-[#8fbc8f] text-[#25351f] shadow-[inset_0_0_0_1px_rgba(62,74,50,0.34),0_2px_6px_rgba(93,107,77,0.12)] hover:bg-[#7eab7e] hover:text-[#1f2c19] hover:shadow-[inset_0_0_0_1px_rgba(62,74,50,0.5),0_3px_8px_rgba(93,107,77,0.16)]'
74 : 'border-[#65794d] bg-[#d4e8c6] text-[#28331f] shadow-[0_2px_8px_rgba(93,107,77,0.12)] hover:border-[#4f623d] hover:bg-[#c3dcb2] hover:text-[#202b18]'
75 : compact
76 ? 'bg-[#fffdf8]/72 text-[#5d6b4d] hover:bg-[#dfeccd] hover:text-[#33402a] hover:shadow-[inset_0_0_0_1px_rgba(93,107,77,0.18)]'
77 : 'border-[#d8ccb5]/75 bg-white/65 text-[#7f8a70] hover:border-[#a9c394] hover:bg-[#dfeccd] hover:text-[#33402a]'
78 }`}
79 >
80 {t(option.labelKey)}
81 </button>
82 )
83 })}
84 </div>
85 )
86 }
87
87 lines Plain Text