DeliveryEstimate
"Arrives Tue 4 – Thu 6 Nov", worked out from how many days delivery takes, working days if asked.
Demo
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.qwemain.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>}Related
AddressCardA 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 downloadsCheckoutStepsCart → Details → Payment → Done: the steps of a checkout, those done as links back, the current one marked.5 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 downloadsOrderTrackerOrdered → shipped → out for delivery → delivered, with when each happened, the expected date and the tracking link.5 views · 6 downloads
Thread
Thread 0 posts
On DeliveryEstimate: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.