Commerce

ProductGrid

Products as ProductCards in a grid that fits as many across as there is room for, from a list of records.

#commerce#grid#card#list#price

Demo

Preview
  • SaleTrail runner
    Northwind

    Trail runner

    $89.00was $120.00, −26% off
  • Wool beanie
    Northwind

    Wool beanie

    Only a few left
    $24.00
  • NewInsulated bottle

    Insulated bottle

    $32.50
  • Rain jacket

    Rain jacket

    Out of stock
    $149.00
  • Day pack, 22 l

    Day pack, 22 l

    $64.00
  • Merino socks, 3 pairs

    Merino socks, 3 pairs

    $29.00was $36.00, −19% off

Click Add to cart on any card.

No products

Get it

It needs theme.qwe, as every component does, and price.qwe and product_card.qwe; 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/price.qwe$ curl -O https://quillolang.org/components/ui/product_card.qwe$ curl -O https://quillolang.org/components/ui/product_grid.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/product_grid.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/product_grid.qwe
let product_grid_demo_items = [    { id: 1, name: "Trail runner", brand: "Northwind", price: 89, old: 120, image: "https://picsum.photos/seed/runner/400/300", rating: 4.5, reviews: 128, badge: "Sale", badge_tone: "danger" },    { id: 2, name: "Wool beanie", brand: "Northwind", price: 24, image: "https://picsum.photos/seed/beanie/400/300", rating: 4, reviews: 37, stock: "low" },    { id: 3, name: "Insulated bottle", price: 32.5, image: "https://picsum.photos/seed/bottle/400/300", rating: 3.8, reviews: 9, badge: "New" },    { id: 4, name: "Rain jacket", price: 149, image: "https://picsum.photos/seed/jacket/400/300", stock: "out" },    { id: 5, name: "Day pack, 22 l", price: 64, image: "https://picsum.photos/seed/pack/400/300", rating: 4.7, reviews: 211 },    { id: 6, name: "Merino socks, 3 pairs", price: 29, old: 36, image: "https://picsum.photos/seed/socks/400/300", rating: 4.2, reviews: 54 },]component ProductGridDemoLive() {    state last = null    <div.demo-stack>        <ProductGrid products={product_grid_demo_items} size={180} card_size="sm" on_add={(p) => { last = p.name }}/>        <p.demo-note>{last == null ? "Click Add to cart on any card." : `Added "${last}" (on_add is given the product).`}</p>    </div>}view ProductGridDemo() =    <div.demo-stack>        <ProductGridDemoLive/>        <ProductGrid products={[]} />    </div>

Source

ui/product_grid.qwe
// ProductGrid: products as ProductCards in a grid that fits as many across as// there is room for (this file needs product_card.qwe and price.qwe).////   <ProductGrid products={db.query("select * from products")} action="/cart" currency="EUR"/>//   <ProductGrid products={picks} size={200} on_add={(p) => { cart = cart | push(p) }}/>//// products: a list of maps with ProductCard's props (id, name, price, old, image,// alt, href, brand, rating, reviews, badge, badge_tone, stock); other fields are// ignored. currency, locale, cents, action, add_label, ratio, card_size ("sm" or// "md"): the same for every card. size: each column's width at least, in pixels// (220). gap: between cards, in pixels (16). empty: what to say with no products// ("No products"). label: what screen readers call the grid ("Products").// on_add(product): inside one of your components, given the product's map when// its button is clicked (without an action).import ui/product_card.qwe use ProductCardimport ui/theme.qwe use ui_clslet product_grid_css = css`.ui-product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(var(--s, 220px), 100%), 1fr)); gap: var(--g, 16px);  margin: 0; padding: 0; list-style: none; }.ui-product-grid > li { display: flex; min-width: 0; }.ui-product-grid > li > .ui-product { flex: 1; }.ui-product-grid-empty { padding: 32px; border: 1px dashed var(--ui-border); border-radius: var(--ui-radius); color: var(--ui-muted);  font: 14px/1.4 var(--ui-font); text-align: center; }`view ProductGrid(products: list = [], size: int = 220, gap: int = 16, currency: str = "USD", locale: str? = null,                 cents: bool = true, action: str? = null, add_label: str = "Add to cart", ratio: str = "4/3",                 card_size: str = "md", empty: str = "No products", label: str = "Products", on_add = null,                 class: str? = null) {    style global product_grid_css    len(products) == 0        ? <div class={ui_cls(["ui-product-grid-empty", class])} role="status">{empty}</div>        : <ul class={ui_cls(["ui-product-grid", class])} style={`--s: ${size}px; --g: ${gap}px`} aria-label={label}>            {for [i, p] in enumerate(products) => <li key={get(p, "id") ?? i}>                <ProductCard {...p} id={get(p, "id") != null ? str(p.id) : null} currency={get(p, "currency") ?? currency} locale={locale} cents={cents}                             action={action} add_label={add_label} ratio={ratio} size={card_size}                             on_add={() => { on_add && on_add(p) }}/>            </li>}        </ul>}
Thread
65Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.