[IMP] website_sale_aplicoop: accessibility and responsive polish — phase 8
Quantity control layout: changed from wrapping flex to deliberate two-row
grid so the add-to-cart button sits full-width underneath the stepper,
avoiding accidental line breaks and giving the primary action more pulsing
area. Also removed the /Kg suffix's redundant font rules.
Order card delivery row: reordered to badge-then-date (visually centred),
removed the "Delivery" label, and swapped bg-primary to text-bg-primary for
proper contrast on the home-delivery badge (3.13:1 minimum).
Tooltip translations: moved hardcoded static tooltips from data-bs-title
(untranslatable) to title (QWeb-translatable). Handled the edge case of
"Save Cart" and "Back to Cart" which had translations but no model_terms
reference in the POT, causing the merge to discard them — added the view
reference so translations now apply.
Load-from-history page: added accessibility: a visible status message
("Loading your order…"), a <noscript> fallback with link to the group
order, lang and viewport meta tags, and localised strings for all three
languages. Gave the page a minimal inline style block since it does not
inherit the token system (no website.layout).
Translations: 11 new entries (es/eu/ca) for new/reworded UI strings, plus
two code catalogue entries (products found, Close) that needed the
#. odoo-python comment for _() resolution. Documented the silent-failure
pattern in docs/TRANSLATIONS.md: the POT merge, untranslatable attributes,
and missing code comments.
Tests: 246 passing. Pre-commit: clean.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
162ba0b570
commit
5de7573fba
35 changed files with 2181 additions and 2413 deletions
|
|
@ -16,7 +16,7 @@ website_sale_aplicoop/static/src/css/
|
|||
│
|
||||
├── base/
|
||||
│ ├── variables.css ← Variables CSS globales (colores, tipografía, espaciados)
|
||||
│ └── utilities.css ← Clases utilitarias (.sr-only, .text-muted, etc)
|
||||
│ └── utilities.css ← Clases utilitarias (.text-muted, .word-wrap-break, etc)
|
||||
│
|
||||
├── layout/
|
||||
│ ├── pages.css ← Fondos y layouts de páginas (eskaera-page, etc)
|
||||
|
|
@ -62,7 +62,8 @@ website_sale_aplicoop/static/src/css/
|
|||
- **variables.css** (~80 líneas)
|
||||
Colores, tipografía, espaciados, sombras, transiciones, z-index
|
||||
- **utilities.css** (~15 líneas)
|
||||
Clases utilitarias reutilizables (.sr-only, .text-muted, etc)
|
||||
Clases utilitarias reutilizables (.text-muted, .word-wrap-break, etc).
|
||||
Para texto solo-lector-de-pantalla usa `.visually-hidden` de Bootstrap.
|
||||
|
||||
### **layout/** - Estructura Global
|
||||
- **pages.css** (~70 líneas)
|
||||
|
|
|
|||
|
|
@ -1,34 +1,26 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/base/utilities.css */
|
||||
|
||||
/**
|
||||
* Utility classes used throughout the project
|
||||
* Utility classes
|
||||
*
|
||||
* Screen-reader-only text: use Bootstrap's own `.visually-hidden` /
|
||||
* `.visually-hidden-focusable`, shipped in web.assets_frontend. The local
|
||||
* `.sr-only` copy (the Bootstrap 4 name, dropped in 5.x) is gone, as are
|
||||
* `.word-wrap-break` and `.text-xs`, which no template ever used.
|
||||
*/
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
.word-wrap-break {
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.text-xs {
|
||||
font-size: 0.85rem;
|
||||
/* Scoped to the addon's pages: unscoped this redefined Bootstrap's .text-muted
|
||||
for the whole frontend, and needed !important to do it. Two classes beat
|
||||
Bootstrap's one, so the flag is no longer necessary. */
|
||||
:is(.eskaera-page, .eskaera-shop-page, .eskaera-generic-page, .eskaera-checkout-page) .text-muted {
|
||||
color: var(--ac-text-secondary);
|
||||
}
|
||||
|
||||
/* Set by realtime_search.js to filter the grid. A utility has to beat the
|
||||
component it lands on — .product-card declares display:flex at the same
|
||||
specificity and loads later — so this is the one place the flag is the
|
||||
mechanism rather than a workaround. Bootstrap's own utility layer does the
|
||||
same for every one of its classes. */
|
||||
.hidden-product {
|
||||
display: none !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,72 +1,228 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/base/variables.css */
|
||||
|
||||
/**
|
||||
* CSS Custom Properties (Variables)
|
||||
* Colores, tipografía, espaciados centralizados
|
||||
* Design tokens (CSS custom properties)
|
||||
*
|
||||
* The ONLY file in this addon allowed to contain colour literals.
|
||||
*
|
||||
* Odoo 18 ships Bootstrap 5.3 with `$variable-prefix: ''`
|
||||
* (web/static/src/scss/bootstrap_overridden.scss), so Bootstrap's root custom
|
||||
* properties are exposed UNPREFIXED: --primary, --body-bg, --border-color, …
|
||||
* Brand tokens alias them so the website theme editor keeps control of the palette;
|
||||
* the literal is only the fallback when the bundle is loaded outside a themed page.
|
||||
*
|
||||
* Contrast ratios noted below are against --ac-surface (#fff) and are the reason
|
||||
* a given literal was chosen. Do not "tidy" them without re-checking WCAG AA.
|
||||
*/
|
||||
|
||||
:root {
|
||||
/* ========== COLORS ========== */
|
||||
--primary-color: var(--primary, #007bff);
|
||||
--primary-dark: var(--primary-dark, #0056b3);
|
||||
--secondary-color: var(--secondary, #6c757d);
|
||||
--success-color: var(--success, #28a745);
|
||||
--danger-color: #dc3545;
|
||||
--warning-color: #ffc107;
|
||||
--info-color: #17a2b8;
|
||||
--light-color: #f8f9fa;
|
||||
/* ========== BRAND ========== */
|
||||
--ac-color-primary: var(--primary, #007bff);
|
||||
/* White text on --ac-color-primary is only 3.98:1 (fails AA for body text).
|
||||
Use -strong whenever text sits ON the colour: 7.04:1. */
|
||||
--ac-color-primary-strong: #0056b3;
|
||||
--ac-color-secondary: var(--secondary, #6c757d);
|
||||
--ac-color-accent: #7c3aed; /* white on it: 5.70:1 */
|
||||
--ac-color-accent-strong: #6d28d9; /* white on it: 7.10:1 */
|
||||
|
||||
/* Order cards carry their own indigo accent, and special orders an amber one. */
|
||||
--ac-color-order: #5a67d8; /* white on it: 4.81:1 */
|
||||
--ac-color-order-strong: #4c57bd; /* 6.17:1 */
|
||||
--ac-color-order-deep: #3d4898; /* 8.14:1 */
|
||||
--ac-color-order-border: rgb(90 103 216 / 12%);
|
||||
--ac-color-order-border-hover: rgb(90 103 216 / 25%);
|
||||
--ac-surface-order: linear-gradient(180deg, #fff 0%, #fbfdff 100%);
|
||||
--ac-surface-order-hover: linear-gradient(180deg, #fff 0%, #f7faff 100%);
|
||||
|
||||
--ac-color-special: #f59e0b;
|
||||
--ac-color-special-strong: #d97706;
|
||||
--ac-color-special-border: rgb(245 158 11 / 35%);
|
||||
--ac-color-special-border-hover: rgb(245 158 11 / 50%);
|
||||
--ac-surface-special: linear-gradient(180deg, #fffdf0 0%, #fffbea 100%);
|
||||
--ac-surface-special-hover: linear-gradient(180deg, #fffdf0 0%, #fff8db 100%);
|
||||
/* White on amber is 2.15:1. Amber always takes dark text: 7.60:1. */
|
||||
--ac-text-on-special: #1a202c;
|
||||
|
||||
/* ========== FEEDBACK ========== */
|
||||
--ac-color-success: var(--success, #28a745);
|
||||
/* #28a745 is only 3.13:1 on white — fine as a fill, not as text. */
|
||||
--ac-color-success-strong: #1e7e34; /* 5.14:1 */
|
||||
--ac-color-success-deep: #1a6e2e; /* hover/active on -strong */
|
||||
|
||||
/* Warning alert: amber surface with its own readable foreground (6.30:1). */
|
||||
--ac-surface-warning: #fef3c7;
|
||||
--ac-border-warning: #fcd34d;
|
||||
--ac-text-warning: #92400e;
|
||||
--ac-color-danger: var(--danger, #dc3545);
|
||||
--ac-color-warning: var(--warning, #ffc107);
|
||||
--ac-color-info: var(--info, #17a2b8);
|
||||
|
||||
/* ========== SURFACES ========== */
|
||||
--ac-surface: var(--body-bg, #fff);
|
||||
--ac-surface-sunken: var(--light, #f8f9fa);
|
||||
--ac-surface-muted: #f3f3f3;
|
||||
--ac-surface-tint: rgb(0 123 255 / 6%);
|
||||
--ac-surface-tint-hover: rgb(108 117 125 / 10%);
|
||||
|
||||
/* ========== TEXT (all ≥ 4.5:1 on --ac-surface) ========== */
|
||||
--ac-text-primary: var(--body-color, #1a202c); /* 16.32:1 */
|
||||
--ac-text-secondary: #4a5568; /* 7.53:1 */
|
||||
--ac-text-muted: #6b7280; /* 4.83:1 */
|
||||
--ac-text-on-fill: #fff;
|
||||
|
||||
/* ========== BORDERS ========== */
|
||||
/* Decorative separators and card outlines. */
|
||||
--ac-border: var(--border-color, #e2e8f0);
|
||||
--ac-border-subtle: #e0e0e0;
|
||||
/* Boundaries of interactive controls (inputs, steppers): WCAG 1.4.11 needs
|
||||
≥ 3:1 against the adjacent surface. #8a919a is 3.18:1. */
|
||||
--ac-border-strong: #8a919a;
|
||||
|
||||
/* ========== FOCUS RING ========== */
|
||||
--ac-focus-ring-color: var(--primary, #007bff); /* 3.98:1 — ok for a focus indicator */
|
||||
--ac-focus-ring-width: 2px;
|
||||
--ac-focus-ring-offset: 2px;
|
||||
|
||||
/* ========== TYPOGRAPHY ========== */
|
||||
--ac-font-family: var(
|
||||
--font-sans-serif,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
"Segoe UI",
|
||||
Roboto,
|
||||
"Helvetica Neue",
|
||||
Arial,
|
||||
sans-serif
|
||||
);
|
||||
|
||||
/* Fluid scale: one continuous ramp instead of per-breakpoint overrides.
|
||||
Always rem + vw, never pure vw, so browser zoom keeps working. */
|
||||
--ac-text-2xs: clamp(0.6875rem, 0.66rem + 0.1vw, 0.75rem);
|
||||
--ac-text-xs: clamp(0.75rem, 0.72rem + 0.12vw, 0.8125rem);
|
||||
--ac-text-sm: clamp(0.8125rem, 0.79rem + 0.14vw, 0.875rem);
|
||||
--ac-text-base: clamp(0.875rem, 0.85rem + 0.18vw, 1rem);
|
||||
--ac-text-md: clamp(1rem, 0.96rem + 0.2vw, 1.125rem);
|
||||
--ac-text-lg: clamp(1.125rem, 1.06rem + 0.3vw, 1.375rem);
|
||||
--ac-text-xl: clamp(1.375rem, 1.25rem + 0.6vw, 1.75rem);
|
||||
--ac-text-2xl: clamp(1.75rem, 1.5rem + 1vw, 2.25rem);
|
||||
|
||||
--ac-leading-tight: 1.2;
|
||||
--ac-leading-snug: 1.35;
|
||||
--ac-leading-normal: 1.5;
|
||||
|
||||
--ac-weight-normal: 400;
|
||||
--ac-weight-medium: 500;
|
||||
--ac-weight-semibold: 600;
|
||||
--ac-weight-bold: 700;
|
||||
|
||||
/* ========== SPACING ========== */
|
||||
--ac-space-3xs: 0.125rem;
|
||||
--ac-space-2xs: 0.25rem;
|
||||
--ac-space-xs: 0.375rem;
|
||||
--ac-space-sm: 0.5rem;
|
||||
--ac-space-md: 1rem;
|
||||
--ac-space-lg: 1.5rem;
|
||||
--ac-space-xl: 2rem;
|
||||
--ac-space-2xl: 3rem;
|
||||
|
||||
/* ========== RADIUS ========== */
|
||||
--ac-radius-sm: 0.25rem;
|
||||
--ac-radius-md: 0.5rem;
|
||||
--ac-radius-lg: 0.75rem;
|
||||
--ac-radius-xl: 1rem;
|
||||
--ac-radius-pill: 50rem;
|
||||
|
||||
/* ========== ELEVATION ========== */
|
||||
--ac-shadow-sm: 0 2px 8px rgb(0 0 0 / 8%);
|
||||
--ac-shadow-md: 0 4px 12px rgb(0 0 0 / 10%);
|
||||
--ac-shadow-lg: 0 10px 25px rgb(0 0 0 / 12%);
|
||||
|
||||
/* ========== MOTION ========== */
|
||||
--ac-transition-fast: 150ms ease-out;
|
||||
--ac-transition-normal: 220ms cubic-bezier(0.2, 0.9, 0.2, 1);
|
||||
--ac-transition-slow: 400ms ease;
|
||||
|
||||
/* ========== CONTROLS ========== */
|
||||
/* Fluid control size: replaces six per-breakpoint width/height overrides. */
|
||||
--ac-control-size: clamp(2.25rem, 2.05rem + 0.7vw, 2.5rem);
|
||||
/* 44px. WCAG 2.2 AA (2.5.8) only requires 24px, but 44px is the AAA figure
|
||||
(2.5.5) and the practical minimum for touch. Applied on coarse pointers. */
|
||||
--ac-touch-target: 2.75rem;
|
||||
--ac-control-border-width: 1px;
|
||||
|
||||
/* ========== 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;
|
||||
--ac-z-sticky: 1020;
|
||||
--ac-z-fixed: 1030;
|
||||
--ac-z-modal: 1040;
|
||||
--ac-z-popover: 1050;
|
||||
--ac-z-tooltip: 1060;
|
||||
--ac-z-notification: 9999;
|
||||
|
||||
/* ==========================================================================
|
||||
LEGACY ALIASES — do not use in new code.
|
||||
Kept so the not-yet-migrated partials keep rendering. Delete each one once
|
||||
`grep -rn "var(--<name>)" static/src/` comes back empty.
|
||||
========================================================================== */
|
||||
--primary-color: var(--ac-color-primary);
|
||||
/* Was `var(--primary-dark, #0056b3)`: a custom property cannot reference
|
||||
itself — that made the declaration invalid at computed-value time, so the
|
||||
five consumers in buttons.css / order-card.css silently rendered with no
|
||||
colour at all. */
|
||||
--primary-dark: var(--ac-color-primary-strong);
|
||||
--secondary-color: var(--ac-color-secondary);
|
||||
--success-color: var(--ac-color-success);
|
||||
--danger-color: var(--ac-color-danger);
|
||||
--warning-color: var(--ac-color-warning);
|
||||
--info-color: var(--ac-color-info);
|
||||
--light-color: var(--ac-surface-sunken);
|
||||
--dark-color: #2d3748;
|
||||
|
||||
/* Text colors */
|
||||
--text-primary: #1a202c;
|
||||
--text-secondary: #4a5568;
|
||||
--text-muted: #6b7280;
|
||||
--text-primary: var(--ac-text-primary);
|
||||
--text-secondary: var(--ac-text-secondary);
|
||||
--text-muted: var(--ac-text-muted);
|
||||
|
||||
/* Border colors */
|
||||
--border-light: #e2e8f0;
|
||||
--border-light: var(--ac-border);
|
||||
--border-medium: #cbd5e0;
|
||||
--border-dark: #718096;
|
||||
|
||||
/* ========== TYPOGRAPHY ========== */
|
||||
--font-family-base: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
|
||||
Arial, sans-serif;
|
||||
--font-family-base: var(--ac-font-family);
|
||||
--font-weight-light: 300;
|
||||
--font-weight-normal: 400;
|
||||
--font-weight-medium: 500;
|
||||
--font-weight-semibold: 600;
|
||||
--font-weight-bold: 700;
|
||||
--font-weight-normal: var(--ac-weight-normal);
|
||||
--font-weight-medium: var(--ac-weight-medium);
|
||||
--font-weight-semibold: var(--ac-weight-semibold);
|
||||
--font-weight-bold: var(--ac-weight-bold);
|
||||
--font-weight-extrabold: 800;
|
||||
|
||||
/* ========== SPACING ========== */
|
||||
--spacing-xs: 0.25rem;
|
||||
--spacing-sm: 0.5rem;
|
||||
--spacing-md: 1rem;
|
||||
--spacing-lg: 1.5rem;
|
||||
--spacing-xl: 2rem;
|
||||
--spacing-2xl: 3rem;
|
||||
--spacing-xs: var(--ac-space-2xs);
|
||||
--spacing-sm: var(--ac-space-sm);
|
||||
--spacing-md: var(--ac-space-md);
|
||||
--spacing-lg: var(--ac-space-lg);
|
||||
--spacing-xl: var(--ac-space-xl);
|
||||
--spacing-2xl: var(--ac-space-2xl);
|
||||
|
||||
/* ========== BORDER RADIUS ========== */
|
||||
--radius-sm: 0.25rem;
|
||||
--radius-md: 0.5rem;
|
||||
--radius-lg: 0.75rem;
|
||||
--radius-xl: 1rem;
|
||||
--radius-sm: var(--ac-radius-sm);
|
||||
--radius-md: var(--ac-radius-md);
|
||||
--radius-lg: var(--ac-radius-lg);
|
||||
--radius-xl: var(--ac-radius-xl);
|
||||
|
||||
/* ========== SHADOWS ========== */
|
||||
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
--shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.12);
|
||||
--shadow-sm: var(--ac-shadow-sm);
|
||||
--shadow-md: var(--ac-shadow-md);
|
||||
--shadow-lg: var(--ac-shadow-lg);
|
||||
|
||||
/* ========== TRANSITIONS ========== */
|
||||
--transition-fast: 200ms ease;
|
||||
--transition-normal: 320ms cubic-bezier(0.2, 0.9, 0.2, 1);
|
||||
--transition-normal: var(--ac-transition-normal);
|
||||
--transition-slow: 500ms ease;
|
||||
|
||||
/* ========== Z-INDEX ========== */
|
||||
--z-dropdown: 1000;
|
||||
--z-sticky: 1020;
|
||||
--z-fixed: 1030;
|
||||
--z-modal: 1040;
|
||||
--z-popover: 1050;
|
||||
--z-tooltip: 1060;
|
||||
--z-notification: 9999;
|
||||
--z-dropdown: var(--ac-z-dropdown);
|
||||
--z-sticky: var(--ac-z-sticky);
|
||||
--z-fixed: var(--ac-z-fixed);
|
||||
--z-modal: var(--ac-z-modal);
|
||||
--z-popover: var(--ac-z-popover);
|
||||
--z-tooltip: var(--ac-z-tooltip);
|
||||
--z-notification: var(--ac-z-notification);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,77 +1,68 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/components/alerts.css */
|
||||
|
||||
/**
|
||||
* Alert and notification component styles
|
||||
* Alerts, toasts and notifications
|
||||
*
|
||||
* `.alert-warning` is scoped to the addon's pages: unscoped it redefined
|
||||
* Bootstrap's own alert for the whole frontend. `.group-order-alert` and its
|
||||
* .info/.warning variants were dead — no template emits them.
|
||||
*/
|
||||
|
||||
.group-order-alert {
|
||||
background-color: #e7f3ff;
|
||||
border-left: 4px solid var(--primary-color);
|
||||
color: #004085;
|
||||
padding: 1rem;
|
||||
border-radius: 0.375rem;
|
||||
:is(.eskaera-page, .eskaera-shop-page, .eskaera-generic-page, .eskaera-checkout-page)
|
||||
.alert-warning {
|
||||
--alert-bg: var(--ac-surface-warning);
|
||||
--alert-border-color: var(--ac-border-warning);
|
||||
--alert-color: var(--ac-text-warning);
|
||||
margin-bottom: var(--ac-space-xl);
|
||||
padding: var(--ac-space-md);
|
||||
border-radius: var(--ac-radius-md);
|
||||
}
|
||||
|
||||
.group-order-alert.info {
|
||||
background-color: #d1ecf1;
|
||||
border-left-color: #17a2b8;
|
||||
color: #0c5460;
|
||||
:is(.eskaera-page, .eskaera-shop-page, .eskaera-generic-page, .eskaera-checkout-page)
|
||||
.alert-warning
|
||||
i {
|
||||
margin-right: var(--ac-space-xs);
|
||||
font-size: var(--ac-text-md);
|
||||
}
|
||||
|
||||
.group-order-alert.warning {
|
||||
background-color: #fff3cd;
|
||||
border-left-color: #ffc107;
|
||||
color: #856404;
|
||||
:is(.eskaera-page, .eskaera-shop-page, .eskaera-generic-page, .eskaera-checkout-page)
|
||||
.alert-warning
|
||||
strong {
|
||||
font-weight: var(--ac-weight-bold);
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
background-color: #fef3c7;
|
||||
border-color: #fcd34d;
|
||||
color: #92400e;
|
||||
margin-bottom: 2rem;
|
||||
border-radius: 0.5rem;
|
||||
padding: 1.25rem;
|
||||
.eskaera-delivery-notice {
|
||||
margin-top: var(--ac-space-md);
|
||||
border-left: 4px solid var(--ac-color-info);
|
||||
}
|
||||
|
||||
.alert-warning i {
|
||||
margin-right: 0.75rem;
|
||||
font-size: 1.1rem;
|
||||
.eskaera-delivery-notice .fa-truck {
|
||||
margin-right: var(--ac-space-sm);
|
||||
color: var(--ac-color-info);
|
||||
}
|
||||
|
||||
.alert-warning strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
/* ---------- Toast (added to cart) ---------- */
|
||||
|
||||
#delivery-info-alert {
|
||||
margin-top: 1rem;
|
||||
border-left: 4px solid #0dcaf0;
|
||||
}
|
||||
|
||||
#delivery-info-alert .fa-truck {
|
||||
margin-right: 0.5rem;
|
||||
color: #0dcaf0;
|
||||
}
|
||||
|
||||
/* Toast Notification Animation */
|
||||
.toast-notification {
|
||||
position: fixed;
|
||||
bottom: 30px;
|
||||
right: 30px;
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
padding: 1rem 1.5rem;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
inset: auto var(--ac-space-lg) var(--ac-space-lg) auto;
|
||||
z-index: var(--ac-z-notification);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-weight: 500;
|
||||
z-index: 9999;
|
||||
gap: var(--ac-space-xs);
|
||||
max-width: 25rem;
|
||||
padding: var(--ac-space-md) var(--ac-space-lg);
|
||||
padding-bottom: calc(var(--ac-space-md) + env(safe-area-inset-bottom, 0px));
|
||||
border-radius: var(--ac-radius-sm);
|
||||
/* White on --ac-color-success is 3.13:1; the strong tone is 5.14:1. */
|
||||
background-color: var(--ac-color-success-strong);
|
||||
color: var(--ac-text-on-fill);
|
||||
box-shadow: var(--ac-shadow-lg);
|
||||
font-weight: var(--ac-weight-medium);
|
||||
word-break: break-word;
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: opacity 0.3s ease, transform 0.3s ease;
|
||||
max-width: 400px;
|
||||
word-break: break-word;
|
||||
transition: opacity var(--ac-transition-normal), transform var(--ac-transition-normal);
|
||||
}
|
||||
|
||||
.toast-notification.show {
|
||||
|
|
@ -80,6 +71,41 @@
|
|||
}
|
||||
|
||||
.toast-notification i {
|
||||
font-size: 1.2rem;
|
||||
min-width: 20px;
|
||||
min-width: 1.25rem;
|
||||
font-size: var(--ac-text-md);
|
||||
}
|
||||
|
||||
/* ---------- Floating notification (_showNotification) ---------- */
|
||||
|
||||
/* Was a 200-character inline style written from JS on every call. */
|
||||
.eskaera-notification {
|
||||
position: fixed;
|
||||
top: 5rem;
|
||||
right: var(--ac-space-md);
|
||||
z-index: var(--ac-z-notification);
|
||||
min-width: 18.75rem;
|
||||
max-width: 31.25rem;
|
||||
padding: var(--ac-space-lg);
|
||||
font-size: var(--ac-text-md);
|
||||
box-shadow: var(--ac-shadow-lg);
|
||||
transition: opacity var(--ac-transition-normal);
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.eskaera-notification {
|
||||
left: var(--ac-space-md);
|
||||
right: var(--ac-space-md);
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.toast-notification,
|
||||
.eskaera-notification {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.toast-notification {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,103 +1,102 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/components/buttons.css */
|
||||
|
||||
/**
|
||||
* Button and action component styles
|
||||
* Buttons
|
||||
*
|
||||
* Colours are set through Bootstrap 5.3's own --btn-* custom properties, which
|
||||
* Odoo exposes unprefixed. That wins on the cascade without !important and
|
||||
* keeps every state (hover, active, disabled) consistent, instead of
|
||||
* overriding background-color and leaving the others behind.
|
||||
*
|
||||
* `.btn-add-to-cart` and `.btn-checkout` used to live here; no template or
|
||||
* script emits either name — the real ones are `.add-to-cart-btn` (see
|
||||
* components/quantity-control.css) and `.checkout-btn-lg`.
|
||||
*/
|
||||
|
||||
.btn-add-to-cart {
|
||||
background-color: var(--primary-color);
|
||||
border-color: var(--primary-color);
|
||||
color: white;
|
||||
:is(.eskaera-page, .eskaera-shop-page, .eskaera-generic-page, .eskaera-checkout-page)
|
||||
:is(.btn-primary, .btn-success) {
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
}
|
||||
|
||||
.btn-add-to-cart:focus {
|
||||
outline: 3px solid var(--primary-color);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
/* ---------- Checkout actions ---------- */
|
||||
|
||||
.btn-add-to-cart:hover {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.btn-checkout {
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
|
||||
border: none;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-checkout:focus {
|
||||
outline: 3px solid #667eea;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.btn-checkout:hover {
|
||||
background: linear-gradient(135deg, var(--primary-dark) 0%, var(--primary-dark) 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
.btn-success {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-primary:disabled,
|
||||
.btn-success:disabled {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
/* Checkout action buttons */
|
||||
.checkout-actions {
|
||||
margin-top: 2rem;
|
||||
margin-top: var(--ac-space-xl);
|
||||
}
|
||||
|
||||
.checkout-actions .btn {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
transition: all 0.3s ease;
|
||||
--btn-border-radius: var(--ac-radius-md);
|
||||
--btn-font-size: var(--ac-text-md);
|
||||
--btn-font-weight: var(--ac-weight-semibold);
|
||||
--btn-padding-y: var(--ac-space-xs);
|
||||
--btn-padding-x: var(--ac-space-lg);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.checkout-actions .btn-success {
|
||||
background-color: var(--success-color);
|
||||
border-color: var(--success-color);
|
||||
}
|
||||
|
||||
.checkout-actions .btn-success:hover {
|
||||
background-color: #218838;
|
||||
border-color: #218838;
|
||||
box-shadow: 0 4px 12px rgba(40, 167, 69, 0.3);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.checkout-actions .btn-outline-secondary {
|
||||
color: #ebeef0;
|
||||
border-color: #cad2d8;
|
||||
}
|
||||
|
||||
.checkout-actions .btn-outline-secondary:hover {
|
||||
color: white;
|
||||
background-color: #6c757d;
|
||||
border-color: #6c757d;
|
||||
box-shadow: 0 4px 12px rgba(108, 117, 125, 0.3);
|
||||
letter-spacing: 0.05em;
|
||||
transition: background-color var(--ac-transition-fast), border-color var(--ac-transition-fast),
|
||||
box-shadow var(--ac-transition-fast), transform var(--ac-transition-fast);
|
||||
}
|
||||
|
||||
.checkout-actions .btn i {
|
||||
margin-right: 0.5rem;
|
||||
margin-right: var(--ac-space-sm);
|
||||
}
|
||||
|
||||
.checkout-actions .btn-success {
|
||||
--btn-bg: var(--ac-color-success-strong);
|
||||
--btn-border-color: var(--ac-color-success-strong);
|
||||
--btn-color: var(--ac-text-on-fill);
|
||||
--btn-hover-bg: var(--ac-color-success-deep);
|
||||
--btn-hover-border-color: var(--ac-color-success-deep);
|
||||
--btn-hover-color: var(--ac-text-on-fill);
|
||||
}
|
||||
|
||||
/* "Back to cart". The previous #ebeef0 text sat at 1.17:1 on the white
|
||||
checkout card — the label was invisible until hover. */
|
||||
.checkout-actions .btn-outline-secondary {
|
||||
--btn-color: var(--ac-text-secondary);
|
||||
--btn-border-color: var(--ac-border-strong);
|
||||
--btn-hover-color: var(--ac-text-on-fill);
|
||||
--btn-hover-bg: var(--ac-color-secondary);
|
||||
--btn-hover-border-color: var(--ac-color-secondary);
|
||||
}
|
||||
|
||||
/* ---------- Long-label buttons ---------- */
|
||||
|
||||
.save-order-btn,
|
||||
.save-order-btn-styled,
|
||||
.checkout-btn-lg {
|
||||
padding: var(--ac-space-sm) var(--ac-space-md);
|
||||
font-size: var(--ac-text-md);
|
||||
white-space: nowrap;
|
||||
font-size: 1.1rem;
|
||||
padding: 0.6rem 1.2rem;
|
||||
}
|
||||
|
||||
.save-icon-size {
|
||||
font-size: 1.2rem;
|
||||
/* ---------- States ---------- */
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.checkout-actions .btn-success:hover,
|
||||
.checkout-actions .btn-outline-secondary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--ac-shadow-md);
|
||||
}
|
||||
}
|
||||
|
||||
.checkout-actions .btn:focus-visible,
|
||||
.save-order-btn:focus-visible,
|
||||
.checkout-btn-lg:focus-visible {
|
||||
outline: var(--ac-focus-ring-width) solid var(--ac-focus-ring-color);
|
||||
outline-offset: var(--ac-focus-ring-offset);
|
||||
}
|
||||
|
||||
@media (pointer: coarse) {
|
||||
.checkout-actions .btn,
|
||||
.save-order-btn,
|
||||
.checkout-btn-lg {
|
||||
min-height: var(--ac-touch-target);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.checkout-actions .btn,
|
||||
.checkout-actions .btn:hover {
|
||||
transform: none;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,236 +1,177 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/components/cart.css */
|
||||
|
||||
/**
|
||||
* Shopping cart component styles
|
||||
* Cart sidebar
|
||||
*
|
||||
* Markup (eskaera_shop):
|
||||
* .card.sticky-top.cart-sticky-position
|
||||
* ├ .card-header → #cart-title + .btn-group.cart-btn-group (4 icon buttons)
|
||||
* ├ .card-body.eskaera-cart-items[aria-live=polite]
|
||||
* │ └ injected by website_sale.js: .list-group > .list-group-item, .cart-total
|
||||
* └ .card-footer → clear cart + checkout
|
||||
*
|
||||
* The .list-group-item rules are scoped to the container: unscoped, they hit
|
||||
* every Bootstrap list group on the site, which is what forced three rounds of
|
||||
* re-declaration in layout/responsive.css.
|
||||
*/
|
||||
|
||||
.sticky-cart {
|
||||
top: 20px;
|
||||
.cart-sticky-position {
|
||||
top: var(--ac-space-md);
|
||||
}
|
||||
|
||||
.cart-header {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
padding: 0.25rem;
|
||||
border-radius: 0.25rem 0.25rem 0 0;
|
||||
}
|
||||
|
||||
.cart-header h5 {
|
||||
color: white;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.cart-header .btn {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.cart-items {
|
||||
max-height: 400px;
|
||||
/* Cap the scroll area against the viewport, not a fixed pixel height, so it
|
||||
still fits when text is enlarged. */
|
||||
.cart-items,
|
||||
.eskaera-cart-items {
|
||||
max-height: min(60vh, 25rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#cart-items-container {
|
||||
padding: 0.2rem 0.4rem;
|
||||
.eskaera-cart-items {
|
||||
padding: var(--ac-space-2xs) var(--ac-space-xs);
|
||||
font-size: var(--ac-text-base);
|
||||
}
|
||||
|
||||
#cart-items-container .list-group {
|
||||
.eskaera-cart-items .list-group {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#cart-items-container p.text-muted {
|
||||
margin: 0.4rem 0;
|
||||
.eskaera-cart-items p.text-muted {
|
||||
margin: var(--ac-space-2xs) 0;
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
padding: 0.4rem 0.6rem;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
.cart-empty-message {
|
||||
font-size: var(--ac-text-base);
|
||||
}
|
||||
|
||||
.list-group-item.d-flex {
|
||||
gap: 0.5rem;
|
||||
/* ---------- Cart lines ---------- */
|
||||
|
||||
.eskaera-cart-items .list-group-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--ac-space-2xs);
|
||||
padding: var(--ac-space-xs) var(--ac-space-sm);
|
||||
border-bottom: 1px solid var(--ac-border);
|
||||
font-size: var(--ac-text-base);
|
||||
}
|
||||
|
||||
.list-group-item h6 {
|
||||
margin: 0;
|
||||
margin-bottom: 0.2rem;
|
||||
font-weight: 600;
|
||||
.eskaera-cart-items .list-group-item h6 {
|
||||
margin: 0 0 var(--ac-space-3xs);
|
||||
font-size: var(--ac-text-base);
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
line-height: var(--ac-leading-snug);
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-word;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.list-group-item small {
|
||||
.eskaera-cart-items .list-group-item small {
|
||||
display: block;
|
||||
font-size: 0.75rem;
|
||||
color: #6c757d;
|
||||
font-size: var(--ac-text-xs);
|
||||
color: var(--ac-text-muted);
|
||||
}
|
||||
|
||||
.list-group-item .d-flex {
|
||||
min-width: auto;
|
||||
.eskaera-cart-items .list-group-item .d-flex {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
gap: var(--ac-space-sm);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.list-group-item .remove-from-cart {
|
||||
flex-shrink: 0;
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
/* Line subtotal. The previous #667eea was 3.42:1 at this size — under AA. */
|
||||
.eskaera-cart-items .list-group-item strong {
|
||||
min-width: 3.75rem;
|
||||
font-size: var(--ac-text-base);
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
color: var(--ac-color-primary-strong);
|
||||
}
|
||||
|
||||
.eskaera-cart-items .list-group-item > div:first-child {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Colours come from Bootstrap's .btn-danger, already on the element. */
|
||||
.remove-from-cart {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.15rem 0.25rem;
|
||||
font-size: 0.7rem;
|
||||
flex-shrink: 0;
|
||||
/* 24px is the WCAG 2.2 AA floor (2.5.8); touch gets the full target below. */
|
||||
min-width: 1.5rem;
|
||||
min-height: 1.5rem;
|
||||
padding: var(--ac-space-3xs) var(--ac-space-2xs);
|
||||
font-size: var(--ac-text-2xs);
|
||||
cursor: pointer;
|
||||
background-color: #dc3545;
|
||||
color: #ffffff;
|
||||
border: 1px solid #dc3545;
|
||||
border-radius: 3px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.list-group-item .remove-from-cart:hover {
|
||||
background-color: #bb2d3b;
|
||||
border-color: #bb2d3b;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.list-group-item .remove-from-cart i {
|
||||
font-size: 0.85rem;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.list-group-item strong {
|
||||
min-width: 60px;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
font-size: 0.875rem;
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.list-group-item.d-flex > div:first-child {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.list-group-item.d-flex > div:first-child h6 {
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
white-space: normal;
|
||||
transition: background-color var(--ac-transition-fast), transform var(--ac-transition-fast);
|
||||
}
|
||||
|
||||
.cart-total {
|
||||
padding: 1rem;
|
||||
background-color: #f8f9fa;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
border-top: 2px solid var(--primary-color);
|
||||
padding: var(--ac-space-md);
|
||||
border-top: 2px solid var(--ac-color-primary);
|
||||
background-color: var(--ac-surface-sunken);
|
||||
font-size: var(--ac-text-lg);
|
||||
font-weight: var(--ac-weight-bold);
|
||||
text-align: right;
|
||||
color: var(--primary-color);
|
||||
color: var(--ac-color-primary-strong);
|
||||
}
|
||||
|
||||
.cart-item-remove {
|
||||
cursor: pointer;
|
||||
color: #dc3545;
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
/* ---------- Header actions ---------- */
|
||||
|
||||
.cart-item-remove:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Cart header buttons styling */
|
||||
#save-cart-btn,
|
||||
#reload-cart-btn {
|
||||
font-weight: 600;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
margin-right: 0.25rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#save-cart-btn {
|
||||
background-color: #007bff;
|
||||
border-color: #0056b3;
|
||||
}
|
||||
|
||||
#save-cart-btn:hover {
|
||||
background-color: #0056b3;
|
||||
border-color: #004085;
|
||||
box-shadow: 0 4px 8px rgba(0, 86, 179, 0.3);
|
||||
}
|
||||
|
||||
#save-cart-btn:active {
|
||||
transform: scale(0.95);
|
||||
box-shadow: 0 2px 4px rgba(0, 86, 179, 0.3);
|
||||
}
|
||||
|
||||
#reload-cart-btn {
|
||||
background-color: #17a2b8;
|
||||
border-color: #117a8b;
|
||||
}
|
||||
|
||||
#reload-cart-btn:hover {
|
||||
background-color: #117a8b;
|
||||
border-color: #0c5460;
|
||||
box-shadow: 0 4px 8px rgba(17, 122, 139, 0.3);
|
||||
}
|
||||
|
||||
#reload-cart-btn:active {
|
||||
transform: scale(0.95);
|
||||
box-shadow: 0 2px 4px rgba(17, 122, 139, 0.3);
|
||||
}
|
||||
|
||||
.card-header .btn-group {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#cart-title {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.cart-btn-group-nowrap,
|
||||
.card-header .btn-group,
|
||||
.cart-btn-group {
|
||||
flex-shrink: 0;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.cart-header-btn {
|
||||
padding: 0.25rem;
|
||||
/* These four icon buttons were 0.5rem type with 0.1rem padding — roughly an
|
||||
18px target, under the 24px AA minimum, for the cart's primary actions. */
|
||||
.cart-btn-compact {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 2rem;
|
||||
min-height: 2rem;
|
||||
padding: var(--ac-space-2xs);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.cart-icon-size {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.cart-body-text {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.cart-body-lg {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.cart-title-lg {
|
||||
font-size: 1.5rem;
|
||||
font-size: var(--ac-text-base);
|
||||
}
|
||||
|
||||
.cart-title-sm {
|
||||
font-size: 1.1rem;
|
||||
font-size: var(--ac-text-md);
|
||||
}
|
||||
|
||||
.cart-btn-compact {
|
||||
padding: 0.1rem;
|
||||
min-width: auto;
|
||||
font-size: 0.5rem;
|
||||
line-height: 0.5;
|
||||
height: auto;
|
||||
/* ---------- States ---------- */
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.remove-from-cart:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
.cart-sticky-position {
|
||||
top: 20px;
|
||||
.remove-from-cart:focus-visible,
|
||||
.cart-btn-compact:focus-visible {
|
||||
outline: var(--ac-focus-ring-width) solid var(--ac-focus-ring-color);
|
||||
outline-offset: var(--ac-focus-ring-offset);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@media (pointer: coarse) {
|
||||
.cart-btn-compact,
|
||||
.remove-from-cart {
|
||||
min-width: var(--ac-touch-target);
|
||||
min-height: var(--ac-touch-target);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.remove-from-cart,
|
||||
.remove-from-cart:hover {
|
||||
transform: none;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,99 +1,129 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/components/forms.css */
|
||||
|
||||
/**
|
||||
* Form and input component styles
|
||||
* Form controls
|
||||
*
|
||||
* Everything here is scoped to an Eskaera page root. The previous version
|
||||
* styled bare `label`, `input[type="text"]`, `input[type="number"]` and
|
||||
* `select`, which reaches every form in web.assets_frontend — the website
|
||||
* login, the contact form, any other module's frontend widgets — not just this
|
||||
* addon's pages.
|
||||
*/
|
||||
|
||||
label {
|
||||
font-weight: 600;
|
||||
color: #2d3748;
|
||||
:is(.eskaera-page, .eskaera-shop-page, .eskaera-generic-page, .eskaera-checkout-page) label {
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
color: var(--ac-text-secondary);
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.form-select {
|
||||
border-color: #cbd5e0;
|
||||
font-size: 1rem;
|
||||
:is(.eskaera-page, .eskaera-shop-page, .eskaera-generic-page, .eskaera-checkout-page)
|
||||
:is(.form-control, .form-select, input[type="text"], input[type="number"], select) {
|
||||
/* WCAG 1.4.11: an input's border is what identifies it, so ≥ 3:1. */
|
||||
border: 1px solid var(--ac-border-strong);
|
||||
font-size: var(--ac-text-base);
|
||||
color: var(--ac-text-primary);
|
||||
background-color: var(--ac-surface);
|
||||
}
|
||||
|
||||
.form-control:focus,
|
||||
.form-select:focus {
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||
/* One focus treatment for every control on these pages, keyboard only. */
|
||||
:is(.eskaera-page, .eskaera-shop-page, .eskaera-generic-page, .eskaera-checkout-page)
|
||||
:is(.form-control, .form-select, .form-check-input, input, select, textarea):focus-visible {
|
||||
outline: var(--ac-focus-ring-width) solid var(--ac-focus-ring-color);
|
||||
outline-offset: var(--ac-focus-ring-offset);
|
||||
border-color: var(--ac-color-primary);
|
||||
}
|
||||
|
||||
input[type="number"],
|
||||
input[type="text"],
|
||||
select {
|
||||
background-color: #ffffff;
|
||||
color: #212529;
|
||||
border: 1px solid #ced4da;
|
||||
/* Bootstrap draws its own ring through a box-shadow on :focus; keep it in
|
||||
token colours so mouse focus still reads, without a second outline. */
|
||||
:is(.eskaera-page, .eskaera-shop-page, .eskaera-generic-page, .eskaera-checkout-page)
|
||||
:is(.form-control, .form-select):focus {
|
||||
border-color: var(--ac-color-primary);
|
||||
box-shadow: 0 0 0 0.2rem rgb(0 123 255 / 20%);
|
||||
}
|
||||
|
||||
input[type="number"]:focus,
|
||||
input[type="text"]:focus,
|
||||
select:focus {
|
||||
outline: 2px solid #667eea;
|
||||
outline-offset: 0;
|
||||
border-color: var(--primary-color);
|
||||
/* ---------- Search and category filter ---------- */
|
||||
|
||||
.eskaera-filters :is(.form-control, .form-select) {
|
||||
height: auto;
|
||||
padding: var(--ac-space-xs) var(--ac-space-sm);
|
||||
font-size: var(--ac-text-base);
|
||||
}
|
||||
|
||||
.form-check {
|
||||
/* The clear-search button sits inside the input; give it a real target. */
|
||||
.search-clear-btn {
|
||||
position: absolute;
|
||||
inset-block-start: 50%;
|
||||
inset-inline-end: var(--ac-space-2xs);
|
||||
transform: translateY(-50%);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
font-size: var(--ac-text-lg);
|
||||
line-height: 1;
|
||||
color: var(--ac-text-secondary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.search-clear-btn.is-visible {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.search-input-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-input-wrapper .form-control {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
|
||||
/* ---------- Home delivery checkbox ---------- */
|
||||
|
||||
.eskaera-delivery-check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 1rem 1.25rem;
|
||||
margin-left: 0;
|
||||
gap: var(--ac-space-sm);
|
||||
padding: var(--ac-space-md);
|
||||
}
|
||||
|
||||
.form-check-input {
|
||||
margin-right: 0.75rem;
|
||||
.eskaera-delivery-check .form-check-input {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Compact search and filter inputs */
|
||||
#realtime-search-input,
|
||||
#realtime-category-select {
|
||||
font-size: 0.95rem;
|
||||
padding: 0.375rem 0.75rem;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#realtimeSearch-filters .form-control,
|
||||
#realtimeSearch-filters .form-select {
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.form-check-label {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#home-delivery-checkbox {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
margin: 0;
|
||||
border: 2px solid var(--ac-color-primary);
|
||||
border-radius: var(--ac-radius-sm);
|
||||
cursor: pointer;
|
||||
border: 2px solid #0d6efd;
|
||||
border-radius: 0.25rem;
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
|
||||
#home-delivery-checkbox:checked {
|
||||
background-color: #0d6efd;
|
||||
border-color: #0d6efd;
|
||||
.eskaera-delivery-check .form-check-input:checked {
|
||||
border-color: var(--ac-color-primary);
|
||||
background-color: var(--ac-color-primary);
|
||||
}
|
||||
|
||||
#home-delivery-checkbox:focus {
|
||||
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
|
||||
.form-check-label[for="home-delivery-checkbox"] {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: #212529;
|
||||
cursor: pointer;
|
||||
.eskaera-delivery-check .form-check-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
font-size: var(--ac-text-md);
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
color: var(--ac-text-primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.help-text-sm {
|
||||
font-size: 0.85rem;
|
||||
/* ---------- Touch ---------- */
|
||||
|
||||
@media (pointer: coarse) {
|
||||
:is(.eskaera-page, .eskaera-shop-page, .eskaera-generic-page, .eskaera-checkout-page)
|
||||
:is(.form-control, .form-select) {
|
||||
min-height: var(--ac-touch-target);
|
||||
}
|
||||
|
||||
.search-clear-btn {
|
||||
width: var(--ac-touch-target);
|
||||
height: var(--ac-touch-target);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,43 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/components/order-card.css */
|
||||
|
||||
/**
|
||||
* Order card (Eskaera) component styles
|
||||
* Order card (Eskaera)
|
||||
*
|
||||
* Markup (eskaera_page):
|
||||
* .eskaera-order-card-wrapper
|
||||
* └ .eskaera-order-card[.eskaera-order-card--special]
|
||||
* └ .card-body
|
||||
* ├ .order-badge-position (product count)
|
||||
* ├ a.eskaera-order-card-link → .card-header-top (image, title, description)
|
||||
* ├ .card-meta-compact > .meta-grid (dates, badges)
|
||||
* └ a.btn (Browse products)
|
||||
*
|
||||
* Note the link only wraps the header, so the whole card is NOT clickable —
|
||||
* the hover/focus treatment below is applied to the card while the pointer is
|
||||
* anywhere over it, but `cursor: pointer` is left to the two real links.
|
||||
*/
|
||||
|
||||
.eskaera-order-card-link {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
display: block;
|
||||
width: 100%;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.eskaera-order-card {
|
||||
position: relative;
|
||||
background: linear-gradient(180deg, #ffffff 0%, #fbfdff 100%);
|
||||
border: 1px solid rgba(90, 103, 216, 0.12);
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 6px 18px rgba(28, 37, 80, 0.06);
|
||||
transition: transform 320ms cubic-bezier(0.2, 0.9, 0.2, 1), box-shadow 320ms, border-color 320ms,
|
||||
background 320ms;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 290px;
|
||||
/* min-height in rem, not px: at 200% zoom a px floor clips the content. */
|
||||
min-height: 18rem;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--ac-color-order-border);
|
||||
border-radius: var(--ac-radius-lg);
|
||||
background: var(--ac-surface-order);
|
||||
box-shadow: var(--ac-shadow-md);
|
||||
overflow: hidden;
|
||||
transition: transform var(--ac-transition-normal), box-shadow var(--ac-transition-normal),
|
||||
border-color var(--ac-transition-normal), background var(--ac-transition-normal);
|
||||
animation: slideInUp 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) both;
|
||||
}
|
||||
|
||||
|
|
@ -33,371 +46,281 @@
|
|||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Accent bar along the top edge. */
|
||||
.eskaera-order-card::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
inset: 0 0 auto;
|
||||
height: 6px;
|
||||
background: linear-gradient(90deg, var(--primary-color), var(--primary-dark));
|
||||
background: linear-gradient(90deg, var(--ac-color-order), var(--ac-color-order-strong));
|
||||
}
|
||||
|
||||
.eskaera-order-card-link:hover .eskaera-order-card {
|
||||
transform: translateY(-8px) scale(1.01);
|
||||
box-shadow: 0 20px 50px rgba(90, 103, 216, 0.15), 0 0 30px rgba(90, 103, 216, 0.1);
|
||||
border: 1px solid rgba(90, 103, 216, 0.25);
|
||||
background: linear-gradient(180deg, #ffffff 0%, #f7faff 100%);
|
||||
}
|
||||
|
||||
.eskaera-order-card-link:hover .eskaera-order-card::before {
|
||||
animation: shimmer 0.6s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
left: 0;
|
||||
}
|
||||
50% {
|
||||
left: 100%;
|
||||
}
|
||||
100% {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.eskaera-order-card .card-body {
|
||||
padding: 0.6rem 0.8rem 0 0.8rem;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.eskaera-order-card .card-title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
color: #1f2937;
|
||||
margin: 0;
|
||||
line-height: 1.15;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.order-desc-text {
|
||||
font-size: 0.8rem;
|
||||
color: #6b7280;
|
||||
margin: 0;
|
||||
line-height: 1.3;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.order-desc-sm {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.order-desc-md {
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.eskaera-order-card .btn {
|
||||
margin-top: auto;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 0.6rem;
|
||||
padding: 0.6rem 1.2rem;
|
||||
font-weight: 600;
|
||||
border-radius: 6px;
|
||||
border: none !important;
|
||||
font-size: 0.85rem;
|
||||
transition: all 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
background: linear-gradient(135deg, #5a67d8, #4c57bd) !important;
|
||||
color: white !important;
|
||||
box-shadow: 0 4px 12px rgba(90, 103, 216, 0.2) !important;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
text-decoration: none !important;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.eskaera-order-card .btn::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
transform: translate(-50%, -50%);
|
||||
transition: width 0.5s, height 0.5s;
|
||||
}
|
||||
|
||||
.eskaera-order-card .btn:active::before {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.eskaera-order-card .btn:hover {
|
||||
box-shadow: 0 8px 24px rgba(90, 103, 216, 0.4), inset 0 0 20px rgba(255, 255, 255, 0.2) !important;
|
||||
transform: translateY(-3px) scale(1.03);
|
||||
background: linear-gradient(135deg, #4c57bd, #3d4898) !important;
|
||||
}
|
||||
|
||||
/* Center button within card body */
|
||||
.eskaera-order-card .card-body > .btn {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
/* Order card header spacing */
|
||||
.order-card-header-spacing {
|
||||
margin-top: 0.9rem;
|
||||
}
|
||||
|
||||
/* Order thumbnail small */
|
||||
.order-thumbnail-sm {
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
border: 2px solid rgba(90, 103, 216, 0.1);
|
||||
}
|
||||
|
||||
/* Order thumbnail medium */
|
||||
.order-thumbnail-md {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Order thumbnail checkout */
|
||||
.order-thumbnail-checkout,
|
||||
.checkout-thumbnail {
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
object-fit: cover;
|
||||
border-radius: 6px;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
/* ---------- Header ---------- */
|
||||
|
||||
.card-header-top {
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
gap: var(--ac-space-sm);
|
||||
align-items: flex-start;
|
||||
margin-bottom: 0.3rem;
|
||||
height: 100px;
|
||||
overflow: hidden;
|
||||
margin-bottom: var(--ac-space-2xs);
|
||||
}
|
||||
|
||||
.card-header-top > div:last-child {
|
||||
text-align: left;
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.card-header-top .card-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.card-badges .badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
.eskaera-order-card .card-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
gap: var(--ac-space-2xs);
|
||||
padding: var(--ac-space-sm) var(--ac-space-sm) 0;
|
||||
}
|
||||
|
||||
.eskaera-order-card .card-title {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
font-size: var(--ac-text-base);
|
||||
font-weight: var(--ac-weight-bold);
|
||||
line-height: var(--ac-leading-tight);
|
||||
color: var(--ac-text-primary);
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.order-desc-text {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
font-size: var(--ac-text-xs);
|
||||
line-height: var(--ac-leading-snug);
|
||||
color: var(--ac-text-muted);
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* ---------- Thumbnails ---------- */
|
||||
|
||||
.order-thumbnail-sm {
|
||||
flex-shrink: 0;
|
||||
width: 5.625rem;
|
||||
height: 5.625rem;
|
||||
border: 2px solid var(--ac-color-order-border);
|
||||
border-radius: var(--ac-radius-md);
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.order-thumbnail-md {
|
||||
flex-shrink: 0;
|
||||
width: 7.5rem;
|
||||
height: 7.5rem;
|
||||
border-radius: var(--ac-radius-md);
|
||||
box-shadow: var(--ac-shadow-sm);
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
/* ---------- Product-count badge ---------- */
|
||||
|
||||
.order-badge-position {
|
||||
position: absolute;
|
||||
top: var(--ac-space-md);
|
||||
right: var(--ac-space-md);
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.order-badge-custom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--ac-space-sm);
|
||||
padding: var(--ac-space-sm) var(--ac-space-xs);
|
||||
border-radius: var(--ac-radius-sm);
|
||||
font-size: var(--ac-text-sm);
|
||||
font-weight: var(--ac-weight-bold);
|
||||
box-shadow: var(--ac-shadow-md);
|
||||
}
|
||||
|
||||
/* ---------- Meta block ---------- */
|
||||
|
||||
.card-meta-compact {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0;
|
||||
margin: 0.2rem auto 0 auto;
|
||||
padding: 0.6rem 0.8rem;
|
||||
border-top: 1px solid rgba(90, 103, 216, 0.08);
|
||||
background: rgba(245, 247, 255, 0.4);
|
||||
border-radius: 0 0 0.75rem 0.75rem;
|
||||
width: 100%;
|
||||
margin: var(--ac-space-2xs) auto 0;
|
||||
padding: var(--ac-space-sm);
|
||||
border-top: 1px solid var(--ac-color-order-border);
|
||||
border-radius: 0 0 var(--ac-radius-lg) var(--ac-radius-lg);
|
||||
background: var(--ac-surface-sunken);
|
||||
}
|
||||
|
||||
.card-meta-compact .card-meta-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
/* Meta table styles for clean date display */
|
||||
.meta-table {
|
||||
width: auto;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.8rem;
|
||||
margin: 0 auto;
|
||||
text-align: left;
|
||||
min-height: 160px;
|
||||
display: table;
|
||||
}
|
||||
|
||||
.meta-table tbody {
|
||||
display: table-row-group;
|
||||
}
|
||||
|
||||
.meta-row {
|
||||
display: table-row;
|
||||
font-size: 0.8rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.meta-label-cell {
|
||||
display: table-cell;
|
||||
padding: 0.25rem 0.6rem 0.25rem 0;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
text-align: right;
|
||||
vertical-align: top;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.meta-label-cell span {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.meta-value-cell {
|
||||
display: table-cell;
|
||||
padding: 0.25rem 0;
|
||||
color: #6b7280;
|
||||
text-align: left;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.meta-value-cell .badge {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-size: 0.7rem;
|
||||
padding: 0.2rem 0.5rem;
|
||||
}
|
||||
|
||||
.meta-label {
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
min-width: 85px;
|
||||
}
|
||||
|
||||
.meta-value {
|
||||
color: #6b7280;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.order-badge-position {
|
||||
position: absolute;
|
||||
top: 1.25rem;
|
||||
right: 1.25rem;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.order-badge-custom {
|
||||
font-weight: 700;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85rem;
|
||||
box-shadow: 0 4px 12px rgba(90, 103, 216, 0.3);
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
/* Meta grid - compact horizontal layout for order card metadata */
|
||||
.meta-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem 1rem;
|
||||
justify-content: center;
|
||||
gap: var(--ac-space-sm) var(--ac-space-md);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.meta-grid .meta-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
font-size: 0.8rem;
|
||||
gap: var(--ac-space-2xs);
|
||||
font-size: var(--ac-text-xs);
|
||||
}
|
||||
|
||||
.meta-grid .meta-label {
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
min-width: auto;
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
color: var(--ac-text-secondary);
|
||||
}
|
||||
|
||||
.meta-grid .meta-value {
|
||||
color: #6b7280;
|
||||
color: var(--ac-text-muted);
|
||||
}
|
||||
|
||||
.meta-grid .badge {
|
||||
font-size: 0.75rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.meta-grid .badge i {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
/* Special order card */
|
||||
.eskaera-order-card--special {
|
||||
background: linear-gradient(180deg, #fffdf0 0%, #fffbea 100%);
|
||||
border: 1px solid rgba(245, 158, 11, 0.35);
|
||||
box-shadow: 0 6px 18px rgba(245, 158, 11, 0.12);
|
||||
}
|
||||
|
||||
.eskaera-order-card--special::before {
|
||||
background: linear-gradient(90deg, #f59e0b, #d97706);
|
||||
}
|
||||
|
||||
.eskaera-order-card-link:hover .eskaera-order-card--special {
|
||||
box-shadow: 0 20px 50px rgba(245, 158, 11, 0.2), 0 0 30px rgba(245, 158, 11, 0.12);
|
||||
border-color: rgba(245, 158, 11, 0.5);
|
||||
background: linear-gradient(180deg, #fffdf0 0%, #fff8db 100%);
|
||||
}
|
||||
|
||||
.special-order-badge {
|
||||
background: linear-gradient(135deg, #f59e0b, #d97706) !important;
|
||||
color: #fff !important;
|
||||
font-size: 0.75rem;
|
||||
padding: 0.25rem 0.6rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 2px 6px rgba(245, 158, 11, 0.3);
|
||||
gap: var(--ac-space-2xs);
|
||||
padding: var(--ac-space-2xs) var(--ac-space-xs);
|
||||
font-size: var(--ac-text-2xs);
|
||||
}
|
||||
|
||||
.meta-item--full {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Home delivery: its own row, badge then date, centred as a pair — so it stays
|
||||
centred whether or not the date is there. */
|
||||
.meta-grid .meta-item--delivery {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
gap: var(--ac-space-sm);
|
||||
}
|
||||
|
||||
/* ---------- Call to action ---------- */
|
||||
|
||||
/* Bootstrap 5.3 drives .btn from unprefixed custom properties, so the card's
|
||||
own colours are set by redefining those instead of piling up !important. */
|
||||
.eskaera-order-card .btn {
|
||||
--btn-color: var(--ac-text-on-fill);
|
||||
--btn-bg: var(--ac-color-order);
|
||||
--btn-border-color: transparent;
|
||||
--btn-hover-color: var(--ac-text-on-fill);
|
||||
--btn-hover-bg: var(--ac-color-order-strong);
|
||||
--btn-hover-border-color: transparent;
|
||||
--btn-active-color: var(--ac-text-on-fill);
|
||||
--btn-active-bg: var(--ac-color-order-deep);
|
||||
--btn-active-border-color: transparent;
|
||||
--btn-border-radius: var(--ac-radius-sm);
|
||||
--btn-font-size: var(--ac-text-sm);
|
||||
--btn-font-weight: var(--ac-weight-semibold);
|
||||
--btn-padding-y: var(--ac-space-sm);
|
||||
--btn-padding-x: var(--ac-space-md);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--ac-space-sm);
|
||||
margin: auto auto var(--ac-space-sm);
|
||||
box-shadow: var(--ac-shadow-sm);
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
transition: background-color var(--ac-transition-fast), box-shadow var(--ac-transition-fast),
|
||||
transform var(--ac-transition-fast);
|
||||
}
|
||||
|
||||
/* ---------- Special orders ---------- */
|
||||
|
||||
.eskaera-order-card--special {
|
||||
border-color: var(--ac-color-special-border);
|
||||
background: var(--ac-surface-special);
|
||||
}
|
||||
|
||||
.eskaera-order-card--special::before {
|
||||
background: linear-gradient(90deg, var(--ac-color-special), var(--ac-color-special-strong));
|
||||
}
|
||||
|
||||
.special-order-badge {
|
||||
/* Amber needs dark text — white on it is 2.15:1. */
|
||||
--badge-color: var(--ac-text-on-special);
|
||||
--badge-font-size: var(--ac-text-2xs);
|
||||
--badge-border-radius: var(--ac-radius-sm);
|
||||
--badge-padding-x: var(--ac-space-xs);
|
||||
--badge-padding-y: var(--ac-space-2xs);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--ac-space-2xs);
|
||||
background: linear-gradient(135deg, var(--ac-color-special), var(--ac-color-special-strong));
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
box-shadow: var(--ac-shadow-sm);
|
||||
}
|
||||
|
||||
/* ---------- States ---------- */
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.eskaera-order-card:hover {
|
||||
transform: translateY(-8px);
|
||||
border-color: var(--ac-color-order-border-hover);
|
||||
background: var(--ac-surface-order-hover);
|
||||
box-shadow: var(--ac-shadow-lg);
|
||||
}
|
||||
|
||||
.eskaera-order-card--special:hover {
|
||||
border-color: var(--ac-color-special-border-hover);
|
||||
background: var(--ac-surface-special-hover);
|
||||
}
|
||||
|
||||
.eskaera-order-card .btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--ac-shadow-md);
|
||||
}
|
||||
}
|
||||
|
||||
/* Keyboard users get the same emphasis as a hover, plus a ring on the card
|
||||
that holds the focused link. */
|
||||
.eskaera-order-card:focus-within {
|
||||
border-color: var(--ac-color-order-border-hover);
|
||||
background: var(--ac-surface-order-hover);
|
||||
box-shadow: var(--ac-shadow-lg);
|
||||
}
|
||||
|
||||
.eskaera-order-card-link:focus-visible,
|
||||
.eskaera-order-card .btn:focus-visible {
|
||||
outline: var(--ac-focus-ring-width) solid var(--ac-focus-ring-color);
|
||||
outline-offset: var(--ac-focus-ring-offset);
|
||||
border-radius: var(--ac-radius-sm);
|
||||
}
|
||||
|
||||
/* The entry animation is decorative; motion sensitivity outranks it, and the
|
||||
hover lift has to stop moving too. */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.eskaera-order-card {
|
||||
animation: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.eskaera-order-card:hover,
|
||||
.eskaera-order-card .btn,
|
||||
.eskaera-order-card .btn:hover {
|
||||
transform: none;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,238 +1,204 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/components/product-card.css */
|
||||
|
||||
/**
|
||||
* Product card component styles
|
||||
* Product card
|
||||
*
|
||||
* Markup (eskaera_shop_products):
|
||||
* .product-card-wrapper.product-card
|
||||
* └ .card
|
||||
* ├ img.product-img-cover | .product-img-placeholder
|
||||
* ├ .card-body (title, tags, supplier, origin, 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.
|
||||
*/
|
||||
|
||||
.product-card {
|
||||
background-color: #fff;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
transition: box-shadow 0.3s, transform 0.2s;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.5rem;
|
||||
height: 100%;
|
||||
padding: var(--ac-space-2xs);
|
||||
border: 1px solid var(--ac-border-subtle);
|
||||
border-radius: var(--ac-radius-lg);
|
||||
background-color: var(--ac-surface);
|
||||
box-shadow: var(--ac-shadow-sm);
|
||||
overflow: hidden;
|
||||
outline: none;
|
||||
transition: box-shadow var(--ac-transition-normal), transform var(--ac-transition-normal);
|
||||
}
|
||||
|
||||
.product-card:hover,
|
||||
.product-card:focus-within {
|
||||
transform: translateY(-4px) scale(1.01);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.13);
|
||||
outline: 2px solid var(--primary-color, #007bff);
|
||||
outline-offset: 2px;
|
||||
/* Bootstrap 5.3 drives .card through unprefixed custom properties, so the inner
|
||||
card can be flattened without !important and without touching the markup. */
|
||||
.product-card > .card {
|
||||
--card-bg: transparent;
|
||||
--card-border-width: 0;
|
||||
--card-border-radius: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.product-card .product-image {
|
||||
height: 120px;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 8px 8px 0 0;
|
||||
background: #f3f3f3;
|
||||
display: block;
|
||||
}
|
||||
/* ---------- Media ---------- */
|
||||
|
||||
.product-img-cover {
|
||||
height: 120px;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 8px 8px 0 0;
|
||||
box-shadow: 0 2px 8px rgba(40, 39, 39, 0.09);
|
||||
background: #f3f3f3;
|
||||
.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);
|
||||
border-radius: var(--ac-radius-md) var(--ac-radius-md) 0 0;
|
||||
object-fit: cover;
|
||||
background-color: var(--ac-surface-muted);
|
||||
}
|
||||
|
||||
.product-img-placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--ac-text-muted);
|
||||
}
|
||||
|
||||
/* ---------- Body ---------- */
|
||||
|
||||
.product-card .card-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
flex-grow: 1;
|
||||
padding: 0.4rem 0.55rem 0.5rem;
|
||||
position: relative;
|
||||
background: linear-gradient(135deg, rgba(0, 123, 255, 0.07) 0%, rgba(0, 123, 255, 0.04) 100%);
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.product-card:hover .card-body,
|
||||
.product-card:focus-within .card-body {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(108, 117, 125, 0.13) 0%,
|
||||
rgba(108, 117, 125, 0.09) 100%
|
||||
);
|
||||
/* Sized to its own content, not stretched: the add-to-cart form below is
|
||||
what aligns across the row (see quantity-control.css), so the text/price
|
||||
block stays compact instead of ballooning to match a taller sibling. */
|
||||
gap: var(--ac-space-3xs);
|
||||
padding: var(--ac-space-2xs) var(--ac-space-xs) var(--ac-space-2xs);
|
||||
background: linear-gradient(135deg, var(--ac-surface-tint) 0%, transparent 100%);
|
||||
transition: background var(--ac-transition-normal);
|
||||
}
|
||||
|
||||
.product-card .card-title {
|
||||
flex-grow: 1;
|
||||
margin: 0 0 0.1rem 0;
|
||||
min-height: auto;
|
||||
display: block;
|
||||
word-wrap: break-word;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
/* Reserve both lines so single-line titles don't stagger the grid. */
|
||||
min-height: calc(2em * var(--ac-leading-tight));
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
overflow-wrap: break-word;
|
||||
font-size: 1rem !important;
|
||||
line-height: 1.15;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
color: #1a202c;
|
||||
font-size: var(--ac-text-base);
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
line-height: var(--ac-leading-tight);
|
||||
letter-spacing: 0.01em;
|
||||
text-align: center;
|
||||
color: var(--ac-text-primary);
|
||||
}
|
||||
|
||||
.product-card .card-text {
|
||||
margin-bottom: 0.08rem;
|
||||
margin-bottom: 0;
|
||||
font-size: var(--ac-text-sm);
|
||||
text-align: center;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.product-card .card-text strong {
|
||||
display: block;
|
||||
margin-bottom: 0.1rem;
|
||||
font-size: 1.15rem;
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.product-card .product-supplier {
|
||||
text-align: center;
|
||||
color: #4a5568;
|
||||
font-weight: 400;
|
||||
margin-bottom: 0.08rem;
|
||||
font-size: 0.85rem !important;
|
||||
}
|
||||
/* ---------- Tags ---------- */
|
||||
|
||||
.product-tags {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.12rem;
|
||||
gap: var(--ac-space-3xs);
|
||||
justify-content: center;
|
||||
font-weight: 400;
|
||||
font-size: 1rem !important;
|
||||
margin: 0 0 0.08rem 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* The per-tag colour is a record value, so it arrives as the --ac-tag-color
|
||||
custom property set inline on the element (see eskaera_shop_products). */
|
||||
.badge-km {
|
||||
background-color: var(--primary-color, #007bff) !important;
|
||||
color: #fff !important;
|
||||
font-weight: 600 !important;
|
||||
padding: 0.18rem 0.32rem !important;
|
||||
font-size: 0.68rem !important;
|
||||
border-radius: 0.22rem;
|
||||
display: inline-block;
|
||||
border: 1px solid #007bff;
|
||||
--badge-padding-x: var(--ac-space-2xs);
|
||||
--badge-padding-y: var(--ac-space-3xs);
|
||||
--badge-font-size: var(--ac-text-2xs);
|
||||
--badge-font-weight: var(--ac-weight-semibold);
|
||||
--badge-color: var(--ac-text-on-fill);
|
||||
--badge-border-radius: var(--ac-radius-sm);
|
||||
border: 1px solid var(--ac-tag-color, var(--ac-color-primary-strong));
|
||||
background-color: var(--ac-tag-color, var(--ac-color-primary-strong));
|
||||
white-space: nowrap;
|
||||
margin-right: 0.08rem;
|
||||
margin-bottom: 0.08rem;
|
||||
}
|
||||
|
||||
.card-body p.card-text {
|
||||
/* ---------- Supplier & origin ---------- */
|
||||
|
||||
.product-card .product-supplier,
|
||||
.product-card .product-origin {
|
||||
margin: 0;
|
||||
font-size: var(--ac-text-xs);
|
||||
font-weight: var(--ac-weight-normal);
|
||||
text-align: center;
|
||||
margin-bottom: 0.35rem;
|
||||
min-height: 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--primary-color, #007bff);
|
||||
color: #fff;
|
||||
border-radius: 0.18rem;
|
||||
font-size: 0.98rem;
|
||||
color: var(--ac-text-secondary);
|
||||
}
|
||||
|
||||
.card-body p.card-text strong {
|
||||
display: inline;
|
||||
font-size: 1.18rem !important;
|
||||
color: var(--primary-color, #007bff);
|
||||
margin-bottom: 0;
|
||||
.product-card .product-origin .fa {
|
||||
margin-right: var(--ac-space-3xs);
|
||||
}
|
||||
|
||||
/* ---------- Price ---------- */
|
||||
|
||||
.product-card .product-price-display {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--ac-space-2xs);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.product-card .product-price-main {
|
||||
font-size: var(--ac-text-lg);
|
||||
font-weight: var(--ac-weight-bold);
|
||||
line-height: var(--ac-leading-tight);
|
||||
white-space: nowrap;
|
||||
color: var(--ac-color-primary-strong);
|
||||
}
|
||||
|
||||
.product-img-fixed {
|
||||
object-fit: cover;
|
||||
height: 120px;
|
||||
width: 100%;
|
||||
border-radius: 8px 8px 0 0;
|
||||
background: #f3f3f3;
|
||||
display: block;
|
||||
.product-card .product-unit-price {
|
||||
margin: 0;
|
||||
font-size: var(--ac-text-xs);
|
||||
text-align: center;
|
||||
color: var(--ac-text-secondary);
|
||||
}
|
||||
|
||||
.product-img-placeholder {
|
||||
height: 120px;
|
||||
width: 100%;
|
||||
border-radius: 8px 8px 0 0;
|
||||
background: #f3f3f3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
color: #ccc;
|
||||
}
|
||||
/* ---------- States ---------- */
|
||||
|
||||
/* Responsive: tablet (≤768px) — compresión moderada */
|
||||
@media (max-width: 768px) {
|
||||
.product-card .product-image,
|
||||
.product-img-cover,
|
||||
.product-img-fixed,
|
||||
.product-img-placeholder {
|
||||
height: 90px;
|
||||
/* Hover effects only where a pointer can actually hover — on touch they stick
|
||||
after a tap and read as a stuck selection. */
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.product-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: var(--ac-shadow-lg);
|
||||
}
|
||||
|
||||
.product-card:hover .card-body {
|
||||
background: linear-gradient(135deg, var(--ac-surface-tint-hover) 0%, transparent 100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Keyboard focus only: a ring, and no transform — moving the card under the
|
||||
caret while tabbing is disorienting. */
|
||||
.product-card:focus-visible,
|
||||
.product-card:focus-within {
|
||||
outline: var(--ac-focus-ring-width) solid var(--ac-focus-ring-color);
|
||||
outline-offset: var(--ac-focus-ring-offset);
|
||||
}
|
||||
|
||||
.product-card:focus-within .card-body {
|
||||
background: linear-gradient(135deg, var(--ac-surface-tint-hover) 0%, transparent 100%);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.product-card,
|
||||
.product-card .card-body {
|
||||
padding: 0.35rem 0.45rem 0.4rem;
|
||||
transition: none;
|
||||
}
|
||||
.card-body p.card-text {
|
||||
margin-bottom: 0.25rem;
|
||||
min-height: 1.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive: móvil (≤480px) — compresión máxima */
|
||||
@media (max-width: 480px) {
|
||||
.product-card {
|
||||
padding: 0.15rem;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.product-card .product-image,
|
||||
.product-img-cover,
|
||||
.product-img-fixed,
|
||||
.product-img-placeholder {
|
||||
height: 60px;
|
||||
border-radius: 5px 5px 0 0;
|
||||
}
|
||||
.product-card .card-body {
|
||||
padding: 0.25rem 0.3rem 0.3rem;
|
||||
}
|
||||
.product-card .card-title {
|
||||
font-size: 0.82rem !important;
|
||||
line-height: 1.15;
|
||||
margin-bottom: 0.05rem;
|
||||
}
|
||||
.product-card .card-text {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.badge-km {
|
||||
font-size: 0.55rem !important;
|
||||
padding: 0.1rem 0.18rem !important;
|
||||
}
|
||||
.product-tags {
|
||||
font-size: 0.82rem !important;
|
||||
gap: 0.08rem;
|
||||
margin-bottom: 0.05rem;
|
||||
}
|
||||
.card-body p.card-text {
|
||||
min-height: 1rem;
|
||||
font-size: 0.85rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.product-card .product-supplier {
|
||||
font-size: 0.72rem !important;
|
||||
margin-bottom: 0.05rem;
|
||||
.product-card:hover {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Accesibilidad: focus visible */
|
||||
.product-card:focus-visible {
|
||||
outline: 2.5px solid var(--primary-color, #007bff);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,405 +1,220 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/components/quantity-control.css */
|
||||
|
||||
/**
|
||||
* Quantity control (+ - input) component styles
|
||||
* Quantity control — stepper (− input +) plus the add-to-cart button.
|
||||
*
|
||||
* Markup (eskaera_shop_products):
|
||||
* form.add-to-cart-form
|
||||
* └ .qty-control
|
||||
* ├ label.visually-hidden
|
||||
* ├ button.qty-decrease
|
||||
* ├ input.product-qty
|
||||
* ├ button.qty-increase
|
||||
* └ button.add-to-cart-btn
|
||||
*
|
||||
* Sizing is fluid (--ac-control-size), which replaces the six per-breakpoint
|
||||
* bands this component used to carry. The only query left is a pointer query:
|
||||
* what actually changes between a phone and a desktop is the input device, not
|
||||
* the viewport width.
|
||||
*/
|
||||
|
||||
/* Formulario agregar al carrito */
|
||||
/* margin-top: auto pins this to the bottom of .product-card > .card (which is
|
||||
stretched to the grid row's tallest sibling) so every card's button ends up
|
||||
at the same height, without ballooning the text/price block above it — see
|
||||
.product-card .card-body in product-card.css. */
|
||||
.add-to-cart-form {
|
||||
width: 100%;
|
||||
gap: 0;
|
||||
padding: 0.5rem;
|
||||
margin-top: 0.25rem;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
border: 1px solid #e9ecef;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
margin-top: auto;
|
||||
padding: var(--ac-space-3xs);
|
||||
border: 1px solid var(--ac-border);
|
||||
border-radius: var(--ac-radius-sm);
|
||||
background-color: var(--ac-surface-sunken);
|
||||
}
|
||||
|
||||
.add-to-cart-form .input-group {
|
||||
/* A grid, not a wrapping flex row: four 44px controls never fit across a card
|
||||
that is ~150px wide, so the row used to wrap and drop "+" onto its own line
|
||||
next to the cart button. Two deliberate rows instead — the stepper across the
|
||||
top, the primary action full width underneath, where it is easier to hit. */
|
||||
.qty-control {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
gap: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* ---------- Stepper ---------- */
|
||||
|
||||
.qty-control .qty-decrease,
|
||||
.qty-control .qty-increase {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 36px;
|
||||
flex-shrink: 0;
|
||||
width: var(--ac-control-size);
|
||||
height: var(--ac-control-size);
|
||||
padding: 0;
|
||||
/* WCAG 1.4.11: the boundary is what identifies the control, so it needs
|
||||
≥ 3:1 against the surface behind it. */
|
||||
border: var(--ac-control-border-width) solid var(--ac-border-strong);
|
||||
font-size: var(--ac-text-sm);
|
||||
color: var(--ac-text-secondary);
|
||||
background-color: var(--ac-surface);
|
||||
cursor: pointer;
|
||||
transition: color var(--ac-transition-fast), border-color var(--ac-transition-fast),
|
||||
background-color var(--ac-transition-fast);
|
||||
}
|
||||
|
||||
.qty-control .qty-decrease {
|
||||
border-start-start-radius: var(--ac-radius-sm);
|
||||
border-end-start-radius: var(--ac-radius-sm);
|
||||
border-start-end-radius: 0;
|
||||
border-end-end-radius: 0;
|
||||
}
|
||||
|
||||
.qty-control .qty-increase {
|
||||
border-start-end-radius: var(--ac-radius-sm);
|
||||
border-end-end-radius: var(--ac-radius-sm);
|
||||
border-start-start-radius: 0;
|
||||
border-end-start-radius: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-form .product-qty {
|
||||
flex: 1 1 auto;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
padding: 0.3rem;
|
||||
min-width: 32px;
|
||||
max-width: 70px;
|
||||
border: 2px solid #dee2e6;
|
||||
/* Fills the middle grid column; min-width 0 lets it shrink on a narrow card
|
||||
instead of pushing the "+" button out of the row. */
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: var(--ac-control-size);
|
||||
padding: 0 var(--ac-space-2xs);
|
||||
/* Collapse the shared edge with the two stepper buttons. */
|
||||
border: var(--ac-control-border-width) solid var(--ac-border-strong);
|
||||
border-inline-width: 0;
|
||||
border-radius: 0;
|
||||
background-color: #ffffff;
|
||||
transition: all 0.2s ease;
|
||||
font-size: var(--ac-text-base);
|
||||
font-weight: var(--ac-weight-bold);
|
||||
text-align: center;
|
||||
color: var(--ac-text-primary);
|
||||
background-color: var(--ac-surface);
|
||||
appearance: textfield;
|
||||
-moz-appearance: textfield;
|
||||
height: 36px;
|
||||
line-height: 30px;
|
||||
transition: border-color var(--ac-transition-fast), box-shadow var(--ac-transition-fast);
|
||||
}
|
||||
|
||||
.add-to-cart-form .product-qty::-webkit-outer-spin-button,
|
||||
.add-to-cart-form .product-qty::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.add-to-cart-form .product-qty:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-color, #007bff);
|
||||
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
|
||||
background-color: #ffffff;
|
||||
}
|
||||
/* ---------- Add to cart ---------- */
|
||||
|
||||
/* Contenedor de control de cantidad */
|
||||
.qty-control {
|
||||
.add-to-cart-form .add-to-cart-btn {
|
||||
/* Full width on its own row, under the stepper. */
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
/* Botones de cantidad + y - */
|
||||
.qty-control .qty-decrease,
|
||||
.qty-control .qty-increase {
|
||||
min-width: 36px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
height: var(--ac-control-size);
|
||||
margin-top: var(--ac-space-3xs);
|
||||
padding: 0;
|
||||
gap: 0;
|
||||
font-size: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2px solid #dee2e6;
|
||||
background-color: #ffffff;
|
||||
color: #495057;
|
||||
transition: all 0.2s ease;
|
||||
border: none;
|
||||
border-radius: var(--ac-radius-sm);
|
||||
font-size: var(--ac-text-sm);
|
||||
color: var(--ac-text-on-fill);
|
||||
background-color: var(--ac-color-accent);
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
transition: background-color var(--ac-transition-fast), transform var(--ac-transition-fast);
|
||||
}
|
||||
|
||||
.qty-control .qty-decrease:hover,
|
||||
.qty-control .qty-increase:hover {
|
||||
border-color: var(--primary-color, #007bff);
|
||||
color: var(--primary-color, #007bff);
|
||||
background-color: #f8f9fa;
|
||||
.add-to-cart-form .add-to-cart-btn .fa {
|
||||
font-size: var(--ac-text-md);
|
||||
}
|
||||
|
||||
/* Out of stock stays focusable and clickable on purpose: the handler answers
|
||||
with an explanation instead of the control silently doing nothing. It is
|
||||
marked aria-disabled in the template, so the styling has to read as
|
||||
unavailable without relying on colour alone (the icon changes to fa-ban). */
|
||||
.add-to-cart-form .add-to-cart-btn[data-out-of-stock="true"] {
|
||||
color: var(--ac-text-secondary);
|
||||
background-color: var(--ac-surface-muted);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* ---------- States ---------- */
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.qty-control .qty-decrease:hover,
|
||||
.qty-control .qty-increase:hover {
|
||||
border-color: var(--ac-color-primary);
|
||||
color: var(--ac-color-primary-strong);
|
||||
background-color: var(--ac-surface-sunken);
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn:hover {
|
||||
background-color: var(--ac-color-accent-strong);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn[data-out-of-stock="true"]:hover {
|
||||
background-color: var(--ac-surface-muted);
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
.qty-control .qty-decrease:active,
|
||||
.qty-control .qty-increase:active {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn {
|
||||
white-space: nowrap;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
margin: 0;
|
||||
font-size: 0.8rem;
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
min-width: 36px;
|
||||
max-width: 36px;
|
||||
min-height: 36px;
|
||||
max-height: 36px;
|
||||
flex-shrink: 0;
|
||||
border: none;
|
||||
background-color: #7c3aed !important;
|
||||
color: #ffffff !important;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn:hover {
|
||||
background-color: #6d28d9 !important;
|
||||
transform: scale(1.05);
|
||||
background-color: var(--ac-surface-sunken);
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn:active {
|
||||
background-color: #5b21b6 !important;
|
||||
background-color: var(--ac-color-accent-strong);
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn i {
|
||||
font-size: 1rem;
|
||||
.qty-control .qty-decrease:focus-visible,
|
||||
.qty-control .qty-increase:focus-visible,
|
||||
.add-to-cart-form .add-to-cart-btn:focus-visible,
|
||||
.add-to-cart-form .product-qty:focus-visible {
|
||||
outline: var(--ac-focus-ring-width) solid var(--ac-focus-ring-color);
|
||||
outline-offset: var(--ac-focus-ring-offset);
|
||||
/* Raise the focused control so the ring is not clipped by its neighbours. */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Pantallas muy grandes: 1600px+ (6 columnas) */
|
||||
@media (min-width: 1600px) {
|
||||
.add-to-cart-form {
|
||||
padding: 0.35rem;
|
||||
gap: 0.08rem;
|
||||
}
|
||||
.add-to-cart-form .product-qty:focus-visible {
|
||||
border-color: var(--ac-color-primary);
|
||||
}
|
||||
|
||||
.add-to-cart-form .input-group {
|
||||
height: 32px;
|
||||
gap: 0.06rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .product-qty {
|
||||
font-size: 1rem;
|
||||
min-width: 28px;
|
||||
max-width: 60px;
|
||||
height: 32px;
|
||||
padding: 0.2rem;
|
||||
}
|
||||
/* ---------- Input device ---------- */
|
||||
|
||||
/* Touch: grow every target to 44px. WCAG 2.2 AA (2.5.8) only asks for 24px,
|
||||
but 44px is the AAA figure (2.5.5) and what a thumb actually needs. */
|
||||
@media (pointer: coarse) {
|
||||
.qty-control .qty-decrease,
|
||||
.qty-control .qty-increase {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 0.9rem;
|
||||
width: var(--ac-touch-target);
|
||||
height: var(--ac-touch-target);
|
||||
}
|
||||
|
||||
.add-to-cart-form .product-qty,
|
||||
.add-to-cart-form .add-to-cart-btn {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
min-width: 32px;
|
||||
max-width: 32px;
|
||||
font-size: 0.75rem;
|
||||
height: var(--ac-touch-target);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pantallas grandes: 1400-1599px (5 columnas) */
|
||||
@media (max-width: 1599px) and (min-width: 1400px) {
|
||||
.add-to-cart-form {
|
||||
padding: 0.36rem;
|
||||
gap: 0.07rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .input-group {
|
||||
height: 32px;
|
||||
gap: 0.05rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .product-qty {
|
||||
font-size: 1rem;
|
||||
min-width: 28px;
|
||||
max-width: 62px;
|
||||
height: 32px;
|
||||
padding: 0.2rem;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.qty-control .qty-decrease,
|
||||
.qty-control .qty-increase {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 0.9rem;
|
||||
.qty-control .qty-increase,
|
||||
.add-to-cart-form .product-qty,
|
||||
.add-to-cart-form .add-to-cart-btn {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
min-width: 32px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pantallas medianas: 1200-1399px (4 columnas) */
|
||||
@media (max-width: 1399px) and (min-width: 1200px) {
|
||||
.add-to-cart-form {
|
||||
padding: 0.34rem;
|
||||
gap: 0.06rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .input-group {
|
||||
height: 32px;
|
||||
gap: 0.05rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .product-qty {
|
||||
font-size: 0.95rem;
|
||||
min-width: 28px;
|
||||
max-width: 60px;
|
||||
height: 32px;
|
||||
padding: 0.2rem;
|
||||
}
|
||||
|
||||
.qty-control .qty-decrease,
|
||||
.qty-control .qty-increase {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
min-width: 32px;
|
||||
font-size: 0.74rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pantallas tablet grandes: 992-1199px (3 columnas) */
|
||||
@media (max-width: 1199px) and (min-width: 992px) {
|
||||
.add-to-cart-form {
|
||||
padding: 0.32rem;
|
||||
gap: 0.04rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .input-group {
|
||||
height: 32px;
|
||||
gap: 0.04rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .product-qty {
|
||||
font-size: 0.9rem;
|
||||
min-width: 28px;
|
||||
max-width: 58px;
|
||||
height: 32px;
|
||||
padding: 0.2rem;
|
||||
}
|
||||
|
||||
.qty-control .qty-decrease,
|
||||
.qty-control .qty-increase {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 0.85rem;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
min-width: 32px;
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pantallas tablet: 768-991px (2-3 columnas) */
|
||||
@media (max-width: 991px) and (min-width: 768px) {
|
||||
.add-to-cart-form {
|
||||
padding: 0.42rem;
|
||||
gap: 0.03rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .input-group {
|
||||
height: 36px;
|
||||
gap: 0.04rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .product-qty {
|
||||
font-size: 1rem;
|
||||
min-width: 32px;
|
||||
max-width: 68px;
|
||||
height: 36px;
|
||||
padding: 0.3rem;
|
||||
}
|
||||
|
||||
.qty-control .qty-decrease,
|
||||
.qty-control .qty-increase {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
font-size: 0.95rem;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn {
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
min-width: 36px;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Móvil grande: 576-767px (2 columnas) */
|
||||
@media (max-width: 767px) and (min-width: 576px) {
|
||||
.add-to-cart-form {
|
||||
padding: 0.35rem;
|
||||
gap: 0.1rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .input-group {
|
||||
height: 34px;
|
||||
gap: 0.08rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .product-qty {
|
||||
font-size: 0.9rem;
|
||||
min-width: 30px;
|
||||
max-width: 64px;
|
||||
height: 34px;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.qty-control .qty-decrease,
|
||||
.qty-control .qty-increase {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
font-size: 0.9rem;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn {
|
||||
height: 34px;
|
||||
width: 34px;
|
||||
min-width: 34px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Móvil pequeño: < 576px (1 columna) */
|
||||
@media (max-width: 575px) {
|
||||
.add-to-cart-form {
|
||||
padding: 0.3rem;
|
||||
gap: 0.08rem;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.add-to-cart-form .input-group {
|
||||
height: 32px;
|
||||
gap: 0.06rem;
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
|
||||
.add-to-cart-form .product-qty {
|
||||
font-size: 0.8rem;
|
||||
min-width: 28px;
|
||||
max-width: 60px;
|
||||
height: 32px;
|
||||
padding: 0.2rem;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.qty-control .qty-decrease,
|
||||
.qty-control .qty-increase {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 0.8rem;
|
||||
border-width: 1px;
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
.qty-control {
|
||||
width: auto;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
min-width: 32px;
|
||||
max-width: 32px;
|
||||
font-size: 0.75rem;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn i {
|
||||
font-size: 0.8rem;
|
||||
.add-to-cart-form .add-to-cart-btn:hover,
|
||||
.add-to-cart-form .add-to-cart-btn:active {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,70 +4,103 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* Tag Filter Badges Component
|
||||
* Tag filter badges
|
||||
*
|
||||
* Styles for interactive tag filter badges in the product search/filter bar.
|
||||
* Badges toggle between secondary (unselected) and primary (selected) states.
|
||||
* Toggle buttons above the product grid. Three states:
|
||||
* (default) nothing selected — each badge wears its own tag colour
|
||||
* .is-selected this tag is filtering
|
||||
* .is-dimmed another tag is filtering, this one is not
|
||||
*
|
||||
* realtime_search.js used to paint all three by writing nine
|
||||
* style.setProperty(..., "important") calls per click. It now only toggles
|
||||
* these classes and aria-pressed; the appearance lives here.
|
||||
*
|
||||
* The per-tag colour arrives as --ac-tag-color, set inline from the record.
|
||||
*/
|
||||
|
||||
/* Container for all tag filter badges */
|
||||
.tag-filter-badges {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem 0;
|
||||
justify-content: center;
|
||||
gap: var(--ac-space-sm);
|
||||
padding: var(--ac-space-xs) 0;
|
||||
}
|
||||
|
||||
/* Individual tag filter badge button */
|
||||
.tag-filter-badge {
|
||||
cursor: pointer;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
/* 24px is the AA floor (WCAG 2.2 §2.5.8); coarse pointers get 44 below. */
|
||||
min-height: 1.5rem;
|
||||
padding: var(--ac-space-sm) var(--ac-space-xs);
|
||||
border: 1px solid var(--ac-tag-color, var(--ac-color-secondary));
|
||||
border-radius: var(--ac-radius-sm);
|
||||
background-color: var(--ac-tag-color, var(--ac-color-secondary));
|
||||
font-size: var(--ac-text-sm);
|
||||
font-weight: var(--ac-weight-medium);
|
||||
color: var(--ac-text-on-fill);
|
||||
white-space: nowrap;
|
||||
transition: all 0.2s ease-in-out;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
display: inline-block;
|
||||
border: 1px solid;
|
||||
color: #ffffff !important;
|
||||
transition: background-color var(--ac-transition-fast), border-color var(--ac-transition-fast),
|
||||
box-shadow var(--ac-transition-fast), transform var(--ac-transition-fast);
|
||||
}
|
||||
|
||||
/* Tags sin color definido en Odoo: usar color secundario del tema */
|
||||
.tag-filter-badge.tag-use-theme-color {
|
||||
background-color: var(--bs-secondary, #6c757d);
|
||||
border-color: var(--bs-secondary, #6c757d);
|
||||
}
|
||||
|
||||
/* Product card tags (badge-km) sin color definido: usar color del tema */
|
||||
/* Tags with no colour of their own fall back to the theme's secondary. The old
|
||||
var(--bs-secondary) never resolved: Odoo emits Bootstrap's custom properties
|
||||
unprefixed, so that lookup always landed on its hardcoded fallback. */
|
||||
.tag-filter-badge.tag-use-theme-color,
|
||||
.badge-km.tag-use-theme-color {
|
||||
background-color: var(--bs-secondary, #6c757d);
|
||||
border-color: var(--bs-secondary, #6c757d);
|
||||
color: #ffffff !important;
|
||||
border-color: var(--ac-color-secondary);
|
||||
background-color: var(--ac-color-secondary);
|
||||
color: var(--ac-text-on-fill);
|
||||
}
|
||||
|
||||
.tag-filter-badge:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||
filter: brightness(0.9);
|
||||
/* Active filter: the strong primary, which also carries white text at 7.04:1. */
|
||||
.tag-filter-badge.is-selected {
|
||||
border-color: var(--ac-color-primary-strong);
|
||||
background-color: var(--ac-color-primary-strong);
|
||||
box-shadow: var(--ac-shadow-sm);
|
||||
}
|
||||
|
||||
/* Not part of the current filter while others are. */
|
||||
.tag-filter-badge.is-dimmed {
|
||||
border-color: var(--ac-color-secondary);
|
||||
background-color: var(--ac-color-secondary);
|
||||
}
|
||||
|
||||
/* Counter text inside badge */
|
||||
.tag-filter-badge .tag-count {
|
||||
font-weight: 600;
|
||||
margin-left: 0.25rem;
|
||||
margin-left: var(--ac-space-2xs);
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.tag-filter-badges {
|
||||
gap: 0.375rem;
|
||||
}
|
||||
/* ---------- States ---------- */
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.tag-filter-badge:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--ac-shadow-md);
|
||||
filter: brightness(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
.tag-filter-badge:focus-visible {
|
||||
outline: var(--ac-focus-ring-width) solid var(--ac-focus-ring-color);
|
||||
outline-offset: var(--ac-focus-ring-offset);
|
||||
}
|
||||
|
||||
@media (pointer: coarse) {
|
||||
.tag-filter-badge {
|
||||
padding: 0.375rem 0.625rem;
|
||||
font-size: 0.8125rem;
|
||||
min-height: var(--ac-touch-target);
|
||||
padding-inline: var(--ac-space-md);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.tag-filter-badge,
|
||||
.tag-filter-badge:hover {
|
||||
transform: none;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,83 +7,142 @@
|
|||
/* Unified header for both shop and checkout pages */
|
||||
.eskaera-order-header,
|
||||
.checkout-header {
|
||||
background: white;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 2rem;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
padding: clamp(var(--ac-space-md), 2vw, var(--ac-space-xl));
|
||||
border: 1px solid var(--ac-border-subtle);
|
||||
border-radius: var(--ac-radius-md);
|
||||
background: var(--ac-surface);
|
||||
box-shadow: var(--ac-shadow-sm);
|
||||
}
|
||||
|
||||
.eskaera-order-header h1,
|
||||
.checkout-header h1 {
|
||||
color: #2d3748;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1.5rem;
|
||||
border-bottom: 3px solid var(--primary-color, #007bff);
|
||||
padding-bottom: 1rem;
|
||||
margin-bottom: var(--ac-space-md);
|
||||
padding-bottom: var(--ac-space-md);
|
||||
border-bottom: 3px solid var(--ac-color-primary);
|
||||
font-size: var(--ac-text-2xl);
|
||||
font-weight: var(--ac-weight-bold);
|
||||
color: var(--ac-text-primary);
|
||||
}
|
||||
|
||||
.order-info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-weight: 700;
|
||||
color: #2d3748;
|
||||
font-size: 1.05rem;
|
||||
margin-bottom: 0.5rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.info-value,
|
||||
.info-date {
|
||||
font-size: 1.35rem;
|
||||
color: #1a202c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.info-date {
|
||||
display: block;
|
||||
font-size: 1.25rem;
|
||||
color: #2d3748;
|
||||
font-weight: 500;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
/* Title styling for both pages */
|
||||
.checkout-title,
|
||||
.eskaera-order-header h1 {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: #1a202c;
|
||||
margin-bottom: 1rem;
|
||||
.checkout-title {
|
||||
margin-bottom: var(--ac-space-md);
|
||||
font-size: var(--ac-text-2xl);
|
||||
font-weight: var(--ac-weight-bold);
|
||||
color: var(--ac-text-primary);
|
||||
}
|
||||
|
||||
.checkout-order-name {
|
||||
font-size: 1.5rem;
|
||||
color: #2d3748;
|
||||
font-weight: 600;
|
||||
font-size: var(--ac-text-lg);
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
color: var(--ac-text-secondary);
|
||||
}
|
||||
|
||||
/* Info value styling */
|
||||
.info-value {
|
||||
font-size: 1.1rem;
|
||||
/* ==========================================================================
|
||||
Order info: label / value pairs
|
||||
Rendered as <dl><dt class="info-label"><dd class="info-value">.
|
||||
Column count follows the viewport: 4 (label, value, label, value) on
|
||||
desktop, 2 (one pair per row) from sm, stacked below that. Cells carry the
|
||||
rules themselves and column-gap stays 0, so each row reads as one
|
||||
uninterrupted line instead of a dashed one.
|
||||
========================================================================== */
|
||||
|
||||
.order-info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
align-items: baseline;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.order-info-grid > .info-label {
|
||||
padding-block: var(--ac-space-sm) 0;
|
||||
/* Small, muted and spaced out, so the label never competes with its value.
|
||||
--ac-text-secondary keeps it at 7.53:1 despite the smaller size. */
|
||||
font-size: var(--ac-text-xs);
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
line-height: var(--ac-leading-snug);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--ac-text-secondary);
|
||||
}
|
||||
|
||||
.order-info-grid > .info-value {
|
||||
margin: 0;
|
||||
padding-block: var(--ac-space-2xs) var(--ac-space-sm);
|
||||
border-bottom: 1px solid var(--ac-border);
|
||||
font-size: var(--ac-text-md);
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
line-height: var(--ac-leading-snug);
|
||||
color: var(--ac-text-primary);
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Multi-line values (pickup slots) keep their own rhythm. */
|
||||
.order-info-grid .info-value-line + .info-value-line {
|
||||
margin-top: var(--ac-space-2xs);
|
||||
}
|
||||
|
||||
/* Two columns: label and value side by side, one pair per row. */
|
||||
@media (min-width: 576px) {
|
||||
.order-info-grid {
|
||||
grid-template-columns: auto 1fr;
|
||||
}
|
||||
|
||||
.order-info-grid > .info-label {
|
||||
padding-block: var(--ac-space-sm);
|
||||
padding-inline-end: var(--ac-space-md);
|
||||
border-bottom: 1px solid var(--ac-border);
|
||||
}
|
||||
|
||||
.order-info-grid > .info-value {
|
||||
padding-block: var(--ac-space-sm);
|
||||
padding-inline-end: var(--ac-space-md);
|
||||
}
|
||||
}
|
||||
|
||||
/* Four columns: two pairs per row, split by a vertical rule. The second pair
|
||||
always starts on an even <dt>, because grid places the cells in source
|
||||
order. */
|
||||
@media (min-width: 992px) {
|
||||
.order-info-grid {
|
||||
grid-template-columns: auto minmax(0, 1fr) auto minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.order-info-grid > .info-label:nth-of-type(even) {
|
||||
padding-inline-start: var(--ac-space-lg);
|
||||
border-inline-start: 1px solid var(--ac-border);
|
||||
}
|
||||
}
|
||||
|
||||
/* Single label/value pair, used in the checkout info row where each pair sits in
|
||||
its own Bootstrap column. */
|
||||
.info-pair {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.info-pair > .info-label {
|
||||
margin-bottom: var(--ac-space-3xs);
|
||||
font-size: var(--ac-text-xs);
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
line-height: var(--ac-leading-snug);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--ac-text-secondary);
|
||||
}
|
||||
|
||||
.info-pair > .info-value {
|
||||
margin: 0;
|
||||
font-size: var(--ac-text-md);
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
line-height: var(--ac-leading-snug);
|
||||
color: var(--ac-text-primary);
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Standalone date line used by the checkout header. */
|
||||
.info-date {
|
||||
font-size: 1rem;
|
||||
display: block;
|
||||
margin-top: var(--ac-space-2xs);
|
||||
font-size: var(--ac-text-base);
|
||||
font-weight: var(--ac-weight-medium);
|
||||
color: var(--ac-text-secondary);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,106 +1,67 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/layout/pages.css */
|
||||
|
||||
/**
|
||||
* Page backgrounds and main layout structures
|
||||
* Page shells: backgrounds and the container stacking above them.
|
||||
*
|
||||
* These styles used to reach far outside the addon:
|
||||
* - `html, body { background: transparent !important }` stripped the
|
||||
* background from EVERY page of the website, addon or not.
|
||||
* - `body.website_published { … !important }` was meant to put it back, but
|
||||
* no page carries that class — checked against the rendered HTML of the
|
||||
* orders, shop and checkout pages, whose <body> has no class at all. Both
|
||||
* rules were therefore dead weight on top of a site-wide side effect.
|
||||
* - `#wrap { padding: 2rem 0 }` styled Odoo's own page wrapper everywhere.
|
||||
* On these pages #wrap *is* the Eskaera root, so the padding moved onto the
|
||||
* root classes and the ID selector is gone.
|
||||
*
|
||||
* The body reset now applies only to pages that actually contain an Eskaera
|
||||
* root, which is enough specificity to win without !important.
|
||||
*/
|
||||
|
||||
html,
|
||||
body {
|
||||
background-color: transparent !important;
|
||||
background: transparent !important;
|
||||
body:has(.eskaera-page),
|
||||
body:has(.eskaera-shop-page),
|
||||
body:has(.eskaera-generic-page),
|
||||
body:has(.eskaera-checkout-page) {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
body.website_published {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
color-mix(in srgb, var(--primary-color) 30%, white),
|
||||
color-mix(in srgb, var(--primary-color) 60%, black)
|
||||
) !important;
|
||||
}
|
||||
|
||||
body.website_published .eskaera-shop-page,
|
||||
body.website_published .eskaera-checkout-page {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
/* Generic page background mixin */
|
||||
.eskaera-page,
|
||||
.eskaera-shop-page,
|
||||
.eskaera-generic-page,
|
||||
.eskaera-checkout-page {
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
/* dvh tracks the mobile browser chrome; vh stays as the fallback. */
|
||||
min-height: 100vh;
|
||||
min-height: 100dvh;
|
||||
padding: var(--ac-space-xl) 0;
|
||||
}
|
||||
|
||||
.eskaera-page,
|
||||
.eskaera-generic-page {
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
color-mix(in srgb, var(--primary-color) 10%, white),
|
||||
color-mix(in srgb, var(--primary-color) 70%, black)
|
||||
) !important;
|
||||
color-mix(in srgb, var(--ac-color-primary) 10%, white),
|
||||
color-mix(in srgb, var(--ac-color-primary) 70%, black)
|
||||
);
|
||||
}
|
||||
|
||||
.eskaera-shop-page {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
color-mix(in srgb, var(--primary-color) 10%, white),
|
||||
color-mix(in srgb, var(--primary-color) 10%, rgb(135, 135, 135))
|
||||
) !important;
|
||||
color-mix(in srgb, var(--ac-color-primary) 10%, white),
|
||||
color-mix(in srgb, var(--ac-color-primary) 10%, rgb(135, 135, 135))
|
||||
);
|
||||
}
|
||||
|
||||
.eskaera-checkout-page {
|
||||
background: linear-gradient(
|
||||
-135deg,
|
||||
color-mix(in srgb, var(--primary-color) 0%, white),
|
||||
color-mix(in srgb, var(--primary-color) 60%, black)
|
||||
) !important;
|
||||
white,
|
||||
color-mix(in srgb, var(--ac-color-primary) 60%, black)
|
||||
);
|
||||
}
|
||||
|
||||
.eskaera-page::before,
|
||||
.eskaera-generic-page::before {
|
||||
background-image: radial-gradient(
|
||||
circle at 20% 50%,
|
||||
color-mix(in srgb, var(--primary-color, white) 20%, transparent) 0%,
|
||||
transparent 50%
|
||||
),
|
||||
radial-gradient(
|
||||
circle at 80% 80%,
|
||||
color-mix(in srgb, var(--primary-color) 25%, transparent) 0%,
|
||||
transparent 50%
|
||||
),
|
||||
radial-gradient(
|
||||
circle at 40% 20%,
|
||||
color-mix(in srgb, var(--primary-color, white) 15%, transparent) 0%,
|
||||
transparent 50%
|
||||
);
|
||||
}
|
||||
|
||||
.eskaera-shop-page::before {
|
||||
background-image: radial-gradient(
|
||||
circle at 15% 30%,
|
||||
color-mix(in srgb, var(--primary-color, white) 18%, transparent) 0%,
|
||||
transparent 50%
|
||||
),
|
||||
radial-gradient(
|
||||
circle at 85% 70%,
|
||||
color-mix(in srgb, var(--primary-color) 22%, transparent) 0%,
|
||||
transparent 50%
|
||||
);
|
||||
}
|
||||
|
||||
.eskaera-checkout-page::before {
|
||||
background-image: radial-gradient(
|
||||
circle at 20% 50%,
|
||||
color-mix(in srgb, var(--primary-color, white) 20%, transparent) 0%,
|
||||
transparent 50%
|
||||
),
|
||||
radial-gradient(
|
||||
circle at 80% 80%,
|
||||
color-mix(in srgb, var(--primary-color) 25%, transparent) 0%,
|
||||
transparent 50%
|
||||
);
|
||||
}
|
||||
/* ---------- Decorative glow overlay ---------- */
|
||||
|
||||
.eskaera-page::before,
|
||||
.eskaera-shop-page::before,
|
||||
|
|
@ -108,28 +69,61 @@ body.website_published .eskaera-checkout-page {
|
|||
.eskaera-checkout-page::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.eskaera-page::before,
|
||||
.eskaera-generic-page::before {
|
||||
background-image: radial-gradient(
|
||||
circle at 20% 50%,
|
||||
color-mix(in srgb, var(--ac-color-primary) 20%, transparent) 0%,
|
||||
transparent 50%
|
||||
),
|
||||
radial-gradient(
|
||||
circle at 80% 80%,
|
||||
color-mix(in srgb, var(--ac-color-primary) 25%, transparent) 0%,
|
||||
transparent 50%
|
||||
),
|
||||
radial-gradient(
|
||||
circle at 40% 20%,
|
||||
color-mix(in srgb, var(--ac-color-primary) 15%, transparent) 0%,
|
||||
transparent 50%
|
||||
);
|
||||
}
|
||||
|
||||
.eskaera-shop-page::before {
|
||||
background-image: radial-gradient(
|
||||
circle at 15% 30%,
|
||||
color-mix(in srgb, var(--ac-color-primary) 18%, transparent) 0%,
|
||||
transparent 50%
|
||||
),
|
||||
radial-gradient(
|
||||
circle at 85% 70%,
|
||||
color-mix(in srgb, var(--ac-color-primary) 22%, transparent) 0%,
|
||||
transparent 50%
|
||||
);
|
||||
}
|
||||
|
||||
.eskaera-checkout-page::before {
|
||||
background-image: radial-gradient(
|
||||
circle at 20% 50%,
|
||||
color-mix(in srgb, var(--ac-color-primary) 20%, transparent) 0%,
|
||||
transparent 50%
|
||||
),
|
||||
radial-gradient(
|
||||
circle at 80% 80%,
|
||||
color-mix(in srgb, var(--ac-color-primary) 25%, transparent) 0%,
|
||||
transparent 50%
|
||||
);
|
||||
}
|
||||
|
||||
/* Content sits above the overlay. */
|
||||
.eskaera-page > .container,
|
||||
.eskaera-shop-page > .container,
|
||||
.eskaera-generic-page > div,
|
||||
.eskaera-checkout-page > .container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
#wrap {
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.group-order-shop {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,103 +1,21 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/layout/responsive.css */
|
||||
|
||||
/**
|
||||
* Responsive design breakpoints and adjustments
|
||||
* All media queries centralized here for easier maintenance
|
||||
* NOTE: products-grid.css has its own breakpoints and should NOT be overridden here
|
||||
* Responsive adjustments — do not add to it.
|
||||
*
|
||||
* Centralising every media query here was the original plan; in practice this
|
||||
* file drifted out of sync with the components it overrode and needed
|
||||
* !important to win — twenty of them at its peak. Each component now owns its
|
||||
* queries at the bottom of its own file, and most need none at all once sizing
|
||||
* is fluid. What is left here is thumbnail geometry and table density, which
|
||||
* belong to no single component.
|
||||
*/
|
||||
|
||||
@media (max-width: 992px) {
|
||||
/* Cart sidebar */
|
||||
.sticky-cart {
|
||||
position: static !important;
|
||||
margin-top: 2rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cart-items {
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
#cart-items-container {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.list-group-item h6 {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.list-group-item strong {
|
||||
min-width: 70px;
|
||||
}
|
||||
|
||||
.cart-header {
|
||||
padding: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cart-header h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.cart-title-lg {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
#save-cart-btn,
|
||||
#reload-cart-btn {
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-size: 0.9rem;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.card-header .btn-group {
|
||||
gap: 0.5rem !important;
|
||||
}
|
||||
|
||||
/* Order list grid */
|
||||
.eskaera-orders,
|
||||
.eskaera-orders-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
/* Header (shared between eskaera and checkout) */
|
||||
.eskaera-order-header,
|
||||
.checkout-header {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.eskaera-order-header h1,
|
||||
.checkout-header h1 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.checkout-title,
|
||||
.eskaera-order-header h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.checkout-order-name {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
/* Fix header flex layout for mobile */
|
||||
.eskaera-order-header .d-flex,
|
||||
.checkout-header .d-flex {
|
||||
flex-direction: column !important;
|
||||
gap: 1rem !important;
|
||||
align-items: flex-start !important;
|
||||
}
|
||||
/* Header type and the info grid scale from layout/header.css; the title row
|
||||
stacks through Bootstrap's flex-column/flex-md-row utilities. Order cards,
|
||||
order list, product card and quantity control all size themselves from
|
||||
their own files. */
|
||||
|
||||
.order-thumbnail-md {
|
||||
max-width: 100%;
|
||||
|
|
@ -105,413 +23,54 @@
|
|||
height: auto;
|
||||
}
|
||||
|
||||
/* Order info grid */
|
||||
.order-info-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
/* Eskaera page headings */
|
||||
.eskaera-page h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.eskaera-page > .container > .row:first-child p {
|
||||
font-size: 1.1rem !important;
|
||||
}
|
||||
|
||||
/* Order cards */
|
||||
.eskaera-order-card {
|
||||
min-height: 250px;
|
||||
}
|
||||
|
||||
.eskaera-order-card .card-body {
|
||||
padding: 0.5rem 0.6rem 0 0.6rem;
|
||||
gap: 0.15rem;
|
||||
}
|
||||
|
||||
.eskaera-order-card .card-title {
|
||||
font-size: 0.9rem;
|
||||
-webkit-line-clamp: 3;
|
||||
}
|
||||
|
||||
.order-desc-text {
|
||||
font-size: 0.75rem;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.eskaera-order-card .btn {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.8rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.order-thumbnail-sm {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
}
|
||||
|
||||
.order-thumbnail-md {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
/* Header with image and text */
|
||||
.eskaera-order-card .d-flex {
|
||||
gap: 0.75rem !important;
|
||||
}
|
||||
|
||||
.eskaera-order-card .card-footer {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
/* Order list */
|
||||
.eskaera-orders,
|
||||
.eskaera-orders-grid {
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
/* Product grid */
|
||||
.card-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
/* Product quantity controls */
|
||||
.add-to-cart-form .product-qty {
|
||||
font-size: 1rem;
|
||||
min-width: 50px;
|
||||
height: 32px;
|
||||
padding: 0.25rem 0.35rem;
|
||||
}
|
||||
|
||||
.qty-control .qty-decrease,
|
||||
.qty-control .qty-increase {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.add-to-cart-form .add-to-cart-btn {
|
||||
height: 36px;
|
||||
min-height: 36px;
|
||||
padding: 0.35rem 0.5rem;
|
||||
font-size: 1rem;
|
||||
min-width: 44px;
|
||||
}
|
||||
|
||||
.add-to-cart-form .input-group {
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
/* Checkout summary */
|
||||
.checkout-summary-container {
|
||||
padding: 1rem;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.checkout-summary-table {
|
||||
font-size: 0.95rem;
|
||||
min-width: 500px; /* Prevent table collapse */
|
||||
}
|
||||
|
||||
.checkout-summary-table thead th {
|
||||
padding: 0.75rem 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.checkout-summary-table tbody td {
|
||||
padding: 0.75rem 0.5rem;
|
||||
}
|
||||
|
||||
.total-amount {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.summary-heading {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.checkout-actions .btn {
|
||||
font-size: 1rem;
|
||||
padding: 0.6rem 1.2rem;
|
||||
width: 4.375rem;
|
||||
height: 4.375rem;
|
||||
}
|
||||
|
||||
.group-order-header {
|
||||
padding: 1rem 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.product-card .product-image {
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
.checkout-container {
|
||||
padding: 1rem;
|
||||
padding: var(--ac-space-md) 0;
|
||||
margin-bottom: var(--ac-space-md);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
/* Cart items */
|
||||
.list-group-item.d-flex {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.list-group-item h6 {
|
||||
font-size: 0.85rem;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.list-group-item small {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.list-group-item .d-flex {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.list-group-item strong {
|
||||
min-width: auto;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.list-group-item .remove-from-cart {
|
||||
min-width: 28px;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
.cart-items {
|
||||
max-height: 250px;
|
||||
}
|
||||
|
||||
.sticky-cart {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
/* Checkout type scales fluidly from sections/checkout.css; only the table's
|
||||
density genuinely changes here, and the container's padding with it. */
|
||||
|
||||
.toast-notification {
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
left: 20px;
|
||||
inset: auto var(--ac-space-md) var(--ac-space-md);
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
#save-cart-btn,
|
||||
#reload-cart-btn {
|
||||
padding: 0.3rem 0.4rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.card-header .d-flex {
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem !important;
|
||||
}
|
||||
|
||||
.card-header .btn-group {
|
||||
gap: 0.25rem !important;
|
||||
}
|
||||
|
||||
.card-header .btn-group .btn {
|
||||
padding: 0.3rem 0.4rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.form-check {
|
||||
padding: 1rem 1.5rem !important;
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.form-check-input {
|
||||
margin-left: 0 !important;
|
||||
margin-right: 1rem !important;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.form-check-label[for="home-delivery-checkbox"] {
|
||||
font-size: 1rem !important;
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.eskaera-order-header,
|
||||
.checkout-header {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.eskaera-order-header h1,
|
||||
.checkout-header h1 {
|
||||
font-size: 1.25rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.checkout-title,
|
||||
.eskaera-order-header h1 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.checkout-order-name {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Eskaera page */
|
||||
.eskaera-page h1 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.eskaera-page > .container > .row:first-child {
|
||||
margin-bottom: 1.5rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.eskaera-page > .container > .row:first-child p {
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
|
||||
/* Order cards */
|
||||
.eskaera-order-card {
|
||||
min-height: 220px;
|
||||
}
|
||||
|
||||
.eskaera-order-card .card-body {
|
||||
padding: 0.4rem 0.5rem 0 0.5rem;
|
||||
}
|
||||
|
||||
.eskaera-order-card .card-title {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.order-desc-text {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.eskaera-order-card .btn {
|
||||
padding: 0.45rem 0.85rem;
|
||||
font-size: 0.75rem;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.order-thumbnail-sm {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
width: 3.75rem;
|
||||
height: 3.75rem;
|
||||
}
|
||||
|
||||
.order-thumbnail-md {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
/* Order list */
|
||||
.eskaera-orders,
|
||||
.eskaera-orders-grid {
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 1rem;
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
}
|
||||
|
||||
.eskaera-empty-state {
|
||||
padding: 2rem 0.5rem;
|
||||
padding: var(--ac-space-xl) var(--ac-space-sm);
|
||||
}
|
||||
|
||||
.eskaera-empty-state .alert {
|
||||
font-size: 0.95rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* Checkout */
|
||||
.checkout-summary-container {
|
||||
padding: 0.75rem;
|
||||
padding: var(--ac-space-sm);
|
||||
}
|
||||
|
||||
.checkout-summary-table {
|
||||
font-size: 0.85rem;
|
||||
min-width: 450px;
|
||||
}
|
||||
|
||||
.checkout-summary-table thead th {
|
||||
padding: 0.5rem 0.35rem;
|
||||
font-size: 0.75rem;
|
||||
min-width: 28rem;
|
||||
}
|
||||
|
||||
.checkout-summary-table thead th,
|
||||
.checkout-summary-table tbody td {
|
||||
padding: 0.5rem 0.35rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.total-amount {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.total-label {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.currency {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.summary-heading {
|
||||
font-size: 1.25rem;
|
||||
padding-left: 0.75rem;
|
||||
}
|
||||
|
||||
.checkout-actions .btn {
|
||||
font-size: 0.9rem;
|
||||
padding: 0.6rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Product card typography responsive scaling */
|
||||
@media screen and (min-width: 1600px) {
|
||||
.product-tags {
|
||||
font-size: 1.1rem !important;
|
||||
}
|
||||
|
||||
/* Scale down quantity input for 6-column layout */
|
||||
.add-to-cart-form .product-qty {
|
||||
font-size: 0.85rem;
|
||||
max-width: 55px;
|
||||
}
|
||||
|
||||
.add-to-cart-form .qty-decrease,
|
||||
.add-to-cart-form .qty-increase {
|
||||
font-size: 0.75rem;
|
||||
min-width: 28px;
|
||||
min-height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1400px) and (max-width: 1599px) {
|
||||
.product-tags {
|
||||
font-size: 1.25rem !important;
|
||||
}
|
||||
|
||||
/* Scale down quantity input for 5-column layout */
|
||||
.add-to-cart-form .product-qty {
|
||||
font-size: 0.9rem;
|
||||
max-width: 60px;
|
||||
}
|
||||
|
||||
.add-to-cart-form .qty-decrease,
|
||||
.add-to-cart-form .qty-increase {
|
||||
font-size: 0.8rem;
|
||||
min-width: 30px;
|
||||
min-height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.card-grid {
|
||||
grid-template-columns: 1fr;
|
||||
padding: var(--ac-space-sm) var(--ac-space-2xs);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,64 +1,67 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/sections/checkout.css */
|
||||
|
||||
/**
|
||||
* Checkout page section styles
|
||||
* Checkout page
|
||||
*
|
||||
* The summary table keeps a min-width and scrolls inside its own container
|
||||
* rather than reflowing into cards: the four columns (product, qty, price,
|
||||
* subtotal) are read across, and stacking them loses that. The container is
|
||||
* focusable so the scroll is reachable without a pointer.
|
||||
*/
|
||||
|
||||
.checkout-container {
|
||||
background-color: white;
|
||||
padding: 2rem;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.checkout-summary {
|
||||
background-color: #f8f9fa;
|
||||
padding: 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
margin-bottom: 2rem;
|
||||
margin-bottom: var(--ac-space-xl);
|
||||
padding: var(--ac-space-lg);
|
||||
border-radius: var(--ac-radius-md);
|
||||
background-color: var(--ac-surface-sunken);
|
||||
}
|
||||
|
||||
.checkout-summary-container {
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
margin-bottom: var(--ac-space-xl);
|
||||
padding: var(--ac-space-lg);
|
||||
border-radius: var(--ac-radius-lg);
|
||||
background: var(--ac-surface);
|
||||
box-shadow: var(--ac-shadow-sm);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.checkout-summary-container:focus-visible {
|
||||
outline: var(--ac-focus-ring-width) solid var(--ac-focus-ring-color);
|
||||
outline-offset: var(--ac-focus-ring-offset);
|
||||
}
|
||||
|
||||
.checkout-summary-table {
|
||||
margin-bottom: 0;
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
.checkout-summary-table thead {
|
||||
background-color: #2d3748;
|
||||
color: white;
|
||||
min-width: 30rem;
|
||||
font-size: var(--ac-text-md);
|
||||
}
|
||||
|
||||
.checkout-summary-table thead th {
|
||||
font-weight: 700;
|
||||
padding: 1rem 0.75rem;
|
||||
text-transform: uppercase;
|
||||
font-size: 1rem;
|
||||
letter-spacing: 0.5px;
|
||||
padding: var(--ac-space-md) var(--ac-space-xs);
|
||||
border: none;
|
||||
font-size: var(--ac-text-base);
|
||||
font-weight: var(--ac-weight-bold);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.checkout-summary-table tbody tr {
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.checkout-summary-table tbody tr:hover {
|
||||
background-color: #f7fafc;
|
||||
border-bottom: 1px solid var(--ac-border);
|
||||
transition: background-color var(--ac-transition-fast);
|
||||
}
|
||||
|
||||
.checkout-summary-table tbody td {
|
||||
padding: 1rem 0.75rem;
|
||||
padding: var(--ac-space-md) var(--ac-space-xs);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Figures line up column-wise instead of drifting with glyph widths. */
|
||||
.checkout-summary-table .col-price,
|
||||
.checkout-summary-table .col-subtotal,
|
||||
.checkout-summary-table td.text-end {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.checkout-summary-table .col-name {
|
||||
width: 50%;
|
||||
}
|
||||
|
|
@ -76,52 +79,68 @@
|
|||
}
|
||||
|
||||
.checkout-summary-table .empty-message {
|
||||
background-color: #f7fafc;
|
||||
background-color: var(--ac-surface-sunken);
|
||||
}
|
||||
|
||||
/* ---------- Total ---------- */
|
||||
|
||||
.checkout-total-section {
|
||||
border-top: 2px solid #e2e8f0;
|
||||
padding-top: 1.5rem;
|
||||
margin-top: 1rem;
|
||||
margin-top: var(--ac-space-md);
|
||||
padding-top: var(--ac-space-lg);
|
||||
border-top: 2px solid var(--ac-border);
|
||||
}
|
||||
|
||||
.total-row {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
align-items: baseline;
|
||||
gap: var(--ac-space-sm);
|
||||
}
|
||||
|
||||
.total-label {
|
||||
font-weight: 700;
|
||||
font-size: 1.2rem;
|
||||
color: #1a202c;
|
||||
font-size: var(--ac-text-md);
|
||||
font-weight: var(--ac-weight-bold);
|
||||
color: var(--ac-text-primary);
|
||||
}
|
||||
|
||||
.total-amount {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: var(--success-color);
|
||||
min-width: 120px;
|
||||
min-width: 7.5rem;
|
||||
font-size: var(--ac-text-2xl);
|
||||
font-weight: var(--ac-weight-bold);
|
||||
font-variant-numeric: tabular-nums;
|
||||
text-align: right;
|
||||
/* --ac-color-success is 3.13:1 on white: fine for the 2xl total, but the
|
||||
darker tone keeps it readable if the type scale ever shrinks. */
|
||||
color: var(--ac-color-success-strong);
|
||||
}
|
||||
|
||||
.currency {
|
||||
font-size: 1.2rem;
|
||||
color: #2d3748;
|
||||
font-weight: 600;
|
||||
font-size: var(--ac-text-md);
|
||||
font-weight: var(--ac-weight-semibold);
|
||||
color: var(--ac-text-secondary);
|
||||
}
|
||||
|
||||
.summary-heading {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
color: #1a202c;
|
||||
border-left: 4px solid var(--success-color);
|
||||
padding-left: 1rem;
|
||||
padding-left: var(--ac-space-md);
|
||||
border-left: 4px solid var(--ac-color-success-strong);
|
||||
font-size: var(--ac-text-xl);
|
||||
font-weight: var(--ac-weight-bold);
|
||||
color: var(--ac-text-primary);
|
||||
}
|
||||
|
||||
.checkout-order-desc {
|
||||
word-wrap: break-word;
|
||||
color: var(--ac-text-secondary);
|
||||
overflow-wrap: break-word;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.checkout-summary-table tbody tr:hover {
|
||||
background-color: var(--ac-surface-sunken);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.checkout-summary-table tbody tr {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,63 +1,21 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/sections/info-cards.css */
|
||||
|
||||
/**
|
||||
* Info cards and grid section styles
|
||||
* Info cards
|
||||
*
|
||||
* The meta block that used to be duplicated here now lives with its component
|
||||
* (components/order-card.css): `.card-meta-compact`, `.meta-label` and
|
||||
* `.meta-value` were declared in both files, and this one — loading last — won,
|
||||
* silently overriding the component. `.card-grid`, `.card-col`, `.card-meta-list`
|
||||
* and `.meta-row` were dead: no template ever emitted them.
|
||||
*/
|
||||
|
||||
.order-info-card {
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
border-radius: var(--ac-radius-lg);
|
||||
background: var(--ac-surface);
|
||||
box-shadow: var(--ac-shadow-sm);
|
||||
}
|
||||
|
||||
.order-info-card .card-body {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.5rem;
|
||||
align-items: start;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.card-meta-compact {
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.card-meta-compact .card-meta-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.meta-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
.meta-label {
|
||||
font-weight: 700;
|
||||
color: #2d3748;
|
||||
min-width: fit-content;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.meta-value {
|
||||
font-weight: 400;
|
||||
color: #27292c;
|
||||
word-break: break-word;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.card-col {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.card-col .card-text strong {
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
padding: var(--ac-space-md);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,48 +1,54 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/sections/order-list.css */
|
||||
|
||||
/**
|
||||
* Order list and Eskaera page section styles
|
||||
* Order list (Eskaera index page)
|
||||
*
|
||||
* The grid derived its column count from three breakpoints (3 / 2 / 1) that
|
||||
* each had to out-specify the previous one — the mobile rule needed
|
||||
* !important. Deriving it from the available width removes all three.
|
||||
*/
|
||||
|
||||
.eskaera-page h1 {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 700;
|
||||
color: #2d3748;
|
||||
margin-bottom: 0.5rem;
|
||||
margin-bottom: var(--ac-space-sm);
|
||||
font-size: var(--ac-text-2xl);
|
||||
font-weight: var(--ac-weight-bold);
|
||||
text-align: center;
|
||||
color: var(--ac-text-primary);
|
||||
}
|
||||
|
||||
.eskaera-page > .container > .row:first-child {
|
||||
margin-bottom: 2rem;
|
||||
border-bottom: 2px solid #e2e8f0;
|
||||
padding-bottom: 1.5rem;
|
||||
margin-bottom: var(--ac-space-xl);
|
||||
padding-bottom: var(--ac-space-lg);
|
||||
border-bottom: 2px solid var(--ac-border);
|
||||
}
|
||||
|
||||
.eskaera-page > .container > .row:first-child p {
|
||||
font-size: 1.3rem !important;
|
||||
color: #4a5568;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
font-size: var(--ac-text-md);
|
||||
font-weight: var(--ac-weight-medium);
|
||||
text-align: center;
|
||||
color: var(--ac-text-secondary);
|
||||
}
|
||||
|
||||
.eskaera-orders,
|
||||
.eskaera-orders-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 2rem;
|
||||
/* 20rem keeps three across a full-width container and drops to one on a
|
||||
phone, without any breakpoint doing the counting. */
|
||||
grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
|
||||
gap: var(--ac-space-lg);
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.eskaera-empty-state {
|
||||
padding: var(--ac-space-2xl) var(--ac-space-md);
|
||||
text-align: center;
|
||||
padding: 3rem 1rem;
|
||||
}
|
||||
|
||||
.eskaera-empty-state .alert {
|
||||
max-width: 500px;
|
||||
max-width: 31.25rem;
|
||||
margin: 0 auto;
|
||||
font-size: 1.05rem;
|
||||
border-radius: 0.5rem;
|
||||
border-radius: var(--ac-radius-md);
|
||||
font-size: var(--ac-text-base);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,29 @@
|
|||
/* filepath: website_sale_aplicoop/static/src/css/sections/products-grid.css */
|
||||
|
||||
/**
|
||||
* Products grid section styles
|
||||
* Products grid
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 9rem is the card's minimum width; at the widest container (1320px minus the
|
||||
* category sidebar) it still resolves to six columns, as before.
|
||||
*/
|
||||
|
||||
.products-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
||||
gap: 1.2rem;
|
||||
margin-bottom: 2rem;
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--ac-space-md);
|
||||
margin-bottom: var(--ac-space-xl);
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.products-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(min(100%, 9rem), 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
.product-card-wrapper {
|
||||
|
|
@ -17,62 +32,7 @@
|
|||
}
|
||||
|
||||
.product-search-highlight {
|
||||
border: 2px solid #007bff;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* Pantallas muy grandes: 1600px+ (6 columnas) */
|
||||
@media screen and (min-width: 1600px) {
|
||||
.products-grid {
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
gap: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pantallas grandes: 1400px-1599px (5 columnas) */
|
||||
@media screen and (min-width: 1400px) and (max-width: 1599px) {
|
||||
.products-grid {
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 1.15rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pantallas medianas: 1200px-1399px (4 columnas) */
|
||||
@media screen and (min-width: 1200px) and (max-width: 1399px) {
|
||||
.products-grid {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pantallas tablet grandes: 992px-1199px (3 columnas) */
|
||||
@media screen and (min-width: 992px) and (max-width: 1199px) {
|
||||
.products-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pantallas tablet: 768px-991px (3 columnas en tablet grande, 2 en tablet pequeña) */
|
||||
@media screen and (min-width: 768px) and (max-width: 991px) {
|
||||
.products-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.95rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pantallas móvil grande: 576px-767px (2 columnas) */
|
||||
@media screen and (min-width: 576px) and (max-width: 767px) {
|
||||
.products-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pantallas móvil pequeño: 1 columna */
|
||||
@media (max-width: 575px) {
|
||||
.products-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
padding: var(--ac-space-sm);
|
||||
border: 2px solid var(--ac-color-primary);
|
||||
border-radius: var(--ac-radius-md);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -194,10 +194,10 @@
|
|||
'<th scope="col" class="col-qty text-center">' +
|
||||
escapeHtml(labels.quantity) +
|
||||
"</th>" +
|
||||
'<th scope="col" class="col-price text-right">' +
|
||||
'<th scope="col" class="col-price text-end">' +
|
||||
escapeHtml(labels.price) +
|
||||
"</th>" +
|
||||
'<th scope="col" class="col-subtotal text-right">' +
|
||||
'<th scope="col" class="col-subtotal text-end">' +
|
||||
escapeHtml(labels.subtotal) +
|
||||
"</th>" +
|
||||
'</tr></thead><tbody id="checkout-summary-tbody"></tbody></table>' +
|
||||
|
|
@ -280,10 +280,10 @@
|
|||
'<td class="text-center">' +
|
||||
qty.toFixed(2).replace(/\.?0+$/, "") +
|
||||
"</td>" +
|
||||
'<td class="text-right">€' +
|
||||
'<td class="text-end">€' +
|
||||
price.toFixed(2) +
|
||||
"</td>" +
|
||||
'<td class="text-right">€' +
|
||||
'<td class="text-end">€' +
|
||||
subtotal.toFixed(2) +
|
||||
"</td>";
|
||||
tbody.appendChild(row);
|
||||
|
|
@ -307,10 +307,10 @@
|
|||
'<td class="text-center">' +
|
||||
qty.toFixed(2).replace(/\.?0+$/, "") +
|
||||
"</td>" +
|
||||
'<td class="text-right">€' +
|
||||
'<td class="text-end">€' +
|
||||
price.toFixed(2) +
|
||||
"</td>" +
|
||||
'<td class="text-right">€' +
|
||||
'<td class="text-end">€' +
|
||||
subtotal.toFixed(2) +
|
||||
"</td>";
|
||||
tbody.appendChild(row);
|
||||
|
|
|
|||
|
|
@ -459,8 +459,9 @@ console.log("[INFINITE_SCROLL] Script loaded!");
|
|||
// Show fallback button
|
||||
var btn = document.getElementById("load-more-btn");
|
||||
if (btn) {
|
||||
// d-none is the only thing hiding it; the button no longer
|
||||
// carries an inline display:none to clear.
|
||||
btn.classList.remove("d-none");
|
||||
btn.style.display = "";
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -141,9 +141,6 @@
|
|||
// Initialize available tags from DOM
|
||||
self._initializeAvailableTags();
|
||||
|
||||
// Store original colors for each tag badge
|
||||
self.originalTagColors = {}; // Maps tag ID to original color
|
||||
|
||||
// Store last values at instance level so polling can access them
|
||||
// Initialize to current values to avoid triggering reset on first poll
|
||||
self.lastSearchValue = self.searchInput.value.trim();
|
||||
|
|
@ -165,9 +162,9 @@
|
|||
// This listener is separate from the filtering listener
|
||||
self.searchInput.addEventListener("input", function () {
|
||||
if (self.searchInput.value.trim().length > 0) {
|
||||
self.clearSearchBtn.style.display = "block";
|
||||
self.clearSearchBtn.classList.add("is-visible");
|
||||
} else {
|
||||
self.clearSearchBtn.style.display = "none";
|
||||
self.clearSearchBtn.classList.remove("is-visible");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -179,7 +176,7 @@
|
|||
|
||||
// Clear the input
|
||||
self.searchInput.value = "";
|
||||
self.clearSearchBtn.style.display = "none";
|
||||
self.clearSearchBtn.classList.remove("is-visible");
|
||||
|
||||
// Update last stored value to prevent polling from detecting "change"
|
||||
self.lastSearchValue = "";
|
||||
|
|
@ -204,7 +201,7 @@
|
|||
|
||||
// Initial check - don't show if empty
|
||||
if (self.searchInput.value.trim().length > 0) {
|
||||
self.clearSearchBtn.style.display = "block";
|
||||
self.clearSearchBtn.classList.add("is-visible");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -283,114 +280,21 @@
|
|||
var tagBadges = document.querySelectorAll('[data-toggle="tag-filter"]');
|
||||
console.log("[realtimeSearch] Found " + tagBadges.length + " tag filter badges");
|
||||
|
||||
// Get theme colors from CSS variables
|
||||
var rootStyles = getComputedStyle(document.documentElement);
|
||||
var primaryColor =
|
||||
rootStyles.getPropertyValue("--bs-primary").trim() ||
|
||||
rootStyles.getPropertyValue("--primary").trim() ||
|
||||
"#0d6efd";
|
||||
var secondaryColor =
|
||||
rootStyles.getPropertyValue("--bs-secondary").trim() ||
|
||||
rootStyles.getPropertyValue("--secondary").trim() ||
|
||||
"#6c757d";
|
||||
|
||||
console.log(
|
||||
"[realtimeSearch] Theme colors - Primary:",
|
||||
primaryColor,
|
||||
"Secondary:",
|
||||
secondaryColor
|
||||
);
|
||||
|
||||
// Store original colors for each badge BEFORE adding event listeners
|
||||
tagBadges.forEach(function (badge) {
|
||||
var tagId = parseInt(badge.getAttribute("data-tag-id"), 10);
|
||||
var tagColor = badge.getAttribute("data-tag-color");
|
||||
|
||||
// Store the original color (either from data-tag-color or use secondary for tags without color)
|
||||
if (tagColor) {
|
||||
self.originalTagColors[tagId] = tagColor;
|
||||
console.log(
|
||||
"[realtimeSearch] Stored original color for tag " + tagId + ": " + tagColor
|
||||
);
|
||||
} else {
|
||||
self.originalTagColors[tagId] = "var(--bs-secondary, " + secondaryColor + ")";
|
||||
console.log("[realtimeSearch] Tag " + tagId + " has no color, using secondary");
|
||||
}
|
||||
});
|
||||
|
||||
tagBadges.forEach(function (badge) {
|
||||
badge.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
var tagId = parseInt(badge.getAttribute("data-tag-id"), 10);
|
||||
var originalColor = self.originalTagColors[tagId];
|
||||
console.log(
|
||||
"[realtimeSearch] Tag badge clicked: " +
|
||||
tagId +
|
||||
" (original color: " +
|
||||
originalColor +
|
||||
")"
|
||||
);
|
||||
|
||||
// Toggle tag selection
|
||||
if (self.selectedTags.has(tagId)) {
|
||||
// Deselect
|
||||
self.selectedTags.delete(tagId);
|
||||
console.log("[realtimeSearch] Tag " + tagId + " deselected");
|
||||
} else {
|
||||
// Select
|
||||
self.selectedTags.add(tagId);
|
||||
console.log("[realtimeSearch] Tag " + tagId + " selected");
|
||||
}
|
||||
|
||||
// Update colors for ALL badges based on selection state
|
||||
tagBadges.forEach(function (badge) {
|
||||
var id = parseInt(badge.getAttribute("data-tag-id"), 10);
|
||||
|
||||
if (self.selectedTags.size === 0) {
|
||||
// No tags selected: restore all to original colors
|
||||
var originalColor = self.originalTagColors[id];
|
||||
badge.style.setProperty("background-color", originalColor, "important");
|
||||
badge.style.setProperty("border-color", originalColor, "important");
|
||||
badge.style.setProperty("color", "#ffffff", "important");
|
||||
console.log(
|
||||
"[realtimeSearch] Badge " +
|
||||
id +
|
||||
" reset to original color (no selection)"
|
||||
);
|
||||
} else if (self.selectedTags.has(id)) {
|
||||
// Selected: primary color
|
||||
badge.style.setProperty(
|
||||
"background-color",
|
||||
"var(--bs-primary, " + primaryColor + ")",
|
||||
"important"
|
||||
);
|
||||
badge.style.setProperty(
|
||||
"border-color",
|
||||
"var(--bs-primary, " + primaryColor + ")",
|
||||
"important"
|
||||
);
|
||||
badge.style.setProperty("color", "#ffffff", "important");
|
||||
console.log(
|
||||
"[realtimeSearch] Badge " + id + " set to primary (selected)"
|
||||
);
|
||||
} else {
|
||||
// Not selected but others are: secondary color
|
||||
badge.style.setProperty(
|
||||
"background-color",
|
||||
"var(--bs-secondary, " + secondaryColor + ")",
|
||||
"important"
|
||||
);
|
||||
badge.style.setProperty(
|
||||
"border-color",
|
||||
"var(--bs-secondary, " + secondaryColor + ")",
|
||||
"important"
|
||||
);
|
||||
badge.style.setProperty("color", "#ffffff", "important");
|
||||
console.log(
|
||||
"[realtimeSearch] Badge " + id + " set to secondary (not selected)"
|
||||
);
|
||||
}
|
||||
});
|
||||
self._syncTagBadgeStates(tagBadges);
|
||||
|
||||
// Filter products (independent of search/category state)
|
||||
// Skip during initialization
|
||||
|
|
@ -647,6 +551,10 @@
|
|||
")"
|
||||
);
|
||||
|
||||
// Announce the outcome to screen readers, which otherwise get no
|
||||
// signal that the grid changed under them.
|
||||
self._announceResults(visibleCount);
|
||||
|
||||
// Auto-load more products if too few are visible
|
||||
self._autoLoadMoreIfNeeded(visibleCount);
|
||||
} catch (error) {
|
||||
|
|
@ -655,6 +563,49 @@
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Reflect the current selection on every tag badge: aria-pressed for
|
||||
* assistive tech, two state classes for the eye. Colours belong to
|
||||
* components/tag-filter.css — this only says which state each badge is in.
|
||||
*
|
||||
* @param {NodeList} tagBadges - All badges in the filter bar
|
||||
*/
|
||||
_syncTagBadgeStates: function (tagBadges) {
|
||||
var self = this;
|
||||
var hasSelection = self.selectedTags.size > 0;
|
||||
|
||||
tagBadges.forEach(function (badge) {
|
||||
var id = parseInt(badge.getAttribute("data-tag-id"), 10);
|
||||
var isSelected = self.selectedTags.has(id);
|
||||
|
||||
badge.classList.toggle("is-selected", isSelected);
|
||||
badge.classList.toggle("is-dimmed", hasSelection && !isSelected);
|
||||
badge.setAttribute("aria-pressed", isSelected ? "true" : "false");
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Write the result count into the polite live region next to the search
|
||||
* box. Labels come from i18nManager, never from a hardcoded literal.
|
||||
*
|
||||
* @param {number} visibleCount - Number of currently visible products
|
||||
*/
|
||||
_announceResults: function (visibleCount) {
|
||||
var status = document.getElementById("realtime-search-status");
|
||||
if (!status) {
|
||||
return;
|
||||
}
|
||||
var i18n = window.i18nManager;
|
||||
var message;
|
||||
if (visibleCount === 0) {
|
||||
message = (i18n && i18n.get("no_results")) || "No products found";
|
||||
} else {
|
||||
message =
|
||||
visibleCount + " " + ((i18n && i18n.get("products_found")) || "products found");
|
||||
}
|
||||
status.textContent = message;
|
||||
},
|
||||
|
||||
_autoLoadMoreIfNeeded: function (visibleCount) {
|
||||
/**
|
||||
* Automatically load more products if there are too few visible on screen.
|
||||
|
|
|
|||
|
|
@ -691,12 +691,16 @@
|
|||
|
||||
var notification = document.createElement("div");
|
||||
notification.className =
|
||||
"alert alert-" + type + " alert-dismissible fade show position-fixed";
|
||||
notification.style.cssText =
|
||||
"top: 80px; right: 20px; z-index: 9999; min-width: 300px; max-width: 500px; font-size: 18px; padding: 1.5rem; transition: opacity 0.3s ease-out;";
|
||||
"alert alert-" + type + " alert-dismissible fade show eskaera-notification";
|
||||
// Announce it: errors and warnings are the whole point of this helper,
|
||||
// and without a live role a screen reader never hears them.
|
||||
notification.setAttribute("role", type === "error" ? "alert" : "status");
|
||||
notification.setAttribute("aria-live", type === "error" ? "assertive" : "polite");
|
||||
notification.innerHTML =
|
||||
message +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert"></button>';
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="' +
|
||||
((window.i18nManager && window.i18nManager.get("close")) || "Close") +
|
||||
'"></button>';
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
|
|
@ -1253,13 +1257,17 @@
|
|||
// Create toast element
|
||||
var toast = document.createElement("div");
|
||||
toast.className = "toast-notification";
|
||||
toast.setAttribute("role", "status");
|
||||
|
||||
// Get translated "added to cart" label from server
|
||||
var labels = this._getLabels();
|
||||
var addedMsg = labels.added_to_cart || "added to cart";
|
||||
|
||||
toast.innerHTML =
|
||||
'<i class="fa fa-check"></i> <strong>' + productName + "</strong> " + addedMsg;
|
||||
'<i class="fa fa-check" aria-hidden="true"></i> <strong>' +
|
||||
this.escapeHtml(productName) +
|
||||
"</strong> " +
|
||||
addedMsg;
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
|
|
@ -1551,7 +1559,7 @@
|
|||
// Simple approach: if response is very short, assume no more products
|
||||
if (html.trim().length < 100) {
|
||||
console.log("[LAZY_LOADING] No more products, hiding load-more button");
|
||||
btn.style.display = "none";
|
||||
btn.classList.add("d-none");
|
||||
} else {
|
||||
// Re-enable button for next page
|
||||
btn.disabled = false;
|
||||
|
|
@ -1595,7 +1603,7 @@
|
|||
|
||||
if (Object.keys(this.cart).length === 0) {
|
||||
cartContainer.innerHTML =
|
||||
'<p class="text-muted" style="font-size: 1.1rem;">' +
|
||||
'<p class="text-muted cart-empty-message">' +
|
||||
(labels.empty_cart || "This order's cart is empty.") +
|
||||
"</p>";
|
||||
return;
|
||||
|
|
@ -1612,20 +1620,20 @@
|
|||
total += subtotal;
|
||||
|
||||
html +=
|
||||
'<div class="list-group-item" style="font-size: 1.05rem;">' +
|
||||
'<div class="list-group-item">' +
|
||||
'<div class="mb-2">' +
|
||||
'<h6 class="mb-0" style="font-size: 1.1rem;">' +
|
||||
'<h6 class="mb-0">' +
|
||||
self.escapeHtml(item.name) +
|
||||
"</h6>" +
|
||||
"</div>" +
|
||||
'<div class="d-flex justify-content-between align-items-center">' +
|
||||
'<small class="text-muted" style="font-size: 1rem;">' +
|
||||
'<small class="text-muted">' +
|
||||
parseFloat(item.qty).toFixed(1) +
|
||||
" x €" +
|
||||
item.price.toFixed(2) +
|
||||
"</small>" +
|
||||
'<div class="d-flex align-items-center gap-2">' +
|
||||
'<strong style="font-size: 1.1rem;">€' +
|
||||
"<strong>€" +
|
||||
subtotal.toFixed(2) +
|
||||
"</strong>" +
|
||||
'<button class="btn btn-sm btn-danger remove-from-cart" ' +
|
||||
|
|
@ -1644,11 +1652,7 @@
|
|||
});
|
||||
|
||||
html += "</div>";
|
||||
html +=
|
||||
'<div class="cart-total mt-3 pt-3" style="font-size: 1.2rem; font-weight: bold;">' +
|
||||
"Total: €" +
|
||||
total.toFixed(2) +
|
||||
"</div>";
|
||||
html += '<div class="cart-total mt-3 pt-3">' + "Total: €" + total.toFixed(2) + "</div>";
|
||||
|
||||
cartContainer.innerHTML = html;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue