persist database grid page in url

This commit is contained in:
Justin Edmund 2025-12-20 01:06:34 -08:00
parent 5b74e90ef8
commit 422b5762d3

View file

@ -12,6 +12,7 @@
import type { CollectionFilterState } from '$lib/components/collection/CollectionFilters.svelte' import type { CollectionFilterState } from '$lib/components/collection/CollectionFilters.svelte'
import { onMount, onDestroy } from 'svelte' import { onMount, onDestroy } from 'svelte'
import { goto } from '$app/navigation' import { goto } from '$app/navigation'
import { page } from '$app/stores'
import type { Snippet } from 'svelte' import type { Snippet } from 'svelte'
@ -19,10 +20,11 @@
resource: 'weapons' | 'characters' | 'summons' resource: 'weapons' | 'characters' | 'summons'
columns: IColumn[] columns: IColumn[]
pageSize?: number pageSize?: number
leftActions?: Snippet
headerActions?: Snippet headerActions?: Snippet
} }
const { resource, columns, pageSize: initialPageSize = 20, headerActions }: Props = $props() const { resource, columns, pageSize: initialPageSize = 20, leftActions, headerActions }: Props = $props()
// State // State
let data = $state<any[]>([]) let data = $state<any[]>([])
@ -72,13 +74,25 @@
// Grid API reference // Grid API reference
let api: any let api: any
// Update URL with current page (without triggering navigation)
function updateUrl(pageNum: number) {
const url = new URL($page.url)
if (pageNum === 1) {
url.searchParams.delete('page')
} else {
url.searchParams.set('page', String(pageNum))
}
// Use replaceState to update URL without adding history entry
goto(url.pathname + url.search, { replaceState: true, noScroll: true, keepFocus: true })
}
// Load data // Load data
async function loadData(page: number = 1) { async function loadData(pageNum: number = 1, updateUrlParam: boolean = true) {
loading = true loading = true
try { try {
const result = await provider.loadPage(page) const result = await provider.loadPage(pageNum)
data = result data = result
currentPage = page currentPage = pageNum
// Get pagination metadata from provider // Get pagination metadata from provider
const meta = provider.getPaginationMeta() const meta = provider.getPaginationMeta()
@ -90,6 +104,11 @@
pageSize = meta.pageSize pageSize = meta.pageSize
} }
} }
// Update URL to reflect current page
if (updateUrlParam) {
updateUrl(pageNum)
}
} catch (error) { } catch (error) {
console.error('Failed to load data:', error) console.error('Failed to load data:', error)
} finally { } finally {
@ -205,9 +224,11 @@
const startItem = $derived((currentPage - 1) * pageSize + 1) const startItem = $derived((currentPage - 1) * pageSize + 1)
const endItem = $derived(Math.min(currentPage * pageSize, total)) const endItem = $derived(Math.min(currentPage * pageSize, total))
// Load initial data // Load initial data from URL page param
onMount(() => { onMount(() => {
loadData() const pageParam = $page.url.searchParams.get('page')
const initialPage = pageParam ? Math.max(1, parseInt(pageParam, 10) || 1) : 1
loadData(initialPage, false) // Don't update URL on initial load
}) })
// Clean up timeout on destroy // Clean up timeout on destroy
@ -224,6 +245,10 @@
<div class="grid"> <div class="grid">
<div class="controls"> <div class="controls">
{#if leftActions}
{@render leftActions()}
{/if}
<CollectionFilters <CollectionFilters
entityType={resource === 'characters' ? 'character' : resource === 'summons' ? 'summon' : 'weapon'} entityType={resource === 'characters' ? 'character' : resource === 'summons' ? 'summon' : 'weapon'}
bind:elementFilters bind:elementFilters