From 666109ef7daacb8809ed4e7c433faa320c2cd372 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 17 Sep 2025 10:45:44 -0700 Subject: [PATCH] feat: enhance database pages with uncap columns --- .../database/DatabaseGridWithProvider.svelte | 46 +++++++++++-------- src/routes/database/+layout.svelte | 16 +++++++ src/routes/database/characters/+page.svelte | 17 +++++-- src/routes/database/summons/+page.svelte | 17 +++++-- src/routes/database/weapons/+page.svelte | 17 +++++-- src/routes/database/weapons/[id]/+page.svelte | 28 +++++++---- 6 files changed, 100 insertions(+), 41 deletions(-) diff --git a/src/lib/components/database/DatabaseGridWithProvider.svelte b/src/lib/components/database/DatabaseGridWithProvider.svelte index 470fcec5..9dbe2e03 100644 --- a/src/lib/components/database/DatabaseGridWithProvider.svelte +++ b/src/lib/components/database/DatabaseGridWithProvider.svelte @@ -8,7 +8,7 @@ import { Grid } from 'wx-svelte-grid' import type { IColumn, IRow } from 'wx-svelte-grid' import { DatabaseProvider } from '$lib/providers/DatabaseProvider' - import { onMount } from 'svelte' + import { onMount, onDestroy } from 'svelte' import { goto } from '$app/navigation' interface Props { @@ -31,6 +31,7 @@ let total = $state(0) let searchTerm = $state('') let pageSize = $state(initialPageSize) + let searchTimeout: ReturnType | undefined // Create provider const provider = new DatabaseProvider({ resource, pageSize: initialPageSize }) @@ -101,31 +102,31 @@ const handlePageSizeChange = async (event: Event) => { const target = event.target as HTMLSelectElement const newPageSize = Number(target.value) + pageSize = newPageSize // Update local state immediately await provider.setPageSize(newPageSize) loadData(1) } - // Filter data based on search - const filteredData = $derived.by(() => { - if (!searchTerm) return data + // Handle search with debounce + const handleSearch = (term: string) => { + // Clear existing timeout + if (searchTimeout) { + clearTimeout(searchTimeout) + } - const term = searchTerm.toLowerCase() - return data.filter(item => { - // Search in name - if (item.name) { - const name = typeof item.name === 'string' - ? item.name - : item.name.en || item.name.ja || '' - if (name.toLowerCase().includes(term)) return true - } + // Set new timeout for debounced search + searchTimeout = setTimeout(() => { + provider.setSearchQuery(term) + loadData(1) // Reset to first page when searching + }, 300) // 300ms debounce + } - // Search in other string fields - return Object.values(item).some(value => - typeof value === 'string' && value.toLowerCase().includes(term) - ) - }) + // Watch for search term changes + $effect(() => { + handleSearch(searchTerm) }) + // Computed values const startItem = $derived((currentPage - 1) * pageSize + 1) const endItem = $derived(Math.min(currentPage * pageSize, total)) @@ -134,6 +135,13 @@ onMount(() => { loadData() }) + + // Clean up timeout on destroy + onDestroy(() => { + if (searchTimeout) { + clearTimeout(searchTimeout) + } + })
@@ -166,7 +174,7 @@ {/if} import { localizeHref } from '$lib/paraglide/runtime' + import { onMount } from 'svelte' const baseHref = localizeHref('/database') const summonsHref = localizeHref('/database/summons') const charactersHref = localizeHref('/database/characters') const weaponsHref = localizeHref('/database/weapons') + + // Apply wider layout to the main element for database pages + onMount(() => { + const main = document.querySelector('main') + if (main) { + main.classList.add('database-layout') + } + + return () => { + const main = document.querySelector('main') + if (main) { + main.classList.remove('database-layout') + } + } + })
diff --git a/src/routes/database/characters/+page.svelte b/src/routes/database/characters/+page.svelte index fd873b8a..b956c350 100644 --- a/src/routes/database/characters/+page.svelte +++ b/src/routes/database/characters/+page.svelte @@ -5,6 +5,8 @@ import type { IColumn } from 'wx-svelte-grid' import CharacterImageCell from '$lib/components/database/cells/CharacterImageCell.svelte' import ElementCell from '$lib/components/database/cells/ElementCell.svelte' + import CharacterUncapCell from '$lib/components/database/cells/CharacterUncapCell.svelte' + import LastUpdatedCell from '$lib/components/database/cells/LastUpdatedCell.svelte' import { getRarityLabel } from '$lib/utils/rarity' // Column configuration for characters @@ -43,10 +45,17 @@ cell: ElementCell }, { - id: 'max_level', - header: 'Max Level', - width: 80, - sort: true + id: 'uncap', + header: 'Uncap', + width: 160, + cell: CharacterUncapCell + }, + { + id: 'last_updated', + header: 'Last Updated', + width: 120, + sort: true, + cell: LastUpdatedCell } ] diff --git a/src/routes/database/summons/+page.svelte b/src/routes/database/summons/+page.svelte index 493e0474..d217e009 100644 --- a/src/routes/database/summons/+page.svelte +++ b/src/routes/database/summons/+page.svelte @@ -5,6 +5,8 @@ import type { IColumn } from 'wx-svelte-grid' import SummonImageCell from '$lib/components/database/cells/SummonImageCell.svelte' import ElementCell from '$lib/components/database/cells/ElementCell.svelte' + import SummonUncapCell from '$lib/components/database/cells/SummonUncapCell.svelte' + import LastUpdatedCell from '$lib/components/database/cells/LastUpdatedCell.svelte' import { getRarityLabel } from '$lib/utils/rarity' // Column configuration for summons @@ -43,10 +45,17 @@ cell: ElementCell }, { - id: 'max_level', - header: 'Max Level', - width: 80, - sort: true + id: 'uncap', + header: 'Uncap', + width: 160, + cell: SummonUncapCell + }, + { + id: 'last_updated', + header: 'Last Updated', + width: 120, + sort: true, + cell: LastUpdatedCell } ] diff --git a/src/routes/database/weapons/+page.svelte b/src/routes/database/weapons/+page.svelte index 6c5ab738..0ceb3df8 100644 --- a/src/routes/database/weapons/+page.svelte +++ b/src/routes/database/weapons/+page.svelte @@ -6,6 +6,8 @@ import WeaponImageCell from '$lib/components/database/cells/WeaponImageCell.svelte' import ElementCell from '$lib/components/database/cells/ElementCell.svelte' import ProficiencyCell from '$lib/components/database/cells/ProficiencyCell.svelte' + import WeaponUncapCell from '$lib/components/database/cells/WeaponUncapCell.svelte' + import LastUpdatedCell from '$lib/components/database/cells/LastUpdatedCell.svelte' import { getRarityLabel } from '$lib/utils/rarity' // Column configuration for weapons @@ -51,10 +53,17 @@ cell: ProficiencyCell }, { - id: 'max_level', - header: 'Max Level', - width: 80, - sort: true + id: 'uncap', + header: 'Uncap', + width: 160, + cell: WeaponUncapCell + }, + { + id: 'last_updated', + header: 'Last Updated', + width: 120, + sort: true, + cell: LastUpdatedCell } ] diff --git a/src/routes/database/weapons/[id]/+page.svelte b/src/routes/database/weapons/[id]/+page.svelte index feb388dc..67804650 100644 --- a/src/routes/database/weapons/[id]/+page.svelte +++ b/src/routes/database/weapons/[id]/+page.svelte @@ -46,7 +46,9 @@ {getWeaponName(weapon.name)} { e.currentTarget.src = '/images/placeholders/placeholder-weapon-main.png' }} + onerror={(e) => { + e.currentTarget.src = '/images/placeholders/placeholder-weapon-main.png' + }} />
@@ -188,7 +190,9 @@ } } - .loading, .error, .not-found { + .loading, + .error, + .not-found { text-align: center; padding: spacing.$unit * 4; @@ -257,7 +261,7 @@ gap: spacing.$unit * 0.5; .label { - font-weight: typography.$semibold; + font-weight: typography.$medium; color: #666; min-width: 100px; } @@ -266,12 +270,14 @@ color: #333; } - .element-display, .proficiency-display { + .element-display, + .proficiency-display { display: flex; align-items: center; gap: spacing.$unit * 0.25; - .element-icon, .proficiency-icon { + .element-icon, + .proficiency-icon { width: 25px; height: auto; } @@ -281,7 +287,8 @@ } } - .weapon-details, .weapon-skills { + .weapon-details, + .weapon-skills { padding: spacing.$unit * 2; border-bottom: 1px solid #e5e5e5; @@ -309,7 +316,7 @@ border-radius: 4px; .label { - font-weight: typography.$semibold; + font-weight: typography.$medium; color: #666; } @@ -331,7 +338,7 @@ .skill-name { font-size: typography.$font-medium; - font-weight: typography.$semibold; + font-weight: typography.$medium; margin: 0 0 spacing.$unit * 0.5 0; color: #333; } @@ -362,8 +369,9 @@ } } - .details-grid, .skills-grid { + .details-grid, + .skills-grid { grid-template-columns: 1fr; } } - \ No newline at end of file +