feat: enhance database pages with uncap columns
This commit is contained in:
parent
6f428f2aa3
commit
666109ef7d
6 changed files with 100 additions and 41 deletions
|
|
@ -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<typeof setTimeout> | 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)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="database-grid">
|
||||
|
|
@ -166,7 +174,7 @@
|
|||
{/if}
|
||||
|
||||
<Grid
|
||||
data={filteredData}
|
||||
data={data}
|
||||
{columns}
|
||||
{init}
|
||||
sizes={{ rowHeight: 80 }}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,26 @@
|
|||
<script lang="ts">
|
||||
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')
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<section class="db-nav">
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -46,7 +46,9 @@
|
|||
<img
|
||||
src={getWeaponImage(weapon)}
|
||||
alt={getWeaponName(weapon.name)}
|
||||
onerror={(e) => { e.currentTarget.src = '/images/placeholders/placeholder-weapon-main.png' }}
|
||||
onerror={(e) => {
|
||||
e.currentTarget.src = '/images/placeholders/placeholder-weapon-main.png'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="weapon-info">
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in a new issue