Finance

MemberCard

A co-op or credit union member's card: photo or initials, name and number, member since, share capital and status.

#finance#coop#card#user#no-js

Demo

Preview

Bayanihan Multi-Purpose Cooperative

Lourdes Villanueva

Regular member

Status: active
Member no.
M-004217
Member since
Share capital
₱18,500.00

Tomas de la Cruz Reyes

Associate member

Status: dormant
Member no.
M-010388
Member since
Share capital
₱2,500.50

No transaction since Jan 2025

Lakeshore Teachers Credit Union

Harriet Okafor

Status: suspended
Member no.
CU-88213
Member since
Share capital
$5.00 (1 share)

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

Example

The code of the preview above.

demos/member_card.qwe
view MemberCardDemo() =    <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px">        <MemberCard id="member-card-demo-active" name="Lourdes Villanueva" number="M-004217" since="2014-03-04" share_capital={18500}                    currency="PHP" coop="Bayanihan Multi-Purpose Cooperative" kind="Regular member" href="#member-4217"/>        <MemberCard id="member-card-demo-dormant" name="Tomas de la Cruz Reyes" number="M-010388" since="2019-07-15" share_capital={2500.5}                    currency="PHP" status="dormant" kind="Associate member" note="No transaction since Jan 2025"/>        <MemberCard id="member-card-demo-usd" name="Harriet Okafor" number="CU-88213" since="2008-11-20" share_capital="$5.00 (1 share)"                    coop="Lakeshore Teachers Credit Union" status="suspended"/>    </div>

Source

ui/member_card.qwe
// MemberCard: a co-operative's or credit union's member, on a card: the photo or// the initials, the name and member number, since when they are a member, their// share capital and whether the membership is active or dormant.////   <MemberCard name="Lourdes Villanueva" number="M-004217" since="2014-03-04" share_capital={18500}//               currency="PHP" coop="Bayanihan Multi-Purpose Cooperative" kind="Regular member"/>//   <MemberCard name="Tomas Reyes" number="M-010388" since="2019-07-15" share_capital={2500} currency="PHP"//               status="dormant" note="No transaction since Jan 2025" photo="/members/10388.jpg"/>//// name: the member's name. number: their member number. since: the date they// joined, ISO ("2014-03-04"), shown as "Mar 4, 2014"; text that is not a date as// it is. share_capital: what they hold, a number or a decimal written in// `currency` (ISO code, "USD") for `locale` (the program's by default), or text// already formatted. status: "active" (default, green), "dormant" (amber), or any// other word ("suspended", "terminated"), grey. photo: an image; without one the// initials are shown ("LV"). coop: the co-op's name across the top. kind: the// kind of membership ("Regular member", "Associate"). note: a line at the bottom.// href: makes the name a link to the member's page. id: the element's id.import ui/theme.qwe use ui_clslet member_card_css = css`.ui-member-card { display: grid; gap: 14px; min-width: 0; max-width: 380px; padding: 18px 20px; border: 1px solid var(--ui-border);  border-radius: var(--ui-radius); background: var(--ui-surface); color: var(--ui-fg); font: 14px/1.45 var(--ui-font);  border-top: 4px solid var(--ui-accent); }.ui-member-card-coop { margin: 0; color: var(--ui-muted); font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }.ui-member-card-head { display: flex; align-items: center; gap: 14px; min-width: 0; }.ui-member-card-photo, .ui-member-card-initials { flex: none; width: 56px; height: 56px; border-radius: 50%; }.ui-member-card-photo { object-fit: cover; background: var(--ui-subtle); }.ui-member-card-initials { display: grid; place-items: center; background: var(--ui-accent-soft); color: var(--ui-accent);  font-size: 19px; font-weight: 650; letter-spacing: .02em; }.ui-member-card-who { display: grid; gap: 2px; min-width: 0; }.ui-member-card .ui-member-card-name { display: block; margin: 0; font-size: 17px; font-weight: 650; line-height: 1.25; overflow-wrap: anywhere; }.ui-member-card-name a { color: inherit; text-decoration: none; }.ui-member-card-name a:hover { color: var(--ui-accent); text-decoration: underline; }.ui-member-card-name a:focus-visible { outline: none; box-shadow: var(--ui-focus); border-radius: 3px; }.ui-member-card-kind { margin: 0; color: var(--ui-muted); font-size: 13px; }.ui-member-card-status { justify-self: start; display: inline-flex; align-items: center; gap: 6px; padding: 1px 9px; border-radius: 999px;  font-size: 12px; font-weight: 600; background: var(--ui-subtle); color: var(--ui-muted); text-transform: capitalize; }.ui-member-card-status::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }.ui-member-card-active .ui-member-card-status { background: var(--ui-success-soft); color: var(--ui-success); }.ui-member-card-dormant .ui-member-card-status { background: var(--ui-warning-soft); color: var(--ui-warning); }.ui-member-card-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: 10px 16px; margin: 0;  padding-top: 12px; border-top: 1px solid var(--ui-border); }.ui-member-card-facts div { display: grid; gap: 1px; min-width: 0; }.ui-member-card-facts dt { color: var(--ui-muted); font-size: 12px; }.ui-member-card-facts dd { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; }.ui-member-card-facts time { white-space: nowrap; }.ui-member-card-num { font-family: var(--ui-mono); font-size: 13px; }.ui-member-card-note { margin: 0; color: var(--ui-muted); font-size: 13px; }.ui-member-card-dormant { border-top-color: var(--ui-warning); }.ui-member-card-other { border-top-color: var(--ui-muted); }`// "Lourdes Villanueva" as "LV": the first letters of the first and last names.fn member_card_initials(name: str) -> str {    let words = split(trim(name), " ") | filter((w) => w != "")    if len(words) == 0 { return "?" }    let first = upper(slice(words[0], 0, 1))    len(words) == 1 ? first : first + upper(slice(words[len(words) - 1], 0, 1))}// An amount in its currency; text as it is.fn member_card_money(amount, currency: str, locale: str?) -> str {    if amount == null { return "" }    if type_of(amount) == "str" { return amount }    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)}// An ISO date as "Mar 4, 2014"; other text as it is.fn member_card_date(d, locale: str?) -> str =    date.valid(str(d), "date") ? date.format(str(d), { locale: locale ?? "en-US", style: "medium" }) : str(d)view MemberCard(name: str, number: str, since = null, share_capital = null, currency: str = "USD", locale: str? = null,                status: str = "active", photo: str? = null, coop: str? = null, kind: str? = null, note: str? = null,                href: str? = null, id: str? = null, class: str? = null) {    style global member_card_css    let mood = status == "active" || status == "dormant" ? status : "other"    <article class={ui_cls(["ui-member-card", `ui-member-card-${mood}`, class])} id={id} aria-label={`Member ${name}, ${number}`}>        {coop != null && <p.ui-member-card-coop>{coop}</p>}        <div.ui-member-card-head>            {photo != null ? <img.ui-member-card-photo src={photo} alt=""/>                           : <span.ui-member-card-initials aria-hidden="true">{member_card_initials(name)}</span>}            <div.ui-member-card-who>                <h3.ui-member-card-name>{href != null ? <a href={href}>{name}</a> : name}</h3>                {kind != null && <p.ui-member-card-kind>{kind}</p>}                <span.ui-member-card-status><span.ui-sr>Status: </span>{status}</span>            </div>        </div>        <dl.ui-member-card-facts>            <div><dt>Member no.</dt><dd.ui-member-card-num>{number}</dd></div>            {since != null && <div><dt>Member since</dt><dd><time datetime={str(since)}>{member_card_date(since, locale)}</time></dd></div>}            {share_capital != null && <div><dt>Share capital</dt><dd.ui-member-card-capital>{member_card_money(share_capital, currency, locale)}</dd></div>}        </dl>        {note != null && <p.ui-member-card-note>{note}</p>}    </article>}
Thread
86Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.