feat: extract Pagination component and use it on all paginated pages
All checks were successful
Build and Push Frontend Image / build (push) Successful in 1m13s
All checks were successful
Build and Push Frontend Image / build (push) Successful in 1m13s
- New lib/components/pagination/pagination.svelte with numbered pages, ellipsis for large ranges, and prev/next buttons - All 6 admin pages (users, articles, videos, recordings, comments, queues) now show enumerated page numbers next to the "Showing X–Y of Z" label; offset is derived from page number * limit - Public pages (videos, models, magazine) replace their inline totalPages/pageNumbers derived state with the shared component - Removes ~80 lines of duplicated pagination logic across 9 files Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Button } from "$lib/components/ui/button";
|
||||||
|
import { _ } from "svelte-i18n";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
currentPage: number;
|
||||||
|
totalPages: number;
|
||||||
|
onPageChange: (page: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { currentPage, totalPages, onPageChange }: Props = $props();
|
||||||
|
|
||||||
|
const pageNumbers = $derived(() => {
|
||||||
|
const pages: (number | -1)[] = [];
|
||||||
|
if (totalPages <= 7) {
|
||||||
|
for (let i = 1; i <= totalPages; i++) pages.push(i);
|
||||||
|
} else {
|
||||||
|
pages.push(1);
|
||||||
|
if (currentPage > 3) pages.push(-1);
|
||||||
|
for (
|
||||||
|
let i = Math.max(2, currentPage - 1);
|
||||||
|
i <= Math.min(totalPages - 1, currentPage + 1);
|
||||||
|
i++
|
||||||
|
)
|
||||||
|
pages.push(i);
|
||||||
|
if (currentPage < totalPages - 2) pages.push(-1);
|
||||||
|
pages.push(totalPages);
|
||||||
|
}
|
||||||
|
return pages;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if totalPages > 1}
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
disabled={currentPage <= 1}
|
||||||
|
onclick={() => onPageChange(currentPage - 1)}
|
||||||
|
>
|
||||||
|
{$_("common.previous")}
|
||||||
|
</Button>
|
||||||
|
{#each pageNumbers() as p, i (i)}
|
||||||
|
{#if p === -1}
|
||||||
|
<span class="px-2 text-muted-foreground select-none">…</span>
|
||||||
|
{:else}
|
||||||
|
<Button
|
||||||
|
variant={p === currentPage ? "default" : "outline"}
|
||||||
|
size="sm"
|
||||||
|
class="min-w-9"
|
||||||
|
onclick={() => onPageChange(p)}
|
||||||
|
>
|
||||||
|
{p}
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
disabled={currentPage >= totalPages}
|
||||||
|
onclick={() => onPageChange(currentPage + 1)}
|
||||||
|
>
|
||||||
|
{$_("common.next")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
import type { Article } from "$lib/types";
|
import type { Article } from "$lib/types";
|
||||||
import TimeAgo from "javascript-time-ago";
|
import TimeAgo from "javascript-time-ago";
|
||||||
import Meta from "$lib/components/meta/meta.svelte";
|
import Meta from "$lib/components/meta/meta.svelte";
|
||||||
|
import Pagination from "$lib/components/pagination/pagination.svelte";
|
||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
|
|
||||||
@@ -204,7 +205,7 @@
|
|||||||
|
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
{#if data.total > data.limit}
|
{#if data.total > data.limit}
|
||||||
<div class="flex items-center justify-between mt-4">
|
<div class="flex items-center justify-between mt-4 flex-wrap gap-3">
|
||||||
<span class="text-sm text-muted-foreground">
|
<span class="text-sm text-muted-foreground">
|
||||||
{$_("admin.users.showing", {
|
{$_("admin.users.showing", {
|
||||||
values: {
|
values: {
|
||||||
@@ -214,32 +215,15 @@
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
<div class="flex gap-2">
|
<Pagination
|
||||||
<Button
|
currentPage={Math.floor(data.offset / data.limit) + 1}
|
||||||
size="sm"
|
totalPages={Math.ceil(data.total / data.limit)}
|
||||||
variant="outline"
|
onPageChange={(p) => {
|
||||||
disabled={data.offset === 0}
|
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
||||||
onclick={() => {
|
params.set("offset", String((p - 1) * data.limit));
|
||||||
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
goto(`?${params.toString()}`);
|
||||||
params.set("offset", String(Math.max(0, data.offset - data.limit)));
|
}}
|
||||||
goto(`?${params.toString()}`);
|
/>
|
||||||
}}
|
|
||||||
>
|
|
||||||
{$_("common.previous")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
disabled={data.offset + data.limit >= data.total}
|
|
||||||
onclick={() => {
|
|
||||||
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
|
||||||
params.set("offset", String(data.offset + data.limit));
|
|
||||||
goto(`?${params.toString()}`);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{$_("common.next")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
import * as Dialog from "$lib/components/ui/dialog";
|
import * as Dialog from "$lib/components/ui/dialog";
|
||||||
import TimeAgo from "javascript-time-ago";
|
import TimeAgo from "javascript-time-ago";
|
||||||
import Meta from "$lib/components/meta/meta.svelte";
|
import Meta from "$lib/components/meta/meta.svelte";
|
||||||
|
import Pagination from "$lib/components/pagination/pagination.svelte";
|
||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
const timeAgo = new TimeAgo("en");
|
const timeAgo = new TimeAgo("en");
|
||||||
@@ -153,7 +154,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if data.total > data.limit}
|
{#if data.total > data.limit}
|
||||||
<div class="flex items-center justify-between mt-4">
|
<div class="flex items-center justify-between mt-4 flex-wrap gap-3">
|
||||||
<span class="text-sm text-muted-foreground">
|
<span class="text-sm text-muted-foreground">
|
||||||
{$_("admin.users.showing", {
|
{$_("admin.users.showing", {
|
||||||
values: {
|
values: {
|
||||||
@@ -163,28 +164,15 @@
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
<div class="flex gap-2">
|
<Pagination
|
||||||
<Button
|
currentPage={Math.floor(data.offset / data.limit) + 1}
|
||||||
size="sm"
|
totalPages={Math.ceil(data.total / data.limit)}
|
||||||
variant="outline"
|
onPageChange={(p) => {
|
||||||
disabled={data.offset === 0}
|
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
||||||
onclick={() => {
|
params.set("offset", String((p - 1) * data.limit));
|
||||||
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
goto(`?${params.toString()}`);
|
||||||
params.set("offset", String(Math.max(0, data.offset - data.limit)));
|
}}
|
||||||
goto(`?${params.toString()}`);
|
/>
|
||||||
}}>{$_("common.previous")}</Button
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
disabled={data.offset + data.limit >= data.total}
|
|
||||||
onclick={() => {
|
|
||||||
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
|
||||||
params.set("offset", String(data.offset + data.limit));
|
|
||||||
goto(`?${params.toString()}`);
|
|
||||||
}}>{$_("common.next")}</Button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
import { Badge } from "$lib/components/ui/badge";
|
import { Badge } from "$lib/components/ui/badge";
|
||||||
import type { Job } from "$lib/services";
|
import type { Job } from "$lib/services";
|
||||||
import Meta from "$lib/components/meta/meta.svelte";
|
import Meta from "$lib/components/meta/meta.svelte";
|
||||||
|
import Pagination from "$lib/components/pagination/pagination.svelte";
|
||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
|
|
||||||
@@ -271,7 +272,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if data.total > data.limit}
|
{#if data.total > data.limit}
|
||||||
<div class="flex items-center justify-between mt-4">
|
<div class="flex items-center justify-between mt-4 flex-wrap gap-3">
|
||||||
<span class="text-sm text-muted-foreground">
|
<span class="text-sm text-muted-foreground">
|
||||||
{$_("admin.users.showing", {
|
{$_("admin.users.showing", {
|
||||||
values: {
|
values: {
|
||||||
@@ -281,24 +282,11 @@
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
<div class="flex gap-2">
|
<Pagination
|
||||||
<Button
|
currentPage={Math.floor(data.offset / data.limit) + 1}
|
||||||
size="sm"
|
totalPages={Math.ceil(data.total / data.limit)}
|
||||||
variant="outline"
|
onPageChange={(p) => navigate({ offset: String((p - 1) * data.limit) })}
|
||||||
disabled={data.offset === 0}
|
/>
|
||||||
onclick={() => navigate({ offset: String(Math.max(0, data.offset - data.limit)) })}
|
|
||||||
>
|
|
||||||
{$_("common.previous")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
disabled={data.offset + data.limit >= data.total}
|
|
||||||
onclick={() => navigate({ offset: String(data.offset + data.limit) })}
|
|
||||||
>
|
|
||||||
{$_("common.next")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
import type { Recording } from "$lib/types";
|
import type { Recording } from "$lib/types";
|
||||||
import TimeAgo from "javascript-time-ago";
|
import TimeAgo from "javascript-time-ago";
|
||||||
import Meta from "$lib/components/meta/meta.svelte";
|
import Meta from "$lib/components/meta/meta.svelte";
|
||||||
|
import Pagination from "$lib/components/pagination/pagination.svelte";
|
||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
const timeAgo = new TimeAgo("en");
|
const timeAgo = new TimeAgo("en");
|
||||||
@@ -179,7 +180,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if data.total > data.limit}
|
{#if data.total > data.limit}
|
||||||
<div class="flex items-center justify-between mt-4">
|
<div class="flex items-center justify-between mt-4 flex-wrap gap-3">
|
||||||
<span class="text-sm text-muted-foreground">
|
<span class="text-sm text-muted-foreground">
|
||||||
{$_("admin.users.showing", {
|
{$_("admin.users.showing", {
|
||||||
values: {
|
values: {
|
||||||
@@ -189,28 +190,15 @@
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
<div class="flex gap-2">
|
<Pagination
|
||||||
<Button
|
currentPage={Math.floor(data.offset / data.limit) + 1}
|
||||||
size="sm"
|
totalPages={Math.ceil(data.total / data.limit)}
|
||||||
variant="outline"
|
onPageChange={(p) => {
|
||||||
disabled={data.offset === 0}
|
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
||||||
onclick={() => {
|
params.set("offset", String((p - 1) * data.limit));
|
||||||
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
goto(`?${params.toString()}`);
|
||||||
params.set("offset", String(Math.max(0, data.offset - data.limit)));
|
}}
|
||||||
goto(`?${params.toString()}`);
|
/>
|
||||||
}}>{$_("common.previous")}</Button
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
disabled={data.offset + data.limit >= data.total}
|
|
||||||
onclick={() => {
|
|
||||||
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
|
||||||
params.set("offset", String(data.offset + data.limit));
|
|
||||||
goto(`?${params.toString()}`);
|
|
||||||
}}>{$_("common.next")}</Button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
import * as Dialog from "$lib/components/ui/dialog";
|
import * as Dialog from "$lib/components/ui/dialog";
|
||||||
import type { User } from "$lib/types";
|
import type { User } from "$lib/types";
|
||||||
import Meta from "$lib/components/meta/meta.svelte";
|
import Meta from "$lib/components/meta/meta.svelte";
|
||||||
|
import Pagination from "$lib/components/pagination/pagination.svelte";
|
||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
|
|
||||||
@@ -228,7 +229,7 @@
|
|||||||
|
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
{#if data.total > data.limit}
|
{#if data.total > data.limit}
|
||||||
<div class="flex items-center justify-between mt-4">
|
<div class="flex items-center justify-between mt-4 flex-wrap gap-3">
|
||||||
<span class="text-sm text-muted-foreground">
|
<span class="text-sm text-muted-foreground">
|
||||||
{$_("admin.users.showing", {
|
{$_("admin.users.showing", {
|
||||||
values: {
|
values: {
|
||||||
@@ -238,32 +239,15 @@
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
<div class="flex gap-2">
|
<Pagination
|
||||||
<Button
|
currentPage={Math.floor(data.offset / data.limit) + 1}
|
||||||
size="sm"
|
totalPages={Math.ceil(data.total / data.limit)}
|
||||||
variant="outline"
|
onPageChange={(p) => {
|
||||||
disabled={data.offset === 0}
|
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
||||||
onclick={() => {
|
params.set("offset", String((p - 1) * data.limit));
|
||||||
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
goto(`?${params.toString()}`);
|
||||||
params.set("offset", String(Math.max(0, data.offset - data.limit)));
|
}}
|
||||||
goto(`?${params.toString()}`);
|
/>
|
||||||
}}
|
|
||||||
>
|
|
||||||
{$_("common.previous")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
disabled={data.offset + data.limit >= data.total}
|
|
||||||
onclick={() => {
|
|
||||||
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
|
||||||
params.set("offset", String(data.offset + data.limit));
|
|
||||||
goto(`?${params.toString()}`);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{$_("common.next")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
import * as Dialog from "$lib/components/ui/dialog";
|
import * as Dialog from "$lib/components/ui/dialog";
|
||||||
import type { Video } from "$lib/types";
|
import type { Video } from "$lib/types";
|
||||||
import Meta from "$lib/components/meta/meta.svelte";
|
import Meta from "$lib/components/meta/meta.svelte";
|
||||||
|
import Pagination from "$lib/components/pagination/pagination.svelte";
|
||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
|
|
||||||
@@ -209,7 +210,7 @@
|
|||||||
|
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
{#if data.total > data.limit}
|
{#if data.total > data.limit}
|
||||||
<div class="flex items-center justify-between mt-4">
|
<div class="flex items-center justify-between mt-4 flex-wrap gap-3">
|
||||||
<span class="text-sm text-muted-foreground">
|
<span class="text-sm text-muted-foreground">
|
||||||
{$_("admin.users.showing", {
|
{$_("admin.users.showing", {
|
||||||
values: {
|
values: {
|
||||||
@@ -219,32 +220,15 @@
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
<div class="flex gap-2">
|
<Pagination
|
||||||
<Button
|
currentPage={Math.floor(data.offset / data.limit) + 1}
|
||||||
size="sm"
|
totalPages={Math.ceil(data.total / data.limit)}
|
||||||
variant="outline"
|
onPageChange={(p) => {
|
||||||
disabled={data.offset === 0}
|
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
||||||
onclick={() => {
|
params.set("offset", String((p - 1) * data.limit));
|
||||||
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
goto(`?${params.toString()}`);
|
||||||
params.set("offset", String(Math.max(0, data.offset - data.limit)));
|
}}
|
||||||
goto(`?${params.toString()}`);
|
/>
|
||||||
}}
|
|
||||||
>
|
|
||||||
{$_("common.previous")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
disabled={data.offset + data.limit >= data.total}
|
|
||||||
onclick={() => {
|
|
||||||
const params = new SvelteURLSearchParams(page.url.searchParams.toString());
|
|
||||||
params.set("offset", String(data.offset + data.limit));
|
|
||||||
goto(`?${params.toString()}`);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{$_("common.next")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
import Meta from "$lib/components/meta/meta.svelte";
|
import Meta from "$lib/components/meta/meta.svelte";
|
||||||
import SexyBackground from "$lib/components/background/background.svelte";
|
import SexyBackground from "$lib/components/background/background.svelte";
|
||||||
import PageHero from "$lib/components/page-hero/page-hero.svelte";
|
import PageHero from "$lib/components/page-hero/page-hero.svelte";
|
||||||
|
import Pagination from "$lib/components/pagination/pagination.svelte";
|
||||||
|
|
||||||
const timeAgo = new TimeAgo("en");
|
const timeAgo = new TimeAgo("en");
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
@@ -50,22 +51,6 @@
|
|||||||
goto(`?${params.toString()}`);
|
goto(`?${params.toString()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalPages = $derived(Math.ceil(data.total / data.limit));
|
|
||||||
|
|
||||||
const pageNumbers = $derived(() => {
|
|
||||||
const pages: (number | -1)[] = [];
|
|
||||||
if (totalPages <= 7) {
|
|
||||||
for (let i = 1; i <= totalPages; i++) pages.push(i);
|
|
||||||
} else {
|
|
||||||
pages.push(1);
|
|
||||||
if (data.page > 3) pages.push(-1);
|
|
||||||
for (let i = Math.max(2, data.page - 1); i <= Math.min(totalPages - 1, data.page + 1); i++)
|
|
||||||
pages.push(i);
|
|
||||||
if (data.page < totalPages - 2) pages.push(-1);
|
|
||||||
pages.push(totalPages);
|
|
||||||
}
|
|
||||||
return pages;
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Meta title={$_("magazine.title")} description={$_("magazine.description")} />
|
<Meta title={$_("magazine.title")} description={$_("magazine.description")} />
|
||||||
@@ -308,38 +293,13 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
{#if totalPages > 1}
|
{#if Math.ceil(data.total / data.limit) > 1}
|
||||||
<div class="flex flex-col items-center gap-3 mt-10">
|
<div class="flex flex-col items-center gap-3 mt-10">
|
||||||
<div class="flex items-center gap-1">
|
<Pagination
|
||||||
<Button
|
currentPage={data.page}
|
||||||
variant="outline"
|
totalPages={Math.ceil(data.total / data.limit)}
|
||||||
size="sm"
|
onPageChange={goToPage}
|
||||||
disabled={data.page <= 1}
|
/>
|
||||||
onclick={() => goToPage(data.page - 1)}
|
|
||||||
class="border-primary/20 hover:bg-primary/10">{$_("common.previous")}</Button
|
|
||||||
>
|
|
||||||
{#each pageNumbers() as p, i (i)}
|
|
||||||
{#if p === -1}
|
|
||||||
<span class="px-2 text-muted-foreground select-none">…</span>
|
|
||||||
{:else}
|
|
||||||
<Button
|
|
||||||
variant={p === data.page ? "default" : "outline"}
|
|
||||||
size="sm"
|
|
||||||
onclick={() => goToPage(p)}
|
|
||||||
class={p === data.page
|
|
||||||
? "bg-gradient-to-r from-primary to-accent min-w-9"
|
|
||||||
: "border-primary/20 hover:bg-primary/10 min-w-9"}>{p}</Button
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
disabled={data.page >= totalPages}
|
|
||||||
onclick={() => goToPage(data.page + 1)}
|
|
||||||
class="border-primary/20 hover:bg-primary/10">{$_("common.next")}</Button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<p class="text-sm text-muted-foreground">
|
<p class="text-sm text-muted-foreground">
|
||||||
{$_("common.total_results", { values: { total: data.total } })}
|
{$_("common.total_results", { values: { total: data.total } })}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
import Meta from "$lib/components/meta/meta.svelte";
|
import Meta from "$lib/components/meta/meta.svelte";
|
||||||
import SexyBackground from "$lib/components/background/background.svelte";
|
import SexyBackground from "$lib/components/background/background.svelte";
|
||||||
import PageHero from "$lib/components/page-hero/page-hero.svelte";
|
import PageHero from "$lib/components/page-hero/page-hero.svelte";
|
||||||
|
import Pagination from "$lib/components/pagination/pagination.svelte";
|
||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
|
|
||||||
@@ -43,22 +44,6 @@
|
|||||||
goto(`?${params.toString()}`);
|
goto(`?${params.toString()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalPages = $derived(Math.ceil(data.total / data.limit));
|
|
||||||
|
|
||||||
const pageNumbers = $derived(() => {
|
|
||||||
const pages: (number | -1)[] = [];
|
|
||||||
if (totalPages <= 7) {
|
|
||||||
for (let i = 1; i <= totalPages; i++) pages.push(i);
|
|
||||||
} else {
|
|
||||||
pages.push(1);
|
|
||||||
if (data.page > 3) pages.push(-1);
|
|
||||||
for (let i = Math.max(2, data.page - 1); i <= Math.min(totalPages - 1, data.page + 1); i++)
|
|
||||||
pages.push(i);
|
|
||||||
if (data.page < totalPages - 2) pages.push(-1);
|
|
||||||
pages.push(totalPages);
|
|
||||||
}
|
|
||||||
return pages;
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Meta title={$_("models.title")} description={$_("models.description")} />
|
<Meta title={$_("models.title")} description={$_("models.description")} />
|
||||||
@@ -196,38 +181,13 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
{#if totalPages > 1}
|
{#if Math.ceil(data.total / data.limit) > 1}
|
||||||
<div class="flex flex-col items-center gap-3 mt-10">
|
<div class="flex flex-col items-center gap-3 mt-10">
|
||||||
<div class="flex items-center gap-1">
|
<Pagination
|
||||||
<Button
|
currentPage={data.page}
|
||||||
variant="outline"
|
totalPages={Math.ceil(data.total / data.limit)}
|
||||||
size="sm"
|
onPageChange={goToPage}
|
||||||
disabled={data.page <= 1}
|
/>
|
||||||
onclick={() => goToPage(data.page - 1)}
|
|
||||||
class="border-primary/20 hover:bg-primary/10">{$_("common.previous")}</Button
|
|
||||||
>
|
|
||||||
{#each pageNumbers() as p, i (i)}
|
|
||||||
{#if p === -1}
|
|
||||||
<span class="px-2 text-muted-foreground select-none">…</span>
|
|
||||||
{:else}
|
|
||||||
<Button
|
|
||||||
variant={p === data.page ? "default" : "outline"}
|
|
||||||
size="sm"
|
|
||||||
onclick={() => goToPage(p)}
|
|
||||||
class={p === data.page
|
|
||||||
? "bg-gradient-to-r from-primary to-accent min-w-9"
|
|
||||||
: "border-primary/20 hover:bg-primary/10 min-w-9"}>{p}</Button
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
disabled={data.page >= totalPages}
|
|
||||||
onclick={() => goToPage(data.page + 1)}
|
|
||||||
class="border-primary/20 hover:bg-primary/10">{$_("common.next")}</Button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<p class="text-sm text-muted-foreground">
|
<p class="text-sm text-muted-foreground">
|
||||||
{$_("common.total_results", { values: { total: data.total } })}
|
{$_("common.total_results", { values: { total: data.total } })}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
import Meta from "$lib/components/meta/meta.svelte";
|
import Meta from "$lib/components/meta/meta.svelte";
|
||||||
import SexyBackground from "$lib/components/background/background.svelte";
|
import SexyBackground from "$lib/components/background/background.svelte";
|
||||||
import PageHero from "$lib/components/page-hero/page-hero.svelte";
|
import PageHero from "$lib/components/page-hero/page-hero.svelte";
|
||||||
|
import Pagination from "$lib/components/pagination/pagination.svelte";
|
||||||
import TimeAgo from "javascript-time-ago";
|
import TimeAgo from "javascript-time-ago";
|
||||||
import { formatVideoDuration } from "$lib/utils";
|
import { formatVideoDuration } from "$lib/utils";
|
||||||
|
|
||||||
@@ -46,22 +47,6 @@
|
|||||||
goto(`?${params.toString()}`);
|
goto(`?${params.toString()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalPages = $derived(Math.ceil(data.total / data.limit));
|
|
||||||
|
|
||||||
const pageNumbers = $derived(() => {
|
|
||||||
const pages: (number | -1)[] = [];
|
|
||||||
if (totalPages <= 7) {
|
|
||||||
for (let i = 1; i <= totalPages; i++) pages.push(i);
|
|
||||||
} else {
|
|
||||||
pages.push(1);
|
|
||||||
if (data.page > 3) pages.push(-1);
|
|
||||||
for (let i = Math.max(2, data.page - 1); i <= Math.min(totalPages - 1, data.page + 1); i++)
|
|
||||||
pages.push(i);
|
|
||||||
if (data.page < totalPages - 2) pages.push(-1);
|
|
||||||
pages.push(totalPages);
|
|
||||||
}
|
|
||||||
return pages;
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Meta title={$_("videos.title")} description={$_("videos.description")} />
|
<Meta title={$_("videos.title")} description={$_("videos.description")} />
|
||||||
@@ -256,38 +241,13 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
{#if totalPages > 1}
|
{#if Math.ceil(data.total / data.limit) > 1}
|
||||||
<div class="flex flex-col items-center gap-3 mt-10">
|
<div class="flex flex-col items-center gap-3 mt-10">
|
||||||
<div class="flex items-center gap-1">
|
<Pagination
|
||||||
<Button
|
currentPage={data.page}
|
||||||
variant="outline"
|
totalPages={Math.ceil(data.total / data.limit)}
|
||||||
size="sm"
|
onPageChange={goToPage}
|
||||||
disabled={data.page <= 1}
|
/>
|
||||||
onclick={() => goToPage(data.page - 1)}
|
|
||||||
class="border-primary/20 hover:bg-primary/10">{$_("common.previous")}</Button
|
|
||||||
>
|
|
||||||
{#each pageNumbers() as p, i (i)}
|
|
||||||
{#if p === -1}
|
|
||||||
<span class="px-2 text-muted-foreground select-none">…</span>
|
|
||||||
{:else}
|
|
||||||
<Button
|
|
||||||
variant={p === data.page ? "default" : "outline"}
|
|
||||||
size="sm"
|
|
||||||
onclick={() => goToPage(p)}
|
|
||||||
class={p === data.page
|
|
||||||
? "bg-gradient-to-r from-primary to-accent min-w-9"
|
|
||||||
: "border-primary/20 hover:bg-primary/10 min-w-9"}>{p}</Button
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
disabled={data.page >= totalPages}
|
|
||||||
onclick={() => goToPage(data.page + 1)}
|
|
||||||
class="border-primary/20 hover:bg-primary/10">{$_("common.next")}</Button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<p class="text-sm text-muted-foreground">
|
<p class="text-sm text-muted-foreground">
|
||||||
{$_("common.total_results", { values: { total: data.total } })}
|
{$_("common.total_results", { values: { total: data.total } })}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user