fix: use pushState + popstate for instant tab switching
This commit is contained in:
parent
21bda28910
commit
4fda863339
1 changed files with 20 additions and 19 deletions
|
|
@ -1,7 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount, getContext, setContext, onDestroy } from 'svelte'
|
import { onMount, getContext, setContext, onDestroy } from 'svelte'
|
||||||
import { goto } from '$app/navigation'
|
import { pushState } from '$app/navigation'
|
||||||
import { page } from '$app/state'
|
|
||||||
import type { Party, GridCharacter, GridWeapon, GridSummon } from '$lib/types/api/party'
|
import type { Party, GridCharacter, GridWeapon, GridSummon } from '$lib/types/api/party'
|
||||||
import { partyStore } from '$lib/stores/partyStore.svelte'
|
import { partyStore } from '$lib/stores/partyStore.svelte'
|
||||||
|
|
||||||
|
|
@ -105,17 +104,8 @@
|
||||||
characters: GridType.Character
|
characters: GridType.Character
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive activeTab from URL params (single source of truth)
|
// Use $state for instant UI updates - initialized from server-provided initialTab
|
||||||
// This ensures back/forward navigation works correctly
|
let activeTab = $state<GridType>(initialTab ?? GridType.Weapon)
|
||||||
// Falls back to initialTab prop for SSR hydration
|
|
||||||
let activeTab = $derived.by(() => {
|
|
||||||
const urlTab = page.params.tab as string | undefined
|
|
||||||
if (urlTab) {
|
|
||||||
return tabMap[urlTab] ?? GridType.Weapon
|
|
||||||
}
|
|
||||||
// Use initialTab for SSR or when no tab in URL
|
|
||||||
return initialTab ?? GridType.Weapon
|
|
||||||
})
|
|
||||||
|
|
||||||
let loading = $state(false)
|
let loading = $state(false)
|
||||||
let error = $state<string | null>(null)
|
let error = $state<string | null>(null)
|
||||||
|
|
@ -279,12 +269,12 @@
|
||||||
const partyElement = $derived((party as any)?.element)
|
const partyElement = $derived((party as any)?.element)
|
||||||
|
|
||||||
function handleTabChange(tab: GridType) {
|
function handleTabChange(tab: GridType) {
|
||||||
// Update URL (adds to browser history)
|
activeTab = tab // Instant UI update
|
||||||
// activeTab is derived from URL params, so it will update automatically
|
|
||||||
// Always use explicit tab path (e.g., /weapons not just /) to ensure navigation triggers
|
// Update URL without navigation (no load function, instant)
|
||||||
const basePath = `/teams/${party.shortcode}`
|
const basePath = `/teams/${party.shortcode}`
|
||||||
const newPath = `${basePath}/${tab}s`
|
const newPath = `${basePath}/${tab}s`
|
||||||
goto(newPath, { noScroll: true, keepFocus: true })
|
pushState(newPath, {})
|
||||||
|
|
||||||
// Update selectedSlot to the first valid empty slot for this tab
|
// Update selectedSlot to the first valid empty slot for this tab
|
||||||
const nextEmpty = findNextEmptySlot(party, tab)
|
const nextEmpty = findNextEmptySlot(party, tab)
|
||||||
|
|
@ -604,8 +594,19 @@
|
||||||
// Get edit key for this party if it exists
|
// Get edit key for this party if it exists
|
||||||
editKey = getEditKey(party.shortcode) ?? undefined
|
editKey = getEditKey(party.shortcode) ?? undefined
|
||||||
|
|
||||||
// No longer need to verify party data integrity after hydration
|
// Handle browser back/forward navigation for tabs
|
||||||
// since $state.raw prevents the hydration mismatch
|
const handlePopState = () => {
|
||||||
|
const path = window.location.pathname
|
||||||
|
const match = path.match(/\/teams\/[^/]+\/(\w+)$/)
|
||||||
|
const urlTabSlug = match?.[1]
|
||||||
|
const newTab = urlTabSlug ? (tabMap[urlTabSlug] ?? GridType.Weapon) : GridType.Weapon
|
||||||
|
if (activeTab !== newTab) {
|
||||||
|
activeTab = newTab
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('popstate', handlePopState)
|
||||||
|
return () => window.removeEventListener('popstate', handlePopState)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Grid service wrapper using TanStack Query mutations
|
// Grid service wrapper using TanStack Query mutations
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue