ProgressList
Items each with a label, a bar and its value or percentage, marked in red when one goes over its limit.
Demo
- Travel$1,840 of $2,500
- SoftwareAnnual licences renewed in March$2,900 of $2,500
- Hardware$600 of $4,000
- TrainingNot started
- Yes64%
- Maybe21%
- No15%
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/progress_list.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/progress_list.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/progress_list.qwe
view ProgressListDemo() = <div.demo-row style="align-items: flex-start; gap: 32px"> <div style="flex: 1 1 280px; max-width: 380px"> <ProgressList id="progress-list-demo-budget" label="Budget by category" items={[ { label: "Travel", value: 1840, limit: 2500, note: "$1,840 of $2,500" }, { label: "Software", value: 2900, limit: 2500, note: "$2,900 of $2,500", description: "Annual licences renewed in March" }, { label: "Hardware", value: 600, limit: 4000, note: "$600 of $4,000", tone: "success" }, { label: "Training", value: 0, limit: 1000, note: "Not started", tone: "neutral" }, ]}/> </div> <div style="flex: 1 1 240px; max-width: 320px"> <ProgressList id="progress-list-demo-poll" label="Would you recommend us?" show="percent" order="desc" size="sm" items={[ { label: "Maybe", value: 21 }, { label: "Yes", value: 64, tone: "success" }, { label: "No", value: 15, tone: "warning" }, ]}/> </div> </div>Source
ui/progress_list.qwe
// ProgressList: items each with a label, a bar and its value: goals, budgets by// category, storage by kind, skills, survey answers.//// <ProgressList label="Budget" items={[// { label: "Travel", value: 1840, limit: 2500, note: "$1,840 of $2,500" },// { label: "Software", value: 2900, limit: 2500, note: "$2,900 of $2,500" },// ]}/>// <ProgressList show="percent" items={[{ label: "Yes", value: 62 }, { label: "No", value: 38 }]}/>//// items: maps of { label, value, limit?, note?, tone?, description? }: value of// limit (the list's limit, 100 by default); note: the text on the right (by// default what show says); tone: the bar's colour, "accent" (default),// "neutral", "success", "warning", "danger" or "info". description: a line under// the label. show: what the right side says without a note: "value" ("1,840 /// 2,500", default), "percent" ("74%") or "none". over: when a value passes its// limit the bar is full and in the danger tone (true, default). order: "desc" or// "asc" orders the items by their share. size: "sm" or "md" (default): the// bars' thickness. label: the list's name for screen readers. Each bar is a// role="progressbar" named by its label.import ui/theme.qwe use ui_clslet progress_list_css = css`.ui-progresslist { display: grid; gap: 14px; margin: 0; padding: 0; list-style: none; font: 14px/1.4 var(--ui-font); color: var(--ui-fg); }.ui-progresslist-sm { gap: 10px; font-size: 13px; }.ui-progresslist-item { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 5px 12px; --t: var(--ui-accent); }.ui-progresslist-neutral { --t: var(--ui-muted); }.ui-progresslist-success { --t: var(--ui-success); }.ui-progresslist-warning { --t: var(--ui-warning); }.ui-progresslist-danger { --t: var(--ui-danger); }.ui-progresslist-info { --t: var(--ui-info); }.ui-progresslist-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }.ui-progresslist-desc { display: block; color: var(--ui-muted); font-size: 12px; font-weight: 400; white-space: normal; }.ui-progresslist-note { color: var(--ui-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }.ui-progresslist-over .ui-progresslist-note { color: var(--ui-danger); font-weight: 600; }.ui-progresslist-track { grid-column: 1 / -1; height: 8px; overflow: hidden; border-radius: 999px; background: var(--ui-subtle); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ui-border) 60%, transparent); }.ui-progresslist-sm .ui-progresslist-track { height: 5px; }.ui-progresslist-fill { height: 100%; border-radius: inherit; background: var(--t); transition: width .3s ease; }@media (prefers-reduced-motion: reduce) { .ui-progresslist-fill { transition: none; } }`fn progress_list_num(n: num) -> str = format_number(round(n * 100) / 100, "en-US")// A number for an ARIA value: plain, whole ones without ".0".fn progress_list_plain(n: num) -> str { let r = round(n * 100) / 100 r == floor(r) ? str(floor(r)) : str(r)}view ProgressList(items: list, limit: num = 100, show: str = "value", over: bool = true, order: str? = null, size: str = "md", label: str? = null, id: str? = null, class: str? = null) { style global progress_list_css let share = (it: map) => { let top = it.limit ?? limit top <= 0 ? 0 : it.value / top } let ordered = order == "desc" ? reverse(sort_by(items, (it) => share(it))) : order == "asc" ? sort_by(items, (it) => share(it)) : items <ul class={ui_cls(["ui-progresslist", size == "sm" && "ui-progresslist-sm", class])} id={id} aria-label={label}> {for it in ordered => { let top = it.limit ?? limit let past = over && it.value > top let pct = top <= 0 ? 0 : round(min([max([it.value, 0]), top]) * 1000 / top) / 10 let real = top <= 0 ? 0 : round(it.value * 100 / top) let note = it.note ?? (show == "percent" ? `${real}%` : show == "value" ? `${progress_list_num(it.value)} / ${progress_list_num(top)}` : null) <li class={ui_cls(["ui-progresslist-item", `ui-progresslist-${past ? "danger" : (it.tone ?? "accent")}`, past && "ui-progresslist-over"])}> <span.ui-progresslist-label>{it.label}{it.description != null && <span.ui-progresslist-desc>{it.description}</span>}</span> {note != null ? <span.ui-progresslist-note>{note}</span> : <span></span>} <div.ui-progresslist-track role="progressbar" aria-label={it.label} aria-valuemin="0" aria-valuemax={progress_list_plain(top)} aria-valuenow={progress_list_plain(min([max([it.value, 0]), top]))} aria-valuetext={note ?? `${real}%`}> <div.ui-progresslist-fill style={`width: ${pct}%`}></div> </div> </li> }} </ul>}Related
ScorecardA score out of a maximum as a filled ring, with a letter grade, a verdict and the parts it is made of.8 views · 5 downloadsActivityFeedA 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 · 8 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 downloads
Thread
Thread 0 posts
On ProgressList: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.