| 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 |