Implemented phase 1 for the POC prototype in the Website service.

This commit is contained in:
javier committed 2026-09-21 11:16:52 +02:00
1 parent 6d7ab4bcba
commit ea89ea892a
37 files changed
+4173 -43

No files matched your search

@@ -0,0 +1,107 @@
import Elementary
/// The page links under a card grid; renders nothing for a single page.
struct Pagination: HTML {
// MARK: Properties
/// The page shown, counted from one.
let current: Int
/// The path of a given page.
let path: @Sendable (Int) -> String
/// The number of pages.
let total: Int
// MARK: Initializers
/// Creates the page links.
/// - Parameters:
/// - current: the page shown, counted from one.
/// - total: the number of pages.
/// - path: the path of a given page.
init(
current: Int,
total: Int,
path: @escaping @Sendable (Int) -> String
) {
self.current = current
self.path = path
self.total = total
}
// MARK: Computed
var body: some HTML {
if total > 1 {
nav(
.class("pagination"),
.custom(
name: "aria-label",
value: "Pagination"
)
) {
for page in 1...total {
if page == current {
a(
.class("pagination__page"),
.href(path(page)),
.custom(
name: "aria-current",
value: "page"
)
) {
"\(page)"
}
} else {
a(
.class("pagination__page"),
.href(path(page))
) {
"\(page)"
}
}
}
if current < total {
a(
.class("pagination__next"),
.href(path(current + 1))
) {
"Next"
}
}
}
}
}
}
// MARK: - Extensions
extension Pagination {
// MARK: Methods
/// Cuts the items of one page out of a list, clamping the page to the list's range.
/// - Parameters:
/// - items: the whole list.
/// - page: the page asked for, counted from one.
/// - size: the number of items on a page.
/// - Returns: the page's items, the page actually shown, and the number of pages.
static func slice<Item>(
_ items: [Item],
page: Int,
size: Int
) -> (items: [Item], current: Int, total: Int) {
let total = max((items.count + size - 1) / size, 1)
let current = min(max(page, 1), total)
return (
Array(items.dropFirst((current - 1) * size).prefix(size)),
current,
total
)
}
}