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

@@ -2,50 +2,58 @@
<v-card class="product-card" elevation="2" rounded="lg">
<!-- Imagen del Producto -->
<div class="product-image-container">
<v-img
:src="product.img"
<v-img
:src="product.img"
:alt="product.name"
class="product-img"
class="product-img"
cover
max-height="140"
max-height="300"
aspect-ratio="1"
>
<template v-slot:placeholder>
<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>
</template>
</v-img>
</div>
<!-- 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 -->
<v-tooltip location="top" :text="product.name">
<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 }}
</h3>
</template>
</v-tooltip>
<!-- Sección de Precios -->
<div class="prices-section mb-1">
<div class="prices-section mb-2">
<!-- Precio Unitario -->
<div class="price-row">
<div class="price-row mb-1">
<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) }}
</div>
</div>
<!-- Precio Total -->
<div class="price-row">
<span class="price-label text-caption">Precio total</span>
<v-chip
color="success"
variant="flat"
size="x-small"
class="price-total-chip font-weight-bold"
<v-chip
color="success"
variant="flat"
size="small"
class="price-total-chip font-weight-bold mt-1"
>
{{ currency(product.price * product.quantity) }}
</v-chip>
@@ -54,11 +62,11 @@
</v-card-text>
<!-- 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">
<v-btn
<v-btn
icon
size="small"
size="small"
variant="tonal"
color="error"
class="qty-btn"
@@ -67,7 +75,7 @@
>
<v-icon size="20">mdi-minus</v-icon>
</v-btn>
<v-text-field
v-model.number="product.quantity"
type="number"
@@ -81,10 +89,10 @@
aria-label="Cantidad"
@input="handleQuantityChange"
/>
<v-btn
<v-btn
icon
size="small"
size="small"
variant="tonal"
color="success"
class="qty-btn"
@@ -162,7 +170,7 @@ export default {
.product-image-container {
position: relative;
width: 100%;
height: 140px;
height: 100%;
overflow: hidden;
background: linear-gradient(135deg, #fafafa 0%, #ffffff 100%);
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
@@ -190,16 +198,16 @@ export default {
}
.product-name {
font-size: 0.85rem;
font-size: 0.95rem;
font-weight: 500;
color: #1a1a1a;
line-height: 1.2;
line-height: 1.3;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
min-height: 2rem;
min-height: 2.5rem;
letter-spacing: 0.01em;
}
@@ -211,20 +219,20 @@ export default {
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
gap: 4px;
}
.price-row {
display: flex;
flex-direction: column;
align-items: center;
gap: 1px;
gap: 2px;
}
.price-label {
text-transform: uppercase;
letter-spacing: 0.8px;
font-size: 0.6rem;
font-size: 0.65rem;
color: #9e9e9e;
font-weight: 500;
}
@@ -232,14 +240,14 @@ export default {
.price-value {
color: #1565c0;
letter-spacing: 0.02em;
font-size: 0.9rem;
font-size: 1.1rem;
}
.price-total-chip {
letter-spacing: 0.03em;
font-size: 0.75rem;
padding: 0 10px;
height: 22px;
font-size: 0.9rem;
padding: 0 12px;
height: 26px;
box-shadow: 0 2px 8px rgba(76, 175, 80, 0.25);
}
@@ -259,8 +267,8 @@ export default {
}
.quantity-input {
max-width: 55px;
min-width: 55px;
max-width: 65px;
min-width: 65px;
}
.quantity-input :deep(.v-field) {
@@ -272,10 +280,10 @@ export default {
.quantity-input :deep(.v-field__input) {
text-align: center;
font-weight: 700;
font-size: 0.85rem;
font-size: 0.95rem;
color: #1a1a1a;
padding: 2px 0;
min-height: 28px;
padding: 4px 0;
min-height: 32px;
}
.quantity-input :deep(.v-field__field) {
@@ -301,23 +309,153 @@ export default {
/* Móvil pequeño (< 375px) */
@media (max-width: 374px) {
.product-image-container {
height: 130px;
.product-content {
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 {
padding: 8px;
}
.product-name {
font-size: 0.8rem;
min-height: 1.9rem;
}
.price-value {
font-size: 0.85rem;
}
.quantity-input {
max-width: 50px;
min-width: 50px;
@@ -329,11 +467,11 @@ export default {
.product-image-container {
height: 140px;
}
.product-name {
font-size: 0.85rem;
}
.price-value {
font-size: 0.9rem;
}
@@ -344,29 +482,29 @@ export default {
.product-image-container {
height: 150px;
}
.product-content {
padding: 10px;
}
.product-name {
font-size: 0.9rem;
min-height: 2.1rem;
}
.price-label {
font-size: 0.62rem;
}
.price-value {
font-size: 0.95rem;
}
.price-total-chip {
font-size: 0.8rem;
height: 24px;
}
.quantity-input {
max-width: 58px;
min-width: 58px;
@@ -378,40 +516,40 @@ export default {
.product-image-container {
height: 160px;
}
.product-content {
padding: 12px 10px;
}
.product-name {
font-size: 0.95rem;
min-height: 2.2rem;
}
.price-label {
font-size: 0.63rem;
}
.price-value {
font-size: 1rem;
}
.price-total-chip {
font-size: 0.85rem;
height: 25px;
padding: 0 11px;
}
.product-actions {
padding: 6px;
padding-bottom: 8px;
}
.quantity-input {
max-width: 58px;
min-width: 58px;
}
.qty-btn {
width: 32px;
height: 32px;
@@ -423,20 +561,20 @@ export default {
.product-image-container {
height: 170px;
}
.product-content {
padding: 14px 12px;
}
.product-name {
font-size: 1rem;
font-size: 2rem;
min-height: 2.4rem;
}
.price-value {
font-size: 1.05rem;
}
.price-total-chip {
font-size: 0.9rem;
height: 26px;
@@ -448,12 +586,12 @@ export default {
.product-image-container {
height: 180px;
}
.product-name {
font-size: 1.05rem;
min-height: 2.5rem;
}
.price-value {
font-size: 1.1rem;
}

View File

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