Initial SvelteKit frontend port of windwiderstand.de
Full parity with Astro site: content rows, post/tag routes, pagination, event badges + OSM map, comments, Live-Search via /api/search-index, CMS image proxy, RSS, sitemap. Deploy: Dockerfile + docker-compose.prod.yml + Gitea Actions workflow to build + push to git.pm86.de registry and ssh-deploy to Contabo.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
<script lang="ts">
|
||||
import '$lib/iconify-offline';
|
||||
import Icon from "@iconify/svelte";
|
||||
import { useTranslate } from "$lib/translations";
|
||||
import { T } from "$lib/translations";
|
||||
|
||||
const t = useTranslate();
|
||||
|
||||
let {
|
||||
currentPage = 1,
|
||||
totalPages = 1,
|
||||
basePath = "/posts",
|
||||
activeTag = null,
|
||||
}: {
|
||||
currentPage: number;
|
||||
totalPages: number;
|
||||
basePath?: string;
|
||||
activeTag?: string | null;
|
||||
} = $props();
|
||||
|
||||
function tagHref(tagSlug: string | null): string {
|
||||
if (!tagSlug) return basePath;
|
||||
return `${basePath}/tag/${encodeURIComponent(tagSlug)}`;
|
||||
}
|
||||
|
||||
function pageHref(page: number): string {
|
||||
if (page <= 1) return tagHref(activeTag ?? null);
|
||||
const tagPart = activeTag
|
||||
? `/tag/${encodeURIComponent(activeTag)}`
|
||||
: "";
|
||||
return `${basePath}${tagPart}/page/${page}`;
|
||||
}
|
||||
|
||||
const showPagination = $derived(totalPages > 1);
|
||||
const hasPrev = $derived(currentPage > 1);
|
||||
const hasNext = $derived(currentPage < totalPages);
|
||||
const prevPage = $derived(currentPage - 1);
|
||||
const nextPage = $derived(currentPage + 1);
|
||||
|
||||
const pageNumbers = $derived.by(() => {
|
||||
const max = 5;
|
||||
let start = Math.max(1, currentPage - Math.floor(max / 2));
|
||||
const end = Math.min(totalPages, start + max - 1);
|
||||
if (end - start + 1 < max) start = Math.max(1, end - max + 1);
|
||||
return Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
||||
});
|
||||
|
||||
const paginationLinkClass =
|
||||
" bg-linear-to-b from-stein-50 to-stein-100 rounded-full h-6 w-6 mx-[2px] flex justify-center items-center text-stein-950 no-underline text-xs font-medium border border-stein-200 shadow-md";
|
||||
</script>
|
||||
|
||||
{#if showPagination}
|
||||
<div class="inline-flex py-4">
|
||||
<div class="flex">
|
||||
{#if hasPrev}
|
||||
<a href={pageHref(prevPage)} class={paginationLinkClass} aria-label={t(T.pagination_prev)}>
|
||||
<Icon icon="mdi:chevron-left" class="text-xs" aria-hidden="true" />
|
||||
</a>
|
||||
{/if}
|
||||
{#each pageNumbers as num}
|
||||
<a
|
||||
href={pageHref(num)}
|
||||
class="{paginationLinkClass} {num === currentPage ? 'opacity-50 shadow-none' : ''}"
|
||||
aria-current={num === currentPage ? 'page' : undefined}
|
||||
>
|
||||
{num}
|
||||
</a>
|
||||
{/each}
|
||||
{#if hasNext}
|
||||
<a href={pageHref(nextPage)} class={paginationLinkClass} aria-label={t(T.pagination_next)}>
|
||||
<Icon icon="mdi:chevron-right" class="text-xs" aria-hidden="true" />
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
Reference in New Issue
Block a user