AddressCard
A saved address with a Default badge and Edit and Remove, as submit buttons in a plain form or callbacks.
Demo
Edit and Remove call on_edit and on_remove.
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/address_card.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/address_card.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/address_card.qwe
component AddressCardDemoLive() { state did = null <div.demo-stack style="width: 300px"> <AddressCard id="a2" name="Grace Hopper" street="1 Infinite Loop" city="Cupertino" region="CA" postcode="95014" country="United States" email="grace@example.com" kind="Billing" on_edit={() => { did = "edit" }} on_remove={() => { did = "remove" }}/> <p.demo-note>{did == null ? "Edit and Remove call on_edit and on_remove." : `Clicked ${did}.`}</p> </div>}view AddressCardDemo() = <div.demo-row style="align-items: flex-start; gap: 20px"> <div style="width: 300px"> <AddressCard id="a1" name="Ada Lovelace" lines={["12 St James's Square", "London SW1Y 4JH", "United Kingdom"]} phone="+44 20 7946 0000" kind="Shipping" default={true} action="/addresses" removable={false}/> </div> <AddressCardDemoLive/> <div style="width: 300px"> <AddressCard name="Linus Torvalds" street="Kaivokatu 8" city="Helsinki" postcode="00100" country="Finland" selected={true} edit_href="#address_card"/> </div> </div>Source
ui/address_card.qwe
// AddressCard: a saved address: the name, the lines, the phone, a Default// badge, and Edit and Remove. In a plain <form> the two are submit buttons// (`action`), so they work without a script; inside one of your components// they call on_edit() and on_remove().//// <AddressCard id="a1" name="Ada Lovelace" lines={["12 St James's Square", "London SW1Y 4JH", "United Kingdom"]}// phone="+44 20 7946 0000" kind="Shipping" default={true} action="/addresses"/>// <AddressCard name="Ada Lovelace" street="12 St James's Square" city="London" postcode="SW1Y 4JH" country="United Kingdom"// on_edit={() => { editing = true }} on_remove={() => { gone = true }}/>//// name: whose address. lines: its lines, as written; or street, street2, city,// region, postcode, country, laid out "city, region postcode" and the country// last. phone, email: lines under it with their links. kind: a word above// ("Shipping", "Billing"). default: the Default badge; default_label other// words. id: the address's id. action: a URL the buttons post to, the id as// `address` and `do` as "edit" or "remove"; edit_href makes Edit a link// instead. on_edit(), on_remove(): inside one of your components. removable:// false hides Remove (a default address, say). selected: outlined in the accent,// for a list to pick from.import ui/theme.qwe use ui_clslet address_card_css = css`.ui-address { position: relative; display: grid; gap: 8px; min-width: 0; padding: 16px 18px; border: 1px solid var(--ui-border); border-radius: var(--ui-radius); background: var(--ui-surface); font: 14px/1.5 var(--ui-font); color: var(--ui-fg); }.ui-address-selected { border-color: var(--ui-accent); box-shadow: inset 0 0 0 1px var(--ui-accent); }.ui-address-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }.ui-address-kind { font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; color: var(--ui-muted); }.ui-address-default { display: inline-flex; align-items: center; height: 20px; padding: 0 8px; border-radius: 999px; background: var(--ui-accent-soft); color: var(--ui-accent); font: 600 11px/1 var(--ui-font); }.ui-address-body { margin: 0; font-style: normal; }.ui-address-name { display: block; font-weight: 600; }.ui-address-contact { display: grid; gap: 2px; margin: 0; font-size: 13px; color: var(--ui-muted); }.ui-address-contact a { color: inherit; text-decoration: none; }.ui-address-contact a:hover { color: var(--ui-accent); text-decoration: underline; }.ui-address-actions { display: flex; gap: 14px; margin-top: 2px; padding-top: 10px; border-top: 1px solid var(--ui-border); font-size: 13px; }.ui-address-actions a, .ui-address-actions button { padding: 0; border: 0; background: none; color: var(--ui-accent); font: inherit; font-weight: 500; text-decoration: none; cursor: pointer; border-radius: 3px; }.ui-address-actions a:hover, .ui-address-actions button:hover { text-decoration: underline; }.ui-address-actions a:focus-visible, .ui-address-actions button:focus-visible { outline: none; box-shadow: var(--ui-focus); }.ui-address-actions .ui-address-remove { color: var(--ui-danger); }.ui-address-form { display: contents; }`view AddressCard(name: str? = null, lines: list = [], street: str? = null, street2: str? = null, city: str? = null, region: str? = null, postcode: str? = null, country: str? = null, phone: str? = null, email: str? = null, kind: str? = null, default: bool = false, default_label: str = "Default", id: str? = null, action: str? = null, edit_href: str? = null, removable: bool = true, selected: bool = false, on_edit = null, on_remove = null, class: str? = null) { style global address_card_css let town = join([city, region] | filter((x) => x != null && x != ""), ", ") let place = trim(town + (postcode != null ? ` ${postcode}` : "")) let made = len(lines) > 0 ? lines : [street, street2, place, country] | filter((l) => l != null && l != "") let has_actions = action != null || edit_href != null || on_edit != null || (removable && on_remove != null) let edit = action != null ? <button type="submit" name="do" value="edit">Edit<span.ui-sr> address{name != null && ` of ${name}`}</span></button> : edit_href != null ? <a href={edit_href}>Edit<span.ui-sr> address{name != null && ` of ${name}`}</span></a> : on_edit != null ? <button type="button" @click={() => { on_edit() }}>Edit<span.ui-sr> address{name != null && ` of ${name}`}</span></button> : null let remove = !removable ? null : action != null ? <button.ui-address-remove type="submit" name="do" value="remove">Remove<span.ui-sr> address{name != null && ` of ${name}`}</span></button> : on_remove != null ? <button.ui-address-remove type="button" @click={() => { on_remove() }}>Remove<span.ui-sr> address{name != null && ` of ${name}`}</span></button> : null let actions = <div.ui-address-actions>{edit}{remove}</div> <div class={ui_cls(["ui-address", selected && "ui-address-selected", class])} data-address={id}> {(kind != null || default) && <div.ui-address-head> {kind != null && <span.ui-address-kind>{kind}</span>} {default && <span.ui-address-default>{default_label}</span>} </div>} <address.ui-address-body> {name != null && <span.ui-address-name>{name}</span>} {for [i, l] in enumerate(made) => [i > 0 && <br/>, l]} {(phone != null || email != null) && <span.ui-address-contact> {phone != null && <a href={`tel:${replace(phone, " ", "")}`}>{phone}</a>} {email != null && <a href={`mailto:${email}`}>{email}</a>} </span>} </address> {has_actions && (action != null ? <form.ui-address-form method="post" action={action}> {id != null && <input type="hidden" name="address" value={id}/>} {actions} </form> : actions)} </div>}Related
PaymentMethodsWays to pay as radio cards with their marks: card (with the brands taken), PayPal, Apple Pay, Google Pay, bank, cash.6 views · 6 downloadsShippingOptionsShipping methods as radio cards, each with its price and how long it takes; a plain form sends the choice.7 views · 7 downloadsContactCardA person's contact details as tel:, mailto: and map links, with a vCard to download in one tap.5 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 downloads
Thread
Thread 0 posts
On AddressCard: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.