feat: optimize product images to e-commerce standard (600x600 → 300px display)

INDUSTRY STANDARD IMPLEMENTATION:
- Change placeholder images from 300x200 (3:2) to 600x600 (1:1 square)
- Set max-height to 300px with aspect-ratio 1:1 for consistent display
- Follow e-commerce best practices (Amazon, Shopify, Mercado Libre)

TEMPLATE CHANGES:
- catalog.vue: Update placeholder URL to 600x600 square images
- Card.vue: Add aspect-ratio="1" for perfect square display
- Card.vue: Increase max-height from 140px to 300px
- Restore padding: pa-2 → pa-3 (8px → 12px)
- Restore title size: text-subtitle-2 → text-subtitle-1
- Restore margins: mb-1 → mb-2
- Restore chip size: x-small → small
- Restore footer padding: pa-2 → pa-2 pb-3

CSS CHANGES:
- Remove fixed height from .product-image-container (use 100% for flexibility)
- Product name: 0.85rem → 0.95rem, min-height 2rem → 2.5rem
- Price label: 0.6rem → 0.65rem
- Price value: 0.9rem → 1.1rem
- Price chip: height 22px → 26px, font 0.75rem → 0.9rem
- Quantity input: 55px → 65px, font 0.85rem → 0.95rem
- Section gaps: 2px → 4px, row gaps: 1px → 2px

RESPONSIVE STRATEGY (optimized for 300px max):
- Mobile XS (<375px): Natural scaling, compact layout
- Mobile (375-559px): Natural scaling, readable text
- Tablet (560-959px): Enhanced padding and fonts
- Desktop (≥960px): Full 300px display with optimal spacing
- Desktop L/XL: Maintain 300px with enhanced typography

RESULT:
- Square images (1:1) matching industry standard
- 600x600 source allows retina displays and zoom
- 300px display on desktop (sweet spot for catalogs)
- Responsive scaling maintains aspect ratio
- Professional e-commerce appearance
This commit is contained in:
2026-05-28 23:25:17 -05:00
parent 398a4cf79d
commit 38c1d8c17c
2 changed files with 206 additions and 68 deletions

View File

@@ -7,33 +7,41 @@
:alt="product.name" :alt="product.name"
class="product-img" class="product-img"
cover cover
max-height="140" max-height="300"
aspect-ratio="1"
> >
<template v-slot:placeholder> <template v-slot:placeholder>
<div class="d-flex align-center justify-center fill-height"> <div class="d-flex align-center justify-center fill-height">
<v-progress-circular indeterminate color="primary" size="32"></v-progress-circular> <v-progress-circular
indeterminate
color="primary"
size="32"
></v-progress-circular>
</div> </div>
</template> </template>
</v-img> </v-img>
</div> </div>
<!-- Contenido de la Tarjeta --> <!-- Contenido de la Tarjeta -->
<v-card-text class="product-content pa-2 text-center"> <v-card-text class="product-content pa-3 text-center">
<!-- Título del Producto --> <!-- Título del Producto -->
<v-tooltip location="top" :text="product.name"> <v-tooltip location="top" :text="product.name">
<template v-slot:activator="{ props }"> <template v-slot:activator="{ props }">
<h3 class="product-name text-subtitle-2 font-weight-medium mb-1" v-bind="props"> <h3
class="product-name text-subtitle-1 font-weight-medium mb-2"
v-bind="props"
>
{{ product.name }} {{ product.name }}
</h3> </h3>
</template> </template>
</v-tooltip> </v-tooltip>
<!-- Sección de Precios --> <!-- Sección de Precios -->
<div class="prices-section mb-1"> <div class="prices-section mb-2">
<!-- Precio Unitario --> <!-- Precio Unitario -->
<div class="price-row"> <div class="price-row mb-1">
<span class="price-label text-caption">Precio unitario</span> <span class="price-label text-caption">Precio unitario</span>
<div class="price-value text-body-2 font-weight-bold text-primary"> <div class="price-value text-body-1 font-weight-bold text-primary">
{{ currency(product.price) }} {{ currency(product.price) }}
</div> </div>
</div> </div>
@@ -44,8 +52,8 @@
<v-chip <v-chip
color="success" color="success"
variant="flat" variant="flat"
size="x-small" size="small"
class="price-total-chip font-weight-bold" class="price-total-chip font-weight-bold mt-1"
> >
{{ currency(product.price * product.quantity) }} {{ currency(product.price * product.quantity) }}
</v-chip> </v-chip>
@@ -54,7 +62,7 @@
</v-card-text> </v-card-text>
<!-- Footer con Controles de Cantidad --> <!-- Footer con Controles de Cantidad -->
<v-card-actions class="product-actions pa-2 justify-center"> <v-card-actions class="product-actions pa-2 pb-3 justify-center">
<div class="quantity-controls"> <div class="quantity-controls">
<v-btn <v-btn
icon icon
@@ -162,7 +170,7 @@ export default {
.product-image-container { .product-image-container {
position: relative; position: relative;
width: 100%; width: 100%;
height: 140px; height: 100%;
overflow: hidden; overflow: hidden;
background: linear-gradient(135deg, #fafafa 0%, #ffffff 100%); background: linear-gradient(135deg, #fafafa 0%, #ffffff 100%);
border-bottom: 1px solid rgba(0, 0, 0, 0.05); border-bottom: 1px solid rgba(0, 0, 0, 0.05);
@@ -190,16 +198,16 @@ export default {
} }
.product-name { .product-name {
font-size: 0.85rem; font-size: 0.95rem;
font-weight: 500; font-weight: 500;
color: #1a1a1a; color: #1a1a1a;
line-height: 1.2; line-height: 1.3;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
min-height: 2rem; min-height: 2.5rem;
letter-spacing: 0.01em; letter-spacing: 0.01em;
} }
@@ -211,20 +219,20 @@ export default {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 2px; gap: 4px;
} }
.price-row { .price-row {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 1px; gap: 2px;
} }
.price-label { .price-label {
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.8px; letter-spacing: 0.8px;
font-size: 0.6rem; font-size: 0.65rem;
color: #9e9e9e; color: #9e9e9e;
font-weight: 500; font-weight: 500;
} }
@@ -232,14 +240,14 @@ export default {
.price-value { .price-value {
color: #1565c0; color: #1565c0;
letter-spacing: 0.02em; letter-spacing: 0.02em;
font-size: 0.9rem; font-size: 1.1rem;
} }
.price-total-chip { .price-total-chip {
letter-spacing: 0.03em; letter-spacing: 0.03em;
font-size: 0.75rem; font-size: 0.9rem;
padding: 0 10px; padding: 0 12px;
height: 22px; height: 26px;
box-shadow: 0 2px 8px rgba(76, 175, 80, 0.25); box-shadow: 0 2px 8px rgba(76, 175, 80, 0.25);
} }
@@ -259,8 +267,8 @@ export default {
} }
.quantity-input { .quantity-input {
max-width: 55px; max-width: 65px;
min-width: 55px; min-width: 65px;
} }
.quantity-input :deep(.v-field) { .quantity-input :deep(.v-field) {
@@ -272,10 +280,10 @@ export default {
.quantity-input :deep(.v-field__input) { .quantity-input :deep(.v-field__input) {
text-align: center; text-align: center;
font-weight: 700; font-weight: 700;
font-size: 0.85rem; font-size: 0.95rem;
color: #1a1a1a; color: #1a1a1a;
padding: 2px 0; padding: 4px 0;
min-height: 28px; min-height: 32px;
} }
.quantity-input :deep(.v-field__field) { .quantity-input :deep(.v-field__field) {
@@ -301,10 +309,140 @@ export default {
/* Móvil pequeño (< 375px) */ /* Móvil pequeño (< 375px) */
@media (max-width: 374px) { @media (max-width: 374px) {
.product-image-container { .product-content {
height: 130px; padding: 10px;
} }
.product-name {
font-size: 0.9rem;
min-height: 2.4rem;
}
.price-value {
font-size: 1rem;
}
.quantity-input {
max-width: 60px;
min-width: 60px;
}
}
/* Móvil estándar (375px - 559px) */
@media (min-width: 375px) and (max-width: 559px) {
.product-name {
font-size: 0.95rem;
}
.price-value {
font-size: 1.05rem;
}
}
/* Tablet (560px - 959px) */
@media (min-width: 560px) and (max-width: 959px) {
.product-content {
padding: 14px;
}
.product-name {
font-size: 1rem;
min-height: 2.6rem;
}
.price-label {
font-size: 0.68rem;
}
.price-value {
font-size: 1.15rem;
}
.price-total-chip {
font-size: 0.95rem;
height: 28px;
}
.quantity-input {
max-width: 70px;
min-width: 70px;
}
}
/* Desktop (≥ 960px) */
@media (min-width: 960px) {
.product-content {
padding: 16px 14px;
}
.product-name {
font-size: 1.05rem;
min-height: 2.7rem;
}
.price-label {
font-size: 0.7rem;
}
.price-value {
font-size: 1.2rem;
}
.price-total-chip {
font-size: 1rem;
height: 30px;
padding: 0 14px;
}
.product-actions {
padding: 8px;
padding-bottom: 12px;
}
.quantity-input {
max-width: 70px;
min-width: 70px;
}
.qty-btn {
width: 36px;
height: 36px;
}
}
/* Desktop Large (≥ 1280px) */
@media (min-width: 1280px) {
.product-content {
padding: 18px 16px;
}
.product-name {
font-size: 1.1rem;
min-height: 2.8rem;
}
.price-value {
font-size: 1.25rem;
}
.price-total-chip {
font-size: 1.05rem;
height: 32px;
}
}
/* Desktop Extra Large (≥ 1920px) */
@media (min-width: 1920px) {
.product-name {
font-size: 1.15rem;
min-height: 3rem;
}
.price-value {
font-size: 1.3rem;
}
}
.product-content { .product-content {
padding: 8px; padding: 8px;
} }
@@ -429,7 +567,7 @@ export default {
} }
.product-name { .product-name {
font-size: 1rem; font-size: 2rem;
min-height: 2.4rem; min-height: 2.4rem;
} }

View File

@@ -377,7 +377,7 @@ export default {
quantity: 0, quantity: 0,
img: img:
product.img || product.img ||
`https://picsum.photos/300/200?random=${product.id}`, `https://picsum.photos/600/600?random=${product.id}`,
})); }));
}) })
.catch((error) => { .catch((error) => {