Use cards for shop

This commit is contained in:
Jeremy Thomas
2024-06-11 01:20:25 +01:00
parent af7c31b613
commit 83fcfdcf5e
7 changed files with 136 additions and 60 deletions

View File

@@ -64,6 +64,13 @@
"icon": "fa-brands fa-patreon", "icon": "fa-brands fa-patreon",
"path": "/become-a-bulma-sponsor/" "path": "/become-a-bulma-sponsor/"
}, },
"shop": {
"name": "Shop",
"subtitle": "The Official Bulma Shop",
"color": "success",
"icon": "fa-solid fa-store",
"path": "/shop/"
},
"brand": { "brand": {
"name": "Bulma Brand", "name": "Bulma Brand",
"subtitle": "The official Bulma logos", "subtitle": "The official Bulma logos",
@@ -750,7 +757,7 @@
"path": "/documentation/helpers/other-helpers/" "path": "/documentation/helpers/other-helpers/"
} }
}, },
"navbar": ["docs", "expo", "love", "sponsor"], "navbar": ["docs", "expo", "love", "sponsor", "shop"],
"navbar_icons": ["github", "twitter"], "navbar_icons": ["github", "twitter"],
"navbar_more": ["made-with-bulma", "backers", "brand", "extensions"], "navbar_more": ["made-with-bulma", "backers", "brand", "extensions"],
"category_ids": [ "category_ids": [

View File

@@ -36,6 +36,9 @@
{% else %} {% else %}
{{ link.name }} {{ link.name }}
{% endif %} {% endif %}
{% if include.link_id == "shop" %}
<span class="tag is-success">New!</span>
{% endif %}
</span> </span>
{% endunless %} {% endunless %}
</a> </a>

View File

@@ -54,7 +54,8 @@
} }
&.is-system, &.is-system,
&.is-docs { &.is-docs,
&.is-shop {
--h: #{cv.getVar("success-h")}; --h: #{cv.getVar("success-h")};
--s: #{cv.getVar("success-s")}; --s: #{cv.getVar("success-s")};
--l: #{cv.getVar("success-l")}; --l: #{cv.getVar("success-l")};

View File

@@ -34259,7 +34259,7 @@ has-background-moon.is-hoverable:active {
--s: var(--bulma-info-s); --s: var(--bulma-info-s);
--l: var(--bulma-info-l); --l: var(--bulma-info-l);
} }
.bd-nav-item.is-system, .bd-nav-item.is-docs { .bd-nav-item.is-system, .bd-nav-item.is-docs, .bd-nav-item.is-shop {
--h: var(--bulma-success-h); --h: var(--bulma-success-h);
--s: var(--bulma-success-s); --s: var(--bulma-success-s);
--l: var(--bulma-success-l); --l: var(--bulma-success-l);
@@ -38852,6 +38852,13 @@ has-background-moon.is-hoverable:active {
--theme-color: hsl(var(--theme-h), var(--theme-s), var(--theme-l)); --theme-color: hsl(var(--theme-h), var(--theme-s), var(--theme-l));
} }
.bd-theme-shop {
--theme-h: var(--bulma-success-h);
--theme-s: var(--bulma-success-s);
--theme-l: var(--bulma-success-l);
--theme-color: hsl(var(--theme-h), var(--theme-s), var(--theme-l));
}
.bd-theme-features { .bd-theme-features {
--theme-h: var(--bulma-danger-h); --theme-h: var(--bulma-danger-h);
--theme-s: var(--bulma-danger-s); --theme-s: var(--bulma-danger-s);

View File

@@ -58,6 +58,7 @@ document.addEventListener("DOMContentLoaded", () => {
}; };
}; };
const THEME_COLOR = "success";
const STORAGE_CART_ID = "bulma-shop-cart-id"; const STORAGE_CART_ID = "bulma-shop-cart-id";
const CURRENCIES = { const CURRENCIES = {
@@ -264,7 +265,7 @@ document.addEventListener("DOMContentLoaded", () => {
currencyCode currencyCode
} }
} }
lines(first: 20) { lines(first: 24) {
edges { edges {
node { node {
id id
@@ -326,6 +327,7 @@ document.addEventListener("DOMContentLoaded", () => {
const $cart = document.getElementById("cart"); const $cart = document.getElementById("cart");
const $cartClose = document.querySelectorAll(".shop-cart-close"); const $cartClose = document.querySelectorAll(".shop-cart-close");
const $openCart = document.getElementById("open-cart"); const $openCart = document.getElementById("open-cart");
const $cartCount = document.getElementById("cart-count");
const $emptyCart = document.getElementById("empty-cart"); const $emptyCart = document.getElementById("empty-cart");
const $fullCart = document.getElementById("full-cart"); const $fullCart = document.getElementById("full-cart");
const $cartItems = document.getElementById("cart-items"); const $cartItems = document.getElementById("cart-items");
@@ -450,7 +452,9 @@ document.addEventListener("DOMContentLoaded", () => {
const buildOptions = (el, product) => { const buildOptions = (el, product) => {
const { variants } = product; const { variants } = product;
const $options = El("buttons has-addons are-small variants"); const $options = El(
"shop-product-variants buttons has-addons are-small variants",
);
$options.className += variants.length > 1 ? " multiple" : " single"; $options.className += variants.length > 1 ? " multiple" : " single";
if (variants.length > 1) { if (variants.length > 1) {
@@ -475,7 +479,7 @@ document.addEventListener("DOMContentLoaded", () => {
}; };
const buildAddButton = (el, product) => { const buildAddButton = (el, product) => {
const $buy = El("button is-primary is-medium", "button"); const $buy = El(`button is-${THEME_COLOR}`, "button");
$buy.innerText = "Add to cart"; $buy.innerText = "Add to cart";
$buy.addEventListener("click", async (event) => { $buy.addEventListener("click", async (event) => {
@@ -493,7 +497,7 @@ document.addEventListener("DOMContentLoaded", () => {
$products.classList.add("has-loaded"); $products.classList.add("has-loaded");
} }
if ($products.childElementCount > 4) { if ($products.childElementCount > Number($products.dataset.count)) {
return; return;
} }
@@ -504,14 +508,16 @@ document.addEventListener("DOMContentLoaded", () => {
return; return;
} }
const el = El(`shop-product shop-product-${getId(product.id)}`); const $card = El(`card shop-product shop-product-${getId(product.id)}`);
el.dataset.id = id; $card.dataset.id = id;
const el = El("card-content");
const $figure = El("shop-product-image image is-square", "figure"); const $figure = El("shop-product-image image is-square", "figure");
const $img = document.createElement("img"); const $img = document.createElement("img");
$img.src = featuredImage.url; $img.src = featuredImage.url;
$figure.appendChild($img); $figure.appendChild($img);
el.appendChild($figure); $card.appendChild($figure);
$figure.addEventListener("click", async (event) => { $figure.addEventListener("click", async (event) => {
event.preventDefault(); event.preventDefault();
@@ -536,8 +542,8 @@ document.addEventListener("DOMContentLoaded", () => {
}); });
el.appendChild($buttons); el.appendChild($buttons);
$card.appendChild(el);
$products.appendChild(el); $products.appendChild($card);
}); });
}; };
@@ -549,11 +555,14 @@ document.addEventListener("DOMContentLoaded", () => {
const { checkoutUrl, cost, lines } = state.cart; const { checkoutUrl, cost, lines } = state.cart;
if (lines.length > 0) { if (lines.length > 0) {
$openCart.classList.add("is-primary"); $openCart.classList.add(`is-${THEME_COLOR}`);
$cartItems.replaceChildren(); $cartItems.replaceChildren();
$emptyCart.style.display = "none"; $emptyCart.style.display = "none";
$fullCart.style.display = "block"; $fullCart.style.display = "block";
$cartCount.style.display = "inline-flex";
let totalCount = 0;
lines.forEach((line) => { lines.forEach((line) => {
const variantId = line.merchandise.id; const variantId = line.merchandise.id;
@@ -585,7 +594,7 @@ document.addEventListener("DOMContentLoaded", () => {
if (variant.title !== "Default Title") { if (variant.title !== "Default Title") {
const $tag = El( const $tag = El(
"shop-item-variant button is-primary is-small is-outlined", `shop-item-variant button is-${THEME_COLOR} is-small is-outlined`,
"span", "span",
); );
$tag.innerText = `${variant.title}`; $tag.innerText = `${variant.title}`;
@@ -595,6 +604,7 @@ document.addEventListener("DOMContentLoaded", () => {
const $quantity = El("shop-item-quantity button is-static", "span"); const $quantity = El("shop-item-quantity button is-static", "span");
$quantity.innerText = `${line.quantity}`; $quantity.innerText = `${line.quantity}`;
$right.appendChild($quantity); $right.appendChild($quantity);
totalCount += line.quantity;
const $buttons = El("shop-item-actions"); const $buttons = El("shop-item-actions");
@@ -671,14 +681,17 @@ document.addEventListener("DOMContentLoaded", () => {
$total.appendChild($totalRight); $total.appendChild($totalRight);
$cartItems.appendChild($total); $cartItems.appendChild($total);
const $checkout = El("button is-primary is-fullwidth", "a"); const $checkout = El(`button is-${THEME_COLOR} is-fullwidth`, "a");
$checkout.innerText = "Checkout"; $checkout.innerText = "Checkout";
$checkout.href = checkoutUrl; $checkout.href = checkoutUrl;
$cartItems.appendChild($checkout); $cartItems.appendChild($checkout);
$cartCount.innerText = totalCount;
} else { } else {
$openCart.classList.remove("is-primary"); $openCart.classList.remove(`is-${THEME_COLOR}`);
$emptyCart.style.display = "block"; $emptyCart.style.display = "block";
$fullCart.style.display = "none"; $fullCart.style.display = "none";
$cartCount.style.display = "none";
} }
}; };
@@ -707,9 +720,9 @@ document.addEventListener("DOMContentLoaded", () => {
$variants.forEach(($el) => { $variants.forEach(($el) => {
if ($el.dataset.id === product.selectedVariant) { if ($el.dataset.id === product.selectedVariant) {
$el.classList.add("is-primary"); $el.classList.add(`is-${THEME_COLOR}`);
} else { } else {
$el.classList.remove("is-primary"); $el.classList.remove(`is-${THEME_COLOR}`);
} }
}); });
}); });
@@ -771,7 +784,7 @@ document.addEventListener("DOMContentLoaded", () => {
const query = ` const query = `
query allProducts ${context} { query allProducts ${context} {
products(first: 10) { products(first: 12) {
edges { edges {
node { node {
id id
@@ -784,7 +797,7 @@ document.addEventListener("DOMContentLoaded", () => {
width width
} }
handle handle
images(first: 10) { images(first: 6) {
edges { edges {
node { node {
height height
@@ -804,7 +817,7 @@ document.addEventListener("DOMContentLoaded", () => {
} }
} }
title title
variants(first: 10) { variants(first: 12) {
edges { edges {
node { node {
availableForSale availableForSale

View File

@@ -1,7 +1,7 @@
--- ---
title: "The Bulma Shop" title: "The Official Bulma Shop"
layout: default layout: default
theme: primary theme: shop
route: shop route: shop
hide_footer: true hide_footer: true
breadcrumb: breadcrumb:
@@ -14,36 +14,47 @@ breadcrumb:
--shop-duration: 500ms; --shop-duration: 500ms;
} }
.shop-open-cart { .shop-hero {
margin-top: 1.5rem; min-height: calc(100vh - 6.5rem);
} }
@media screen and (min-width: 800px) { .shop-hero .bd-hero {
position: relative;
}
.shop-hero .bd-hero-body {
position: relative;
margin: 0 auto;
max-width: 110rem;
width: 100%;
}
.shop-open-cart {
margin-top: 1.5rem;
min-width: 10em;
}
.shop-open-cart .tag {
margin: 0 -0.625em 0 0.625em;
padding: 0 0.5em;
min-width: 2em;
background-color: transparent;
color: currentColor;
border: 1px solid currentColor;
}
@media screen and (min-width: 1000px) {
.shop-open-cart { .shop-open-cart {
margin-top: 0; margin-top: 0;
position: absolute; position: fixed;
right: 3rem; bottom: 1.5rem;
top: calc(50% - 1rem); right: 1.5rem;
z-index: 30;
} }
} }
.shop-product-heading { .shop-cart-count {
align-items: center; background-color: var(--bulma-primary-50);
gap: 1em;
justify-content: space-between;
display: flex;
font-size: 1.25em;
margin-bottom: 0.25em;
}
.shop-product-title {
color: var(--bulma-text-strong);
font-weight: 700;
}
.shop-product-price {
color: var(--bulma-text-strong);
font-size: 0.875em;
} }
.shop-cart, .shop-cart,
@@ -59,7 +70,7 @@ breadcrumb:
.shop-cart { .shop-cart {
opacity: 0; opacity: 0;
position: fixed; position: fixed;
z-index: 10; z-index: 40;
pointer-events: none; pointer-events: none;
} }
@@ -77,7 +88,7 @@ breadcrumb:
max-width: 22rem; max-width: 22rem;
padding: 2rem; padding: 2rem;
position: absolute; position: absolute;
z-index: 20; z-index: 50;
transform: translateX(100%); transform: translateX(100%);
transition-duration: var(--shop-duration); transition-duration: var(--shop-duration);
transition-property: transform; transition-property: transform;
@@ -167,6 +178,8 @@ breadcrumb:
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
gap: 3rem; gap: 3rem;
max-width: 110rem;
margin: 0 auto;
} }
.shop-products.has-loaded .shop-product.is-placeholder { .shop-products.has-loaded .shop-product.is-placeholder {
@@ -176,9 +189,39 @@ breadcrumb:
.shop-product { .shop-product {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-bottom: 0 !important;
overflow: hidden;
} }
.shop-product .variants { .shop-product .card-content {
display: flex;
flex-direction: column;
flex-grow: 1;
}
.shop-product-heading {
align-items: center;
gap: 1em;
justify-content: space-between;
display: flex;
font-size: 1.25em;
margin-top: 0.25em;
margin-bottom: 0.5em;
}
.shop-product-title {
color: var(--bulma-text-strong);
font-weight: 700;
line-height: 1.25;
}
.shop-product-price {
color: var(--bulma-text-strong);
font-size: 0.875em;
}
.shop-product-variants {
margin-bottom: 0 !important;
margin-top: 1em; margin-top: 1em;
} }
@@ -189,9 +232,7 @@ breadcrumb:
} }
.shop-product-image { .shop-product-image {
border-radius: 0.5rem;
cursor: pointer; cursor: pointer;
margin-bottom: 0.5em;
overflow: hidden; overflow: hidden;
} }
@@ -240,6 +281,7 @@ breadcrumb:
.shop-product-buttons { .shop-product-buttons {
justify-content: space-between; justify-content: space-between;
margin-top: 1em;
} }
.shop-modal { .shop-modal {
@@ -262,6 +304,7 @@ breadcrumb:
.shop-modal-content .shop-product-tagline { .shop-modal-content .shop-product-tagline {
color: var(--bulma-text-strong); color: var(--bulma-text-strong);
margin-bottom: 1em;
} }
.shop-modal-content .shop-product-rest { .shop-modal-content .shop-product-rest {
@@ -270,6 +313,7 @@ breadcrumb:
.shop-modal-buttons { .shop-modal-buttons {
justify-content: space-between; justify-content: space-between;
margin-top: 1em;
} }
.shop-modal-close { .shop-modal-close {
@@ -322,11 +366,11 @@ breadcrumb:
</div> </div>
{% endcapture %} {% endcapture %}
<div style="min-height: calc(100vh - 6.5rem);"> <div class="shop-hero">
<section class="bd-hero" style="position: relative;"> <section class="bd-hero">
<div class="bd-hero-body"> <div class="bd-hero-body">
<h1 class="bd-hero-title algolia-lvl0"> <h1 class="bd-hero-title algolia-lvl0">
The Bulma Shop The Official Bulma Shop
</h1> </h1>
<hr class="bd-hr"> <hr class="bd-hr">
@@ -337,9 +381,10 @@ breadcrumb:
<button id="open-cart" class="shop-open-cart button"> <button id="open-cart" class="shop-open-cart button">
<span class="icon"> <span class="icon">
<i class="fa-solid fa-basket-shopping"></i> <i class="fa-solid fa-bag-shopping"></i>
</span> </span>
<span>Open Cart</span> <span>Open Cart</span>
<span id="cart-count" class="shop-cart-count tag" style="display: none;">8</span>
</button> </button>
</div> </div>
</section> </section>
@@ -366,11 +411,10 @@ breadcrumb:
</div> </div>
</div> </div>
<div id="products" class="shop-products"> <div id="products" data-count="8" class="shop-products">
{{ shop_placeholder }} {% for i in (1..8) %}
{{ shop_placeholder }} {{ shop_placeholder }}
{{ shop_placeholder }} {% endfor %}
{{ shop_placeholder }}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -231,6 +231,7 @@ $themes: (
"customize": "info", "customize": "info",
"docs": "success", "docs": "success",
"expo": "warning", "expo": "warning",
"shop": "success",
"features": "danger", "features": "danger",
"helpers": "link", "helpers": "link",
"html": "html", "html": "html",