add URL-based tab routing with pushState sync
This commit is contained in:
parent
5b0d41a020
commit
af27f0fbbc
3 changed files with 42 additions and 4 deletions
|
|
@ -1,5 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { onMount, getContext, setContext, onDestroy } from 'svelte'
|
||||
import { pushState } from '$app/navigation'
|
||||
import { page } from '$app/state'
|
||||
import type { Party, GridCharacter, GridWeapon, GridSummon } from '$lib/types/api/party'
|
||||
import { partyStore } from '$lib/stores/partyStore.svelte'
|
||||
|
||||
|
|
@ -65,9 +67,10 @@
|
|||
party?: Party
|
||||
canEdit?: boolean
|
||||
authUserId?: string
|
||||
initialTab?: GridType
|
||||
}
|
||||
|
||||
let { party: initial, canEdit: canEditServer = false, authUserId }: Props = $props()
|
||||
let { party: initial, canEdit: canEditServer = false, authUserId, initialTab }: Props = $props()
|
||||
|
||||
// Per-route local state using Svelte 5 runes
|
||||
const defaultParty: Party = {
|
||||
|
|
@ -95,7 +98,24 @@
|
|||
partyStore.clear()
|
||||
})
|
||||
|
||||
let activeTab = $state<GridType>(GridType.Weapon)
|
||||
let activeTab = $state<GridType>(initialTab ?? GridType.Weapon)
|
||||
|
||||
// Map URL segment to GridType for back/forward navigation
|
||||
const tabMap: Record<string, GridType> = {
|
||||
weapons: GridType.Weapon,
|
||||
summons: GridType.Summon,
|
||||
characters: GridType.Character
|
||||
}
|
||||
|
||||
// Sync activeTab with URL when user navigates back/forward
|
||||
$effect(() => {
|
||||
const urlTab = page.params.tab as string | undefined
|
||||
const expectedTab = urlTab ? (tabMap[urlTab] ?? GridType.Weapon) : GridType.Weapon
|
||||
if (activeTab !== expectedTab) {
|
||||
activeTab = expectedTab
|
||||
}
|
||||
})
|
||||
|
||||
let loading = $state(false)
|
||||
let error = $state<string | null>(null)
|
||||
let selectedSlot = $state<number>(0)
|
||||
|
|
@ -259,6 +279,12 @@
|
|||
|
||||
function handleTabChange(tab: GridType) {
|
||||
activeTab = tab
|
||||
|
||||
// Update URL with push state (adds to browser history)
|
||||
const basePath = `/teams/${party.shortcode}`
|
||||
const newPath = tab === GridType.Weapon ? basePath : `${basePath}/${tab}s`
|
||||
pushState(newPath, {})
|
||||
|
||||
// Update selectedSlot to the first valid empty slot for this tab
|
||||
const nextEmpty = findNextEmptySlot(party, tab)
|
||||
if (nextEmpty !== SLOT_NOT_FOUND) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ export const load: PageServerLoad = async ({ params, locals }) => {
|
|||
party: party ? structuredClone(party) : null,
|
||||
canEdit: Boolean(canEdit),
|
||||
partyFound,
|
||||
authUserId: authUserId || null
|
||||
authUserId: authUserId || null,
|
||||
tab: params.tab || null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,20 @@
|
|||
import { createQuery } from '@tanstack/svelte-query'
|
||||
import { partyQueries } from '$lib/api/queries/party.queries'
|
||||
import { withInitialData } from '$lib/query/ssr'
|
||||
import { GridType } from '$lib/types/enums'
|
||||
|
||||
let { data }: { data: PageData } = $props()
|
||||
|
||||
// Map URL segment to GridType
|
||||
const tabMap: Record<string, GridType> = {
|
||||
weapons: GridType.Weapon,
|
||||
summons: GridType.Summon,
|
||||
characters: GridType.Character
|
||||
}
|
||||
|
||||
// Initialize from URL or default to Weapon
|
||||
const initialTab = data.tab ? (tabMap[data.tab] ?? GridType.Weapon) : GridType.Weapon
|
||||
|
||||
/**
|
||||
* TanStack Query v6 SSR Integration Example
|
||||
*
|
||||
|
|
@ -33,7 +44,7 @@
|
|||
</script>
|
||||
|
||||
{#if party}
|
||||
<Party party={party} canEdit={data.canEdit || false} authUserId={data.authUserId} />
|
||||
<Party party={party} canEdit={data.canEdit || false} authUserId={data.authUserId} {initialTab} />
|
||||
{:else}
|
||||
<div>
|
||||
<h1>Party not found</h1>
|
||||
|
|
|
|||
Loading…
Reference in a new issue