# Demo: demo-supplements-shop

> **Estado:** ✅ Production-ready (2026-05-28)
> **Última auditoría:** 2026-05-28 — refinamientos UX finales (sticky sidebar + 1:1 cards + Cloudinary on-the-fly)
> **Producto que lo usa:** [supplements-shop](../products/supplements-shop.md)
> **Origen:** clon independiente de `demo-medical` (2026-05-28). A partir de ese momento iteran por separado: medical para consultorios, supplements-shop para tiendas.

---

## 1. Identidad

| Campo | Valor |
|-------|-------|
| **Slug del demo** | `demo-supplements-shop` |
| **Slug base (assets/skin)** | `supplements-shop` |
| **Source Porto** | Hereda de Porto shop-3-columns-sidebar-left (para catalog) y shop-product-sidebar-left (para detalle). Inspiración tipográfica: optimumnutrition.com + 1stphorm.com |
| **Producto que lo usa** | `supplements-shop` (6 shop slugs comerciales) |
| **Patrón welcome** | A — config-heavy (8 secciones, 30+ keys editables) |
| **Skin asociado** | `skin-supplements-shop.css` (azul deep #141F88 + verde menta #4BB98C) |
| **Brand defaults** | primary `#141F88` (azul deep), secondary `#030E68` (azul oscuro), tertiary `#4BB98C` (verde menta), quaternary `#1A2333` (gris oscuro trust bar), fonts Poppins + Shadows Into Light |

---

## 2. Las 7 piezas

| # | Pieza | Archivo | Líneas |
|---|-------|---------|--------|
| 1 | Header | `resources/views/layout/front/headers/demo-supplements-shop.blade.php` | 134 |
| 2 | Footer | `resources/views/layout/front/footers/demo-supplements-shop.blade.php` | 123 |
| 3 | Page-header | `resources/views/layout/front/partials/page-header-supplements-shop.blade.php` | 45 |
| 4 | Welcome | `resources/views/modules/cd-base/frontend/demos/demo-supplements-shop/welcome.blade.php` | 688 |
| 5 | About | `.../demo-supplements-shop/about.blade.php` | 131 |
| 6 | Contact | `.../demo-supplements-shop/contact.blade.php` | 159 |
| 7 | Demo CSS | `public/template/css/demos/demo-supplements-shop.css` | 883 |

Skin: `public/template/css/skins/skin-supplements-shop.css` (~134 líneas)
Imágenes: `public/cd-project/img/demos/supplements-shop/` (9 imgs clonadas de medical)

**Piezas adicionales del módulo products (shop layer)**:
- `modules/products/frontend/demos/demo-supplements-shop/catalogue.blade.php` — listado /products-catalogue
- `modules/products/frontend/demos/demo-supplements-shop/show.blade.php` — detalle producto
- `modules/products/frontend/demos/demo-supplements-shop/cart.blade.php` — carrito
- `modules/products/frontend/demos/demo-supplements-shop/checkout.blade.php` — checkout WhatsApp
- `modules/products/frontend/demos/demo-supplements-shop/confirmation.blade.php` — orden confirmada

---

## 3. Registros en código

| Registro | Archivo | Línea/sección |
|----------|---------|---------------|
| Layout mapping | `app/helpers.php::get_demo_layout_mapping()` | `'demo-supplements-shop' => ['header' => 'demo-supplements-shop', 'footer' => 'demo-supplements-shop']` |
| Skin mapping | `app/helpers.php::get_demo_skin_mapping()` | `'demo-supplements-shop' => 'skin-supplements-shop'` |
| Demos config | `config/demos.php` | type `ecommerce`, features `[products, cart, brands, novedades]` |
| Page headers config | `config/page-headers.php` | partial `page-header-supplements-shop`, default_type `modern` |
| Provision demo cores | `config/provision_demo_cores.php` | `demo-supplements-shop => supplements-shop` |
| Dynamic-headers | 9 archivos (`blog, menu, cd-base, gallery, services, references, products, projects, team-members`) | Cada uno con `@elseif($activeDemo === 'demo-supplements-shop')` branch |
| Admin schema | `database/schemas/demos/demo-supplements-shop.json` | Campos editables del welcome |

---

## 4. Cómo embebe módulos en welcome (8 secciones)

| # | Sección welcome | Módulo / Source | Markup |
|---|-----------------|-----------------|--------|
| A1 | **Hero punchy** | n/a (settings + carouselImages opcional) | Carousel con overlay 0.55 + 2 CTAs (primary + outline-light) + 4 trust signals |
| A2 | **Featured products** | `products` (Product::is_active=true ORDER BY id DESC LIMIT 4) | Grid 4 cards cuadradas 1:1 + badge esquina + precio prominente + add-to-cart inline |
| A3 | **Shop by goal** | n/a (4 settings configurables `welcome.goal_N_*`) | Grid 4 cards con imagen + overlay + título goal + CTA hacia categoría |
| A4 | **Athlete spotlight** | n/a (settings welcome.athlete_image/quote/author) | Split-screen 50/50 imagen + quote + author + CTA |
| A5 | **Brands gallery** | `gallery` o JSON settings `welcome.brands_list` | 6 logos grayscale → color on hover. Soporta JSON string de DB |
| A6 | **About refinado** | n/a (settings welcome.about_*) | 3 pilares con icon + título + texto |
| A7 | **Newsletter** | endpoint `/newsletter-subscribe` (cd-base) | Form email centrado con CTA + small print |
| A8 | **Blog teaser** | `blog` ($featuredPosts) | 3 cards horizontal con imagen + categoría + título + excerpt + lectura |

22+ keys editables a través de admin tab `welcome` para `demo-supplements-shop`.

---

## 5. Customizaciones específicas del demo

### Triple capa de protección anti-imágenes-verticales

Las imágenes de productos (catalog, featured, related) viven 3 layers de defensa:

1. **HTML** — `class="img-fluid w-100 d-block"` + `style="aspect-ratio: 1/1; object-fit: cover"` + `width="600" height="600"`
2. **CSS defensive con `!important`** — `.catalog-product-img` y `.related-product-img` con `aspect-ratio: 1/1 !important; height: auto !important; max-height: none !important`
3. **URL Cloudinary transformada on-the-fly** — helpers `$squareImg($url, 600)` y `$unsplashUrl($url, 600, 600)` inyectan `/upload/w_600,h_600,c_fill,g_auto,q_auto,f_auto/` aunque la URL en DB sea raw

**Por qué 3 capas**: descubrimos que sin defensive CSS, los HTML attrs `width="600" height="600"` se interpretan literal en cols estrechas y rompen el ratio.

### Sticky sidebar (catalog + detalle)

Solo en `≥992px`:
```css
.sidebar-col-sticky { align-self: flex-start }  /* crítico: Bootstrap row es flex */
.sidebar-sticky {
    position: sticky; top: 100px;
    max-height: calc(100vh - 120px); overflow-y: auto;
}
```

El `align-self: flex-start` es indispensable — sin él Bootstrap row estira el col al alto del más alto y rompe sticky.

### Header sticky-shrink Porto

```html
<header data-plugin-options="{'stickyEnabled': true, 'stickyEffect': 'shrink', 'stickyStartAt': 120, 'stickyHeaderContainerHeight': 70}">
```

El header colapsa a ~70px en scroll. Sticky sidebar usa `top: 100px` para dar buffer de 30px.

### Trust bar superior

Fila bg quaternary (`#1A2333`) con 4 items: Envíos / ANMAT / WhatsApp / Asesoramiento. Configurable vía `site.header.trust_*`.

### Cart icon condicional

Visible solo cuando `is_module_active('products')`. Badge dinámico con `CartService->count()`.

### Footer denso 4-cols

Comprá (categorías dinámicas) / Atención (FAQs+Contacto+Carrito) / Sobre Nosotros / Pagos (icons + Powered by BewPro).

---

## 6. Auditoría — 30 items

| Bloque | Items pasan | Estado |
|--------|-------------|--------|
| 1. Anatomía y registros (5) | 5/5 | ✅ helpers, configs, demos.php, page-headers, provision_demo_cores |
| 2. Header / Footer / Page-header (6) | 6/6 | ✅ header con trust bar + CTA, footer 4-cols, page-header modern |
| 3. Welcome / About / Contact (6) | 6/6 | ✅ welcome 8 secciones, about 3 pilares, contact WhatsApp first |
| 4. CSS (demo + skin) (5) | 5/5 | ✅ 883 líneas demo + 134 skin con CSS vars + defensive rules |
| 5. Integración con módulos (4) | 4/4 | ✅ products (catalog+show+cart+checkout+confirmation), blog ($featuredPosts), gallery (brands), faqs (footer link) |
| 6. QA visual (4) | 4/4 | ✅ cards 1:1 cuadradas, sidebar sticky, related 1:1, Cloudinary on-the-fly |
| **TOTAL** | **30/30** | **✅ production-ready** |

**Veredicto**: ✅ production-ready (2026-05-28).

---

## 7. Bugs arreglados

| Archivo | Bug | Fix | Commit |
|---------|-----|-----|--------|
| `catalogue.blade.php` | img class no tenía `img-fluid`, browser usaba HTML attrs `width/height` literal → cards verticales en cols estrechas | Agregado `img-fluid d-block` + defensive `.catalog-product-img` con `!important` | `391d195f` |
| `catalogue.blade.php` | URLs Cloudinary no se transformaban — solo Unsplash | Helper `$squareImg` extendido para `res.cloudinary.com` con regex `/upload/(?!w_)` | `353c2023` |
| `show.blade.php` | Sidebar caía con el scroll, dejando blanco enorme cuando contenido era largo | Class `sidebar-col-sticky` + `sidebar-sticky` con `align-self:flex-start` + `position:sticky; top:100px` | `20491256` |
| `show.blade.php` | Related products eran 3:2 (600×400) — inconsistente con featured/catalog 1:1 | URL transformación a 600×600 + class `related-product-img` + defensive CSS | `19bb1fa6` |
| `welcome.blade.php` | Brands gallery rompía si DB devolvía JSON string en vez de array | Decode + fallback a defaults | (en serie deluxe) |
| `ProductController.php` | `index()` y `show()` no tenían branch para `demo-supplements-shop` → fallback a vistas medical | Agregado `if ($demo === 'demo-supplements-shop') return view('modules.products.frontend.demos.demo-supplements-shop.{catalogue,show}')` | (en serie deluxe) |

---

## 8. Pendientes / Out of scope

- **Logo pack propio** del rubro (actualmente `brand_defaults.logo_pack = "medical"`). Diseñar set con paleta azul + ícono dumbbell/hoja.
- **Brands gallery con logos reales** (necesita licencia formal o subida por cliente). Actualmente placeholder con texto fallback.
- **Integration Mercado Pago / Stripe** para checkout cobro directo. Actualmente solo WhatsApp redirect.
- **Translations EN** del shop products + welcome del rubro (para tenants bilingües).
- **Athlete spotlight con video** opcional (actualmente solo imagen).
- **Reviews/Testimonios de productos** específicos vs los testimonials genéricos del homepage.

---

## 9. Referencias

- Producto: [`../products/supplements-shop.md`](../products/supplements-shop.md)
- Doc portfolio: [`../../productos/supplements-shop/`](../../productos/supplements-shop/) (README + identidad + checklist + componentes-deluxe + modulos-integrados)
- Estándar canónico demos: [`../product-readiness/estandar-demo.md`](../product-readiness/estandar-demo.md)
- Demo overrides pattern: [`DEMO-OVERRIDES-PATTERN.md`](DEMO-OVERRIDES-PATTERN.md)
- Demo checklist genérico: [`DEMO-CHECKLIST.md`](DEMO-CHECKLIST.md)
- Demo hermano (origen del clon): [`demo-medical.md`](demo-medical.md) — pendiente de crear si no existe
- Script de deploy producción: `scripts/deploy/yerbabuena-deploy-final.sh`
