archy/neode-ui/src/stores/uiMode.ts
Dorian 8e38342d53 fix: WebSocket reconnect race, parse error tracking, RPC timeout reduction, vendor chunk split
- F8: Add isReconnecting flag to prevent parallel reconnection attempts
- F9: Track JSON parse errors, force reconnect after 3 consecutive failures
- F11: Reduce RPC timeout to 15s, add jitter to retry backoff
- F12: Add vendor chunk splitting for vue/router/pinia
- F13: DOMPurify already applied to QR SVGs — verified
- F14: Replace O(n) goals alias lookup with Map-based O(1)
- F15: Wrap 7 localStorage.setItem calls in try/catch across 5 stores

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 01:57:05 +00:00

42 lines
1.4 KiB
TypeScript

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { UIMode } from '@/types/api'
const STORAGE_KEY = 'archipelago-ui-mode'
export const useUIModeStore = defineStore('uiMode', () => {
const mode = ref<UIMode>(loadFromStorage())
function loadFromStorage(): UIMode {
const stored = localStorage.getItem(STORAGE_KEY)
if (stored === 'gamer' || stored === 'easy' || stored === 'chat') return stored
return 'gamer'
}
function syncFromBackend(backendMode: UIMode | undefined) {
if (backendMode && ['gamer', 'easy', 'chat'].includes(backendMode)) {
mode.value = backendMode
try { localStorage.setItem(STORAGE_KEY, backendMode) } catch { /* localStorage full or unavailable */ }
}
}
function setMode(newMode: UIMode) {
mode.value = newMode
try { localStorage.setItem(STORAGE_KEY, newMode) } catch { /* localStorage full or unavailable */ }
}
function cycleMode(): UIMode {
const order: UIMode[] = ['easy', 'gamer']
const idx = order.indexOf(mode.value)
const next = order[(idx >= 0 ? idx + 1 : 0) % order.length] as UIMode
setMode(next)
return next
}
const isGamer = computed(() => mode.value === 'gamer')
const isEasy = computed(() => mode.value === 'easy')
const isChat = computed(() => mode.value === 'chat')
return { mode, setMode, cycleMode, syncFromBackend, isGamer, isEasy, isChat }
})