[IMP] website_sale_aplicoop: compact mobile layout for the Eskaera shop
Reorder cart/tags/category/search/products into one flex row with Bootstrap order utilities, so mobile shows cart, tags, category, search, then products, while desktop keeps its current layout. Product cards become a two-column grid of compact tiles from the smallest phones, with a 4:3 photo instead of a tall rectangle. Origin, supplier and tags move behind a per-product "i" toggle instead of always reserving their own row, which also drops the now-unused any_product_has_tags plumbing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
ef1283be7c
commit
6a59d9f6ad
6 changed files with 217 additions and 152 deletions
|
|
@ -152,7 +152,6 @@
|
|||
|
||||
/* ========== PRODUCT CARD MEDIA ========== */
|
||||
--ac-card-media-ratio: 4 / 3;
|
||||
--ac-card-media-height: clamp(5rem, 4rem + 6vw, 8.5rem);
|
||||
|
||||
/* ========== Z-INDEX ========== */
|
||||
--ac-z-dropdown: 1000;
|
||||
|
|
|
|||
|
|
@ -6,13 +6,23 @@
|
|||
* Markup (eskaera_shop_products):
|
||||
* .product-card-wrapper.product-card
|
||||
* └ .card
|
||||
* ├ img.product-img-cover | .product-img-placeholder
|
||||
* ├ .card-body (title, tags, supplier, origin, price)
|
||||
* ├ .product-media
|
||||
* │ ├ img.product-img-cover | .product-img-placeholder
|
||||
* │ └ button.product-info-toggle (only when the product has a
|
||||
* │ tag, a supplier or an origin to show)
|
||||
* ├ .card-body (title, .product-info-panel, price)
|
||||
* └ form.add-to-cart-form → components/quantity-control.css
|
||||
*
|
||||
* The wrapper carries the chrome (border, radius, elevation); the inner
|
||||
* Bootstrap .card is neutralised through its own custom properties so the two
|
||||
* boxes stop drawing a double frame.
|
||||
*
|
||||
* Tags/supplier/origin used to sit unconditionally in the card body so every
|
||||
* card's price row lined up regardless of which fields a product had. The
|
||||
* compact grid has no room for that: they now live in .product-info-panel,
|
||||
* collapsed by default and revealed by .product-info-toggle (see
|
||||
* website_sale.js for the click handler, delegated on #products-grid same as
|
||||
* the quantity stepper).
|
||||
*/
|
||||
|
||||
.product-card {
|
||||
|
|
@ -41,14 +51,23 @@
|
|||
|
||||
/* ---------- Media ---------- */
|
||||
|
||||
.product-media {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-card .product-image,
|
||||
.product-img-cover,
|
||||
.product-img-fixed,
|
||||
.product-img-placeholder {
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
height: var(--ac-card-media-height);
|
||||
/* 4:3, not square: a square photo ate too much vertical space on a
|
||||
two-up mobile grid. aspect-ratio keeps it fluid across card widths
|
||||
instead of a fixed height that over- or under-crops depending on how
|
||||
many columns fit. */
|
||||
aspect-ratio: var(--ac-card-media-ratio);
|
||||
height: auto;
|
||||
border-radius: var(--ac-radius-md) var(--ac-radius-md) 0 0;
|
||||
object-fit: cover;
|
||||
background-color: var(--ac-surface-muted);
|
||||
|
|
@ -61,6 +80,68 @@
|
|||
color: var(--ac-text-muted);
|
||||
}
|
||||
|
||||
/* ---------- Info toggle & panel ---------- */
|
||||
|
||||
.product-info-toggle {
|
||||
position: absolute;
|
||||
top: var(--ac-space-2xs);
|
||||
right: var(--ac-space-2xs);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1.375rem;
|
||||
height: 1.375rem;
|
||||
padding: 0;
|
||||
border: 1px solid var(--ac-border-strong);
|
||||
border-radius: var(--ac-radius-pill);
|
||||
font-size: var(--ac-text-2xs);
|
||||
color: var(--ac-text-secondary);
|
||||
background-color: rgb(255 255 255 / 90%);
|
||||
cursor: pointer;
|
||||
transition: background-color var(--ac-transition-fast), color var(--ac-transition-fast);
|
||||
}
|
||||
|
||||
.product-info-toggle[aria-expanded="true"] {
|
||||
color: var(--ac-text-on-fill);
|
||||
background-color: var(--ac-color-primary-strong);
|
||||
border-color: var(--ac-color-primary-strong);
|
||||
}
|
||||
|
||||
.product-info-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--ac-space-3xs);
|
||||
margin-bottom: var(--ac-space-3xs);
|
||||
padding: var(--ac-space-2xs);
|
||||
border: 1px solid var(--ac-border);
|
||||
border-radius: var(--ac-radius-sm);
|
||||
background-color: var(--ac-surface-sunken);
|
||||
}
|
||||
|
||||
.product-info-panel[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.product-info-toggle:hover {
|
||||
color: var(--ac-text-on-fill);
|
||||
background-color: var(--ac-color-primary);
|
||||
border-color: var(--ac-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.product-info-toggle:focus-visible {
|
||||
outline: var(--ac-focus-ring-width) solid var(--ac-focus-ring-color);
|
||||
outline-offset: var(--ac-focus-ring-offset);
|
||||
}
|
||||
|
||||
@media (pointer: coarse) {
|
||||
.product-info-toggle {
|
||||
width: var(--ac-touch-target);
|
||||
height: var(--ac-touch-target);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- Body ---------- */
|
||||
|
||||
.product-card .card-body {
|
||||
|
|
@ -107,10 +188,6 @@
|
|||
align-content: center;
|
||||
gap: var(--ac-space-3xs);
|
||||
justify-content: center;
|
||||
/* Reserved even when a product has no tags (rendered empty, aria-hidden —
|
||||
see eskaera_shop_products), so the supplier/origin/price rows below line
|
||||
up across every card in the grid row. Matches one row of .badge-km. */
|
||||
min-height: calc(var(--ac-text-2xs) * var(--ac-leading-tight) + 2 * var(--ac-space-3xs) + 2px);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
|
@ -131,14 +208,12 @@
|
|||
|
||||
/* ---------- Supplier & origin ---------- */
|
||||
|
||||
/* Both rows are reserved even when empty (rendered aria-hidden — see
|
||||
eskaera_shop_products) and clamped to a fixed line count, so the price row
|
||||
below lines up across every card in the grid row regardless of which
|
||||
products actually have a supplier name or an origin. */
|
||||
/* Only ever rendered inside .product-info-panel now (see
|
||||
eskaera_shop_products), so there is no longer a cross-card alignment to
|
||||
protect — no reserved space, no forced line clamp. */
|
||||
.product-card .product-supplier,
|
||||
.product-card .product-origin {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
font-size: var(--ac-text-xs);
|
||||
font-weight: var(--ac-weight-normal);
|
||||
text-align: center;
|
||||
|
|
@ -146,17 +221,11 @@
|
|||
}
|
||||
|
||||
.product-card .product-supplier {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
min-height: calc(2em * var(--ac-leading-tight));
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.product-card .product-origin {
|
||||
min-height: calc(1em * var(--ac-leading-tight));
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,17 +5,18 @@
|
|||
*
|
||||
* The grid used to pin an exact column count at seven breakpoints (1 → 6). It
|
||||
* now derives the count from the space available, which keeps the card width
|
||||
* stable no matter how wide the sidebar or the container is. The single query
|
||||
* left is the deliberate design decision: one card per row on phones, where a
|
||||
* two-up grid would shrink names and controls below comfortable size.
|
||||
* stable no matter how wide the sidebar or the container is.
|
||||
*
|
||||
* 9rem is the card's minimum width; at the widest container (1320px minus the
|
||||
* category sidebar) it still resolves to six columns, as before.
|
||||
* Two columns from the smallest phones: with the compact "cromo" card (4:3
|
||||
* photo, no inline tags/supplier/origin — see product-card.css) a single
|
||||
* full-width column read as a tall row rather than a browsable grid. 9rem is
|
||||
* the card's minimum width from 576px up; at the widest container (1320px
|
||||
* minus the category sidebar) it still resolves to six columns, as before.
|
||||
*/
|
||||
|
||||
.products-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: var(--ac-space-md);
|
||||
margin-bottom: var(--ac-space-xl);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1246,6 +1246,23 @@
|
|||
}
|
||||
});
|
||||
|
||||
// Product info toggle: shows/hides the origin/supplier/tags panel
|
||||
// that the compact card no longer displays inline (via event
|
||||
// delegation, same reasoning as the stepper above).
|
||||
productsGrid.addEventListener("click", function (e) {
|
||||
var infoBtn = e.target.closest(".product-info-toggle");
|
||||
if (!infoBtn) return;
|
||||
|
||||
e.preventDefault();
|
||||
var panelId = infoBtn.getAttribute("aria-controls");
|
||||
var panel = panelId ? document.getElementById(panelId) : null;
|
||||
if (!panel) return;
|
||||
|
||||
var isOpen = infoBtn.getAttribute("aria-expanded") === "true";
|
||||
infoBtn.setAttribute("aria-expanded", isOpen ? "false" : "true");
|
||||
panel.hidden = isOpen;
|
||||
});
|
||||
|
||||
// Add to cart button (via event delegation on grid)
|
||||
productsGrid.addEventListener("click", handleAddToCart);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue