Files
fotospiel-app/resources/js/guest/lib/haptics.ts
Codex Agent fa5a1fa367 Added a guest haptics preference and surfaced it in both the settings sheet and /settings, with safe device detection
and a reduced‑motion guard. Haptics now honor the toggle and still fall back gracefully on iOS (switch disabled when
  navigator.vibrate isn’t available).

  What changed

  - Haptics preference storage + gating: resources/js/guest/lib/haptics.ts
  - Preference hook: resources/js/guest/hooks/useHapticsPreference.ts
  - Settings UI toggle in sheet + page: resources/js/guest/components/settings-sheet.tsx, resources/js/guest/pages/
    SettingsPage.tsx
  - i18n labels: resources/js/guest/i18n/messages.ts
  - Tests: resources/js/guest/lib/__tests__/haptics.test.ts
2025-12-27 14:00:12 +01:00

63 lines
1.5 KiB
TypeScript

import { prefersReducedMotion } from './motion';
export type HapticPattern = 'selection' | 'light' | 'medium' | 'success' | 'error';
const PATTERNS: Record<HapticPattern, number | number[]> = {
selection: 10,
light: 15,
medium: 30,
success: [10, 30, 10],
error: [20, 30, 20],
};
export const HAPTICS_STORAGE_KEY = 'guestHapticsEnabled';
export function supportsHaptics(): boolean {
return typeof navigator !== 'undefined' && typeof navigator.vibrate === 'function';
}
export function getHapticsPreference(): boolean {
if (typeof window === 'undefined') {
return true;
}
try {
const raw = window.localStorage.getItem(HAPTICS_STORAGE_KEY);
if (raw === null) {
return true;
}
return raw !== '0';
} catch (error) {
console.warn('Failed to read haptics preference', error);
return true;
}
}
export function setHapticsPreference(enabled: boolean): void {
if (typeof window === 'undefined') {
return;
}
try {
window.localStorage.setItem(HAPTICS_STORAGE_KEY, enabled ? '1' : '0');
} catch (error) {
console.warn('Failed to store haptics preference', error);
}
}
export function isHapticsEnabled(): boolean {
return getHapticsPreference() && supportsHaptics() && !prefersReducedMotion();
}
export function triggerHaptic(pattern: HapticPattern): void {
if (!isHapticsEnabled()) {
return;
}
try {
navigator.vibrate(PATTERNS[pattern]);
} catch (error) {
console.warn('Haptic feedback failed', error);
}
}