add pagination component

Signed-off-by: Tobias Erbshäußer <tobias@tesoft.dev>
This commit is contained in:
2026-05-24 09:22:42 +02:00
parent f54b73b8fb
commit 1b0415d767
2 changed files with 123 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
<template id="tesoft-pagination-template">
<style>
@import "/src/styles/default.css";
:host {
display: block;
}
:host > div {
align-items: center;
display: grid;
grid-template-columns: auto auto auto;
grid-template-rows: auto;
}
.cur-page {
font-size: 1.8rem;
padding: 0 1rem;
}
</style>
<div>
<tesoft-button class="prev" disabled>
<svg xmlns="http://www.w3.org/2000/svg" height="2.4rem" viewBox="0 -960 960 960" width="2.4rem" fill="#000000">
<path d="M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z"/>
</svg>
</tesoft-button>
<div class="cur-page">
1
</div>
<tesoft-button class="next" disabled>
<svg xmlns="http://www.w3.org/2000/svg" height="2.4rem" viewBox="0 -960 960 960" width="2.4rem" fill="#000000">
<path d="M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z"/>
</svg>
</tesoft-button>
</div>
</template>
<script src="/src/components/pagination.ts" type="module"></script>
{% includeOnce 'components/button.njk' %}
+83
View File
@@ -0,0 +1,83 @@
import {TesoftComponent} from "../scripts/main.ts";
import {TesoftButton} from "./button.ts";
export class TesoftPagination extends TesoftComponent {
static observedAttributes = ["cur-page", "last-page"];
private readonly curPageDiv: HTMLDivElement;
private readonly prevButton: TesoftButton;
private readonly nextButton: TesoftButton;
constructor() {
super();
const template = document.getElementById("tesoft-pagination-template") as HTMLTemplateElement;
const templateContent = template.content;
const shadowRoot = this.attachShadow({mode: "open"});
shadowRoot.appendChild(templateContent.cloneNode(true));
this.curPageDiv = shadowRoot.querySelector<HTMLDivElement>(".cur-page")!;
this.prevButton = shadowRoot.querySelector<TesoftButton>(".prev")!;
this.nextButton = shadowRoot.querySelector<TesoftButton>(".next")!;
}
// noinspection JSUnusedGlobalSymbols
attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
if (name === "cur-page") {
this.update(this.parsePage(newValue), this.parsePage(this.getAttribute("last-page")));
} else if (name === "last-page") {
this.update(this.parsePage(this.getAttribute("cur-page")), this.parsePage(newValue));
}
}
set curPage(value: number) {
this.setAttribute("cur-page", value.toString());
}
set lastPage(value: number) {
this.setAttribute("last-page", value.toString());
}
private update(curPage: number, lastPage: number) {
this.curPageDiv.innerText = curPage.toString();
if (curPage <= 1) {
this.prevButton.setAttribute("disabled", "");
} else {
this.prevButton.removeAttribute("disabled");
}
this.prevButton.onclick = () => {
this.dispatchEvent(new CustomEvent("update-page", {
bubbles: true,
cancelable: true,
composed: true,
detail: {
page: curPage - 1,
},
}));
};
if (curPage >= lastPage) {
this.nextButton.setAttribute("disabled", "");
} else {
this.nextButton.removeAttribute("disabled");
}
this.nextButton.onclick = () => {
this.dispatchEvent(new CustomEvent("updatePage", {
bubbles: true,
cancelable: true,
composed: true,
detail: {
page: curPage + 1,
},
}));
};
}
private parsePage(str: string | null): number {
return str ? parseInt(str) : 1;
}
}
customElements.define("tesoft-pagination", TesoftPagination);