CheckoutSteps
Cart → Details → Payment → Done: the steps of a checkout, those done as links back, the current one marked.
Demo
- Cart (done)
- Details
- Payment
- Done
- Cart (done)
- Address (done)
- Payment
- Review
- Cart (done)
- Details (done)
- Payment (done)
- Done (done)
- Bag
- Pay
- Done
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/checkout_steps.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/checkout_steps.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/checkout_steps.qwe
view CheckoutStepsDemo() = <div.demo-stack style="gap: 24px"> <CheckoutSteps current={1}/> <CheckoutSteps current={2} steps={[{ label: "Cart", href: "#cart_item" }, { label: "Address", href: "#checkout_steps" }, "Payment", "Review"]}/> <CheckoutSteps current={4} numbers={false}/> <div.demo-narrow><CheckoutSteps current={0} steps={["Bag", "Pay", "Done"]}/></div> </div>Source
ui/checkout_steps.qwe
// CheckoutSteps: where someone is in a checkout: Cart → Details → Payment →// Done. The steps done are links back when they have an href; the ones to come// are not.//// <CheckoutSteps current={1}/>// <CheckoutSteps current={2} steps={[{ label: "Cart", href: "/cart" }, { label: "Address", href: "/checkout/address" },// "Payment", "Review"]}/>//// steps: strings, or maps of { label, href? } (["Cart", "Details", "Payment",// "Done"]). current: the index of the step being done, from 0; set it to// len(steps) when all are. label: what screen readers call it ("Checkout").// numbers: a number in each step's circle (true); false shows only dots.// On narrow screens only the current step's name shows.import ui/theme.qwe use ui_clslet checkout_steps_css = css`.ui-checkout-steps { display: flex; align-items: center; margin: 0; padding: 0; list-style: none; font: 14px/1.3 var(--ui-font); color: var(--ui-fg); }.ui-checkout-step { display: flex; align-items: center; gap: 8px; min-width: 0; }.ui-checkout-step a { display: inherit; align-items: inherit; gap: inherit; color: inherit; text-decoration: none; border-radius: var(--ui-radius-sm); }.ui-checkout-step a:hover .ui-checkout-label { color: var(--ui-accent); text-decoration: underline; }.ui-checkout-step a:focus-visible { outline: none; box-shadow: var(--ui-focus); }.ui-checkout-mark { display: inline-grid; place-items: center; flex: none; width: 26px; height: 26px; border-radius: 50%; border: 2px solid var(--ui-border); background: var(--ui-surface); color: var(--ui-muted); font: 600 12px/1 var(--ui-font); font-variant-numeric: tabular-nums; }.ui-checkout-mark svg { width: 13px; height: 13px; }.ui-checkout-done .ui-checkout-mark { border-color: var(--ui-accent); background: var(--ui-accent); color: var(--ui-accent-fg); }.ui-checkout-current .ui-checkout-mark { border-color: var(--ui-accent); color: var(--ui-accent); }.ui-checkout-label { font-weight: 500; white-space: nowrap; }.ui-checkout-coming .ui-checkout-label { color: var(--ui-muted); font-weight: 400; }.ui-checkout-current .ui-checkout-label { color: var(--ui-accent); }.ui-checkout-sep { flex: 1 1 24px; min-width: 16px; height: 2px; margin: 0 10px; border-radius: 2px; background: var(--ui-border); }.ui-checkout-sep-done { background: var(--ui-accent); }.ui-checkout-dots .ui-checkout-mark { width: 12px; height: 12px; border-width: 2px; font-size: 0; }.ui-checkout-dots .ui-checkout-mark svg { display: none; }@media (max-width: 600px) { .ui-checkout-step:not(.ui-checkout-current) .ui-checkout-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); } }`view CheckoutSteps(steps: list = ["Cart", "Details", "Payment", "Done"], current: int = 0, label: str = "Checkout", numbers: bool = true, class: str? = null) { style global checkout_steps_css let n = len(steps) <ol class={ui_cls(["ui-checkout-steps", !numbers && "ui-checkout-dots", class])} aria-label={label}> {for [i, s] in enumerate(steps) => { let text = type_of(s) == "str" ? s : s.label let href = type_of(s) == "map" ? get(s, "href") : null let phase = i < current ? "done" : i == current ? "current" : "coming" let inner = [ <span.ui-checkout-mark aria-hidden="true"> {phase == "done" ? <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg> : i + 1} </span>, <span.ui-checkout-label>{text}{phase == "done" && <span.ui-sr> (done)</span>}</span>, ] [ <li class={`ui-checkout-step ui-checkout-${phase}`} aria-current={phase == "current" ? "step" : null}> {phase == "done" && href != null ? <a href={href}>{inner}</a> : inner} </li>, i < n - 1 && <li class={ui_cls(["ui-checkout-sep", i < current && "ui-checkout-sep-done"])} role="presentation" aria-hidden="true"></li>, ] }} </ol>}Related
ProgressNavNumbered steps as links: the ones done link back, this one is marked, and the ones to come wait their turn.6 views · 4 downloadsAddressCardA saved address with a Default badge and Edit and Remove, as submit buttons in a plain form or callbacks.6 views · 7 downloadsBestCouponWorks out the lowest total from several coupons, trying each combination and order under their rules, and explains the winner and why each other coupon lost.3 views · 7 downloadsCartSummarySubtotal, shipping, tax, a discount and the total added up, with a Checkout button as a link, a form or a callback.6 views · 7 downloadsCouponInputA promo code box with Apply: on_apply(code) says whether it took, and an applied code shows with Remove.6 views · 5 downloadsDeliveryEstimate"Arrives Tue 4 – Thu 6 Nov", worked out from how many days delivery takes, working days if asked.6 views · 8 downloads
Thread
Thread 0 posts
On CheckoutSteps: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.