| 1 | export const INDEX_TRANSITION_TYPES = [ |
| 2 | 'none', |
| 3 | 'fade', |
| 4 | 'slide-left', |
| 5 | 'slide-up', |
| 6 | 'push', |
| 7 | 'wipe', |
| 8 | 'zoom', |
| 9 | 'flip', |
| 10 | 'stack', |
| 11 | 'rotate', |
| 12 | 'cube', |
| 13 | 'cover-flow', |
| 14 | 'blur', |
| 15 | 'iris', |
| 16 | 'swing', |
| 17 | 'center-reveal' |
| 18 | ] as const |
| 19 | |
| 20 | export type IndexTransitionType = (typeof INDEX_TRANSITION_TYPES)[number] |
| 21 | |
| 22 | export interface IndexTransitionConfig { |
| 23 | type: IndexTransitionType |
| 24 | durationMs: number |
| 25 | } |
| 26 | |
| 27 | export const DEFAULT_INDEX_TRANSITION_CONFIG: IndexTransitionConfig = { |
| 28 | type: 'fade', |
| 29 | durationMs: 600 |
| 30 | } |
| 31 | |
| 32 | export const INDEX_TRANSITION_PRESETS: ReadonlyArray< |
| 33 | IndexTransitionConfig & { labelKey: string } |
| 34 | > = [ |
| 35 | { type: 'none', durationMs: 0, labelKey: 'sessionDetail.indexTransitionNone' }, |
| 36 | { type: 'fade', durationMs: 600, labelKey: 'sessionDetail.indexTransitionFade' }, |
| 37 | { type: 'slide-left', durationMs: 560, labelKey: 'sessionDetail.indexTransitionSlideLeft' }, |
| 38 | { type: 'slide-up', durationMs: 560, labelKey: 'sessionDetail.indexTransitionSlideUp' }, |
| 39 | { type: 'push', durationMs: 600, labelKey: 'sessionDetail.indexTransitionPush' }, |
| 40 | { type: 'wipe', durationMs: 600, labelKey: 'sessionDetail.indexTransitionWipe' }, |
| 41 | { type: 'zoom', durationMs: 580, labelKey: 'sessionDetail.indexTransitionZoom' }, |
| 42 | { type: 'flip', durationMs: 680, labelKey: 'sessionDetail.indexTransitionFlip' }, |
| 43 | { type: 'stack', durationMs: 640, labelKey: 'sessionDetail.indexTransitionStack' }, |
| 44 | { type: 'rotate', durationMs: 660, labelKey: 'sessionDetail.indexTransitionRotate' }, |
| 45 | { type: 'cube', durationMs: 720, labelKey: 'sessionDetail.indexTransitionCube' }, |
| 46 | { type: 'cover-flow', durationMs: 720, labelKey: 'sessionDetail.indexTransitionCoverFlow' }, |
| 47 | { type: 'blur', durationMs: 640, labelKey: 'sessionDetail.indexTransitionBlur' }, |
| 48 | { type: 'iris', durationMs: 720, labelKey: 'sessionDetail.indexTransitionIris' }, |
| 49 | { type: 'swing', durationMs: 700, labelKey: 'sessionDetail.indexTransitionSwing' }, |
| 50 | { type: 'center-reveal', durationMs: 680, labelKey: 'sessionDetail.indexTransitionCenterReveal' } |
| 51 | ] |
| 52 | |
| 53 | export function isIndexTransitionType(value: unknown): value is IndexTransitionType { |
| 54 | return INDEX_TRANSITION_TYPES.includes(value as IndexTransitionType) |
| 55 | } |
| 56 | |
| 57 | export function normalizeIndexTransitionType(value: unknown): IndexTransitionType { |
| 58 | return isIndexTransitionType(value) ? value : DEFAULT_INDEX_TRANSITION_CONFIG.type |
| 59 | } |
| 60 | |
| 61 | export function defaultDurationForIndexTransition(type: IndexTransitionType): number { |
| 62 | return ( |
| 63 | INDEX_TRANSITION_PRESETS.find((preset) => preset.type === type)?.durationMs ?? |
| 64 | DEFAULT_INDEX_TRANSITION_CONFIG.durationMs |
| 65 | ) |
| 66 | } |
| 67 | |
| 68 | export function clampIndexTransitionDuration( |
| 69 | type: IndexTransitionType, |
| 70 | value: unknown |
| 71 | ): number { |
| 72 | if (type === 'none') return 0 |
| 73 | const numericValue = Number(value) |
| 74 | if (!Number.isFinite(numericValue)) return defaultDurationForIndexTransition(type) |
| 75 | return Math.max(120, Math.min(1200, Math.round(numericValue))) |
| 76 | } |
| 77 | |
| 78 | export function normalizeIndexTransitionConfig(value: { |
| 79 | type?: unknown |
| 80 | durationMs?: unknown |
| 81 | }): IndexTransitionConfig { |
| 82 | const type = normalizeIndexTransitionType(value.type) |
| 83 | return { |
| 84 | type, |
| 85 | durationMs: clampIndexTransitionDuration(type, value.durationMs) |
| 86 | } |
| 87 | } |
| 88 |