mirror of
https://github.com/MewoLab/AquaDX.git
synced 2025-12-14 11:56:15 +08:00
[+] Pagination
This commit is contained in:
60
AquaNet/src/components/Pagination.svelte
Normal file
60
AquaNet/src/components/Pagination.svelte
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
|
||||||
|
export let page: number
|
||||||
|
export let totalPages: number
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
let editing = false
|
||||||
|
let inputPage: number
|
||||||
|
|
||||||
|
function updatePage(newPage: number) {
|
||||||
|
if (newPage > 0 && newPage <= totalPages) dispatch('updatePage', newPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
function startEditing() {
|
||||||
|
inputPage = page
|
||||||
|
editing = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishEditing() {
|
||||||
|
editing = false
|
||||||
|
if (inputPage !== page) updatePage(inputPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeydown(event: KeyboardEvent) {
|
||||||
|
if (event.key === 'Enter') finishEditing()
|
||||||
|
else if (event.key === 'Escape') editing = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="pagination">
|
||||||
|
<button on:click={() => updatePage(page - 1)} disabled={page <= 1}>Previous</button>
|
||||||
|
|
||||||
|
{#if editing}
|
||||||
|
<input bind:value={inputPage} on:blur={finishEditing} on:keydown={handleKeydown} min="1" max={totalPages} autofocus/>
|
||||||
|
{:else}
|
||||||
|
<span on:click={startEditing} role="button" tabindex="0" on:keydown={(e) => e.key === 'Enter' && startEditing()}>
|
||||||
|
Page {page} of {totalPages}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<button on:click={() => updatePage(page + 1)} disabled={page >= totalPages}>Next</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="sass">
|
||||||
|
.pagination
|
||||||
|
display: flex
|
||||||
|
justify-content: center
|
||||||
|
align-items: center
|
||||||
|
margin: 1rem 0
|
||||||
|
gap: 1rem
|
||||||
|
|
||||||
|
input
|
||||||
|
width: 100px
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
span[role="button"]
|
||||||
|
cursor: pointer
|
||||||
|
</style>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { onMount } from "svelte";
|
||||||
import { title } from "../libs/ui";
|
import { title } from "../libs/ui";
|
||||||
import { GAME } from "../libs/sdk";
|
import { GAME } from "../libs/sdk";
|
||||||
import type { GenericRanking } from "../libs/generalTypes";
|
import type { GenericRanking } from "../libs/generalTypes";
|
||||||
@@ -8,6 +9,7 @@
|
|||||||
import { t } from "../libs/i18n";
|
import { t } from "../libs/i18n";
|
||||||
import UserCard from "../components/UserCard.svelte";
|
import UserCard from "../components/UserCard.svelte";
|
||||||
import Tooltip from "../components/Tooltip.svelte";
|
import Tooltip from "../components/Tooltip.svelte";
|
||||||
|
import Pagination from "../components/Pagination.svelte";
|
||||||
|
|
||||||
export let game: GameName = 'mai2';
|
export let game: GameName = 'mai2';
|
||||||
|
|
||||||
@@ -15,15 +17,45 @@
|
|||||||
|
|
||||||
let d: { users: GenericRanking[] };
|
let d: { users: GenericRanking[] };
|
||||||
let error: string | null;
|
let error: string | null;
|
||||||
|
|
||||||
|
let page = 1
|
||||||
|
const perPage = 50
|
||||||
|
let totalPages = 1
|
||||||
|
|
||||||
|
function handleUpdatePage(event: CustomEvent<number>) {
|
||||||
|
page = event.detail;
|
||||||
|
const url = new URL(window.location.toString())
|
||||||
|
url.searchParams.set('page', page.toString())
|
||||||
|
history.pushState({}, '', url.toString())
|
||||||
|
window.scrollTo(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
const url = new URL(window.location.toString())
|
||||||
|
const pageParam = url.searchParams.get('page')
|
||||||
|
if (pageParam) {
|
||||||
|
page = parseInt(pageParam, 10) || 1
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('popstate', () => {
|
||||||
|
const url = new URL(window.location.toString())
|
||||||
|
const pageParam = url.searchParams.get('page')
|
||||||
|
page = parseInt(pageParam, 10) || 1
|
||||||
|
window.scrollTo(0, 0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
Promise.all([GAME.ranking(game)])
|
Promise.all([GAME.ranking(game)])
|
||||||
.then(([users]) => {
|
.then(([users]) => {
|
||||||
console.log(users)
|
d = { users }
|
||||||
d = { users };
|
totalPages = Math.ceil(users.length / perPage)
|
||||||
})
|
})
|
||||||
.catch((e) => error = e.message);
|
.catch((e) => error = e.message);
|
||||||
|
|
||||||
let hoveringUser = "";
|
let hoveringUser = "";
|
||||||
let hoverLoading = false;
|
let hoverLoading = false;
|
||||||
|
|
||||||
|
$: paginatedUsers = d ? d.users.slice((page - 1) * perPage, page * perPage) : []
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main class="content leaderboard">
|
<main class="content leaderboard">
|
||||||
@@ -37,8 +69,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if d}
|
{#if d}
|
||||||
|
{#if page > 1}
|
||||||
|
<Pagination {page} {totalPages} on:updatePage={handleUpdatePage} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="leaderboard-container">
|
<div class="leaderboard-container">
|
||||||
<div class="lb-user" on:mouseenter={() => hoveringUser = d.users[0].username} role="heading" aria-level="2">
|
<div class="lb-user" on:mouseenter={() => hoveringUser = paginatedUsers[0]?.username} role="heading" aria-level="2">
|
||||||
<span class="rank">{t("Leaderboard.Rank")}</span>
|
<span class="rank">{t("Leaderboard.Rank")}</span>
|
||||||
<span class="name"></span>
|
<span class="name"></span>
|
||||||
<span class="rating">{t("Leaderboard.Rating")}</span>
|
<span class="rating">{t("Leaderboard.Rating")}</span>
|
||||||
@@ -46,7 +82,7 @@
|
|||||||
<span class="fc">{t("Leaderboard.FC")}</span>
|
<span class="fc">{t("Leaderboard.FC")}</span>
|
||||||
<span class="ap">{t("Leaderboard.AP")}</span>
|
<span class="ap">{t("Leaderboard.AP")}</span>
|
||||||
</div>
|
</div>
|
||||||
{#each d.users as user, i (user.rank)}
|
{#each paginatedUsers as user, i (user.rank)}
|
||||||
<div class="lb-user" class:alternate={i % 2 === 1} role="listitem"
|
<div class="lb-user" class:alternate={i % 2 === 1} role="listitem"
|
||||||
on:mouseover={() => hoveringUser = user.username} on:focus={() => {}}>
|
on:mouseover={() => hoveringUser = user.username} on:focus={() => {}}>
|
||||||
|
|
||||||
@@ -70,6 +106,8 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Pagination {page} {totalPages} on:updatePage={handleUpdatePage} />
|
||||||
|
|
||||||
<Tooltip triggeredBy=".name" loading={hoverLoading}>
|
<Tooltip triggeredBy=".name" loading={hoverLoading}>
|
||||||
<UserCard username={hoveringUser} {game} setLoading={l => hoverLoading = l} />
|
<UserCard username={hoveringUser} {game} setLoading={l => hoverLoading = l} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -132,5 +170,4 @@
|
|||||||
&.alternate
|
&.alternate
|
||||||
background-color: vars.$ov-light
|
background-color: vars.$ov-light
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user