Produktfotos: Von VanVan im Adminbereich hochgeladene Bilder werden jetzt auf Produktkarten und der Produktdetailseite angezeigt (Hauptbild + klickbare Miniaturbilder), statt immer nur den Platzhalter zu zeigen
This commit is contained in:
@@ -20,9 +20,13 @@ const desc = product.beschreibung[lang];
|
|||||||
---
|
---
|
||||||
<a href={`${localePrefix(lang)}/produkt/${product.slug}/`} class="card product-card">
|
<a href={`${localePrefix(lang)}/produkt/${product.slug}/`} class="card product-card">
|
||||||
<div class="product-media">
|
<div class="product-media">
|
||||||
<div class="img-placeholder" role="img" aria-label={`${t.common.photoSoon}: ${name}`}>
|
{product.bilder && product.bilder.length > 0 ? (
|
||||||
{t.common.photoSoon}<br /><span class="small">{name}</span>
|
<img class="product-photo" src={product.bilder[0]} alt={name} loading="lazy" />
|
||||||
</div>
|
) : (
|
||||||
|
<div class="img-placeholder" role="img" aria-label={`${t.common.photoSoon}: ${name}`}>
|
||||||
|
{t.common.photoSoon}<br /><span class="small">{name}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div class="product-badges">
|
<div class="product-badges">
|
||||||
{product.badges.map((b) => (
|
{product.badges.map((b) => (
|
||||||
<span class={`badge ${b === "sale" ? "badge-sale" : ""}`}>{badgeLabel[b]}</span>
|
<span class={`badge ${b === "sale" ? "badge-sale" : ""}`}>{badgeLabel[b]}</span>
|
||||||
|
|||||||
@@ -42,14 +42,22 @@ const felder: [string, string | undefined][] = [
|
|||||||
|
|
||||||
<div class="grid grid-2 product-detail">
|
<div class="grid grid-2 product-detail">
|
||||||
<div>
|
<div>
|
||||||
<div class="img-placeholder product-hero" role="img" aria-label={`${t.common.photoSoon}: ${name}`}>
|
{product.bilder && product.bilder.length > 0 ? (
|
||||||
{t.common.photoSoon}<br /><span class="small">{t.product.photoNote}</span>
|
<>
|
||||||
</div>
|
<img id="product-hero-img" class="product-photo product-hero" src={product.bilder[0]} alt={name} />
|
||||||
<div class="thumb-row">
|
{product.bilder.length > 1 && (
|
||||||
<div class="img-placeholder thumb"></div>
|
<div class="thumb-row">
|
||||||
<div class="img-placeholder thumb"></div>
|
{product.bilder.map((bild) => (
|
||||||
<div class="img-placeholder thumb"></div>
|
<img class="product-photo thumb" src={bild} alt={name} data-full={bild} />
|
||||||
</div>
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div class="img-placeholder product-hero" role="img" aria-label={`${t.common.photoSoon}: ${name}`}>
|
||||||
|
{t.common.photoSoon}<br /><span class="small">{t.product.photoNote}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -118,4 +126,12 @@ const felder: [string, string | undefined][] = [
|
|||||||
confirm.style.display = "block";
|
confirm.style.display = "block";
|
||||||
setTimeout(() => (confirm.style.display = "none"), 2500);
|
setTimeout(() => (confirm.style.display = "none"), 2500);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Klick auf ein Miniaturbild zeigt es groß im Hauptbild an (mehrere Produktfotos).
|
||||||
|
const heroImg = document.getElementById("product-hero-img") as HTMLImageElement | null;
|
||||||
|
document.querySelectorAll<HTMLImageElement>(".thumb.product-photo").forEach((thumb) => {
|
||||||
|
thumb.addEventListener("click", () => {
|
||||||
|
if (heroImg && thumb.dataset.full) heroImg.src = thumb.dataset.full;
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -42,14 +42,22 @@ const felder: [string, string | undefined][] = [
|
|||||||
|
|
||||||
<div class="grid grid-2 product-detail">
|
<div class="grid grid-2 product-detail">
|
||||||
<div>
|
<div>
|
||||||
<div class="img-placeholder product-hero" role="img" aria-label={`${t.common.photoSoon}: ${name}`}>
|
{product.bilder && product.bilder.length > 0 ? (
|
||||||
{t.common.photoSoon}<br /><span class="small">{t.product.photoNote}</span>
|
<>
|
||||||
</div>
|
<img id="product-hero-img" class="product-photo product-hero" src={product.bilder[0]} alt={name} />
|
||||||
<div class="thumb-row">
|
{product.bilder.length > 1 && (
|
||||||
<div class="img-placeholder thumb"></div>
|
<div class="thumb-row">
|
||||||
<div class="img-placeholder thumb"></div>
|
{product.bilder.map((bild) => (
|
||||||
<div class="img-placeholder thumb"></div>
|
<img class="product-photo thumb" src={bild} alt={name} data-full={bild} />
|
||||||
</div>
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div class="img-placeholder product-hero" role="img" aria-label={`${t.common.photoSoon}: ${name}`}>
|
||||||
|
{t.common.photoSoon}<br /><span class="small">{t.product.photoNote}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -118,4 +126,12 @@ const felder: [string, string | undefined][] = [
|
|||||||
confirm.style.display = "block";
|
confirm.style.display = "block";
|
||||||
setTimeout(() => (confirm.style.display = "none"), 2500);
|
setTimeout(() => (confirm.style.display = "none"), 2500);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Klick auf ein Miniaturbild zeigt es groß im Hauptbild an (mehrere Produktfotos).
|
||||||
|
const heroImg = document.getElementById("product-hero-img") as HTMLImageElement | null;
|
||||||
|
document.querySelectorAll<HTMLImageElement>(".thumb.product-photo").forEach((thumb) => {
|
||||||
|
thumb.addEventListener("click", () => {
|
||||||
|
if (heroImg && thumb.dataset.full) heroImg.src = thumb.dataset.full;
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -42,14 +42,22 @@ const felder: [string, string | undefined][] = [
|
|||||||
|
|
||||||
<div class="grid grid-2 product-detail">
|
<div class="grid grid-2 product-detail">
|
||||||
<div>
|
<div>
|
||||||
<div class="img-placeholder product-hero" role="img" aria-label={`${t.common.photoSoon}: ${name}`}>
|
{product.bilder && product.bilder.length > 0 ? (
|
||||||
{t.common.photoSoon}<br /><span class="small">{t.product.photoNote}</span>
|
<>
|
||||||
</div>
|
<img id="product-hero-img" class="product-photo product-hero" src={product.bilder[0]} alt={name} />
|
||||||
<div class="thumb-row">
|
{product.bilder.length > 1 && (
|
||||||
<div class="img-placeholder thumb"></div>
|
<div class="thumb-row">
|
||||||
<div class="img-placeholder thumb"></div>
|
{product.bilder.map((bild) => (
|
||||||
<div class="img-placeholder thumb"></div>
|
<img class="product-photo thumb" src={bild} alt={name} data-full={bild} />
|
||||||
</div>
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div class="img-placeholder product-hero" role="img" aria-label={`${t.common.photoSoon}: ${name}`}>
|
||||||
|
{t.common.photoSoon}<br /><span class="small">{t.product.photoNote}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -118,4 +126,12 @@ const felder: [string, string | undefined][] = [
|
|||||||
confirm.style.display = "block";
|
confirm.style.display = "block";
|
||||||
setTimeout(() => (confirm.style.display = "none"), 2500);
|
setTimeout(() => (confirm.style.display = "none"), 2500);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Klick auf ein Miniaturbild zeigt es groß im Hauptbild an (mehrere Produktfotos).
|
||||||
|
const heroImg = document.getElementById("product-hero-img") as HTMLImageElement | null;
|
||||||
|
document.querySelectorAll<HTMLImageElement>(".thumb.product-photo").forEach((thumb) => {
|
||||||
|
thumb.addEventListener("click", () => {
|
||||||
|
if (heroImg && thumb.dataset.full) heroImg.src = thumb.dataset.full;
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -42,14 +42,22 @@ const felder: [string, string | undefined][] = [
|
|||||||
|
|
||||||
<div class="grid grid-2 product-detail">
|
<div class="grid grid-2 product-detail">
|
||||||
<div>
|
<div>
|
||||||
<div class="img-placeholder product-hero" role="img" aria-label={`${t.common.photoSoon}: ${name}`}>
|
{product.bilder && product.bilder.length > 0 ? (
|
||||||
{t.common.photoSoon}<br /><span class="small">{t.product.photoNote}</span>
|
<>
|
||||||
</div>
|
<img id="product-hero-img" class="product-photo product-hero" src={product.bilder[0]} alt={name} />
|
||||||
<div class="thumb-row">
|
{product.bilder.length > 1 && (
|
||||||
<div class="img-placeholder thumb"></div>
|
<div class="thumb-row">
|
||||||
<div class="img-placeholder thumb"></div>
|
{product.bilder.map((bild) => (
|
||||||
<div class="img-placeholder thumb"></div>
|
<img class="product-photo thumb" src={bild} alt={name} data-full={bild} />
|
||||||
</div>
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div class="img-placeholder product-hero" role="img" aria-label={`${t.common.photoSoon}: ${name}`}>
|
||||||
|
{t.common.photoSoon}<br /><span class="small">{t.product.photoNote}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -118,4 +126,12 @@ const felder: [string, string | undefined][] = [
|
|||||||
confirm.style.display = "block";
|
confirm.style.display = "block";
|
||||||
setTimeout(() => (confirm.style.display = "none"), 2500);
|
setTimeout(() => (confirm.style.display = "none"), 2500);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Klick auf ein Miniaturbild zeigt es groß im Hauptbild an (mehrere Produktfotos).
|
||||||
|
const heroImg = document.getElementById("product-hero-img") as HTMLImageElement | null;
|
||||||
|
document.querySelectorAll<HTMLImageElement>(".thumb.product-photo").forEach((thumb) => {
|
||||||
|
thumb.addEventListener("click", () => {
|
||||||
|
if (heroImg && thumb.dataset.full) heroImg.src = thumb.dataset.full;
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -220,6 +220,20 @@ a.card:hover {
|
|||||||
background-image: repeating-linear-gradient(135deg, rgba(244,241,247,0.03) 0 2px, transparent 2px 14px);
|
background-image: repeating-linear-gradient(135deg, rgba(244,241,247,0.03) 0 2px, transparent 2px 14px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Echtes Produktfoto (von VanVan im Adminbereich hochgeladen) — ersetzt den Platzhalter, sobald
|
||||||
|
`bilder` am Produkt gesetzt ist. Gleiche Maße/Ecken wie der Platzhalter, damit beim Hochladen
|
||||||
|
des ersten Fotos nichts im Layout springt. */
|
||||||
|
.product-photo {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: var(--radius-m);
|
||||||
|
}
|
||||||
|
.product-media .product-photo { aspect-ratio: 1 / 1; }
|
||||||
|
.thumb.product-photo { cursor: pointer; transition: outline-color 0.2s var(--ease); outline: 2px solid transparent; outline-offset: 2px; }
|
||||||
|
.thumb.product-photo:hover { outline-color: var(--c-accent); }
|
||||||
|
|
||||||
/* Portrait-Frame — edler Bilderrahmen für Porträtfotos (Startseite, Über die Kreative, ...) */
|
/* Portrait-Frame — edler Bilderrahmen für Porträtfotos (Startseite, Über die Kreative, ...) */
|
||||||
.portrait-frame {
|
.portrait-frame {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
Reference in New Issue
Block a user