Data

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.

#chart#progress#list#no-js

Demo

Preview
  1. Write
  2. Review
  3. Merge
  4. Deploy
  1. Order placed (done)Payment held
    paid
  2. Packed (done)At the warehouse
    within a day
  3. ShippedUPS 1Z999
  4. Delivered
  1. Draft
    submit
  2. In reviewTwo approvals
    if approved
  3. 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.qwe
main.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>}
Thread
67Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.