// 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_cls

let 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>
}
