- Current balance
- $2,450.18
- Available
- $2,310.18
- On hold
- $140.00
Updated 2 min ago
A bank account at a glance: type, nickname, masked number, current and available balance, what is on hold, and quick actions.
Updated 2 min ago
Savings
Savings ending in 4931
Joint checking
Joint checking ending in 1266
Overdraft limit £500.00
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/account_card.qweimport ui/theme.qwe use theme_cssuse ui/account_card.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>The code of the preview above.
view AccountCardDemo() = <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 12px"> <AccountCard id="account-card-demo-everyday" kind="Checking" name="Everyday" number="0012 0048 21" balance={2450.18m} available={2310.18m} href="#everyday" transfer_href="#transfer" pay_href="#pay" statements_href="#statements" note="Updated 2 min ago"/> <AccountCard id="account-card-demo-savings" kind="Savings" name="Rainy day" number="DE44 5001 0517 5407 3249 31" balance={12500} currency="EUR" locale="de-DE" tone="success" transfer_href="#transfer" statements_href="#statements"/> <AccountCard id="account-card-demo-joint" kind="Joint checking" name="House" number="7730091266" balance={-84.5m} available={415.5m} currency="GBP" locale="en-GB" tone="warning" pay_href="#pay" note="Overdraft limit £500.00"/> </div>// AccountCard: a bank account at a glance: its type and nickname, the number// masked to its last four, the current balance and what is available to spend// (the difference shown as on hold), the currency, and quick links to transfer,// pay and see statements.//// <AccountCard kind="Checking" name="Everyday" number="0012004821" balance={2450.18m} available={2310.18m}// currency="USD" href="/accounts/1" transfer_href="/transfer?from=1" pay_href="/pay?from=1"// statements_href="/accounts/1/statements"/>// <AccountCard kind="Savings" name="Rainy day" number="DE44 5001 0517 5407 3249 31" balance={12500} currency="EUR" locale="de-DE"/>//// kind: the account's type ("Checking", "Savings", "Credit card"). name: its// nickname. number: the account number, any spacing; only the last four show// ("•••• 4821", read as "ending in 4821"). balance: the current balance, a number// or decimal (below 0, it shows in red and is read as overdrawn). available: what// can be spent now; when it is below the balance, the difference shows as on// hold (left out, the balance is all available). currency: ISO code ("USD");// locale: how amounts are written (the program's, else en-US). href: the account's// page, on the name. transfer_href, pay_href, statements_href: the quick actions,// each shown when given. note: a line at the foot ("Updated 2 min ago"). tone:// the colour of the stripe at the top, "accent" (default), "success", "info",// "warning", "danger" or "neutral". id: the element's id.import ui/theme.qwe use ui_clslet account_card_css = css`.ui-acard { --t: var(--ui-accent); position: relative; display: grid; gap: 14px; min-width: 0; padding: 18px 18px 14px; overflow: hidden; border: 1px solid var(--ui-border); border-radius: var(--ui-radius); background: var(--ui-surface); color: var(--ui-fg); font: 14px/1.4 var(--ui-font); }.ui-acard::before { content: ""; position: absolute; inset: 0 0 auto; height: 3px; background: var(--t); }.ui-acard-success { --t: var(--ui-success); }.ui-acard-info { --t: var(--ui-info); }.ui-acard-warning { --t: var(--ui-warning); }.ui-acard-danger { --t: var(--ui-danger); }.ui-acard-neutral { --t: var(--ui-strong); }.ui-acard-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }.ui-acard-kind { margin: 0; color: var(--ui-muted); font-size: 12px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; }.ui-acard-name { margin: 2px 0 0; font-size: 16px; font-weight: 600; line-height: 1.3; }.ui-acard-name a { color: inherit; text-decoration: none; }.ui-acard-name a:hover { color: var(--ui-accent); }.ui-acard-name a:focus-visible { outline: none; box-shadow: var(--ui-focus); border-radius: 3px; }.ui-acard-number { margin: 2px 0 0; color: var(--ui-muted); font: 13px var(--ui-mono); letter-spacing: .04em; }.ui-acard-currency { flex: none; padding: 2px 8px; border-radius: 999px; background: var(--ui-subtle); color: var(--ui-muted); font-size: 11px; font-weight: 600; letter-spacing: .05em; }.ui-acard-money { display: flex; flex-wrap: wrap; align-content: flex-start; gap: 10px 22px; margin: 0; }.ui-acard-money > div { display: grid; gap: 1px; }.ui-acard-money > div:first-child { flex-basis: 100%; }.ui-acard-money dt { color: var(--ui-muted); font-size: 12px; }.ui-acard-money dd { margin: 0; font-variant-numeric: tabular-nums; }.ui-acard-balance { font-size: 28px; font-weight: 650; line-height: 1.15; letter-spacing: -.01em; }.ui-acard-negative .ui-acard-balance { color: var(--ui-danger); }.ui-acard-avail dd { font-weight: 600; }.ui-acard-hold dd { color: var(--ui-warning); font-weight: 500; }.ui-acard-actions { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 12px 0 0; border-top: 1px solid var(--ui-border); list-style: none; }.ui-acard-actions a { display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 11px; border-radius: var(--ui-radius-sm); background: var(--ui-subtle); color: var(--ui-fg); font-size: 13px; font-weight: 500; text-decoration: none; transition: background .15s, color .15s; }.ui-acard-actions a:hover { background: var(--ui-accent-soft); color: var(--ui-accent); }.ui-acard-actions a:focus-visible { outline: none; box-shadow: var(--ui-focus); }.ui-acard-actions svg { width: 14px; height: 14px; flex: none; }.ui-acard-note { margin: 0; color: var(--ui-muted); font-size: 12px; }@media (prefers-reduced-motion: reduce) { .ui-acard-actions a { transition: none; } }`// An amount as text in its currency: a number or decimal formatted, text as it is.fn account_card_money(amount, currency: str, locale: str?) -> str { if type_of(amount) == "str" { return amount } if amount == null { return "" } let m = money.of(dec(amount), currency, "half_up") if is_err(m) { return str(amount) } locale != null ? money.format(m, locale) : money.format(m)}// The last four letters or digits of an account number: "0012 0048 21" gives "4821".fn account_card_last4(number: str) -> str = slice(re.replace(number, "[^0-9A-Za-z]", ""), -4)view AccountCard(name: str, kind: str = "Account", number: str = "", balance = 0, available = null, currency: str = "USD", locale: str? = null, href: str? = null, transfer_href: str? = null, pay_href: str? = null, statements_href: str? = null, note: str? = null, tone: str = "accent", id: str? = null, class: str? = null) { style global account_card_css let code = upper(currency) let bal = dec(balance) let avail = available != null ? dec(available) : null let hold = avail != null && avail < bal ? bal - avail : null let last4 = account_card_last4(number) let head_id = `${id ?? "account-card-" + re.replace(lower(name), "[^a-z0-9]+", "-")}-name` let has_actions = transfer_href != null || pay_href != null || statements_href != null <article class={ui_cls(["ui-acard", tone != "accent" && `ui-acard-${tone}`, bal < 0 && "ui-acard-negative", class])} id={id} aria-labelledby={head_id}> <header.ui-acard-head> <div> <p.ui-acard-kind>{kind}</p> <h3.ui-acard-name id={head_id}>{href != null ? <a href={href}>{name}</a> : name}</h3> {last4 != "" && <p.ui-acard-number><span aria-hidden="true">•••• {last4}</span><span.ui-sr>{kind} ending in {last4}</span></p>} </div> <span.ui-acard-currency title={`Held in ${code}`}>{code}</span> </header> <dl.ui-acard-money> <div><dt>Current balance</dt> <dd.ui-acard-balance>{account_card_money(bal, code, locale)}{bal < 0 && <span.ui-sr> (overdrawn)</span>}</dd></div> {avail != null && <div.ui-acard-avail><dt>Available</dt><dd>{account_card_money(avail, code, locale)}</dd></div>} {hold != null && <div.ui-acard-hold><dt>On hold</dt><dd>{account_card_money(hold, code, locale)}</dd></div>} </dl> {has_actions && <ul.ui-acard-actions aria-label={`${name}: actions`}> {transfer_href != null && <li><a href={transfer_href}> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 5h11l-3-3M14 11H3l3 3"/></svg>Transfer</a></li>} {pay_href != null && <li><a href={pay_href}> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="1.5" y="3.5" width="13" height="9" rx="1.5"/><path d="M1.5 6.5h13M4 10h3"/></svg>Pay</a></li>} {statements_href != null && <li><a href={statements_href}> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 1.5h5.5L12.5 4.5v10h-8.5z"/><path d="M6 8h4.5M6 11h4.5"/></svg>Statements</a></li>} </ul>} {note != null && <p.ui-acard-note>{note}</p>} </article>}On AccountCard: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.