feat: add persistent badges and admin badge page
This commit is contained in:
@@ -2,6 +2,32 @@
|
||||
<span class="nav-icon">{{ icon_svg(name)|safe }}</span>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro badge_chip(user_badge) -%}
|
||||
<span class="earned-badge">
|
||||
<span class="earned-badge__icon">{{ nav_icon(user_badge.badge_definition.icon_name) }}</span>
|
||||
<span>{{ user_badge.badge_definition.name }}</span>
|
||||
</span>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro badge_card(badge, earned=false, awarded_at=None) -%}
|
||||
<article class="badge-card {% if earned %}badge-card--earned{% endif %}">
|
||||
<div class="badge-card__icon">
|
||||
{{ nav_icon(badge.icon_name) }}
|
||||
</div>
|
||||
<div class="badge-card__body">
|
||||
<strong>{{ badge.name }}</strong>
|
||||
<p class="muted">{{ badge.description }}</p>
|
||||
<div class="chip-row">
|
||||
<span class="point-pill">Bonus {{ badge.bonus_points }}</span>
|
||||
<span class="reward-chip">Schwelle {{ badge.threshold }}</span>
|
||||
{% if awarded_at %}
|
||||
<span class="reward-chip">Freigeschaltet {{ awarded_at|date_de }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro status_badge(task) -%}
|
||||
<span class="status-badge status-badge--{{ task.status }}">{{ task.status_label }}</span>
|
||||
{%- endmacro %}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends "base.html" %}
|
||||
{% from "partials/macros.html" import avatar %}
|
||||
{% from "partials/macros.html" import avatar, badge_chip %}
|
||||
{% block title %}Highscoreboard · Putzliga{% endblock %}
|
||||
{% block page_title %}Highscoreboard{% endblock %}
|
||||
{% block content %}
|
||||
@@ -50,7 +50,14 @@
|
||||
{% if row.badges %}
|
||||
<div class="badge-cloud">
|
||||
{% for badge in row.badges %}
|
||||
<span class="reward-chip">{{ badge.definition.name }} +{{ badge.bonus_points }}</span>
|
||||
{{ badge_chip(badge) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if row.user.awarded_badges %}
|
||||
<div class="badge-cloud">
|
||||
{% for badge in row.user.awarded_badges[:3] %}
|
||||
{{ badge_chip(badge) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
41
app/templates/settings/badges.html
Normal file
41
app/templates/settings/badges.html
Normal file
@@ -0,0 +1,41 @@
|
||||
{% extends "base.html" %}
|
||||
{% from "partials/macros.html" import badge_card, nav_icon %}
|
||||
{% block title %}Badge-Regeln · Putzliga{% endblock %}
|
||||
{% block page_title %}Badge-Regeln{% endblock %}
|
||||
{% block content %}
|
||||
<section class="settings-tabs">
|
||||
{% for endpoint, label, icon in settings_tabs %}
|
||||
<a href="{{ url_for(endpoint) }}" class="settings-tab {% if active_settings_tab == endpoint %}is-active{% endif %}">
|
||||
{{ nav_icon(icon) }}
|
||||
<span>{{ label }}</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<p class="eyebrow">Admin-Bereich</p>
|
||||
<h2>Badges konfigurieren</h2>
|
||||
<p class="muted">Die Icons stammen aus `heinz.marketing` und wurden für Putzliga lokal übernommen. Schwelle, Bonus und Aktiv-Status kannst du hier steuern.</p>
|
||||
<div class="badge-settings">
|
||||
{% for badge in badges %}
|
||||
<form method="post" action="{{ url_for('settings.update_badge', badge_id=badge.id) }}" class="badge-setting-card">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
{{ badge_card(badge) }}
|
||||
<div class="field field--compact">
|
||||
<label>Schwelle</label>
|
||||
<input type="number" name="threshold" min="1" value="{{ badge.threshold }}">
|
||||
</div>
|
||||
<div class="field field--compact">
|
||||
<label>Bonus</label>
|
||||
<input type="number" name="bonus_points" min="0" value="{{ badge.bonus_points }}">
|
||||
</div>
|
||||
<label class="checkbox checkbox--compact">
|
||||
<input type="checkbox" name="active" {% if badge.active %}checked{% endif %}>
|
||||
<span>Aktiv</span>
|
||||
</label>
|
||||
<button type="submit" class="button button--secondary">Badge speichern</button>
|
||||
</form>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,8 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
{% from "partials/macros.html" import avatar, nav_icon %}
|
||||
{% from "partials/macros.html" import avatar, badge_chip, nav_icon %}
|
||||
{% block title %}Optionen · Putzliga{% endblock %}
|
||||
{% block page_title %}Optionen{% endblock %}
|
||||
{% block content %}
|
||||
<section class="settings-tabs">
|
||||
{% for endpoint, label, icon in settings_tabs %}
|
||||
<a href="{{ url_for(endpoint) }}" class="settings-tab {% if active_settings_tab == endpoint %}is-active{% endif %}">
|
||||
{{ nav_icon(icon) }}
|
||||
<span>{{ label }}</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
<section class="two-column">
|
||||
<article class="panel">
|
||||
<p class="eyebrow">Profil & Benachrichtigungen</p>
|
||||
@@ -70,35 +79,19 @@
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<p class="eyebrow">Gamification</p>
|
||||
<h2>Badge-Regeln pflegen</h2>
|
||||
{% if current_user.is_admin %}
|
||||
<div class="badge-settings">
|
||||
{% for badge in badges %}
|
||||
<form method="post" action="{{ url_for('settings.update_badge', badge_id=badge.id) }}" class="badge-setting-card">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div>
|
||||
<strong>{{ badge.name }}</strong>
|
||||
<p class="muted">{{ badge.description }}</p>
|
||||
</div>
|
||||
<div class="field field--compact">
|
||||
<label>Schwelle</label>
|
||||
<input type="number" name="threshold" min="1" value="{{ badge.threshold }}">
|
||||
</div>
|
||||
<div class="field field--compact">
|
||||
<label>Bonus</label>
|
||||
<input type="number" name="bonus_points" min="0" value="{{ badge.bonus_points }}">
|
||||
</div>
|
||||
<label class="checkbox checkbox--compact">
|
||||
<input type="checkbox" name="active" {% if badge.active %}checked{% endif %}>
|
||||
<span>Aktiv</span>
|
||||
</label>
|
||||
<button type="submit" class="button button--secondary">Badge speichern</button>
|
||||
</form>
|
||||
<p class="eyebrow">Deine Trophäenwand</p>
|
||||
<h2>Freigeschaltete Badges</h2>
|
||||
{% if earned_badges %}
|
||||
<div class="earned-badges-grid">
|
||||
{% for badge in earned_badges %}
|
||||
{{ badge_chip(badge) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="muted">Badge-Regeln können nur von einem Admin geändert werden.</p>
|
||||
<p class="muted">Noch keine Badges freigeschaltet. Die ersten kommen schnell, sobald Aufgaben erledigt werden.</p>
|
||||
{% endif %}
|
||||
{% if current_user.is_admin %}
|
||||
<p class="inline-note">Badge-Regeln verwaltest du auf der separaten <a href="{{ url_for('settings.badges') }}">Badge-Seite</a>.</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user