Navigation

Pagination

Links to the pages of a long list: first, last, the ones around this page, and Previous and Next.

#navigation#data#no-js

Demo

Preview

Showing posts 21–30 (page 3 of 8, from state).

Get it

It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.

$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/pagination.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/pagination.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/pagination.qwe
component PaginationDemoLive() {    state page = 3    <div.demo-stack>        <Pagination page={page} pages={8} on_change={(p) => { page = p }}/>        <p.demo-note>Showing posts {(page - 1) * 10 + 1}–{page * 10} (page {page} of 8, from state).</p>    </div>}view PaginationDemo() =    <div.demo-stack>        <Pagination page={5} pages={20} href="/posts?page={page}"/>        <Pagination page={1} pages={20} href="/posts?page={page}" size="sm"/>        <Pagination page={20} pages={20} href="/posts?page={page}" size="sm"/>        <PaginationDemoLive/>    </div>

Source

ui/pagination.qwe
// Pagination: links to the pages of a long list, with the numbers around this one.////   <Pagination page={4} pages={20} href="/posts?page={page}"/>//   <Pagination page={page} pages={8} on_change={(p) => { page = p }}/>//// page: this page, from 1. pages: how many there are. href: each link's address,// with "{page}" standing for its number ("?page={page}" by default).// It shows the first and last pages, `siblings` numbers either side of this one// (1 by default) and … for the gaps: 1 … 4 5 6 … 20. Previous and Next stay in// place, disabled at the ends; on phones they show only their arrow.// size: "sm" or "md" (default). label: what screen readers call it ("Pagination").// on_change(page): inside one of your components, called with the page clicked,// instead of following the link.import ui/theme.qwe use ui_clslet pagination_css = css`.ui-pagination ul { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin: 0; padding: 0; list-style: none; }.ui-pagination-link {  display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-width: 36px; height: 36px;  padding: 0 10px; border: 1px solid transparent; border-radius: var(--ui-radius-sm); background: transparent;  color: var(--ui-fg); font: 500 14px/1 var(--ui-font); font-variant-numeric: tabular-nums; text-decoration: none;  transition: background .15s, border-color .15s, color .15s;}a.ui-pagination-link:hover { background: var(--ui-subtle); border-color: var(--ui-border); }.ui-pagination-link:focus-visible { outline: none; box-shadow: var(--ui-focus); }.ui-pagination-link[aria-current="page"] { background: var(--ui-accent); border-color: var(--ui-accent); color: var(--ui-accent-fg); }.ui-pagination-link[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }.ui-pagination-gap { display: inline-flex; align-items: flex-end; justify-content: center; min-width: 24px; color: var(--ui-muted); }.ui-pagination-arrow { width: 7px; height: 7px; border: solid currentColor; border-width: 0 0 1.5px 1.5px; transform: rotate(45deg); }.ui-pagination-next .ui-pagination-arrow { transform: rotate(-135deg); }.ui-pagination-sm .ui-pagination-link { min-width: 30px; height: 30px; padding: 0 8px; font-size: 13px; }@media (max-width: 600px) {  .ui-pagination ul { gap: 2px; }  .ui-pagination .ui-pagination-link { min-width: 30px; padding: 0 4px; }  .ui-pagination-gap { min-width: 16px; }  .ui-pagination-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }}@media (prefers-reduced-motion: reduce) { .ui-pagination-link { transition: none; } }`// The pages to show around `page`: numbers, and "…" for each gap.fn pagination_window(page: int, pages: int, siblings: int = 1) -> list {    if pages <= 1 { return [1] }    let lo = max([2, min([page - siblings, pages - 1 - 2 * siblings])])    let hi = min([pages - 1, max([page + siblings, 2 + 2 * siblings])])    let left = lo > 3 ? ["…"] : lo == 3 ? [2] : []    let right = hi < pages - 2 ? ["…"] : hi == pages - 2 ? [pages - 1] : []    [1] + left + range(lo, hi + 1) + right + [pages]}view Pagination(page: int = 1, pages: int = 1, href: str = "?page={page}", siblings: int = 1,                size: str = "md", label: str = "Pagination", on_change = null, class: str? = null) {    style global pagination_css    let at = max([1, min([page, pages])])    let link = (n: int) => replace(href, "{page}", str(n))    let go = (n: int) => (e) => {        if on_change != null {            e.preventDefault()            on_change(n)        }    }    <nav class={ui_cls(["ui-pagination", size == "sm" && "ui-pagination-sm", class])} aria-label={label}>        <ul>            <li>{at > 1                ? <a.ui-pagination-link.ui-pagination-prev href={link(at - 1)} rel="prev" @click={go(at - 1)}>                      <span.ui-pagination-arrow aria-hidden="true"></span><span.ui-pagination-word>Previous</span></a>                : <span.ui-pagination-link.ui-pagination-prev aria-disabled="true">                      <span.ui-pagination-arrow aria-hidden="true"></span><span.ui-pagination-word>Previous</span></span>}</li>            {for n in pagination_window(at, pages, siblings) => <li>                {n == "…"                    ? <span.ui-pagination-gap aria-hidden="true">…</span>                    : <a.ui-pagination-link href={link(n)} aria-label={`Page ${n}`}                         aria-current={n == at ? "page" : null} @click={go(n)}>{n}</a>}            </li>}            <li>{at < pages                ? <a.ui-pagination-link.ui-pagination-next href={link(at + 1)} rel="next" @click={go(at + 1)}>                      <span.ui-pagination-word>Next</span><span.ui-pagination-arrow aria-hidden="true"></span></a>                : <span.ui-pagination-link.ui-pagination-next aria-disabled="true">                      <span.ui-pagination-word>Next</span><span.ui-pagination-arrow aria-hidden="true"></span></span>}</li>        </ul>    </nav>}
Thread
66Useful? Like it, or add to its thread below.

Thread 0 posts

On Pagination: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.