fix: SEO- und Barrierefreiheits-Luecken auf Kaufentscheidungsseiten schliessen
Konkrete, verifizierte Luecken auf den Seiten, die Kund:innen von Google aus oder per Link erreichen: - Product-JSON-LD auf der Produktdetailseite ergaenzt um "image" (absolute URLs der hochgeladenen Produktfotos) — fehlte bisher trotz vorhandener Bilder und ist fuer Google Rich-Results/Merchant-Listing mit Sternebewertung + Preis im Suchergebnis erforderlich. - Alt-Text fuer echte (hochgeladene) Bilder aussagekraeftiger: ContentImage uebernimmt jetzt das bereits vorhandene, bisher nur auf Platzhalterkacheln sichtbare "label" (Ernte-Jahr/Typ, Kategorie, Ort) mit in den Alt-Text — wirkt projektweit auf Produktkarten, Ernte-Uebersicht/-Detail und Produkt-Teaser. Produktgalerie-Hauptbild zeigt zusaetzlich die Geschmacksnoten im Alt-Text statt nur des Produktnamens. - Checkout: allgemeine Fehlermeldung nach fehlgeschlagenem Absenden bekommt role="alert" und Fokus wird aktiv dorthin verschoben — bisher rein farblich markiert, Screenreader-Nutzer:innen haetten den Fehler beim geldwerten Bestellabschluss sonst gar nicht mitbekommen. - Cart-Drawer und Warenkorb-Seite: Lagerbestand-Hinweise (Ausverkauft/Nur noch N) treffen asynchron erst nach dem ersten Rendern ein — jetzt in einem persistenten aria-live-Wrapper, damit der Uebergang tatsaechlich angesagt wird statt stumm zu bleiben. Geprueft und bereits solide befunden (keine Aenderung noetig): Shop-Kanonical ignoriert bewusst Such-/Filter-Query-Parameter (kein Duplicate-Content-Risiko), Sitemap deckt Produkt- und Ernte-Detailseiten mit echtem lastmod ab, Produktgalerie-Tastaturbedienung ueber echte <button>-Kacheln mit aria-label/aria-current, Cart-Drawer-Fokusfalle/Fokus-Rueckgabe, Mengen-Steller- aria-live, Farbkontrast von text-honey-dark/text-red-700 auf dem Hintergrund (~4.9:1 bzw. ~6.1:1, beide AA-konform). tsc/vitest/build bleiben gruen (142 Tests).
This commit is contained in:
1 parent
0b2196460a
commit
ac432e261b
6 files changed
+67
-16
No files matched your search
@@ -27,13 +27,18 @@ const PLACEHOLDER_SLIDES: Slide[] = [
|
||||
interface ProductGalleryProps {
|
||||
images: string[];
|
||||
productName: string;
|
||||
/** Kurzbeschreibung (z.B. Geschmacksnoten) fuer aussagekraeftigeren Alt-Text
|
||||
* auf dem Hauptbild — reiner Produktname allein ist fuer Screenreader UND
|
||||
* Bildersuche weniger nuetzlich als Name + kurze inhaltliche Einordnung. */
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export function ProductGallery({ images, productName }: ProductGalleryProps) {
|
||||
export function ProductGallery({ images, productName, description }: ProductGalleryProps) {
|
||||
const slides: Slide[] = images.length > 0 ? images.map((src) => ({ src })) : PLACEHOLDER_SLIDES;
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const active = slides[activeIndex] ?? slides[0];
|
||||
const touchStartX = useRef<number | null>(null);
|
||||
const mainImageAlt = description ? `${productName} – ${description}` : productName;
|
||||
|
||||
function handleTouchStart(event: TouchEvent) {
|
||||
touchStartX.current = event.touches[0].clientX;
|
||||
@@ -63,7 +68,7 @@ export function ProductGallery({ images, productName }: ProductGalleryProps) {
|
||||
>
|
||||
{isImageSlide(active) ? (
|
||||
// eslint-disable-next-line @next/next/no-img-element -- externe Bildquelle noch unbekannt, next/image braucht dafuer eine feste remotePatterns-Konfiguration.
|
||||
<img src={active.src} alt={productName} className="w-full h-full object-cover" draggable={false} />
|
||||
<img src={active.src} alt={mainImageAlt} className="w-full h-full object-cover" draggable={false} />
|
||||
) : (
|
||||
<PlaceholderImage tone={active.tone} label={active.label} className="w-full h-full" />
|
||||
)}
|
||||
|
||||
Reference in new issue
Block a user