FlowSteps
A process as boxes joined by arrows, with words on the arrows, tones and done, current or coming steps; horizontal, or vertical where narrow.
Demo
- Write
- Review
- Merge
- Deploy
- Order placed (done)Payment heldpaid
- Packed (done)At the warehousewithin a day
- ShippedUPS 1Z999
- Delivered
- Draftsubmit
- In reviewTwo approvalsif approved
- Published
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/flow_steps.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/flow_steps.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/flow_steps.qwe
view FlowStepsDemo() = <div.demo-stack> <FlowSteps id="flow-steps-demo-simple" label="Release" steps={["Write", "Review", "Merge", "Deploy"]}/> <FlowSteps id="flow-steps-demo-order" label="Order" numbered={true} steps={[ { title: "Order placed", text: "Payment held", status: "done", then: "paid" }, { title: "Packed", text: "At the warehouse", status: "done", then: "within a day" }, { title: "Shipped", text: "UPS 1Z999", status: "current" }, { title: "Delivered", status: "coming" }, ]}/> <div style="max-width: 420px"> <FlowSteps id="flow-steps-demo-vertical" direction="vertical" label="Review" steps={[ { title: "Draft", tone: "info", then: "submit" }, { title: "In review", text: "Two approvals", tone: "warning", then: "if approved" }, { title: "Published", tone: "success" }, ]}/> </div> </div>Source
ui/flow_steps.qwe
// FlowSteps: a process as boxes joined by arrows: how an order moves, what a// deploy does, the stages of a review. Horizontal, it turns vertical where it has// no room (under 560px of its own width); or always vertical.//// <FlowSteps steps={["Write", "Review", "Merge", "Deploy"]}/>// <FlowSteps direction="vertical" numbered={true} steps={[// { title: "Order placed", text: "Payment is held", tone: "success" },// { title: "Packed", then: "within a day" },// { title: "Shipped", status: "current" },// ]}/>//// steps: strings, or maps of { title, text?, tone?, status?, then? }: text a line// under the title; tone the box's colour ("accent", "success", "warning", "danger",// "info"); status "done", "current" (marked as the step now, aria-current) or// "coming" (faded); then a few words on the arrow after it ("if approved").// direction: "horizontal" (default) or "vertical". numbered: a number on each box.// label: what screen readers call the list ("Steps"). id: its id. It is an <ol>.import ui/theme.qwe use ui_clslet flow_steps_css = css`.ui-flow-steps-wrap { container-type: inline-size; min-width: 0; }.ui-flow-steps { display: flex; align-items: stretch; margin: 0; padding: 0; list-style: none; font: 14px/1.4 var(--ui-font); color: var(--ui-fg); }.ui-flow-steps-item { position: relative; flex: 1 1 0; min-width: 0; display: flex; }.ui-flow-steps-item + .ui-flow-steps-item { margin-left: 48px; }.ui-flow-steps-box { --t: var(--ui-border); flex: 1; display: grid; align-content: start; gap: 3px; min-width: 0; padding: 12px 14px; border: 1px solid var(--t); border-top-width: 3px; border-radius: var(--ui-radius-sm); background: var(--ui-surface); }.ui-flow-steps-accent .ui-flow-steps-box { --t: var(--ui-accent); }.ui-flow-steps-success .ui-flow-steps-box { --t: var(--ui-success); }.ui-flow-steps-warning .ui-flow-steps-box { --t: var(--ui-warning); }.ui-flow-steps-danger .ui-flow-steps-box { --t: var(--ui-danger); }.ui-flow-steps-info .ui-flow-steps-box { --t: var(--ui-info); }.ui-flow-steps-current .ui-flow-steps-box { --t: var(--ui-accent); background: var(--ui-accent-soft); box-shadow: var(--ui-focus); }.ui-flow-steps-coming .ui-flow-steps-box { opacity: .6; border-style: dashed; }.ui-flow-steps-num { display: inline-grid; place-items: center; width: 22px; height: 22px; margin-bottom: 2px; border-radius: 50%; background: var(--ui-subtle); color: var(--ui-muted); font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; }.ui-flow-steps-done .ui-flow-steps-num { background: var(--ui-success); color: #fff; }.ui-flow-steps-current .ui-flow-steps-num { background: var(--ui-accent); color: var(--ui-accent-fg); }.ui-flow-steps-title { font-weight: 600; overflow-wrap: anywhere; }.ui-flow-steps-text { color: var(--ui-muted); font-size: 13px; }.ui-flow-steps-arrow { position: absolute; top: 50%; left: 100%; display: grid; justify-items: center; width: 48px; transform: translateY(-50%); color: var(--ui-strong); }.ui-flow-steps-arrow svg { width: 40px; height: 14px; }.ui-flow-steps-then { margin-bottom: 2px; color: var(--ui-muted); font-size: 11px; line-height: 1.2; text-align: center; overflow-wrap: anywhere; }.ui-flow-steps-vertical { flex-direction: column; max-width: 420px; }.ui-flow-steps-vertical .ui-flow-steps-item + .ui-flow-steps-item { margin: 40px 0 0; }.ui-flow-steps-vertical .ui-flow-steps-arrow { top: 100%; left: 0; right: 0; width: auto; height: 40px; grid-template-columns: 1fr auto 1fr; align-items: center; transform: none; }.ui-flow-steps-vertical .ui-flow-steps-arrow svg { grid-column: 2; width: 40px; transform: rotate(90deg); }.ui-flow-steps-vertical .ui-flow-steps-then { grid-column: 3; justify-self: start; margin: 0 0 0 4px; text-align: left; }@container (max-width: 560px) { .ui-flow-steps { flex-direction: column; } .ui-flow-steps .ui-flow-steps-item + .ui-flow-steps-item { margin: 40px 0 0; } .ui-flow-steps .ui-flow-steps-arrow { top: 100%; left: 0; right: 0; width: auto; height: 40px; grid-template-columns: 1fr auto 1fr; align-items: center; transform: none; } .ui-flow-steps .ui-flow-steps-arrow svg { grid-column: 2; transform: rotate(90deg); } .ui-flow-steps .ui-flow-steps-then { grid-column: 3; justify-self: start; margin: 0 0 0 4px; text-align: left; }}`view FlowSteps(steps: list = [], direction: str = "horizontal", numbered: bool = false, label: str = "Steps", id: str? = null, class: str? = null) { style global flow_steps_css <div.ui-flow-steps-wrap> <ol class={ui_cls(["ui-flow-steps", direction == "vertical" && "ui-flow-steps-vertical", class])} id={id} aria-label={label}> {for [i, s] in enumerate(steps) => { let st = type_of(s) == "str" ? { title: s } : s <li key={i} class={ui_cls(["ui-flow-steps-item", st.tone != null && `ui-flow-steps-${st.tone}`, st.status != null && `ui-flow-steps-${st.status}`])} aria-current={st.status == "current" ? "step" : null}> <div.ui-flow-steps-box> {numbered && <span.ui-flow-steps-num aria-hidden="true">{i + 1}</span>} <span.ui-flow-steps-title>{st.title}{st.status == "done" && <span.ui-sr> (done)</span>}</span> {st.text != null && <span.ui-flow-steps-text>{st.text}</span>} </div> {i < len(steps) - 1 && <div.ui-flow-steps-arrow> {st.then != null && <span.ui-flow-steps-then>{st.then}</span>} <svg viewBox="0 0 40 14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M2 7h34M30 2l6 5-6 5"/> </svg> </div>} </li> }} </ol> </div>}Related
MilestoneListMilestones down a line with dates, done, current, coming or late, a progress bar on those under way, and the whole project's progress.6 views · 7 downloadsOrgChartA tree of people as boxes joined by lines, drawn with CSS on nested lists, with pictures, titles, notes and the reader's place marked.7 views · 5 downloadsProgressListItems each with a label, a bar and its value or percentage, marked in red when one goes over its limit.6 views · 4 downloadsRoadmapColumns (Now, Next, Later) of items with a status badge, tags, a target date and votes; side by side, stacked where narrow.8 views · 6 downloadsScorecardA 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 downloadsChecklistInputCheckboxes under a progress line that says how many are done and fills as they are ticked; each posts with a form.5 views · 7 downloads
Thread
Thread 0 posts
On FlowSteps: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.