Data

RankingList

A ranked list with how each item moved since last time: up, down, the same or new, said in words to screen readers.

#data#list#no-js

Demo

Preview
  1. up 2 placesMidnight CityM831.2M plays
  2. down 1 placeDreamsFleetwood Mac1.1M plays
  3. newRunning Up That HillKate Bush980K plays
  4. no changeHeroesDavid Bowie870K plays
  5. down 3 placesBlue MondayNew Order700K plays
  1. up 6 placesquillo components
  2. no changecss nesting
  3. newserver functions
  4. 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.qwe
main.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>}
Thread
76Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.