Kundenrezensionen jetzt vollständig durch Kund:innen selbst, nicht mehr über Admin

Bisher musste VanVan Bewertungen manuell im CMS eintragen. Jetzt können
angemeldete Kund:innen Rezensionen direkt auf der Produktseite abgeben
(inkl. Herzen-Sternebewertung und Text). Die Durchschnittsbewertung wird
automatisch berechnet und überall live eingebunden: Produktkarten
(shop-weit), Produktdetailseite, Shop-Filter/Sortierung nach Bewertung
und die Kundenstimmen-Sektion auf der Startseite.

Neu dazu: ein Kontobereich fürs Login (Demo-Login per E-Mail), Profilfoto-
Upload, wählbarer Benutzername, und ein Header-Kontomenü, das nur bei
Anmeldung erscheint. Jede Bestellung im Konto-Dashboard hat einen
"Rezension schreiben"-Link, der direkt zur Produktseite führt und dort
per Bestellnummer verknüpft wird; im Profil ist dann sofort sichtbar,
welche Bestellungen schon bewertet wurden.

Technisch als reines Frontend/localStorage-System umgesetzt (kein Backend
in dieser Phase), analog zum bestehenden Warenkorb-Muster. Admin-CMS-Feld
für manuelle Bewertungen entfernt, da Rezensionen jetzt ausschließlich von
Kund:innen kommen (auch aus rechtlichen Gründen: keine Fake-Bewertungen).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
qcigano
2026-08-03 04:17:04 +02:00
co-authored by Claude Sonnet 5
parent d27a858d8f
commit 6f10e41386
28 changed files with 2338 additions and 334 deletions
+144 -1
View File
@@ -550,6 +550,84 @@ a:focus-visible, button:focus-visible {
.account-btn { padding: 0.5em; }
}
/* Konto-Menü in der Kopfzeile — ersetzt den "Anmelden"-Button sobald auf diesem Gerät ein
(Demo-)Konto angemeldet ist (siehe Layout.astro-Script + scripts/account.ts). Gleicher
Verlaufsrand-Knopf-Look wie account-btn, damit der Wechsel nicht wie ein Bruch wirkt. */
.account-area { position: relative; }
.account-menu { position: relative; display: none; align-items: center; }
.account-menu-btn {
display: flex;
align-items: center;
gap: 0.5em;
padding: 0.4em 0.9em 0.4em 0.4em;
border-radius: 999px;
background: linear-gradient(135deg, rgba(95, 211, 236, 0.16), rgba(46, 27, 71, 0.4));
border: 1px solid rgba(95, 211, 236, 0.3);
color: var(--c-text);
font-size: 0.92rem;
font-weight: 600;
cursor: pointer;
transition: border-color 0.2s var(--ease), transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.account-menu-btn:hover {
border-color: var(--c-accent);
transform: translateY(-1px);
box-shadow: 0 8px 20px -8px rgba(95, 211, 236, 0.4);
}
.account-avatar {
width: 29px;
height: 29px;
border-radius: 50%;
background: linear-gradient(155deg, var(--c-accent), var(--c-purple));
background-size: cover;
background-position: center;
display: flex;
align-items: center;
justify-content: center;
color: var(--c-black);
font-size: 0.86rem;
font-weight: 800;
flex-shrink: 0;
}
.account-menu-btn .chevron { font-size: 0.6rem; opacity: 0.7; transition: transform 0.2s var(--ease); }
.account-menu.open .account-menu-btn .chevron { transform: rotate(180deg); }
.account-dropdown {
position: absolute;
top: calc(100% + 0.6rem);
right: 0;
min-width: 180px;
background: var(--c-anthracite-light);
border: 1px solid rgba(244, 241, 247, 0.1);
border-radius: var(--radius-m);
box-shadow: var(--shadow-card);
padding: 0.4rem;
display: none;
flex-direction: column;
gap: 0.15rem;
z-index: 60;
}
.account-menu.open .account-dropdown { display: flex; }
.account-dropdown a,
.account-dropdown button {
display: block;
width: 100%;
text-align: left;
background: none;
border: none;
color: var(--c-text);
padding: 0.6em 0.7em;
border-radius: var(--radius-s);
font-size: 0.9rem;
cursor: pointer;
transition: background 0.15s var(--ease);
}
.account-dropdown a:hover,
.account-dropdown button:hover { background: color-mix(in srgb, var(--c-accent) 12%, transparent); }
@media (max-width: 860px) {
.account-menu-btn .account-username { display: none; }
.account-menu-btn { padding: 0.4em; }
}
/* ============================================================
Geteilte Seiten-Layouts (von allen Sprachversionen genutzt,
damit DE/EN/CH/FR immer exakt gleich aussehen)
@@ -1163,8 +1241,27 @@ a:focus-visible, button:focus-visible {
gap: 1.5rem;
flex-wrap: wrap;
}
.account-head-identity { display: flex; align-items: center; gap: 1rem; }
.account-head h1 { margin: 0.2rem 0 0.5rem; }
.account-head .lead { margin: 0; max-width: 52ch; }
/* Großer Avatar (Kopfzeile des Dashboards + Profil-Bereich) — gleiches Prinzip wie der kleine
Avatar im Header-Konto-Menü (Foto als Hintergrundbild, sonst erster Buchstabe des Namens). */
.account-avatar-lg {
width: 56px;
height: 56px;
border-radius: 50%;
background: linear-gradient(155deg, var(--c-accent), var(--c-purple));
background-size: cover;
background-position: center;
display: flex;
align-items: center;
justify-content: center;
color: var(--c-black);
font-size: 1.4rem;
font-weight: 800;
flex-shrink: 0;
}
@media (max-width: 500px) { .account-head-identity { flex-wrap: wrap; } }
.account-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-top: 1.2rem; }
.account-stat { text-align: center; display: flex; flex-direction: column; gap: 0.25rem; padding: 1.2rem 1rem; }
.account-stat-value { font-family: var(--font-head); font-size: 1.9rem; font-weight: 700; color: var(--c-accent); line-height: 1; }
@@ -1182,14 +1279,24 @@ a:focus-visible, button:focus-visible {
.order-items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.order-items li { display: flex; justify-content: space-between; gap: 1rem; font-size: 0.95rem; color: var(--c-text-muted); }
.order-item-price { color: var(--c-text); white-space: nowrap; }
.order-item-right { display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap; }
.review-link { color: var(--c-accent); font-weight: 600; white-space: nowrap; }
.review-link:hover { text-decoration: underline; }
.review-done-badge { background: rgba(126, 200, 160, 0.28); border-color: rgba(126, 200, 160, 0.5); color: #cfeee0; white-space: nowrap; }
.order-card-foot { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; border-top: 1px dashed rgba(244, 241, 247, 0.14); padding-top: 0.9rem; }
.order-total { font-size: 1.05rem; }
.order-total strong { color: var(--c-accent); }
.order-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.order-tracking-no { margin: 0; color: var(--c-text-muted); }
.order-tracking-no code { font-size: 0.9em; letter-spacing: 0.02em; }
.profile-card { display: flex; flex-direction: column; align-items: flex-start; gap: 0.5rem; }
.profile-card { display: flex; flex-direction: column; align-items: stretch; gap: 1.3rem; }
.profile-card .specs { margin-top: 0; width: 100%; }
.profile-photo-row { display: flex; align-items: center; gap: 1.1rem; }
.profile-photo-btn { display: inline-block; cursor: pointer; }
.profile-field { display: flex; flex-direction: column; gap: 0.4rem; }
.profile-field label { font-size: 0.85rem; color: var(--c-text-muted); }
.profile-field-row { display: flex; gap: 0.6rem; }
.profile-field-row input { flex: 1; }
/* Kundenrezensionen — Herzen in Lila-Babyblau statt Sterne (siehe HeartRating.astro), damit
Bewertungen sich erkennbar in die restliche Seite einfügen statt wie ein fremdes Bewertungs-
@@ -1203,6 +1310,42 @@ a:focus-visible, button:focus-visible {
.review-name { font-weight: 700; }
.review-date { color: var(--c-text-muted); margin-left: auto; }
.review-card p { color: var(--c-text-muted); }
/* Bewertungsformular auf der Produktseite — eigene Karte unter der Rezensionsliste, gleicher
.frm-Look (Formularfelder) wie Kontakt-/Login-Formulare der Seite. */
.review-form-card { margin-top: 1.6rem; }
.review-form-card h3 { margin-top: 0; }
.review-form-card form { display: flex; flex-direction: column; gap: 1rem; margin-top: 1rem; }
.review-form-card label { display: block; font-size: 0.85rem; color: var(--c-text-muted); margin-bottom: 0.4rem; }
.review-form-card input[type="text"],
.review-form-card textarea {
width: 100%;
background: var(--c-anthracite);
color: var(--c-text);
border: 1px solid rgba(244, 241, 247, 0.15);
border-radius: var(--radius-s);
padding: 0.6em 0.8em;
font-family: inherit;
font-size: 0.95rem;
resize: vertical;
}
.review-form-row { display: flex; flex-direction: column; gap: 0.4rem; }
.review-form-label { font-size: 0.85rem; color: var(--c-text-muted); }
.review-login-note, .review-order-note { color: var(--c-text-muted); }
.review-order-note { color: var(--c-accent); font-weight: 600; }
/* Klickbare Herzen-Auswahl im Formular — größer als die Anzeige-Herzen, deutlich als Steuerelement
erkennbar (Hand-Cursor, sanftes Aufskalieren bei Hover). */
.heart-picker { display: inline-flex; gap: 0.2em; }
.heart-pick {
background: none;
border: none;
padding: 0.1em;
cursor: pointer;
line-height: 0;
transition: transform 0.15s var(--ease);
}
.heart-pick:hover { transform: scale(1.15); }
/* Bewertungszeile auf der Produktkarte — dicht unter dem Titel, kein zusätzlicher Abstand nötig,
da .product-card schon einen einheitlichen gap zwischen allen Kindern hat. */
.product-card .heart-rating { margin-top: -0.2rem; }