Commerce

DeliveryEstimate

"Arrives Tue 4 – Thu 6 Nov", worked out from how many days delivery takes, working days if asked.

#commerce#checkout#time#calendar#no-js

Demo

Preview
Arrives – Arrives · Order by 2 pmCollect
Arrives – Arrives – Arrives –

The first row counts from today; the second from dates given, so it reads the same every day.

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/delivery_estimate.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/delivery_estimate.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/delivery_estimate.qwe
view DeliveryEstimateDemo() =    <div.demo-stack>        <div.demo-row style="gap: 28px">            <DeliveryEstimate min_days={2} max_days={4}/>            <DeliveryEstimate min_days={1} business_days={true} cutoff="Order by 2 pm"/>            <DeliveryEstimate min_days={0} label="Collect" icon={false}/>        </div>        <div.demo-row style="gap: 28px">            <DeliveryEstimate from="2026-11-02" min_days={2} max_days={4}/>            <DeliveryEstimate from="2026-10-28" min_days={2} max_days={5}/>            <DeliveryEstimate from="2026-11-05" min_days={1} max_days={3} business_days={true} size="sm"/>        </div>        <p.demo-note>The first row counts from today; the second from dates given, so it reads the same every day.</p>    </div>

Source

ui/delivery_estimate.qwe
// DeliveryEstimate: when an order would arrive, from how many days delivery// takes: "Arrives Tue 4 – Thu 6 Nov", worked out from today (or the date given).////   <DeliveryEstimate min_days={2} max_days={4}/>//   <DeliveryEstimate min_days={1} business_days={true} cutoff="Order by 2 pm"/>//   <DeliveryEstimate min_days={0} label="Collect"/>//// min_days, max_days: the fewest and most days it takes (max_days left out: one// date). from: the date counted from (an ISO date; today when left out).// business_days: count only Monday to Friday, and never land on a weekend (false).// label: the word before the dates ("Arrives"). cutoff: a quieter line after// ("Order by 2 pm"). Counting from today, today reads "today" and tomorrow// "tomorrow"; otherwise the weekday, the day, and the month once when both dates// share it. Each date is// also a <time datetime> for machines. icon: a truck before it (true). size:// "sm" or "md" (default).//// delivery_estimate_dates(from, min_days, max_days, business_days) gives the two// dates, for a cart's own text.import ui/theme.qwe use ui_clslet delivery_estimate_css = css`.ui-delivery { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; font: 14px/1.4 var(--ui-font); color: var(--ui-fg); }.ui-delivery svg { flex: none; width: 20px; height: 20px; color: var(--ui-success); }.ui-delivery-when { font-weight: 600; }.ui-delivery-cutoff { color: var(--ui-muted); }.ui-delivery-sm { font-size: 13px; gap: 6px; }.ui-delivery-sm svg { width: 16px; height: 16px; }`// `from` plus n days; with business_days, n working days, landing on a weekday.fn delivery_estimate_add(from: str, n: int, business_days: bool) -> str {    if !business_days { return date.add_days(from, n) }    let d = from    let left = n    while left > 0 {        d = date.add_days(d, 1)        if date.weekday(d) <= 5 { left -= 1 }    }    while date.weekday(d) > 5 { d = date.add_days(d, 1) }    d}// The first and last dates delivery could be, as [first, last].fn delivery_estimate_dates(from: str, min_days: int, max_days: int? = null, business_days: bool = false) -> list = [    delivery_estimate_add(from, min_days, business_days),    delivery_estimate_add(from, max_days ?? min_days, business_days),]// A date as it reads: "Tue 4" (month: false) or "Tue 4 Nov"; beside today (null// when counting from another date), "today" or "tomorrow".fn delivery_estimate_word(d: str, today: str?, month: bool) -> str {    let gap = today != null ? date.days_between(today, d) : -1    gap == 0 ? "today" : gap == 1 ? "tomorrow" : date.format(d, month ? "ddd D MMM" : "ddd D")}view DeliveryEstimate(min_days: int = 2, max_days: int? = null, from: str? = null, business_days: bool = false,                      label: str = "Arrives", cutoff: str? = null, icon: bool = true, size: str = "md", class: str? = null) {    style global delivery_estimate_css    let start = from ?? date.today()    let today = from == null ? start : null    let [a, b] = delivery_estimate_dates(start, min_days, max_days, business_days)    let same_month = date.parts(a).month == date.parts(b).month    let one = a == b    <span class={ui_cls(["ui-delivery", size == "sm" && "ui-delivery-sm", class])}>        {icon && <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">            <path d="M3 7h11v9H3zM14 10h4l3 3v3h-7zM6 19a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm12 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/>        </svg>}        <span>            {label}{" "}            <span.ui-delivery-when>                <time datetime={a}>{delivery_estimate_word(a, today, one || !same_month)}</time>                {!one && [" – ", <time datetime={b}>{delivery_estimate_word(b, today, true)}</time>]}            </span>        </span>        {cutoff != null && <span.ui-delivery-cutoff>· {cutoff}</span>}    </span>}
Thread
68Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.