diff --git a/.projektstructure.txt b/.projektstructure.txt index fd271dc..d133331 100755 --- a/.projektstructure.txt +++ b/.projektstructure.txt @@ -1,9 +1,9 @@ Anweisung: Projektstruktur (Basis-Template) wie in „papa-kind-treff“ Aktueller Projektstand -- Papa-Kind-Treff nutzt im Mitgliederbereich 100 moderne Portrait-Presets im gewünschten Referenzstil. +- Papa-Kind-Treff nutzt im Mitgliederbereich DiceBear `lorelei` über einen internen API-Proxy mit lokalem Cache. - Relevante Logik liegt in `src/App/Avatar.php`. -- Die Preset-Assets liegen unter `public/assets/avatars/presets/`. +- Der Avatar-Proxy liegt unter `public/page/api/avatar.php`. - Änderungen an Funktionen mit Cookies, LocalStorage, SessionStorage, Geolocation, Tracking oder Drittanbietern müssen immer auch in Datenschutz-/Cookie-Hinweisen und im Consent-Flow berücksichtigt werden. Ziel diff --git a/PROJECT_CONTEXT.md b/PROJECT_CONTEXT.md index 58dcf3d..60658d1 100644 --- a/PROJECT_CONTEXT.md +++ b/PROJECT_CONTEXT.md @@ -1,6 +1,6 @@ # Papa-Kind-Treff – Chat-Kontext -Stand: 2026-07-24 +Stand: 2026-07-26 ## Kurzbeschreibung Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter. Kernbereiche sind lokale Treffen/Events, ein Community-Forum, Mitgliederprofile mit optionalen Kinderinfos und ein Moderations-/Adminbereich. @@ -19,13 +19,13 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter. Kernbereiche sind l - Die Community ist hierarchisch aufgebaut: Kategorien -> Boards -> Threads -> Posts. - Moderation ist getrennt vom normalen Community-Frontend in einem eigenen Adminbereich. - Standortfunktionen sind relevant für lokale Treffen und werden künftig weiter ausgebaut. -- Profilbilder werden aktuell über 100 moderne Preset-Portraits im gewünschten Referenzstil statt über freie Bild-Uploads erzeugt. +- Profilbilder werden aktuell über DiceBear im Stil `lorelei` serverseitig erzeugt und lokal gecacht. ## Navigation / Konto - Eingeloggte Nutzer sehen rechts ein Profil-Menü statt einzelner `Dashboard`-/`Logout`-Buttons. - Das Profil-Menü enthält aktuell `Profil`, `Kinder`, `Termine`, `Community`, `Einstellungen`, `Abmelden`. - Der Mitgliederbereich selbst ist als Layout mit linker Bereichsnavigation aufgebaut. -- Im Profil kann der Nutzer aktuell aus 100 modernen Preset-Varianten wählen, gruppiert nach Hauttönen. +- Im Profil kann der Nutzer aktuell aus Lorelei-Varianten wählen und sich neue Seed-basierte Vorschläge laden. - Debug ist kein Menüpunkt und erscheint nur als Floating-Käfer für `site_admin` bei aktivem Debug-Modus. ## Community und Rechte diff --git a/README.md b/README.md index ca1afa5..4e02bd7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Papa-Kind-Treff -Stand: 2026-07-24 +Stand: 2026-07-26 Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter mit Fokus auf lokale Treffen, Community-Austausch und einen geschützten Mitgliederbereich. @@ -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 - standortbasierte Sortierung für die neuesten Treffen - eigener Einstellungsbereich für Standortfreigabe, Browser-Hinweise und Consent-Verwaltung -- modernes Avatar-System auf Basis von 100 festen Portrait-Presets im Referenzstil, gruppiert nach Hauttönen +- modernes Avatar-System auf Basis von DiceBear `lorelei`, serverseitig über einen lokalen Proxy mit Cache ausgeliefert - Consent-Manager für Analyse und externe Dienste - Navigation aktuell mit `Home`, `Suche`, `Community` - eingeloggte Nutzer sehen rechts ein Profil-Menü mit Direktlinks zu `Profil`, `Kinder`, `Termine`, `Community`, `Einstellungen` @@ -46,6 +46,7 @@ Der aktuelle Code nutzt oder kann nutzen: - lokale Standortspeicherung via Cookie, `localStorage`, `sessionStorage` (`external_services`) - Leaflet von `unpkg.com` (`external_services`) - OpenStreetMap Nominatim (`external_services`) +- DiceBear `lorelei` für serverseitig erzeugte Profilbilder Wichtig: - Nicht notwendige Analyse- und Drittanbieterfunktionen dürfen erst nach Einwilligung aktiv werden. diff --git a/partials/landing/account/dashboard.php b/partials/landing/account/dashboard.php index 3184484..6b38ffe 100755 --- a/partials/landing/account/dashboard.php +++ b/partials/landing/account/dashboard.php @@ -6,7 +6,6 @@ $editing = isset($editEvent) && $editEvent !== null; $actionEvent = $editing ? 'event_update' : 'event_add'; $startVal = $editEvent ? date('Y-m-d\TH:i', strtotime((string)$editEvent['starts_at'])) : ''; $allowNoKidsChecked = $editEvent ? ((int)$editEvent['allow_kids'] === 0) : false; -$activeAvatarPresetGroup = \App\Avatar::presetGroupForPreset((string)($profile['avatar_preset'] ?? 'modern_001')); $sectionLinks = [ 'profile' => 'Profil', 'children' => 'Kinder', @@ -68,7 +67,7 @@ $sectionLinks = [

Dein Profilbild

-

Wähle ein modernes Portrait im Stil der Community. Die Varianten bleiben konsistent, frisch und deutlich näher an der gewünschten Optik.

+

Dein Profilbild wird jetzt mit DiceBear im Stil Lorelei erzeugt. Du wählst eine Variante aus und speicherst deren Seed dauerhaft in deinem Profil.

@@ -303,39 +302,32 @@ $sectionLinks = [
-

Wähle zuerst einen Hautton-Bereich und dann eine passende Variante. Die Vorschau aktualisiert sich sofort.

+

Wähle eine Lorelei-Variante oder lade dir direkt neue Vorschläge. Die Vorschau aktualisiert sich sofort.

-
- $groupMeta): ?> - - +
+
Variante wählen - $groupPresets): ?> -
-
- $meta): ?> - - -
-
- +
+ $meta): ?> + + +
diff --git a/public/assets/avatars/presets/modern_001.png b/public/assets/avatars/presets/modern_001.png index cf3966b..3b5852b 100644 Binary files a/public/assets/avatars/presets/modern_001.png and b/public/assets/avatars/presets/modern_001.png differ diff --git a/public/assets/avatars/presets/modern_002.png b/public/assets/avatars/presets/modern_002.png index 397821e..bd4d0a1 100644 Binary files a/public/assets/avatars/presets/modern_002.png and b/public/assets/avatars/presets/modern_002.png differ diff --git a/public/assets/avatars/presets/modern_003.png b/public/assets/avatars/presets/modern_003.png index 7c00ff4..edd126f 100644 Binary files a/public/assets/avatars/presets/modern_003.png and b/public/assets/avatars/presets/modern_003.png differ diff --git a/public/assets/avatars/presets/modern_004.png b/public/assets/avatars/presets/modern_004.png index f569b9e..cd8d704 100644 Binary files a/public/assets/avatars/presets/modern_004.png and b/public/assets/avatars/presets/modern_004.png differ diff --git a/public/assets/avatars/presets/modern_005.png b/public/assets/avatars/presets/modern_005.png index 7e9fb85..4ca8bcd 100644 Binary files a/public/assets/avatars/presets/modern_005.png and b/public/assets/avatars/presets/modern_005.png differ diff --git a/public/assets/avatars/presets/modern_006.png b/public/assets/avatars/presets/modern_006.png index ef3b5a0..8ecd4f6 100644 Binary files a/public/assets/avatars/presets/modern_006.png and b/public/assets/avatars/presets/modern_006.png differ diff --git a/public/assets/avatars/presets/modern_007.png b/public/assets/avatars/presets/modern_007.png index 88c95e8..9d3da9e 100644 Binary files a/public/assets/avatars/presets/modern_007.png and b/public/assets/avatars/presets/modern_007.png differ diff --git a/public/assets/avatars/presets/modern_008.png b/public/assets/avatars/presets/modern_008.png index 6fe61dd..256c279 100644 Binary files a/public/assets/avatars/presets/modern_008.png and b/public/assets/avatars/presets/modern_008.png differ diff --git a/public/assets/avatars/presets/modern_009.png b/public/assets/avatars/presets/modern_009.png index c1f65cc..98b76ad 100644 Binary files a/public/assets/avatars/presets/modern_009.png and b/public/assets/avatars/presets/modern_009.png differ diff --git a/public/assets/avatars/presets/modern_01.png b/public/assets/avatars/presets/modern_01.png deleted file mode 100644 index 1d72b8f..0000000 Binary files a/public/assets/avatars/presets/modern_01.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_010.png b/public/assets/avatars/presets/modern_010.png index 582e752..c20f42f 100644 Binary files a/public/assets/avatars/presets/modern_010.png and b/public/assets/avatars/presets/modern_010.png differ diff --git a/public/assets/avatars/presets/modern_011.png b/public/assets/avatars/presets/modern_011.png index dbd6bb6..d015725 100644 Binary files a/public/assets/avatars/presets/modern_011.png and b/public/assets/avatars/presets/modern_011.png differ diff --git a/public/assets/avatars/presets/modern_012.png b/public/assets/avatars/presets/modern_012.png index 5dc501d..6e1c296 100644 Binary files a/public/assets/avatars/presets/modern_012.png and b/public/assets/avatars/presets/modern_012.png differ diff --git a/public/assets/avatars/presets/modern_013.png b/public/assets/avatars/presets/modern_013.png index 85462ce..921c86b 100644 Binary files a/public/assets/avatars/presets/modern_013.png and b/public/assets/avatars/presets/modern_013.png differ diff --git a/public/assets/avatars/presets/modern_014.png b/public/assets/avatars/presets/modern_014.png index c4be46a..156a4c0 100644 Binary files a/public/assets/avatars/presets/modern_014.png and b/public/assets/avatars/presets/modern_014.png differ diff --git a/public/assets/avatars/presets/modern_015.png b/public/assets/avatars/presets/modern_015.png index 77b0ae1..97ec793 100644 Binary files a/public/assets/avatars/presets/modern_015.png and b/public/assets/avatars/presets/modern_015.png differ diff --git a/public/assets/avatars/presets/modern_016.png b/public/assets/avatars/presets/modern_016.png index b42957a..c78a267 100644 Binary files a/public/assets/avatars/presets/modern_016.png and b/public/assets/avatars/presets/modern_016.png differ diff --git a/public/assets/avatars/presets/modern_017.png b/public/assets/avatars/presets/modern_017.png index bd8dd19..dab3449 100644 Binary files a/public/assets/avatars/presets/modern_017.png and b/public/assets/avatars/presets/modern_017.png differ diff --git a/public/assets/avatars/presets/modern_018.png b/public/assets/avatars/presets/modern_018.png index 7e5c0db..6d8c7a1 100644 Binary files a/public/assets/avatars/presets/modern_018.png and b/public/assets/avatars/presets/modern_018.png differ diff --git a/public/assets/avatars/presets/modern_019.png b/public/assets/avatars/presets/modern_019.png index 1c4a8ce..e104074 100644 Binary files a/public/assets/avatars/presets/modern_019.png and b/public/assets/avatars/presets/modern_019.png differ diff --git a/public/assets/avatars/presets/modern_02.png b/public/assets/avatars/presets/modern_02.png deleted file mode 100644 index cf3966b..0000000 Binary files a/public/assets/avatars/presets/modern_02.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_020.png b/public/assets/avatars/presets/modern_020.png index 0d2088b..5b01c79 100644 Binary files a/public/assets/avatars/presets/modern_020.png and b/public/assets/avatars/presets/modern_020.png differ diff --git a/public/assets/avatars/presets/modern_021.png b/public/assets/avatars/presets/modern_021.png index 1d72b8f..1c6768b 100644 Binary files a/public/assets/avatars/presets/modern_021.png and b/public/assets/avatars/presets/modern_021.png differ diff --git a/public/assets/avatars/presets/modern_022.png b/public/assets/avatars/presets/modern_022.png index 2bef43d..c839577 100644 Binary files a/public/assets/avatars/presets/modern_022.png and b/public/assets/avatars/presets/modern_022.png differ diff --git a/public/assets/avatars/presets/modern_023.png b/public/assets/avatars/presets/modern_023.png index cbdc7da..3d16be9 100644 Binary files a/public/assets/avatars/presets/modern_023.png and b/public/assets/avatars/presets/modern_023.png differ diff --git a/public/assets/avatars/presets/modern_024.png b/public/assets/avatars/presets/modern_024.png index 03741cd..f82395b 100644 Binary files a/public/assets/avatars/presets/modern_024.png and b/public/assets/avatars/presets/modern_024.png differ diff --git a/public/assets/avatars/presets/modern_025.png b/public/assets/avatars/presets/modern_025.png index 2e48dea..ce5f3ec 100644 Binary files a/public/assets/avatars/presets/modern_025.png and b/public/assets/avatars/presets/modern_025.png differ diff --git a/public/assets/avatars/presets/modern_026.png b/public/assets/avatars/presets/modern_026.png index 4f48292..afe0828 100644 Binary files a/public/assets/avatars/presets/modern_026.png and b/public/assets/avatars/presets/modern_026.png differ diff --git a/public/assets/avatars/presets/modern_027.png b/public/assets/avatars/presets/modern_027.png index 39c603b..73d2f5f 100644 Binary files a/public/assets/avatars/presets/modern_027.png and b/public/assets/avatars/presets/modern_027.png differ diff --git a/public/assets/avatars/presets/modern_028.png b/public/assets/avatars/presets/modern_028.png index 1b5d067..cc2ee71 100644 Binary files a/public/assets/avatars/presets/modern_028.png and b/public/assets/avatars/presets/modern_028.png differ diff --git a/public/assets/avatars/presets/modern_029.png b/public/assets/avatars/presets/modern_029.png index 4343aad..389ea0f 100644 Binary files a/public/assets/avatars/presets/modern_029.png and b/public/assets/avatars/presets/modern_029.png differ diff --git a/public/assets/avatars/presets/modern_03.png b/public/assets/avatars/presets/modern_03.png deleted file mode 100644 index 13e765c..0000000 Binary files a/public/assets/avatars/presets/modern_03.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_030.png b/public/assets/avatars/presets/modern_030.png index 8d20133..d0f2060 100644 Binary files a/public/assets/avatars/presets/modern_030.png and b/public/assets/avatars/presets/modern_030.png differ diff --git a/public/assets/avatars/presets/modern_031.png b/public/assets/avatars/presets/modern_031.png index 91e4af4..415e088 100644 Binary files a/public/assets/avatars/presets/modern_031.png and b/public/assets/avatars/presets/modern_031.png differ diff --git a/public/assets/avatars/presets/modern_032.png b/public/assets/avatars/presets/modern_032.png index e2e7cab..fc6db14 100644 Binary files a/public/assets/avatars/presets/modern_032.png and b/public/assets/avatars/presets/modern_032.png differ diff --git a/public/assets/avatars/presets/modern_033.png b/public/assets/avatars/presets/modern_033.png index 7f52d65..b0e879c 100644 Binary files a/public/assets/avatars/presets/modern_033.png and b/public/assets/avatars/presets/modern_033.png differ diff --git a/public/assets/avatars/presets/modern_034.png b/public/assets/avatars/presets/modern_034.png index 23616e3..744dd02 100644 Binary files a/public/assets/avatars/presets/modern_034.png and b/public/assets/avatars/presets/modern_034.png differ diff --git a/public/assets/avatars/presets/modern_035.png b/public/assets/avatars/presets/modern_035.png index 27894a6..d7544e3 100644 Binary files a/public/assets/avatars/presets/modern_035.png and b/public/assets/avatars/presets/modern_035.png differ diff --git a/public/assets/avatars/presets/modern_036.png b/public/assets/avatars/presets/modern_036.png index 56edaf4..f881b1d 100644 Binary files a/public/assets/avatars/presets/modern_036.png and b/public/assets/avatars/presets/modern_036.png differ diff --git a/public/assets/avatars/presets/modern_037.png b/public/assets/avatars/presets/modern_037.png index 3d3ca82..02cae8a 100644 Binary files a/public/assets/avatars/presets/modern_037.png and b/public/assets/avatars/presets/modern_037.png differ diff --git a/public/assets/avatars/presets/modern_038.png b/public/assets/avatars/presets/modern_038.png index cd94132..6b949e6 100644 Binary files a/public/assets/avatars/presets/modern_038.png and b/public/assets/avatars/presets/modern_038.png differ diff --git a/public/assets/avatars/presets/modern_039.png b/public/assets/avatars/presets/modern_039.png index 19476b0..a8f723c 100644 Binary files a/public/assets/avatars/presets/modern_039.png and b/public/assets/avatars/presets/modern_039.png differ diff --git a/public/assets/avatars/presets/modern_04.png b/public/assets/avatars/presets/modern_04.png deleted file mode 100644 index 4f48292..0000000 Binary files a/public/assets/avatars/presets/modern_04.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_040.png b/public/assets/avatars/presets/modern_040.png index e8931e6..bb3066e 100644 Binary files a/public/assets/avatars/presets/modern_040.png and b/public/assets/avatars/presets/modern_040.png differ diff --git a/public/assets/avatars/presets/modern_041.png b/public/assets/avatars/presets/modern_041.png index c4dee8a..a4cb4c6 100644 Binary files a/public/assets/avatars/presets/modern_041.png and b/public/assets/avatars/presets/modern_041.png differ diff --git a/public/assets/avatars/presets/modern_042.png b/public/assets/avatars/presets/modern_042.png index a3661eb..1a919e4 100644 Binary files a/public/assets/avatars/presets/modern_042.png and b/public/assets/avatars/presets/modern_042.png differ diff --git a/public/assets/avatars/presets/modern_043.png b/public/assets/avatars/presets/modern_043.png index 4b9030e..1adb599 100644 Binary files a/public/assets/avatars/presets/modern_043.png and b/public/assets/avatars/presets/modern_043.png differ diff --git a/public/assets/avatars/presets/modern_044.png b/public/assets/avatars/presets/modern_044.png index 6d553c1..17bdceb 100644 Binary files a/public/assets/avatars/presets/modern_044.png and b/public/assets/avatars/presets/modern_044.png differ diff --git a/public/assets/avatars/presets/modern_045.png b/public/assets/avatars/presets/modern_045.png index 0549cad..8e40411 100644 Binary files a/public/assets/avatars/presets/modern_045.png and b/public/assets/avatars/presets/modern_045.png differ diff --git a/public/assets/avatars/presets/modern_046.png b/public/assets/avatars/presets/modern_046.png index 965b3aa..cb31649 100644 Binary files a/public/assets/avatars/presets/modern_046.png and b/public/assets/avatars/presets/modern_046.png differ diff --git a/public/assets/avatars/presets/modern_047.png b/public/assets/avatars/presets/modern_047.png index a27042c..4915c31 100644 Binary files a/public/assets/avatars/presets/modern_047.png and b/public/assets/avatars/presets/modern_047.png differ diff --git a/public/assets/avatars/presets/modern_048.png b/public/assets/avatars/presets/modern_048.png index 07c5d34..33547cf 100644 Binary files a/public/assets/avatars/presets/modern_048.png and b/public/assets/avatars/presets/modern_048.png differ diff --git a/public/assets/avatars/presets/modern_049.png b/public/assets/avatars/presets/modern_049.png index 54386ee..0196445 100644 Binary files a/public/assets/avatars/presets/modern_049.png and b/public/assets/avatars/presets/modern_049.png differ diff --git a/public/assets/avatars/presets/modern_05.png b/public/assets/avatars/presets/modern_05.png deleted file mode 100644 index 41d7ec7..0000000 Binary files a/public/assets/avatars/presets/modern_05.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_050.png b/public/assets/avatars/presets/modern_050.png index ad15b1f..5aee445 100644 Binary files a/public/assets/avatars/presets/modern_050.png and b/public/assets/avatars/presets/modern_050.png differ diff --git a/public/assets/avatars/presets/modern_051.png b/public/assets/avatars/presets/modern_051.png index f60f64d..b249bed 100644 Binary files a/public/assets/avatars/presets/modern_051.png and b/public/assets/avatars/presets/modern_051.png differ diff --git a/public/assets/avatars/presets/modern_052.png b/public/assets/avatars/presets/modern_052.png index 4624f02..afd19d6 100644 Binary files a/public/assets/avatars/presets/modern_052.png and b/public/assets/avatars/presets/modern_052.png differ diff --git a/public/assets/avatars/presets/modern_053.png b/public/assets/avatars/presets/modern_053.png index 1c6a8ea..ee30fd3 100644 Binary files a/public/assets/avatars/presets/modern_053.png and b/public/assets/avatars/presets/modern_053.png differ diff --git a/public/assets/avatars/presets/modern_054.png b/public/assets/avatars/presets/modern_054.png index 4055d20..c387c87 100644 Binary files a/public/assets/avatars/presets/modern_054.png and b/public/assets/avatars/presets/modern_054.png differ diff --git a/public/assets/avatars/presets/modern_055.png b/public/assets/avatars/presets/modern_055.png index 58a60d6..cde53d6 100644 Binary files a/public/assets/avatars/presets/modern_055.png and b/public/assets/avatars/presets/modern_055.png differ diff --git a/public/assets/avatars/presets/modern_056.png b/public/assets/avatars/presets/modern_056.png index ff7c60d..0f8bb76 100644 Binary files a/public/assets/avatars/presets/modern_056.png and b/public/assets/avatars/presets/modern_056.png differ diff --git a/public/assets/avatars/presets/modern_057.png b/public/assets/avatars/presets/modern_057.png index e497fa3..f5001c5 100644 Binary files a/public/assets/avatars/presets/modern_057.png and b/public/assets/avatars/presets/modern_057.png differ diff --git a/public/assets/avatars/presets/modern_058.png b/public/assets/avatars/presets/modern_058.png index b284ae8..34ca3c9 100644 Binary files a/public/assets/avatars/presets/modern_058.png and b/public/assets/avatars/presets/modern_058.png differ diff --git a/public/assets/avatars/presets/modern_059.png b/public/assets/avatars/presets/modern_059.png index dbf4e3c..fa46e66 100644 Binary files a/public/assets/avatars/presets/modern_059.png and b/public/assets/avatars/presets/modern_059.png differ diff --git a/public/assets/avatars/presets/modern_06.png b/public/assets/avatars/presets/modern_06.png deleted file mode 100644 index ef3b5a0..0000000 Binary files a/public/assets/avatars/presets/modern_06.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_060.png b/public/assets/avatars/presets/modern_060.png index 86ce6bd..50381ce 100644 Binary files a/public/assets/avatars/presets/modern_060.png and b/public/assets/avatars/presets/modern_060.png differ diff --git a/public/assets/avatars/presets/modern_061.png b/public/assets/avatars/presets/modern_061.png index 41d7ec7..ae1cc77 100644 Binary files a/public/assets/avatars/presets/modern_061.png and b/public/assets/avatars/presets/modern_061.png differ diff --git a/public/assets/avatars/presets/modern_062.png b/public/assets/avatars/presets/modern_062.png index a105230..eb9e5ce 100644 Binary files a/public/assets/avatars/presets/modern_062.png and b/public/assets/avatars/presets/modern_062.png differ diff --git a/public/assets/avatars/presets/modern_063.png b/public/assets/avatars/presets/modern_063.png index 0f2a5f0..b30aeb5 100644 Binary files a/public/assets/avatars/presets/modern_063.png and b/public/assets/avatars/presets/modern_063.png differ diff --git a/public/assets/avatars/presets/modern_064.png b/public/assets/avatars/presets/modern_064.png index ff4d886..51f67a6 100644 Binary files a/public/assets/avatars/presets/modern_064.png and b/public/assets/avatars/presets/modern_064.png differ diff --git a/public/assets/avatars/presets/modern_065.png b/public/assets/avatars/presets/modern_065.png index 6b25720..c19c4e2 100644 Binary files a/public/assets/avatars/presets/modern_065.png and b/public/assets/avatars/presets/modern_065.png differ diff --git a/public/assets/avatars/presets/modern_066.png b/public/assets/avatars/presets/modern_066.png index bc36969..606cc12 100644 Binary files a/public/assets/avatars/presets/modern_066.png and b/public/assets/avatars/presets/modern_066.png differ diff --git a/public/assets/avatars/presets/modern_067.png b/public/assets/avatars/presets/modern_067.png index 5756016..94aaf9e 100644 Binary files a/public/assets/avatars/presets/modern_067.png and b/public/assets/avatars/presets/modern_067.png differ diff --git a/public/assets/avatars/presets/modern_068.png b/public/assets/avatars/presets/modern_068.png index cb1235e..a693bdf 100644 Binary files a/public/assets/avatars/presets/modern_068.png and b/public/assets/avatars/presets/modern_068.png differ diff --git a/public/assets/avatars/presets/modern_069.png b/public/assets/avatars/presets/modern_069.png index 5b3d6ca..b7e2047 100644 Binary files a/public/assets/avatars/presets/modern_069.png and b/public/assets/avatars/presets/modern_069.png differ diff --git a/public/assets/avatars/presets/modern_07.png b/public/assets/avatars/presets/modern_07.png deleted file mode 100644 index 5bc203c..0000000 Binary files a/public/assets/avatars/presets/modern_07.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_070.png b/public/assets/avatars/presets/modern_070.png index 27ba06f..0928525 100644 Binary files a/public/assets/avatars/presets/modern_070.png and b/public/assets/avatars/presets/modern_070.png differ diff --git a/public/assets/avatars/presets/modern_071.png b/public/assets/avatars/presets/modern_071.png index cef1f79..91b9506 100644 Binary files a/public/assets/avatars/presets/modern_071.png and b/public/assets/avatars/presets/modern_071.png differ diff --git a/public/assets/avatars/presets/modern_072.png b/public/assets/avatars/presets/modern_072.png index 2003682..f83a646 100644 Binary files a/public/assets/avatars/presets/modern_072.png and b/public/assets/avatars/presets/modern_072.png differ diff --git a/public/assets/avatars/presets/modern_073.png b/public/assets/avatars/presets/modern_073.png index 17699d2..5c94b29 100644 Binary files a/public/assets/avatars/presets/modern_073.png and b/public/assets/avatars/presets/modern_073.png differ diff --git a/public/assets/avatars/presets/modern_074.png b/public/assets/avatars/presets/modern_074.png index d9aa852..0409b11 100644 Binary files a/public/assets/avatars/presets/modern_074.png and b/public/assets/avatars/presets/modern_074.png differ diff --git a/public/assets/avatars/presets/modern_075.png b/public/assets/avatars/presets/modern_075.png index a4781ea..e28f77a 100644 Binary files a/public/assets/avatars/presets/modern_075.png and b/public/assets/avatars/presets/modern_075.png differ diff --git a/public/assets/avatars/presets/modern_076.png b/public/assets/avatars/presets/modern_076.png index 0753e72..757c51c 100644 Binary files a/public/assets/avatars/presets/modern_076.png and b/public/assets/avatars/presets/modern_076.png differ diff --git a/public/assets/avatars/presets/modern_077.png b/public/assets/avatars/presets/modern_077.png index ded7d80..baa965f 100644 Binary files a/public/assets/avatars/presets/modern_077.png and b/public/assets/avatars/presets/modern_077.png differ diff --git a/public/assets/avatars/presets/modern_078.png b/public/assets/avatars/presets/modern_078.png index 2283568..b811a10 100644 Binary files a/public/assets/avatars/presets/modern_078.png and b/public/assets/avatars/presets/modern_078.png differ diff --git a/public/assets/avatars/presets/modern_079.png b/public/assets/avatars/presets/modern_079.png index 1479f01..3d0162b 100644 Binary files a/public/assets/avatars/presets/modern_079.png and b/public/assets/avatars/presets/modern_079.png differ diff --git a/public/assets/avatars/presets/modern_08.png b/public/assets/avatars/presets/modern_08.png deleted file mode 100644 index c4dee8a..0000000 Binary files a/public/assets/avatars/presets/modern_08.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_080.png b/public/assets/avatars/presets/modern_080.png index aae2f18..d5ced01 100644 Binary files a/public/assets/avatars/presets/modern_080.png and b/public/assets/avatars/presets/modern_080.png differ diff --git a/public/assets/avatars/presets/modern_081.png b/public/assets/avatars/presets/modern_081.png index 13e765c..406c40d 100644 Binary files a/public/assets/avatars/presets/modern_081.png and b/public/assets/avatars/presets/modern_081.png differ diff --git a/public/assets/avatars/presets/modern_082.png b/public/assets/avatars/presets/modern_082.png index 315ba11..1d7f06e 100644 Binary files a/public/assets/avatars/presets/modern_082.png and b/public/assets/avatars/presets/modern_082.png differ diff --git a/public/assets/avatars/presets/modern_083.png b/public/assets/avatars/presets/modern_083.png index 020a863..6129f1b 100644 Binary files a/public/assets/avatars/presets/modern_083.png and b/public/assets/avatars/presets/modern_083.png differ diff --git a/public/assets/avatars/presets/modern_084.png b/public/assets/avatars/presets/modern_084.png index 15aa230..d3f3334 100644 Binary files a/public/assets/avatars/presets/modern_084.png and b/public/assets/avatars/presets/modern_084.png differ diff --git a/public/assets/avatars/presets/modern_085.png b/public/assets/avatars/presets/modern_085.png index ba1ef79..a9c5f56 100644 Binary files a/public/assets/avatars/presets/modern_085.png and b/public/assets/avatars/presets/modern_085.png differ diff --git a/public/assets/avatars/presets/modern_086.png b/public/assets/avatars/presets/modern_086.png index 5bc203c..9391698 100644 Binary files a/public/assets/avatars/presets/modern_086.png and b/public/assets/avatars/presets/modern_086.png differ diff --git a/public/assets/avatars/presets/modern_087.png b/public/assets/avatars/presets/modern_087.png index cb8d4c5..9c117d6 100644 Binary files a/public/assets/avatars/presets/modern_087.png and b/public/assets/avatars/presets/modern_087.png differ diff --git a/public/assets/avatars/presets/modern_088.png b/public/assets/avatars/presets/modern_088.png index b236d0e..59e127a 100644 Binary files a/public/assets/avatars/presets/modern_088.png and b/public/assets/avatars/presets/modern_088.png differ diff --git a/public/assets/avatars/presets/modern_089.png b/public/assets/avatars/presets/modern_089.png index dc1c268..b9c0251 100644 Binary files a/public/assets/avatars/presets/modern_089.png and b/public/assets/avatars/presets/modern_089.png differ diff --git a/public/assets/avatars/presets/modern_09.png b/public/assets/avatars/presets/modern_09.png deleted file mode 100644 index 23fcadd..0000000 Binary files a/public/assets/avatars/presets/modern_09.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_090.png b/public/assets/avatars/presets/modern_090.png index f24f1ed..05db369 100644 Binary files a/public/assets/avatars/presets/modern_090.png and b/public/assets/avatars/presets/modern_090.png differ diff --git a/public/assets/avatars/presets/modern_091.png b/public/assets/avatars/presets/modern_091.png index 5a14a10..ec10cb6 100644 Binary files a/public/assets/avatars/presets/modern_091.png and b/public/assets/avatars/presets/modern_091.png differ diff --git a/public/assets/avatars/presets/modern_092.png b/public/assets/avatars/presets/modern_092.png index 8e744e3..a4cfac9 100644 Binary files a/public/assets/avatars/presets/modern_092.png and b/public/assets/avatars/presets/modern_092.png differ diff --git a/public/assets/avatars/presets/modern_093.png b/public/assets/avatars/presets/modern_093.png index 8eb70ab..cf7f591 100644 Binary files a/public/assets/avatars/presets/modern_093.png and b/public/assets/avatars/presets/modern_093.png differ diff --git a/public/assets/avatars/presets/modern_094.png b/public/assets/avatars/presets/modern_094.png index 567cdac..0226046 100644 Binary files a/public/assets/avatars/presets/modern_094.png and b/public/assets/avatars/presets/modern_094.png differ diff --git a/public/assets/avatars/presets/modern_095.png b/public/assets/avatars/presets/modern_095.png index fd72bb7..90d398f 100644 Binary files a/public/assets/avatars/presets/modern_095.png and b/public/assets/avatars/presets/modern_095.png differ diff --git a/public/assets/avatars/presets/modern_096.png b/public/assets/avatars/presets/modern_096.png index e6232bc..e622def 100644 Binary files a/public/assets/avatars/presets/modern_096.png and b/public/assets/avatars/presets/modern_096.png differ diff --git a/public/assets/avatars/presets/modern_097.png b/public/assets/avatars/presets/modern_097.png index 022e649..d824ff6 100644 Binary files a/public/assets/avatars/presets/modern_097.png and b/public/assets/avatars/presets/modern_097.png differ diff --git a/public/assets/avatars/presets/modern_098.png b/public/assets/avatars/presets/modern_098.png index bbe9385..e0f4100 100644 Binary files a/public/assets/avatars/presets/modern_098.png and b/public/assets/avatars/presets/modern_098.png differ diff --git a/public/assets/avatars/presets/modern_099.png b/public/assets/avatars/presets/modern_099.png index 67bf96d..971e31e 100644 Binary files a/public/assets/avatars/presets/modern_099.png and b/public/assets/avatars/presets/modern_099.png differ diff --git a/public/assets/avatars/presets/modern_10.png b/public/assets/avatars/presets/modern_10.png deleted file mode 100644 index bc36969..0000000 Binary files a/public/assets/avatars/presets/modern_10.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_100.png b/public/assets/avatars/presets/modern_100.png index cf7cd6a..9839405 100644 Binary files a/public/assets/avatars/presets/modern_100.png and b/public/assets/avatars/presets/modern_100.png differ diff --git a/public/assets/avatars/presets/modern_11.png b/public/assets/avatars/presets/modern_11.png deleted file mode 100644 index cef1f79..0000000 Binary files a/public/assets/avatars/presets/modern_11.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_12.png b/public/assets/avatars/presets/modern_12.png deleted file mode 100644 index 5a14a10..0000000 Binary files a/public/assets/avatars/presets/modern_12.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_13.png b/public/assets/avatars/presets/modern_13.png deleted file mode 100644 index 965b3aa..0000000 Binary files a/public/assets/avatars/presets/modern_13.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_14.png b/public/assets/avatars/presets/modern_14.png deleted file mode 100644 index 91e4af4..0000000 Binary files a/public/assets/avatars/presets/modern_14.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_15.png b/public/assets/avatars/presets/modern_15.png deleted file mode 100644 index 93d0ccd..0000000 Binary files a/public/assets/avatars/presets/modern_15.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_16.png b/public/assets/avatars/presets/modern_16.png deleted file mode 100644 index 8b31253..0000000 Binary files a/public/assets/avatars/presets/modern_16.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_17.png b/public/assets/avatars/presets/modern_17.png deleted file mode 100644 index 641c82c..0000000 Binary files a/public/assets/avatars/presets/modern_17.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_18.png b/public/assets/avatars/presets/modern_18.png deleted file mode 100644 index f60f64d..0000000 Binary files a/public/assets/avatars/presets/modern_18.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_19.png b/public/assets/avatars/presets/modern_19.png deleted file mode 100644 index 875b937..0000000 Binary files a/public/assets/avatars/presets/modern_19.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_20.png b/public/assets/avatars/presets/modern_20.png deleted file mode 100644 index ff7c60d..0000000 Binary files a/public/assets/avatars/presets/modern_20.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_21.png b/public/assets/avatars/presets/modern_21.png deleted file mode 100644 index 56edaf4..0000000 Binary files a/public/assets/avatars/presets/modern_21.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_22.png b/public/assets/avatars/presets/modern_22.png deleted file mode 100644 index 246fcfc..0000000 Binary files a/public/assets/avatars/presets/modern_22.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_23.png b/public/assets/avatars/presets/modern_23.png deleted file mode 100644 index e6232bc..0000000 Binary files a/public/assets/avatars/presets/modern_23.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_24.png b/public/assets/avatars/presets/modern_24.png deleted file mode 100644 index dbd6bb6..0000000 Binary files a/public/assets/avatars/presets/modern_24.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_25.png b/public/assets/avatars/presets/modern_25.png deleted file mode 100644 index 48d2589..0000000 Binary files a/public/assets/avatars/presets/modern_25.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_26.png b/public/assets/avatars/presets/modern_26.png deleted file mode 100644 index 0753e72..0000000 Binary files a/public/assets/avatars/presets/modern_26.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_27.png b/public/assets/avatars/presets/modern_27.png deleted file mode 100644 index d9c2147..0000000 Binary files a/public/assets/avatars/presets/modern_27.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_28.png b/public/assets/avatars/presets/modern_28.png deleted file mode 100644 index b42957a..0000000 Binary files a/public/assets/avatars/presets/modern_28.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_29.png b/public/assets/avatars/presets/modern_29.png deleted file mode 100644 index 5482b89..0000000 Binary files a/public/assets/avatars/presets/modern_29.png and /dev/null differ diff --git a/public/assets/avatars/presets/modern_30.png b/public/assets/avatars/presets/modern_30.png deleted file mode 100644 index 55ca4b0..0000000 Binary files a/public/assets/avatars/presets/modern_30.png and /dev/null differ diff --git a/public/assets/css/app.css b/public/assets/css/app.css index e8cf479..f379a8f 100755 --- a/public/assets/css/app.css +++ b/public/assets/css/app.css @@ -250,12 +250,6 @@ body { .avatar-builder__layout { display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: 24px; align-items: start; } .avatar-builder__preview { position: sticky; top: 0; display: grid; justify-items: center; gap: 12px; padding: 18px; background: linear-gradient(180deg, #fffdfa, #f8f4ec); border: 1px solid var(--color-border); border-radius: 18px; } .avatar-builder__controls { display: grid; gap: 18px; } -.avatar-preset-filters { display: flex; flex-wrap: wrap; gap: 10px; } -.avatar-preset-filter { border: 1px solid var(--color-border); background: #fff; color: var(--color-text); border-radius: 999px; padding: 10px 14px; font: inherit; font-weight: 700; cursor: pointer; transition: border-color .15s ease, box-shadow .15s ease, background .15s ease, color .15s ease; } -.avatar-preset-filter:hover { border-color: var(--color-primary); color: var(--color-primary); } -.avatar-preset-filter.is-active { background: var(--color-primary); color: var(--color-primary-contrast); border-color: var(--color-primary); box-shadow: 0 10px 20px rgba(41, 31, 22, 0.08); } -.avatar-preset-group { display: none; } -.avatar-preset-group.is-active { display: block; } .avatar-preset-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: 12px; } .avatar-preset-card { position: relative; display: grid; gap: 8px; align-content: start; padding: 10px; border: 1px solid var(--color-border); border-radius: 16px; background: #fff; cursor: pointer; transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease; } .avatar-preset-card:hover { border-color: var(--color-primary); box-shadow: 0 10px 20px rgba(41, 31, 22, 0.08); transform: translateY(-1px); } diff --git a/public/assets/js/app.js b/public/assets/js/app.js index 874b275..7da9edb 100755 --- a/public/assets/js/app.js +++ b/public/assets/js/app.js @@ -739,10 +739,10 @@ document.addEventListener('DOMContentLoaded', () => { const image = preview.querySelector('.pkt-avatar__img'); if (!image) return; - const preset = readValue('avatar_preset'); - if (!preset) return; - - image.src = `/assets/avatars/presets/${preset}.png`; + const checked = form.querySelector('[data-avatar-field="avatar_preset"]:checked'); + const url = checked?.getAttribute('data-avatar-url') || ''; + if (!url) return; + image.src = url; }; document.querySelectorAll('[data-avatar-builder]').forEach((form) => { @@ -752,35 +752,49 @@ document.addEventListener('DOMContentLoaded', () => { field.addEventListener('input', () => updateAvatarPreview(form)); }); - const setActivePresetGroup = (groupKey) => { - form.querySelectorAll('[data-avatar-preset-filter]').forEach((button) => { - const active = button.getAttribute('data-avatar-preset-filter') === groupKey; - button.classList.toggle('is-active', active); - button.setAttribute('aria-selected', active ? 'true' : 'false'); - }); - form.querySelectorAll('[data-avatar-preset-group]').forEach((group) => { - group.classList.toggle('is-active', group.getAttribute('data-avatar-preset-group') === groupKey); - }); + const avatarPrefixes = [ + 'abend', 'ahorn', 'anker', 'atlas', 'berg', 'blick', 'brise', 'echo', + 'eiche', 'fjord', 'fluss', 'fokus', 'hafen', 'herz', 'horizont', 'insel', + 'kiesel', 'kompass', 'kraft', 'linie', 'licht', 'lotse', 'mond', 'morgen', + 'nord', 'pfad', 'quelle', 'rauch', 'runde', 'sand', 'sommer', 'stein', + 'sturm', 'tal', 'ufer', 'wald', 'welle', 'wind', 'winkel', 'zeit', + ]; + const avatarSuffixes = [ + 'alpha', 'atlas', 'balu', 'bravo', 'caspar', 'dario', 'emil', 'felix', + 'fiete', 'finn', 'gerrit', 'hanno', 'ilan', 'joris', 'kian', 'leon', + 'linus', 'maik', 'malo', 'marlon', 'mats', 'mika', 'milan', 'noel', + 'ole', 'oskar', 'pepe', 'quinn', 'remo', 'sam', 'taro', 'timo', + 'veit', 'vito', 'yaro', 'yuri', 'zeno', 'zuri', + ]; + const slugifySeed = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 64) || 'papa-kind-treff'; + const dicebearUrl = (seed) => `/api/avatar?seed=${encodeURIComponent(seed)}`; + const buildSeed = () => { + const prefix = avatarPrefixes[Math.floor(Math.random() * avatarPrefixes.length)]; + const suffix = avatarSuffixes[Math.floor(Math.random() * avatarSuffixes.length)]; + const tail = Math.floor(Math.random() * 997); + return slugifySeed(`${prefix}-${suffix}-${tail}`); }; - const checkedPreset = form.querySelector('[data-avatar-field="avatar_preset"]:checked'); - if (checkedPreset) { - const activeGroup = checkedPreset.closest('[data-avatar-preset-group]')?.getAttribute('data-avatar-preset-group'); - if (activeGroup) setActivePresetGroup(activeGroup); - } - - form.querySelectorAll('[data-avatar-preset-filter]').forEach((button) => { - button.addEventListener('click', () => { - const groupKey = button.getAttribute('data-avatar-preset-filter'); - if (groupKey) setActivePresetGroup(groupKey); - }); - }); - - form.querySelectorAll('[data-avatar-field="avatar_preset"]').forEach((field) => { - field.addEventListener('change', () => { - const activeGroup = field.closest('[data-avatar-preset-group]')?.getAttribute('data-avatar-preset-group'); - if (activeGroup) setActivePresetGroup(activeGroup); + form.querySelector('[data-avatar-reroll]')?.addEventListener('click', () => { + const radios = Array.from(form.querySelectorAll('[data-avatar-field="avatar_preset"]')); + const used = new Set(); + radios.forEach((radio, index) => { + let seed = buildSeed(); + while (used.has(seed)) { + seed = buildSeed(); + } + used.add(seed); + const url = dicebearUrl(seed); + radio.value = seed; + radio.setAttribute('data-avatar-url', url); + radio.checked = index === 0; + const card = radio.closest('.avatar-preset-card'); + card?.querySelector('img')?.setAttribute('src', url); + card?.querySelector('img')?.setAttribute('alt', `Variante ${index + 1}`); + const label = card?.querySelector('.avatar-preset-card__label'); + if (label) label.textContent = index === 0 ? 'Neue Auswahl' : `Variante ${index + 1}`; }); + updateAvatarPreview(form); }); }); diff --git a/public/page/api/avatar.php b/public/page/api/avatar.php new file mode 100644 index 0000000..ad36c0c --- /dev/null +++ b/public/page/api/avatar.php @@ -0,0 +1,39 @@ + [ + 'method' => 'GET', + 'timeout' => 6, + 'header' => "User-Agent: Papa-Kind-Treff/1.0\r\nAccept: image/svg+xml\r\n", + ], + ]); + + $remote = @file_get_contents($url, false, $context); + if (is_string($remote) && str_contains($remote, 'cookiePrefix() . 'client';

Datenschutz & Cookies

-

Stand: 22. Juli 2026

+

Stand: 26. Juli 2026

Diese Hinweise erklären, welche personenbezogenen Daten beim Besuch und bei der Nutzung von Papa-Kind-Treff @@ -149,16 +149,29 @@ $clientCookie = $config->cookiePrefix() . 'client';

-

10. Empfänger und Kategorien von Empfängern

+

10. Profilbilder mit DiceBear

- 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, - Analyse-Dienstleister sowie die oben genannten externen Karten- und Standortdienste gehören. + 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. Der Abruf erfolgt über unsere Anwendung + und wird lokal zwischengespeichert, sodass dein Browser die Avatar-Grafiken nicht direkt bei DiceBear lädt. +

+

+ Rechtsgrundlage ist Art. 6 Abs. 1 lit. b DSGVO, soweit die Avatar-Erzeugung Teil des gewählten + Mitgliederprofils ist, sowie ergänzend Art. 6 Abs. 1 lit. f DSGVO für eine konsistente Darstellung der Plattform.

-

11. Speicherdauer

+

11. Empfänger und Kategorien von Empfängern

+

+ 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, + Analyse-Dienstleister, DiceBear für die serverseitige Avatar-Erzeugung sowie die oben genannten externen Karten- und Standortdienste gehören. +

+
+ +
+

12. Speicherdauer

Wir speichern personenbezogene Daten nur so lange, wie dies für die jeweiligen Zwecke erforderlich ist oder gesetzliche Aufbewahrungspflichten bestehen. Kontodaten, Profilinformationen, Community-Inhalte @@ -173,7 +186,7 @@ $clientCookie = $config->cookiePrefix() . 'client';

-

12. Deine Rechte

+

13. Deine Rechte

Du hast nach Maßgabe der gesetzlichen Voraussetzungen das Recht auf Auskunft, Berichtigung, Löschung, Einschränkung der Verarbeitung, Datenübertragbarkeit und Widerspruch. @@ -185,7 +198,7 @@ $clientCookie = $config->cookiePrefix() . 'client';

-

13. Hinweis zur Aktualisierung

+

14. Hinweis zur Aktualisierung

Diese Hinweise werden angepasst, wenn sich Funktionen, eingesetzte Dienste oder rechtliche Anforderungen ändern. Insbesondere bei neuen Cookies, Tracking-Technologien oder Drittanbietern wird diese Seite ergänzt. diff --git a/schema.sql b/schema.sql index 2ddd237..57065bd 100755 --- a/schema.sql +++ b/schema.sql @@ -30,7 +30,7 @@ CREATE TABLE user_profiles ( lat DECIMAL(10,7) NULL, lng DECIMAL(10,7) NULL, location_tracking_preference ENUM('disabled','prompt','enabled') NOT NULL DEFAULT 'prompt', - avatar_preset VARCHAR(32) NOT NULL DEFAULT 'modern_001', + avatar_preset VARCHAR(64) NOT NULL DEFAULT 'papa-kind-treff', avatar_skin_tone VARCHAR(24) NOT NULL DEFAULT 'warm', avatar_hair_style VARCHAR(24) NOT NULL DEFAULT 'short', avatar_hair_color VARCHAR(24) NOT NULL DEFAULT 'brown', diff --git a/src/App/AccountPages.php b/src/App/AccountPages.php index c93d88c..502b8e7 100755 --- a/src/App/AccountPages.php +++ b/src/App/AccountPages.php @@ -338,7 +338,7 @@ final class AccountPages 'email' => '', 'contact_phone' => '', 'location_tracking_preference' => 'prompt', - 'avatar_preset' => 'modern_001', + 'avatar_preset' => 'papa-kind-treff', 'avatar_skin_tone' => 'warm', 'avatar_hair_style' => 'short', 'avatar_hair_color' => 'brown', @@ -420,9 +420,7 @@ final class AccountPages if (!in_array($section, $allowedSections, true)) { $section = 'profile'; } - $avatarOptions = Avatar::options(); - $avatarPresetOptions = Avatar::presetOptions(); - $avatarPresetGroups = Avatar::presetGroups(); + $avatarPresetOptions = Avatar::seedChoices((string)$profile['avatar_preset']); return compact( 'flash', @@ -439,9 +437,7 @@ final class AccountPages 'communityApplication', 'communityCanApply', 'communityRestrictions', - 'avatarOptions', 'avatarPresetOptions', - 'avatarPresetGroups', 'section', 'allowedSections' ); diff --git a/src/App/Avatar.php b/src/App/Avatar.php index df08d54..132f5fe 100644 --- a/src/App/Avatar.php +++ b/src/App/Avatar.php @@ -8,14 +8,14 @@ final class Avatar public static function defaults(): array { return [ - 'avatar_preset' => 'modern_001', + 'avatar_preset' => 'papa-kind-treff', 'avatar_skin_tone' => 'warm', - 'avatar_hair_style' => 'parted', + 'avatar_hair_style' => 'short', 'avatar_hair_color' => 'brown', 'avatar_eye_color' => 'brown', - 'avatar_beard_style' => 'short', + 'avatar_beard_style' => 'none', 'avatar_glasses_style' => 'none', - 'avatar_head_shape' => 'oval', + 'avatar_head_shape' => 'round', 'avatar_hat_style' => 'none', 'avatar_hat_color' => 'navy', 'avatar_outfit_style' => 'tee', @@ -25,122 +25,7 @@ final class Avatar public static function options(): array { - return [ - 'avatar_skin_tone' => [ - 'fair' => ['label' => 'Hell', 'color' => '#f6d7c1'], - 'warm' => ['label' => 'Warm', 'color' => '#eec0a0'], - 'golden' => ['label' => 'Gold', 'color' => '#d7a179'], - 'deep' => ['label' => 'Tief', 'color' => '#9c633e'], - 'rich' => ['label' => 'Kräftig', 'color' => '#6f432b'], - ], - 'avatar_hair_style' => [ - 'parted' => 'Seitenscheitel', - 'short' => 'Kurz', - 'fade' => 'Fade', - 'curly' => 'Lockig', - 'waves' => 'Wellig', - 'bald' => 'Kahl', - ], - 'avatar_hair_color' => [ - 'black' => ['label' => 'Schwarz', 'color' => '#191919'], - 'brown' => ['label' => 'Braun', 'color' => '#65442f'], - 'blonde' => ['label' => 'Blond', 'color' => '#d3a053'], - 'red' => ['label' => 'Rot', 'color' => '#9f5a34'], - 'gray' => ['label' => 'Grau', 'color' => '#8f8c87'], - ], - 'avatar_eye_color' => [ - 'brown' => ['label' => 'Braun', 'color' => '#5e4330'], - 'hazel' => ['label' => 'Hasel', 'color' => '#7c6848'], - 'green' => ['label' => 'Grün', 'color' => '#4f6c52'], - 'blue' => ['label' => 'Blau', 'color' => '#507196'], - ], - 'avatar_beard_style' => [ - 'none' => 'Ohne', - 'mustache' => 'Schnurrbart', - 'short' => 'Kurz', - 'full' => 'Vollbart', - ], - 'avatar_glasses_style' => [ - 'none' => 'Ohne', - 'round' => 'Rund', - 'square' => 'Eckig', - ], - 'avatar_head_shape' => [ - 'round' => 'Rund', - 'oval' => 'Oval', - 'square' => 'Eckig', - ], - 'avatar_hat_style' => [ - 'none' => 'Ohne', - 'beanie' => 'Beanie', - 'cap' => 'Cap', - ], - 'avatar_hat_color' => [ - 'navy' => ['label' => 'Navy', 'color' => '#42526a'], - 'charcoal' => ['label' => 'Anthrazit', 'color' => '#43464d'], - 'forest' => ['label' => 'Waldgrün', 'color' => '#51634f'], - 'brick' => ['label' => 'Ziegel', 'color' => '#9a5a47'], - 'sand' => ['label' => 'Sand', 'color' => '#baa078'], - ], - 'avatar_outfit_style' => [ - 'tee' => 'T-Shirt', - 'hoodie' => 'Hoodie', - 'polo' => 'Polo', - 'crew' => 'Pullover', - ], - 'avatar_outfit_color' => [ - 'slate' => ['label' => 'Schiefer', 'color' => '#5f7387'], - 'graphite' => ['label' => 'Graphit', 'color' => '#4c515a'], - 'olive' => ['label' => 'Oliv', 'color' => '#667155'], - 'rust' => ['label' => 'Rost', 'color' => '#9f6547'], - 'ocean' => ['label' => 'Ozean', 'color' => '#4e7897'], - ], - ]; - } - - public static function presetGroups(): array - { - return [ - 'fair' => ['label' => 'Helle Hauttöne', 'range' => [1, 20]], - 'warm' => ['label' => 'Warme Hauttöne', 'range' => [21, 40]], - 'golden' => ['label' => 'Goldene Hauttöne', 'range' => [41, 60]], - 'deep' => ['label' => 'Tiefere Hauttöne', 'range' => [61, 80]], - 'rich' => ['label' => 'Kräftige Hauttöne', 'range' => [81, 100]], - ]; - } - - public static function presetOptions(): array - { - $presets = []; - foreach (self::presetGroups() as $groupKey => $group) { - [$start, $end] = $group['range']; - for ($index = $start; $index <= $end; $index++) { - $value = sprintf('modern_%03d', $index); - $presets[$groupKey][$value] = [ - 'label' => 'Variante ' . $index, - 'group' => $groupKey, - 'image' => self::presetPublicPath($value), - ]; - } - } - - return $presets; - } - - public static function presetGroupForPreset(string $preset): string - { - $preset = preg_replace('/[^a-z0-9_]/', '', strtolower($preset)) ?: ''; - if (preg_match('/modern_(\d{3})/', $preset, $matches)) { - $number = (int)$matches[1]; - foreach (self::presetGroups() as $groupKey => $group) { - [$start, $end] = $group['range']; - if ($number >= $start && $number <= $end) { - return $groupKey; - } - } - } - - return 'fair'; + return []; } public static function selectColumns(string $alias = 'p'): string @@ -155,111 +40,117 @@ final class Avatar public static function normalize(array $input): array { $defaults = self::defaults(); - $options = self::options(); $normalized = []; foreach ($defaults as $key => $defaultValue) { $value = (string)($input[$key] ?? $defaultValue); - if (isset($options[$key]) && !array_key_exists($value, $options[$key])) { - $value = $defaultValue; - } - $normalized[$key] = $value; + $normalized[$key] = $key === 'avatar_preset' + ? self::normalizeSeed($value) + : $value; } return $normalized; } + public static function normalizeSeed(string $seed): string + { + $seed = strtolower(trim($seed)); + $seed = preg_replace('/[^a-z0-9]+/', '-', $seed) ?: ''; + $seed = trim($seed, '-'); + + if ($seed === '') { + $seed = self::defaults()['avatar_preset']; + } + + return substr($seed, 0, 64); + } + + public static function seedChoices(string $selectedSeed, int $count = 24): array + { + $selectedSeed = self::normalizeSeed($selectedSeed); + $prefixes = [ + 'abend', 'ahorn', 'anker', 'atlas', 'berg', 'blick', 'brise', 'echo', + 'eiche', 'fjord', 'fluss', 'fokus', 'hafen', 'herz', 'horizont', 'insel', + 'kiesel', 'kompass', 'kraft', 'linie', 'licht', 'lotse', 'mond', 'morgen', + 'nord', 'pfad', 'quelle', 'rauch', 'runde', 'sand', 'sommer', 'stein', + 'sturm', 'tal', 'ufer', 'wald', 'welle', 'wind', 'winkel', 'zeit', + ]; + $suffixes = [ + 'alpha', 'atlas', 'balu', 'bravo', 'caspar', 'dario', 'emil', 'felix', + 'fiete', 'finn', 'gerrit', 'hanno', 'ilan', 'joris', 'kian', 'leon', + 'linus', 'maik', 'malo', 'marlon', 'mats', 'mika', 'milan', 'noel', + 'ole', 'oskar', 'pepe', 'quinn', 'remo', 'sam', 'taro', 'timo', + 'veit', 'vito', 'yaro', 'yuri', 'zeno', 'zuri', + ]; + + $choices = [[ + 'seed' => $selectedSeed, + 'label' => 'Aktuelle Auswahl', + 'image' => self::dicebearUrl($selectedSeed), + ]]; + + $seen = [$selectedSeed => true]; + $base = abs((int)crc32($selectedSeed)); + $index = 0; + + while (count($choices) < $count) { + $prefix = $prefixes[($base + ($index * 7)) % count($prefixes)]; + $suffix = $suffixes[($base + ($index * 11)) % count($suffixes)]; + $candidate = self::normalizeSeed($prefix . '-' . $suffix . '-' . (($base + $index) % 997)); + $index++; + + if (isset($seen[$candidate])) { + continue; + } + + $seen[$candidate] = true; + $choices[] = [ + 'seed' => $candidate, + 'label' => 'Variante ' . count($choices), + 'image' => self::dicebearUrl($candidate), + ]; + } + + return $choices; + } + + public static function dicebearUrl(string $seed): string + { + return '/api/avatar?seed=' . rawurlencode(self::normalizeSeed($seed)); + } + public static function render(array $row, string $name = 'Mitglied', string $size = 'md'): string { $avatar = self::normalize($row); - $presetPath = self::presetPublicPath($avatar['avatar_preset']); - - if ($presetPath !== null) { - return sprintf( - '', - htmlspecialchars(implode(' ', [ - 'pkt-avatar', - 'pkt-avatar--' . preg_replace('/[^a-z0-9\-]/', '', strtolower($size)), - 'pkt-avatar--preset', - ]), ENT_QUOTES), - htmlspecialchars('Avatar von ' . $name, ENT_QUOTES), - htmlspecialchars($presetPath, ENT_QUOTES) - ); - } - - $options = self::options(); - $classes = [ - 'pkt-avatar', - 'pkt-avatar--' . preg_replace('/[^a-z0-9\-]/', '', strtolower($size)), - 'pkt-avatar--layered', - 'pkt-avatar--head-' . $avatar['avatar_head_shape'], - 'pkt-avatar--hair-' . $avatar['avatar_hair_style'], - 'pkt-avatar--beard-' . $avatar['avatar_beard_style'], - 'pkt-avatar--glasses-' . $avatar['avatar_glasses_style'], - 'pkt-avatar--hat-' . $avatar['avatar_hat_style'], - 'pkt-avatar--outfit-' . $avatar['avatar_outfit_style'], - ]; - - $style = sprintf( - '--avatar-skin:%s;--avatar-hair:%s;--avatar-eye:%s;--avatar-hat:%s;--avatar-outfit:%s;', - $options['avatar_skin_tone'][$avatar['avatar_skin_tone']]['color'], - $options['avatar_hair_color'][$avatar['avatar_hair_color']]['color'], - $options['avatar_eye_color'][$avatar['avatar_eye_color']]['color'], - $options['avatar_hat_color'][$avatar['avatar_hat_color']]['color'], - $options['avatar_outfit_color'][$avatar['avatar_outfit_color']]['color'] - ); - - $layers = [ - self::renderLayer('outfit', $avatar['avatar_outfit_style']), - self::renderLayer('head', $avatar['avatar_head_shape']), - self::renderLayer('hair', $avatar['avatar_hair_style']), - self::renderLayer('hat', $avatar['avatar_hat_style']), - self::renderLayer('features', 'default'), - self::renderLayer('beard', $avatar['avatar_beard_style']), - self::renderLayer('glasses', $avatar['avatar_glasses_style']), - ]; + $src = self::dicebearUrl($avatar['avatar_preset']); return sprintf( - '%s', - htmlspecialchars(implode(' ', $classes), ENT_QUOTES), - htmlspecialchars($style, ENT_QUOTES), + '', + htmlspecialchars(implode(' ', [ + 'pkt-avatar', + 'pkt-avatar--' . preg_replace('/[^a-z0-9\-]/', '', strtolower($size)), + 'pkt-avatar--preset', + ]), ENT_QUOTES), htmlspecialchars('Avatar von ' . $name, ENT_QUOTES), - implode('', array_filter($layers)) + htmlspecialchars($src, ENT_QUOTES) ); } - private static function renderLayer(string $category, string $variant): string + public static function fallbackSvg(string $seed, string $label = 'Avatar'): string { - if ($variant === 'none') { - return ''; - } + $seed = self::normalizeSeed($seed); + $initials = strtoupper(substr(preg_replace('/[^a-z]/', '', $seed) ?: 'pk', 0, 2)); + $palette = ['#f5efe5', '#d9c7b3', '#8f6f54', '#37485a', '#c88f5b']; + $hash = abs((int)crc32($seed)); + $bg = $palette[$hash % count($palette)]; + $fg = $hash % 2 === 0 ? '#243142' : '#ffffff'; - $file = self::layerFilePath($category, $variant); - if (!is_file($file)) { - return ''; - } - - $svg = file_get_contents($file); - if ($svg === false) { - return ''; - } - - return '' . $svg . ''; - } - - public static function layerFilePath(string $category, string $variant): string - { - return dirname(__DIR__, 2) . '/public/assets/avatars/layers/modern/' . $category . '/' . $variant . '.svg'; - } - - public static function presetPublicPath(string $preset): ?string - { - $preset = preg_replace('/[^a-z0-9_]/', '', strtolower($preset)) ?: ''; - $file = dirname(__DIR__, 2) . '/public/assets/avatars/presets/' . $preset . '.png'; - if (!is_file($file)) { - return null; - } - - return '/assets/avatars/presets/' . $preset . '.png'; + return sprintf( + '%s', + htmlspecialchars($label, ENT_QUOTES), + htmlspecialchars($bg, ENT_QUOTES), + htmlspecialchars($fg, ENT_QUOTES), + htmlspecialchars($initials, ENT_QUOTES) + ); } } diff --git a/src/App/ProfileSettings.php b/src/App/ProfileSettings.php index 6f13a5c..bea7dbc 100644 --- a/src/App/ProfileSettings.php +++ b/src/App/ProfileSettings.php @@ -29,7 +29,7 @@ final class ProfileSettings } $avatarColumns = [ - 'avatar_preset' => "ALTER TABLE user_profiles ADD COLUMN avatar_preset VARCHAR(32) NOT NULL DEFAULT 'modern_001' AFTER location_tracking_preference", + 'avatar_preset' => "ALTER TABLE user_profiles ADD COLUMN avatar_preset VARCHAR(64) NOT NULL DEFAULT 'papa-kind-treff' AFTER location_tracking_preference", 'avatar_skin_tone' => "ALTER TABLE user_profiles ADD COLUMN avatar_skin_tone VARCHAR(24) NOT NULL DEFAULT 'warm' AFTER location_tracking_preference", 'avatar_hair_style' => "ALTER TABLE user_profiles ADD COLUMN avatar_hair_style VARCHAR(24) NOT NULL DEFAULT 'short' AFTER avatar_skin_tone", 'avatar_hair_color' => "ALTER TABLE user_profiles ADD COLUMN avatar_hair_color VARCHAR(24) NOT NULL DEFAULT 'brown' AFTER avatar_hair_style",