RankingList
A ranked list with how each item moved since last time: up, down, the same or new, said in words to screen readers.
Demo
- up 2 placesMidnight City1.2M plays
- down 1 placeDreams1.1M plays
- newRunning Up That Hill980K plays
- no changeHeroes870K plays
- down 3 placesBlue Monday700K plays
- up 6 placesquillo components
- no changecss nesting
- newserver functions
- down 1 placesqlite wal
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/ranking_list.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/ranking_list.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/ranking_list.qwe
view RankingListDemo() = <div.demo-row style="align-items: flex-start; gap: 32px"> <div style="flex: 1 1 300px; max-width: 400px"> <RankingList id="ranking-list-demo-songs" label="Top songs this week" items={[ { label: "Midnight City", meta: "M83", previous: 3, value: "1.2M plays", href: "#midnight" }, { label: "Dreams", meta: "Fleetwood Mac", previous: 1, value: "1.1M plays" }, { label: "Running Up That Hill", meta: "Kate Bush", value: "980K plays" }, { label: "Heroes", meta: "David Bowie", previous: 4, value: "870K plays" }, { label: "Blue Monday", meta: "New Order", previous: 2, value: "700K plays" }, ]}/> </div> <div style="flex: 1 1 220px; max-width: 300px"> <RankingList id="ranking-list-demo-searches" label="Trending searches" start={11} show_new={false} items={[ { label: "quillo components", move: "up", by: 6 }, { label: "css nesting", move: "same" }, { label: "server functions", move: "new" }, { label: "sqlite wal", move: "down", by: 1 }, ]}/> </div> </div>Source
ui/ranking_list.qwe
// RankingList: a numbered list of what ranks where now, with how each moved since// last time: ▲ 3 up, ▼ 1 down, – the same, NEW: charts, trending searches, a// league table, the most-read articles.//// <RankingList label="Top songs" items={[// { label: "Midnight City", meta: "M83", previous: 3, value: "1.2M plays" },// { label: "Dreams", meta: "Fleetwood Mac", previous: 1 },// { label: "Running Up That Hill", meta: "Kate Bush" }, NEW// ]}/>//// items: in their order now, maps of { label, meta?, value?, href?, previous?,// move? }: previous is the place it had last time (left out: it is new), from// which the move is worked out; or move says it: "up", "down", "same" or "new",// with by (how many places). meta: a line under the label. value: on the right// ("1.2M plays"). href: the label links there. start: the first place's number// (1). show_new: false shows a dash for new items instead of NEW. label: the// list's name for screen readers. id: the element's id. It is an <ol>; each// move is said in words to screen readers ("up 2 places").import ui/theme.qwe use ui_clslet ranking_list_css = css`.ui-ranking { margin: 0; padding: 0; list-style: none; font: 14px/1.4 var(--ui-font); color: var(--ui-fg); }.ui-ranking-row { display: flex; align-items: center; gap: 12px; padding: 9px 4px; }.ui-ranking-row + .ui-ranking-row { border-top: 1px solid var(--ui-border); }.ui-ranking-num { flex: none; width: 28px; text-align: right; font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ui-fg); }.ui-ranking-move { flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 2px; min-width: 42px; height: 22px; padding: 0 6px; border-radius: 999px; font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; --t: var(--ui-muted); color: var(--t); background: color-mix(in srgb, var(--t) 12%, transparent); }.ui-ranking-up { --t: var(--ui-success); }.ui-ranking-down { --t: var(--ui-danger); }.ui-ranking-new { --t: var(--ui-accent); letter-spacing: .04em; }.ui-ranking-same { background: none; }.ui-ranking-move svg { width: 9px; height: 9px; }.ui-ranking-what { flex: 1; min-width: 0; display: grid; }.ui-ranking-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; color: inherit; text-decoration: none; }a.ui-ranking-label:hover { color: var(--ui-accent); text-decoration: underline; }a.ui-ranking-label:focus-visible { outline: none; box-shadow: var(--ui-focus); border-radius: 3px; }.ui-ranking-meta { color: var(--ui-muted); font-size: 12px; }.ui-ranking-value { flex: none; color: var(--ui-muted); font-size: 13px; font-variant-numeric: tabular-nums; }`// How an item moved: { way: "up" | "down" | "same" | "new", by }.fn ranking_list_move(it: map, place: int) -> map { if it.move != null { return { way: it.move, by: it.by ?? 0 } } if it.previous == null { return { way: "new", by: 0 } } let d = it.previous - place { way: d > 0 ? "up" : (d < 0 ? "down" : "same"), by: abs(d) }}view RankingList(items: list, start: int = 1, show_new: bool = true, label: str? = null, id: str? = null, class: str? = null) { style global ranking_list_css <ol class={ui_cls(["ui-ranking", class])} id={id} aria-label={label} start={start != 1 ? str(start) : null}> {for [i, it] in enumerate(items) => { let place = start + i let m = ranking_list_move(it, place) let places = m.by == 1 ? "place" : "places" let words = match m.way { "up" => m.by > 0 ? `up ${m.by} ${places}` : "up" "down" => m.by > 0 ? `down ${m.by} ${places}` : "down" "new" => "new" _ => "no change" } <li.ui-ranking-row data-move={m.way}> <span.ui-ranking-num aria-hidden="true">{place}</span> <span class={ui_cls(["ui-ranking-move", `ui-ranking-${m.way == "new" && !show_new ? "same" : m.way}`])}> <span aria-hidden="true"> {match m.way { "up" => [<svg viewBox="0 0 10 10" fill="currentColor"><path d="M5 1.5L9 8H1z"/></svg>, m.by > 0 && str(m.by)] "down" => [<svg viewBox="0 0 10 10" fill="currentColor"><path d="M5 8.5L1 2h8z"/></svg>, m.by > 0 && str(m.by)] "new" => show_new ? "NEW" : "–" _ => "–" }} </span> <span.ui-sr>{words}</span> </span> <span.ui-ranking-what> {it.href != null ? <a.ui-ranking-label href={it.href}>{it.label}</a> : <span.ui-ranking-label>{it.label}</span>} {it.meta != null && <span.ui-ranking-meta>{it.meta}</span>} </span> {it.value != null && <span.ui-ranking-value>{it.value}</span>} </li> }} </ol>}Related
ActivityFeedA stream of what people did, with their pictures, an icon for each kind of action, when, quotes and day headings.5 views · 7 downloadsChangelogReleases with version, date and label, their changes grouped by kind: Added, Changed, Fixed, Security and the rest.6 views · 7 downloadsDataListRecords as rows with a title, a line of facts, a status badge and actions as links or buttons.6 views · 9 downloadsDescriptionListTerms and their details, stacked or in two columns that stack on phones, on a real <dl>.5 views · 7 downloadsFileListFiles as a table or a grid, with kind icons, sizes and dates, sorted, picked, downloaded or deleted.7 views · 6 downloadsKanbanBoardColumns of cards moved by dragging, by keyboard (Space, the arrows, Space) or with each card's arrows.9 views · 6 downloads
Thread
Thread 0 posts
On RankingList: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.