Pagination
Links to the pages of a long list: first, last, the ones around this page, and Previous and Next.
Demo
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.qwemain.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>}Related
AccordionSections that open under their titles, on the browser's own <details>: exclusive with a group.5 views · 8 downloadsAlphabetIndexA to Z links into a list sorted by name; letters with nothing under them stay in place, disabled.4 views · 7 downloadsBackToTopA button in the corner that shows once the page is scrolled down and takes it back to the top.6 views · 8 downloadsBottomNavA fixed bar of icon tabs along the bottom of a phone's screen, with counts and the current one marked.6 views · 8 downloadsBreadcrumbsWhere this page sits: a trail of links up to the home page, the last one marked as this page.5 views · 7 downloadsCollapsibleNavSide navigation in groups that fold under their titles, the browser remembering which are open.6 views · 8 downloads
Thread
Thread 0 posts
On Pagination: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.