This commit is contained in:
@@ -3,6 +3,10 @@ $app = app();
|
||||
$vm = \App\AccountPages::dashboard($app);
|
||||
extract($vm, EXTR_OVERWRITE);
|
||||
$avatarPlaceholder = 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 12 12%22%3E%3Crect width=%2212%22 height=%2212%22 fill=%22%23f7efe6%22/%3E%3C/svg%3E';
|
||||
$avatarStyleKeys = array_keys($avatarBuilder ?? []);
|
||||
$currentAvatarStyle = (string)($profile['avatar_style'] ?? ($avatarStyleKeys[0] ?? 'lorelei'));
|
||||
$currentAvatarComponents = $avatarBuilder[$currentAvatarStyle]['components'] ?? [];
|
||||
$dashboardUserId = (int)($_SESSION['user_id'] ?? 0);
|
||||
$editing = isset($editEvent) && $editEvent !== null;
|
||||
$actionEvent = $editing ? 'event_update' : 'event_add';
|
||||
$startVal = $editEvent ? date('Y-m-d\TH:i', strtotime((string)$editEvent['starts_at'])) : '';
|
||||
@@ -64,11 +68,11 @@ $sectionLinks = [
|
||||
<div class="account-panel__body">
|
||||
<div class="profile-avatar-panel">
|
||||
<div class="profile-avatar-panel__preview">
|
||||
<?= \App\Avatar\Lorelei::render($profile, $profile['display_name'] ?: 'Papa', 'xl') ?>
|
||||
<?= \App\Avatar\AvatarManager::render($profile, $profile['display_name'] ?: 'Papa', 'xl', $dashboardUserId) ?>
|
||||
</div>
|
||||
<div class="profile-avatar-panel__content">
|
||||
<h3>Dein Profilbild</h3>
|
||||
<p class="muted">Dein Profilbild wird jetzt mit DiceBear im Stil Lorelei erzeugt. Du wählst eine Variante aus und speicherst deren Seed dauerhaft in deinem Profil.</p>
|
||||
<p class="muted">Dein Profilbild wird mit dem Avatar-Generator erzeugt und als feste SVG-Datei zu deinem Konto gespeichert. Stil, Seed und Varianten bleiben dabei in deinem Profil hinterlegt.</p>
|
||||
<button class="btn" type="button" data-modal-open="modalAvatar">Profilbild gestalten</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -298,69 +302,88 @@ $sectionLinks = [
|
||||
</div>
|
||||
<form method="post" class="stack gap-12 avatar-builder" data-avatar-builder style="margin-top:12px;">
|
||||
<input type="hidden" name="action" value="avatar_update">
|
||||
<input type="hidden" name="avatar_preset" value="<?= htmlspecialchars((string)$profile['avatar_preset'], ENT_QUOTES) ?>" data-avatar-field="avatar_preset">
|
||||
<?php if (count($avatarStyleKeys) <= 1): ?>
|
||||
<input type="hidden" name="avatar_style" value="<?= htmlspecialchars($currentAvatarStyle, ENT_QUOTES) ?>" data-avatar-style-select>
|
||||
<?php endif; ?>
|
||||
<input type="hidden" name="avatar_seed" value="<?= htmlspecialchars((string)$profile['avatar_seed'], ENT_QUOTES) ?>" data-avatar-seed>
|
||||
<div class="avatar-builder__layout">
|
||||
<div class="avatar-builder__preview">
|
||||
<div data-avatar-preview>
|
||||
<?= \App\Avatar\Lorelei::render($profile, $profile['display_name'] ?: 'Papa', 'xxl') ?>
|
||||
<?= \App\Avatar\AvatarManager::render($profile, $profile['display_name'] ?: 'Papa', 'xxl', $dashboardUserId) ?>
|
||||
</div>
|
||||
<p class="muted small">Wähle eine Komponente und passe dein neues Profilbild Schritt für Schritt an. Gespeichert wird erst nach Klick auf den Button unten.</p>
|
||||
<?php if (count($avatarStyleKeys) > 1): ?>
|
||||
<div class="stack gap-6" style="max-width:320px; margin:0 auto;">
|
||||
<label class="label" for="avatarStyleSelect">Stil</label>
|
||||
<select id="avatarStyleSelect" name="avatar_style" class="select" data-avatar-style-select>
|
||||
<?php foreach ($avatarBuilder as $styleKey => $styleMeta): ?>
|
||||
<option value="<?= htmlspecialchars($styleKey, ENT_QUOTES) ?>" <?= $styleKey === $currentAvatarStyle ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars((string)$styleMeta['label'], ENT_QUOTES) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="flex gap-12" style="flex-wrap:wrap; justify-content:center;">
|
||||
<button class="btn ghost" type="button" data-avatar-random>Random Profilbild</button>
|
||||
<button class="btn ghost" type="button" data-modal-close>Abbrechen</button>
|
||||
<button class="btn" type="submit">Profilbild speichern</button>
|
||||
</div>
|
||||
<div class="avatar-component-nav" role="tablist" aria-label="Avatar-Komponenten">
|
||||
<?php foreach (\App\Avatar\Lorelei::componentDefinitions() as $field => $meta): ?>
|
||||
<?php
|
||||
$componentOptions = $avatarOptions[$field] ?? [];
|
||||
$componentCount = count(array_filter(array_keys($componentOptions), static fn ($value): bool => (string) $value !== ''));
|
||||
?>
|
||||
<button
|
||||
type="button"
|
||||
class="avatar-component-nav__button <?= $field === 'avatar_lorelei_eyes_variant' ? 'is-active' : '' ?>"
|
||||
data-avatar-component-tab="<?= htmlspecialchars((string)$field, ENT_QUOTES) ?>"
|
||||
aria-selected="<?= $field === 'avatar_lorelei_eyes_variant' ? 'true' : 'false' ?>"
|
||||
>
|
||||
<?= htmlspecialchars((string)$meta['label'], ENT_QUOTES) ?>
|
||||
<span class="muted small">(<?= $componentCount ?>)</span>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="avatar-component-panels">
|
||||
<?php foreach (\App\Avatar\Lorelei::componentDefinitions() as $field => $meta): ?>
|
||||
<section class="avatar-component-panel avatar-component-panel--<?= htmlspecialchars(str_replace(['avatar_lorelei_', '_variant'], '', (string)$field), ENT_QUOTES) ?> <?= $field === 'avatar_lorelei_eyes_variant' ? 'is-active' : '' ?>" data-avatar-component-panel="<?= htmlspecialchars((string)$field, ENT_QUOTES) ?>">
|
||||
<div class="avatar-component-panel__head">
|
||||
<strong><?= htmlspecialchars((string)$meta['label'], ENT_QUOTES) ?></strong>
|
||||
<span class="muted small">Gesamtes Profilbild zur sicheren Vorschau</span>
|
||||
</div>
|
||||
<div class="avatar-component-grid">
|
||||
<?php foreach (\App\Avatar\Lorelei::previewChoices($profile, $field) as $choice): ?>
|
||||
<label class="avatar-component-card">
|
||||
<input
|
||||
type="radio"
|
||||
name="<?= htmlspecialchars((string)$field, ENT_QUOTES) ?>"
|
||||
value="<?= htmlspecialchars((string)$choice['value'], ENT_QUOTES) ?>"
|
||||
data-avatar-field="<?= htmlspecialchars((string)$field, ENT_QUOTES) ?>"
|
||||
<?= $choice['checked'] ? 'checked' : '' ?>
|
||||
>
|
||||
<span class="avatar-component-card__thumb">
|
||||
<img
|
||||
src="<?= htmlspecialchars($avatarPlaceholder, ENT_QUOTES) ?>"
|
||||
alt="<?= htmlspecialchars((string)$choice['label'], ENT_QUOTES) ?>"
|
||||
data-avatar-option-thumb
|
||||
data-avatar-option-src="<?= htmlspecialchars((string)$choice['image'], ENT_QUOTES) ?>"
|
||||
data-avatar-option-field="<?= htmlspecialchars((string)$field, ENT_QUOTES) ?>"
|
||||
data-avatar-option-value="<?= htmlspecialchars((string)$choice['value'], ENT_QUOTES) ?>"
|
||||
>
|
||||
</span>
|
||||
<span class="avatar-component-card__label"><?= htmlspecialchars((string)$choice['label'], ENT_QUOTES) ?></span>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php foreach ($avatarBuilder as $styleKey => $styleMeta): ?>
|
||||
<?php $styleComponents = $styleMeta['components'] ?? []; ?>
|
||||
<div class="avatar-style-group <?= $styleKey === $currentAvatarStyle ? 'is-active' : '' ?>" data-avatar-style-panel="<?= htmlspecialchars($styleKey, ENT_QUOTES) ?>" <?= $styleKey === $currentAvatarStyle ? '' : 'hidden' ?>>
|
||||
<div class="avatar-component-nav" role="tablist" aria-label="Avatar-Komponenten">
|
||||
<?php $firstField = array_key_first($styleComponents); ?>
|
||||
<?php foreach ($styleComponents as $field => $component): ?>
|
||||
<button
|
||||
type="button"
|
||||
class="avatar-component-nav__button <?= $field === $firstField ? 'is-active' : '' ?>"
|
||||
data-avatar-style="<?= htmlspecialchars($styleKey, ENT_QUOTES) ?>"
|
||||
data-avatar-component-tab="<?= htmlspecialchars((string)$field, ENT_QUOTES) ?>"
|
||||
aria-selected="<?= $field === $firstField ? 'true' : 'false' ?>"
|
||||
>
|
||||
<?= htmlspecialchars((string)($component['label'] ?? $field), ENT_QUOTES) ?>
|
||||
<span class="muted small">(<?= (int)($component['count'] ?? 0) ?>)</span>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="avatar-component-panels">
|
||||
<?php foreach ($styleComponents as $field => $component): ?>
|
||||
<section class="avatar-component-panel avatar-component-panel--<?= htmlspecialchars((string)$field, ENT_QUOTES) ?> <?= $field === $firstField ? 'is-active' : '' ?>" data-avatar-style="<?= htmlspecialchars($styleKey, ENT_QUOTES) ?>" data-avatar-component-panel="<?= htmlspecialchars((string)$field, ENT_QUOTES) ?>">
|
||||
<div class="avatar-component-panel__head">
|
||||
<strong><?= htmlspecialchars((string)($component['label'] ?? $field), ENT_QUOTES) ?></strong>
|
||||
<span class="muted small">Gesamtes Profilbild zur sicheren Vorschau</span>
|
||||
</div>
|
||||
<div class="avatar-component-grid">
|
||||
<?php foreach (($component['options'] ?? []) as $choice): ?>
|
||||
<label class="avatar-component-card">
|
||||
<input
|
||||
type="radio"
|
||||
name="avatar_config[<?= htmlspecialchars($styleKey, ENT_QUOTES) ?>][<?= htmlspecialchars((string)$field, ENT_QUOTES) ?>]"
|
||||
value="<?= htmlspecialchars((string)($choice['value'] ?? ''), ENT_QUOTES) ?>"
|
||||
data-avatar-style="<?= htmlspecialchars($styleKey, ENT_QUOTES) ?>"
|
||||
data-avatar-field="<?= htmlspecialchars((string)$field, ENT_QUOTES) ?>"
|
||||
<?= !empty($choice['checked']) ? 'checked' : '' ?>
|
||||
>
|
||||
<span class="avatar-component-card__thumb">
|
||||
<img
|
||||
src="<?= htmlspecialchars($avatarPlaceholder, ENT_QUOTES) ?>"
|
||||
alt="<?= htmlspecialchars((string)($choice['label'] ?? ''), ENT_QUOTES) ?>"
|
||||
data-avatar-option-thumb
|
||||
data-avatar-style="<?= htmlspecialchars($styleKey, ENT_QUOTES) ?>"
|
||||
data-avatar-option-field="<?= htmlspecialchars((string)$field, ENT_QUOTES) ?>"
|
||||
data-avatar-option-value="<?= htmlspecialchars((string)($choice['value'] ?? ''), ENT_QUOTES) ?>"
|
||||
>
|
||||
</span>
|
||||
<span class="avatar-component-card__label"><?= htmlspecialchars((string)($choice['label'] ?? ''), ENT_QUOTES) ?></span>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -115,7 +115,7 @@ $threads = $community
|
||||
?>
|
||||
<article class="forum-row">
|
||||
<div class="forum-row__topic">
|
||||
<div class="forum-row__avatar"><?= \App\Avatar\Lorelei::render($t, (string)($t['display_name'] ?: 'Mitglied'), 'forum-list') ?></div>
|
||||
<div class="forum-row__avatar"><?= \App\Avatar\AvatarManager::render($t, (string)($t['display_name'] ?: 'Mitglied'), 'forum-list', (int)($t['uid'] ?? 0)) ?></div>
|
||||
<div>
|
||||
<h3><a href="/community_thread?id=<?= (int)$t['id'] ?>"><?= htmlspecialchars((string)$t['title'], ENT_QUOTES) ?></a></h3>
|
||||
<div class="forum-row__meta">
|
||||
@@ -206,7 +206,7 @@ $threads = $community
|
||||
?>
|
||||
<article class="forum-row">
|
||||
<div class="forum-row__topic">
|
||||
<div class="forum-row__avatar"><?= \App\Avatar\Lorelei::render($t, (string)($t['display_name'] ?: 'Mitglied'), 'forum-list') ?></div>
|
||||
<div class="forum-row__avatar"><?= \App\Avatar\AvatarManager::render($t, (string)($t['display_name'] ?: 'Mitglied'), 'forum-list', (int)($t['uid'] ?? 0)) ?></div>
|
||||
<div>
|
||||
<h3><a href="/community_thread?id=<?= (int)$t['id'] ?>"><?= htmlspecialchars((string)$t['title'], ENT_QUOTES) ?></a></h3>
|
||||
<div class="forum-row__meta">
|
||||
|
||||
@@ -154,7 +154,7 @@ $userVotes = ($access && $userId) ? $access->getUserPostVotes((int)$userId, $pos
|
||||
|
||||
<article class="forum-post forum-post--lead">
|
||||
<aside class="forum-post__author">
|
||||
<div class="forum-post__avatar"><?= \App\Avatar\Lorelei::render($thread, $threadAuthor, 'forum') ?></div>
|
||||
<div class="forum-post__avatar"><?= \App\Avatar\AvatarManager::render($thread, $threadAuthor, 'forum', (int)($thread['user_id'] ?? 0)) ?></div>
|
||||
<strong><?= htmlspecialchars($threadAuthor, ENT_QUOTES) ?></strong>
|
||||
<span><?= htmlspecialchars(trim((string)($threadLevel['icon'] ?? '') . ' ' . (string)($threadLevel['label'] ?? '')), ENT_QUOTES) ?></span>
|
||||
<span><?= number_format($threadPoints, 1) ?> Punkte</span>
|
||||
@@ -203,7 +203,7 @@ $userVotes = ($access && $userId) ? $access->getUserPostVotes((int)$userId, $pos
|
||||
?>
|
||||
<article class="forum-post<?= $isHighlighted ? ' forum-post--highlighted' : '' ?>">
|
||||
<aside class="forum-post__author">
|
||||
<div class="forum-post__avatar"><?= \App\Avatar\Lorelei::render($p, $postAuthor, 'forum') ?></div>
|
||||
<div class="forum-post__avatar"><?= \App\Avatar\AvatarManager::render($p, $postAuthor, 'forum', (int)($p['user_id'] ?? 0)) ?></div>
|
||||
<strong><?= htmlspecialchars($postAuthor, ENT_QUOTES) ?></strong>
|
||||
<?php if ($isHighlighted): ?>
|
||||
<span class="forum-highlight-badge">Hilfreich hervorgehoben</span>
|
||||
|
||||
@@ -11,7 +11,11 @@ if ($isLoggedIn) {
|
||||
if ($pdo) {
|
||||
$profileSettings = new \App\ProfileSettings($pdo);
|
||||
$profileSettings->ensureSchema();
|
||||
$stmt = $pdo->prepare('SELECT display_name, first_name, avatar_preset, avatar_lorelei_eyes_variant, avatar_lorelei_eyebrows_variant, avatar_lorelei_mouth_variant, avatar_lorelei_glasses_variant, avatar_lorelei_hair_variant, avatar_lorelei_beard_variant, avatar_lorelei_earrings_variant FROM user_profiles WHERE user_id = :id LIMIT 1');
|
||||
$avatarColumns = implode(', ', array_map(
|
||||
static fn(string $column): string => $column,
|
||||
\App\Avatar\AvatarManager::allProfileColumns()
|
||||
));
|
||||
$stmt = $pdo->prepare("SELECT user_id, display_name, first_name, $avatarColumns FROM user_profiles WHERE user_id = :id LIMIT 1");
|
||||
$stmt->execute(['id' => (int)$_SESSION['user_id']]);
|
||||
$profileRow = $stmt->fetch(PDO::FETCH_ASSOC) ?: [];
|
||||
$displayName = trim((string)($profileRow['display_name'] ?? '')) ?: trim((string)($profileRow['first_name'] ?? '')) ?: 'Profil';
|
||||
@@ -48,7 +52,7 @@ if ($isLoggedIn) {
|
||||
<?php if ($isLoggedIn): ?>
|
||||
<div class="profile-menu" data-profile-menu>
|
||||
<button class="profile-menu__trigger" type="button" aria-haspopup="menu" aria-expanded="false" data-profile-menu-trigger>
|
||||
<span class="profile-menu__avatar" aria-hidden="true"><?= \App\Avatar\Lorelei::render($profileRow ?? [], $displayName, 'nav') ?></span>
|
||||
<span class="profile-menu__avatar" aria-hidden="true"><?= \App\Avatar\AvatarManager::render($profileRow ?? [], $displayName, 'nav', (int)($_SESSION['user_id'] ?? 0)) ?></span>
|
||||
<span class="profile-menu__name"><?= htmlspecialchars($displayName, ENT_QUOTES) ?></span>
|
||||
</button>
|
||||
<div class="profile-menu__dropdown" role="menu">
|
||||
|
||||
Reference in New Issue
Block a user