xvxcv
All checks were successful
Deploy / deploy (push) Successful in 55s

This commit is contained in:
2026-07-27 21:40:40 +02:00
parent 36092027d2
commit 932a070652
6 changed files with 24 additions and 15 deletions

View File

@@ -1,9 +1,9 @@
Anweisung: Projektstruktur (Basis-Template) wie in „papa-kind-treff“ Anweisung: Projektstruktur (Basis-Template) wie in „papa-kind-treff“
Aktueller Projektstand Aktueller Projektstand
- Papa-Kind-Treff nutzt im Mitgliederbereich DiceBear `lorelei` direkt für externe SVG-Avatare. - Papa-Kind-Treff nutzt im Mitgliederbereich DiceBear `lorelei` über einen internen API-Proxy mit lokalem Cache.
- Relevante Logik liegt in `src/App/Avatar/Lorelei.php`. - Relevante Logik liegt in `src/App/Avatar/Lorelei.php`.
- Die Avatar-Logik erzeugt direkte DiceBear-URLs; der frühere Proxy wird aktuell nicht mehr für die Auslieferung verwendet. - Der Avatar-Proxy liegt unter `public/page/api/avatar.php`.
- Die visuelle Avatar-Konfiguration liegt im Dashboard-Modal unter `partials/landing/account/dashboard.php` und rendert Komponenten-Vorschauen live nach. - Die visuelle Avatar-Konfiguration liegt im Dashboard-Modal unter `partials/landing/account/dashboard.php` und rendert Komponenten-Vorschauen live nach.
- Neue Grundvarianten werden im gleichen Modal als separates Auswahlraster eingeblendet und übernehmen die aktuell gewählten Lorelei-Komponenten. - Neue Grundvarianten werden im gleichen Modal als separates Auswahlraster eingeblendet und übernehmen die aktuell gewählten Lorelei-Komponenten.
- Alte statische Avatar-Presets und frühere Layer-Assets sind entfernt; aktiv ist nur noch der Lorelei-Generator. - Alte statische Avatar-Presets und frühere Layer-Assets sind entfernt; aktiv ist nur noch der Lorelei-Generator.

View File

@@ -20,9 +20,9 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter. Kernbereiche sind l
- Die Community ist hierarchisch aufgebaut: Kategorien -> Boards -> Threads -> Posts. - Die Community ist hierarchisch aufgebaut: Kategorien -> Boards -> Threads -> Posts.
- Moderation ist getrennt vom normalen Community-Frontend in einem eigenen Adminbereich. - Moderation ist getrennt vom normalen Community-Frontend in einem eigenen Adminbereich.
- Standortfunktionen sind relevant für lokale Treffen und werden künftig weiter ausgebaut. - Standortfunktionen sind relevant für lokale Treffen und werden künftig weiter ausgebaut.
- Profilbilder werden aktuell über DiceBear im Stil `lorelei` direkt als externe SVG geladen. - Profilbilder werden aktuell über DiceBear im Stil `lorelei` serverseitig erzeugt und lokal gecacht.
- Der Avatar-Editor bietet aktuell visuelle Komponenten-Vorschauen statt reiner Text-Dropdowns. - Der Avatar-Editor bietet aktuell visuelle Komponenten-Vorschauen statt reiner Text-Dropdowns.
- Frühere statische Preset-Avatar-Assets wurden entfernt; der aktuelle Stand nutzt nur noch den Generator mit direkter DiceBear-Auslieferung. - Frühere statische Preset-Avatar-Assets wurden entfernt; der aktuelle Stand nutzt nur noch den Generator mit Proxy/Cache.
## Navigation / Konto ## Navigation / Konto
- Eingeloggte Nutzer sehen rechts ein Profil-Menü statt einzelner `Dashboard`-/`Logout`-Buttons. - Eingeloggte Nutzer sehen rechts ein Profil-Menü statt einzelner `Dashboard`-/`Logout`-Buttons.

View File

@@ -17,7 +17,7 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter mit Fokus auf lokale
- Impressum, Datenschutz-&-Cookies-Seite und Über-uns - Impressum, Datenschutz-&-Cookies-Seite und Über-uns
- standortbasierte Sortierung für die neuesten Treffen - standortbasierte Sortierung für die neuesten Treffen
- eigener Einstellungsbereich für Standortfreigabe, Browser-Hinweise und Consent-Verwaltung - eigener Einstellungsbereich für Standortfreigabe, Browser-Hinweise und Consent-Verwaltung
- modernes Avatar-System auf Basis von DiceBear `lorelei`, direkt als externe SVG ausgeliefert - modernes Avatar-System auf Basis von DiceBear `lorelei`, serverseitig über einen lokalen Proxy mit Cache ausgeliefert
- Profilbild-Generator mit visueller Komponenten-Auswahl für Augen, Augenbrauen, Mund, Brille, Haare, Bart und Ohrringe sowie einer separaten Auswahl neuer Grundvarianten - Profilbild-Generator mit visueller Komponenten-Auswahl für Augen, Augenbrauen, Mund, Brille, Haare, Bart und Ohrringe sowie einer separaten Auswahl neuer Grundvarianten
- keine statischen Avatar-Preset-Dateien mehr im Repository; Vorschau und Auswahl laufen vollständig über den Lorelei-Generator - keine statischen Avatar-Preset-Dateien mehr im Repository; Vorschau und Auswahl laufen vollständig über den Lorelei-Generator
- Consent-Manager für Analyse und externe Dienste - Consent-Manager für Analyse und externe Dienste
@@ -50,7 +50,7 @@ Der aktuelle Code nutzt oder kann nutzen:
- lokale Standortspeicherung via Cookie, `localStorage`, `sessionStorage` (`external_services`) - lokale Standortspeicherung via Cookie, `localStorage`, `sessionStorage` (`external_services`)
- Leaflet von `unpkg.com` (`external_services`) - Leaflet von `unpkg.com` (`external_services`)
- OpenStreetMap Nominatim (`external_services`) - OpenStreetMap Nominatim (`external_services`)
- DiceBear `lorelei` für extern geladene Profilbilder - DiceBear `lorelei` für serverseitig erzeugte Profilbilder
Wichtig: Wichtig:
- Nicht notwendige Analyse- und Drittanbieterfunktionen dürfen erst nach Einwilligung aktiv werden. - Nicht notwendige Analyse- und Drittanbieterfunktionen dürfen erst nach Einwilligung aktiv werden.

View File

@@ -744,7 +744,13 @@ document.addEventListener('DOMContentLoaded', () => {
}; };
const avatarComponentFields = Object.keys(avatarComponentFieldMap); const avatarComponentFields = Object.keys(avatarComponentFieldMap);
const avatarEndpoint = 'https://api.dicebear.com/10.x/lorelei/svg'; const avatarEndpoint = '/api/avatar';
const avatarOptionalProbabilityMap = {
avatar_lorelei_glasses_variant: 'glassesProbability',
avatar_lorelei_hair_variant: 'hairProbability',
avatar_lorelei_beard_variant: 'beardProbability',
avatar_lorelei_earrings_variant: 'earringsProbability',
};
const buildAvatarParams = (form, overrides = {}) => { const buildAvatarParams = (form, overrides = {}) => {
const seed = overrides.avatar_preset || readAvatarValue(form, 'avatar_preset'); const seed = overrides.avatar_preset || readAvatarValue(form, 'avatar_preset');
@@ -756,6 +762,12 @@ document.addEventListener('DOMContentLoaded', () => {
? overrides[field] ? overrides[field]
: readAvatarValue(form, field); : readAvatarValue(form, field);
const param = avatarComponentFieldMap[field]; const param = avatarComponentFieldMap[field];
const probabilityParam = avatarOptionalProbabilityMap[field];
if (probabilityParam) {
params.set(probabilityParam, value ? '100' : '0');
}
if (value && param) params.set(param, value); if (value && param) params.set(param, value);
}); });
@@ -771,7 +783,6 @@ document.addEventListener('DOMContentLoaded', () => {
const params = buildAvatarParams(form); const params = buildAvatarParams(form);
if (!params) return; if (!params) return;
params.set('size', '256');
const url = `${avatarEndpoint}?${params.toString()}`; const url = `${avatarEndpoint}?${params.toString()}`;
if (!url) return; if (!url) return;
image.src = url; image.src = url;
@@ -784,7 +795,6 @@ document.addEventListener('DOMContentLoaded', () => {
const params = buildAvatarParams(form, { [field]: value }); const params = buildAvatarParams(form, { [field]: value });
if (!params) return; if (!params) return;
params.set('size', '256');
image.src = `${avatarEndpoint}?${params.toString()}`; image.src = `${avatarEndpoint}?${params.toString()}`;
}); });
}; };
@@ -803,7 +813,6 @@ document.addEventListener('DOMContentLoaded', () => {
card.type = 'button'; card.type = 'button';
card.className = 'avatar-seed-card'; card.className = 'avatar-seed-card';
card.setAttribute('data-avatar-seed-option', seed); card.setAttribute('data-avatar-seed-option', seed);
params.set('size', '256');
card.innerHTML = ` card.innerHTML = `
<span class="avatar-seed-card__thumb"> <span class="avatar-seed-card__thumb">
<img src="${avatarEndpoint}?${params.toString()}" alt="Grundvariante ${index + 1}"> <img src="${avatarEndpoint}?${params.toString()}" alt="Grundvariante ${index + 1}">

View File

@@ -151,9 +151,9 @@ $clientCookie = $config->cookiePrefix() . 'client';
<section> <section>
<h2>10. Profilbilder mit DiceBear</h2> <h2>10. Profilbilder mit DiceBear</h2>
<p> <p>
Profilbilder werden über den Dienst DiceBear im Stil „Lorelei“ erzeugt. Dabei wird für die Profilbilder werden serverseitig über den Dienst DiceBear im Stil „Lorelei“ erzeugt. Dabei wird für die
Generierung nur der im Profil gespeicherte Avatar-Seed verwendet. Dein Browser lädt die Avatar-Grafiken Generierung nur der im Profil gespeicherte Avatar-Seed verwendet. Der Abruf erfolgt über unsere Anwendung
direkt von DiceBear. und wird lokal zwischengespeichert, sodass dein Browser die Avatar-Grafiken nicht direkt bei DiceBear lädt.
</p> </p>
<p> <p>
Rechtsgrundlage ist Art. 6 Abs. 1 lit. b DSGVO, soweit die Avatar-Erzeugung Teil des gewählten Rechtsgrundlage ist Art. 6 Abs. 1 lit. b DSGVO, soweit die Avatar-Erzeugung Teil des gewählten
@@ -166,7 +166,7 @@ $clientCookie = $config->cookiePrefix() . 'client';
<p> <p>
Eine Weitergabe erfolgt nur, soweit sie für den Betrieb der Website oder einzelner Funktionen erforderlich ist. Eine Weitergabe erfolgt nur, soweit sie für den Betrieb der Website oder einzelner Funktionen erforderlich ist.
Dazu können insbesondere technische Hosting-Dienstleister, E-Mail-Dienstleister, Dazu können insbesondere technische Hosting-Dienstleister, E-Mail-Dienstleister,
Analyse-Dienstleister, DiceBear für die Avatar-Erzeugung sowie die oben genannten externen Karten- und Standortdienste gehören. Analyse-Dienstleister, DiceBear für die serverseitige Avatar-Erzeugung sowie die oben genannten externen Karten- und Standortdienste gehören.
</p> </p>
</section> </section>

View File

@@ -127,7 +127,7 @@ final class Lorelei
public static function buildProxyUrl(array $row): string public static function buildProxyUrl(array $row): string
{ {
return 'https://api.dicebear.com/10.x/lorelei/svg?' . http_build_query(self::apiQuery($row) + ['size' => '256']); return '/api/avatar?' . http_build_query(self::apiQuery($row));
} }
public static function previewChoices(array $row, string $field): array public static function previewChoices(array $row, string $field): array