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 { Grid } from 'wx-svelte-grid'
|
||||||
import type { IColumn, IRow } from 'wx-svelte-grid'
|
import type { IColumn, IRow } from 'wx-svelte-grid'
|
||||||
import { DatabaseProvider } from '$lib/providers/DatabaseProvider'
|
import { DatabaseProvider } from '$lib/providers/DatabaseProvider'
|
||||||
import { onMount } from 'svelte'
|
import { onMount, onDestroy } from 'svelte'
|
||||||
import { goto } from '$app/navigation'
|
import { goto } from '$app/navigation'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
let total = $state(0)
|
let total = $state(0)
|
||||||
let searchTerm = $state('')
|
let searchTerm = $state('')
|
||||||
let pageSize = $state(initialPageSize)
|
let pageSize = $state(initialPageSize)
|
||||||
|
let searchTimeout: ReturnType<typeof setTimeout> | undefined
|
||||||
|
|
||||||
// Create provider
|
// Create provider
|
||||||
const provider = new DatabaseProvider({ resource, pageSize: initialPageSize })
|
const provider = new DatabaseProvider({ resource, pageSize: initialPageSize })
|
||||||
|
|
@ -101,31 +102,31 @@
|
||||||
const handlePageSizeChange = async (event: Event) => {
|
const handlePageSizeChange = async (event: Event) => {
|
||||||
const target = event.target as HTMLSelectElement
|
const target = event.target as HTMLSelectElement
|
||||||
const newPageSize = Number(target.value)
|
const newPageSize = Number(target.value)
|
||||||
|
pageSize = newPageSize // Update local state immediately
|
||||||
await provider.setPageSize(newPageSize)
|
await provider.setPageSize(newPageSize)
|
||||||
loadData(1)
|
loadData(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter data based on search
|
// Handle search with debounce
|
||||||
const filteredData = $derived.by(() => {
|
const handleSearch = (term: string) => {
|
||||||
if (!searchTerm) return data
|
// Clear existing timeout
|
||||||
|
if (searchTimeout) {
|
||||||
|
clearTimeout(searchTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
const term = searchTerm.toLowerCase()
|
// Set new timeout for debounced search
|
||||||
return data.filter(item => {
|
searchTimeout = setTimeout(() => {
|
||||||
// Search in name
|
provider.setSearchQuery(term)
|
||||||
if (item.name) {
|
loadData(1) // Reset to first page when searching
|
||||||
const name = typeof item.name === 'string'
|
}, 300) // 300ms debounce
|
||||||
? item.name
|
}
|
||||||
: item.name.en || item.name.ja || ''
|
|
||||||
if (name.toLowerCase().includes(term)) return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search in other string fields
|
// Watch for search term changes
|
||||||
return Object.values(item).some(value =>
|
$effect(() => {
|
||||||
typeof value === 'string' && value.toLowerCase().includes(term)
|
handleSearch(searchTerm)
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// Computed values
|
// Computed values
|
||||||
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))
|
||||||
|
|
@ -134,6 +135,13 @@
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
loadData()
|
loadData()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Clean up timeout on destroy
|
||||||
|
onDestroy(() => {
|
||||||
|
if (searchTimeout) {
|
||||||
|
clearTimeout(searchTimeout)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="database-grid">
|
<div class="database-grid">
|
||||||
|
|
@ -166,7 +174,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
data={filteredData}
|
data={data}
|
||||||
{columns}
|
{columns}
|
||||||
{init}
|
{init}
|
||||||
sizes={{ rowHeight: 80 }}
|
sizes={{ rowHeight: 80 }}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,26 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { localizeHref } from '$lib/paraglide/runtime'
|
import { localizeHref } from '$lib/paraglide/runtime'
|
||||||
|
import { onMount } from 'svelte'
|
||||||
|
|
||||||
const baseHref = localizeHref('/database')
|
const baseHref = localizeHref('/database')
|
||||||
const summonsHref = localizeHref('/database/summons')
|
const summonsHref = localizeHref('/database/summons')
|
||||||
const charactersHref = localizeHref('/database/characters')
|
const charactersHref = localizeHref('/database/characters')
|
||||||
const weaponsHref = localizeHref('/database/weapons')
|
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>
|
</script>
|
||||||
|
|
||||||
<section class="db-nav">
|
<section class="db-nav">
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
import type { IColumn } from 'wx-svelte-grid'
|
import type { IColumn } from 'wx-svelte-grid'
|
||||||
import CharacterImageCell from '$lib/components/database/cells/CharacterImageCell.svelte'
|
import CharacterImageCell from '$lib/components/database/cells/CharacterImageCell.svelte'
|
||||||
import ElementCell from '$lib/components/database/cells/ElementCell.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'
|
import { getRarityLabel } from '$lib/utils/rarity'
|
||||||
|
|
||||||
// Column configuration for characters
|
// Column configuration for characters
|
||||||
|
|
@ -43,10 +45,17 @@
|
||||||
cell: ElementCell
|
cell: ElementCell
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'max_level',
|
id: 'uncap',
|
||||||
header: 'Max Level',
|
header: 'Uncap',
|
||||||
width: 80,
|
width: 160,
|
||||||
sort: true
|
cell: CharacterUncapCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'last_updated',
|
||||||
|
header: 'Last Updated',
|
||||||
|
width: 120,
|
||||||
|
sort: true,
|
||||||
|
cell: LastUpdatedCell
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
import type { IColumn } from 'wx-svelte-grid'
|
import type { IColumn } from 'wx-svelte-grid'
|
||||||
import SummonImageCell from '$lib/components/database/cells/SummonImageCell.svelte'
|
import SummonImageCell from '$lib/components/database/cells/SummonImageCell.svelte'
|
||||||
import ElementCell from '$lib/components/database/cells/ElementCell.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'
|
import { getRarityLabel } from '$lib/utils/rarity'
|
||||||
|
|
||||||
// Column configuration for summons
|
// Column configuration for summons
|
||||||
|
|
@ -43,10 +45,17 @@
|
||||||
cell: ElementCell
|
cell: ElementCell
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'max_level',
|
id: 'uncap',
|
||||||
header: 'Max Level',
|
header: 'Uncap',
|
||||||
width: 80,
|
width: 160,
|
||||||
sort: true
|
cell: SummonUncapCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'last_updated',
|
||||||
|
header: 'Last Updated',
|
||||||
|
width: 120,
|
||||||
|
sort: true,
|
||||||
|
cell: LastUpdatedCell
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
import WeaponImageCell from '$lib/components/database/cells/WeaponImageCell.svelte'
|
import WeaponImageCell from '$lib/components/database/cells/WeaponImageCell.svelte'
|
||||||
import ElementCell from '$lib/components/database/cells/ElementCell.svelte'
|
import ElementCell from '$lib/components/database/cells/ElementCell.svelte'
|
||||||
import ProficiencyCell from '$lib/components/database/cells/ProficiencyCell.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'
|
import { getRarityLabel } from '$lib/utils/rarity'
|
||||||
|
|
||||||
// Column configuration for weapons
|
// Column configuration for weapons
|
||||||
|
|
@ -51,10 +53,17 @@
|
||||||
cell: ProficiencyCell
|
cell: ProficiencyCell
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'max_level',
|
id: 'uncap',
|
||||||
header: 'Max Level',
|
header: 'Uncap',
|
||||||
width: 80,
|
width: 160,
|
||||||
sort: true
|
cell: WeaponUncapCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'last_updated',
|
||||||
|
header: 'Last Updated',
|
||||||
|
width: 120,
|
||||||
|
sort: true,
|
||||||
|
cell: LastUpdatedCell
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,9 @@
|
||||||
<img
|
<img
|
||||||
src={getWeaponImage(weapon)}
|
src={getWeaponImage(weapon)}
|
||||||
alt={getWeaponName(weapon.name)}
|
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>
|
||||||
<div class="weapon-info">
|
<div class="weapon-info">
|
||||||
|
|
@ -188,7 +190,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading, .error, .not-found {
|
.loading,
|
||||||
|
.error,
|
||||||
|
.not-found {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: spacing.$unit * 4;
|
padding: spacing.$unit * 4;
|
||||||
|
|
||||||
|
|
@ -257,7 +261,7 @@
|
||||||
gap: spacing.$unit * 0.5;
|
gap: spacing.$unit * 0.5;
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
font-weight: typography.$semibold;
|
font-weight: typography.$medium;
|
||||||
color: #666;
|
color: #666;
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
}
|
}
|
||||||
|
|
@ -266,12 +270,14 @@
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-display, .proficiency-display {
|
.element-display,
|
||||||
|
.proficiency-display {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: spacing.$unit * 0.25;
|
gap: spacing.$unit * 0.25;
|
||||||
|
|
||||||
.element-icon, .proficiency-icon {
|
.element-icon,
|
||||||
|
.proficiency-icon {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
@ -281,7 +287,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.weapon-details, .weapon-skills {
|
.weapon-details,
|
||||||
|
.weapon-skills {
|
||||||
padding: spacing.$unit * 2;
|
padding: spacing.$unit * 2;
|
||||||
border-bottom: 1px solid #e5e5e5;
|
border-bottom: 1px solid #e5e5e5;
|
||||||
|
|
||||||
|
|
@ -309,7 +316,7 @@
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
font-weight: typography.$semibold;
|
font-weight: typography.$medium;
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,7 +338,7 @@
|
||||||
|
|
||||||
.skill-name {
|
.skill-name {
|
||||||
font-size: typography.$font-medium;
|
font-size: typography.$font-medium;
|
||||||
font-weight: typography.$semibold;
|
font-weight: typography.$medium;
|
||||||
margin: 0 0 spacing.$unit * 0.5 0;
|
margin: 0 0 spacing.$unit * 0.5 0;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
@ -362,8 +369,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.details-grid, .skills-grid {
|
.details-grid,
|
||||||
|
.skills-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue