feat: badge generator pages for printing

This commit is contained in:
vas3k 2024-05-05 17:48:05 +02:00
parent ff72d4c317
commit 248ba3caf4
5 changed files with 231 additions and 3 deletions

View File

@ -19,7 +19,7 @@ from comments.views import create_comment, edit_comment, delete_comment, show_co
retract_comment_vote, pin_comment
from common.feature_flags import feature_switch
from landing.views import landing, docs, godmode_network_settings, godmode_digest_settings, godmode_settings, \
godmode_invite
godmode_invite, badge_generator
from misc.views import stats, network, robots, generate_ical_invite, generate_google_invite, show_achievement
from rooms.views import redirect_to_room_chat, list_rooms
from notifications.views import render_weekly_digest, email_unsubscribe, email_confirm, render_daily_digest, \
@ -196,6 +196,7 @@ urlpatterns = [
path("godmode/network/", godmode_network_settings, name="godmode_network_settings"),
path("godmode/digest/", godmode_digest_settings, name="godmode_digest_settings"),
path("godmode/invite/", godmode_invite, name="godmode_invite"),
path("godmode/badge_generator/", badge_generator, name="badge_generator"),
path("godmode/dev_login/", debug_dev_login, name="debug_dev_login"),
path("godmode/random_login/", debug_random_login, name="debug_random_login"),
path("godmode/login/<str:user_slug>/", debug_login, name="debug_login"),

View File

@ -0,0 +1,194 @@
{% extends "layout.html" %}
{% load static %}
{% load text_filters %}
{% block title %}
Генератор бейджиков — {{ block.super }}
{% endblock %}
{% block css %}
<style>
.badge-generator {
max-width: 800px; /* good for A4 printing */
margin: 0 auto;
}
.badge-generator-results {
}
.badge-generator-table {
table-layout: fixed;
}
.badge-generator-table td {
width: 50%;
padding: 10px;
}
.user-stats {
grid-column-start: 1;
grid-column-end: 3;
font-size: 80%;
gap: 10px;
display: flex;
justify-content: flex-start;
padding-top: 15px;
padding-bottom: 0;
}
.profile-card {
color-adjust: exact;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
grid-template-columns: 90px auto;
column-gap: 15px;
grid-template-rows: auto auto;
box-shadow: none;
margin-bottom: 0;
padding: 20px;
}
.profile-card-info {
font-size: 80%;
padding-top: 0;
}
.profile-user-fullname {
margin-right: 0;
}
.profile-user-nickname {
position: relative;
top: -0.2em;
font-size: 60%;
}
.user-stats {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
align-items: center;
}
.user-stats-item {
font-size: 90%;
display: flex;
flex-direction: row;
gap: 3px;
line-height: 1.1em;
text-align: center;
border-radius: 5px;
min-width: 25px;
padding: 6px 5px 6px;
color: var(--text-color);
background-color: var(--bg-color);
}
</style>
{% endblock %}
{% block content %}
<div class="badge-generator">
<div class="content-header">Генератор бейджиков</div>
<div class="block">
<form action="." method="post">
<span class="form-row">
<textarea name="users">{{ requested_users }}</textarea>
</span>
<span class="form-row">
<label><input type="checkbox" name="hide_bio" value="1" {% if hide_bio %}checked{% endif %}> Спрятать био</label>
</span>
<span class="form-row">
<label><input type="checkbox" name="hide_badges" value="1" {% if hide_badges %}checked{% endif %}> Спрятать бейджики</label>
</span>
<span class="form-row">
<label><input type="checkbox" name="hide_stats" value="1" {% if hide_stats %}checked{% endif %}> Спрятать стаж</label>
</span>
<span class="form-row">
<label>Повторить каждый бейджик N раз <input type="label" name="repeat" value="{{ repeat|default:1 }}"></label>
</span>
<span class="form-row">
<input type="submit" value="Генерировать">
</span>
</form>
</div>
<div class="badge-generator-results">
<table class="badge-generator-table">
<tr>
{% for user in users %}
<td>
<div class="block profile-card h-card">
<div class="profile-card-photo u-photo">
<div class="avatar profile-user-avatar"><img src="{{ user.get_avatar }}" alt="Аватар {{ user.full_name }}" loading="lazy" /></div>
</div>
<div class="profile-card-info">
<a href="{% url "profile" user.slug %}" class="profile-user-name u-url">
<span class="profile-user-fullname {% if user.is_banned or user.deleted_at %}user-name-is-banned{% endif %} p-name">{{ user.full_name }}</span>
<span class="profile-user-nickname p-nickname">@{{ user.slug }}</span>
</a>
{% if user.position or user.company %}
<div class="profile-user-job">
<span class="profile-user-job-position p-job-title">{{ user.position }}</span>
{% if user.company %}— <span class="profile-user-job-company p-org">{{ user.company }}</span>{% endif %}
</div>
{% endif %}
{% if user.city or user.country %}
<div class="profile-user-location">
📍{% if user.city %}<span class="p-locality">{{ user.city }}</span>, {% endif %}<span class="p-country-name">{{ user.country }}</span>
</div>
{% endif %}
{% if not hide_bio and user.bio %}
<div class="profile-user-bio">
{{ user.bio | markdown }}
</div>
{% endif %}
</div>
<div class="user-stats">
{% if not hide_stats %}
<div class="user-stats-item">
{% if user.membership_created_days < 40 %}
<span class="profile-status-number">{{ user.membership_created_days | ceil | cool_number }}</span>
<span class="profile-status-text">{{ user.membership_created_days | ceil | rupluralize:"день,дня,дней" }}</span>
{% elif user.membership_created_days <= 360 %}
<span class="profile-status-number">{{ user.membership_created_days | days_to_months | cool_number }}</span>
<span class="profile-status-text">мес.</span>
{% else %}
<span class="profile-status-number">{{ user.membership_created_days | days_to_years | cool_number }}</span>
<span class="profile-status-text">{{ user.membership_created_days | days_to_years | rupluralize:"год,года,лет" }}</span>
{% endif %}
</div>
<div class="user-stats-item">
<div class="profile-status-number">+{{ user.upvotes | cool_number }}</div>
</div>
{% if user.hat %}
{% include "users/widgets/hat.html" with hat=user.hat %}
{% endif %}
{% endif %}
{% if not hide_badges and user.badges %}
{% include "badges/widgets/badges.html" with badges=user.badges badge_size="small" %}
{% endif %}
</div>
</div>
</td>
{% if forloop.counter|divisibleby:2 %}</tr><tr>{% endif %}
{% endfor %}
</tr>
</table>
</div>
</div>
{% endblock %}

View File

@ -22,6 +22,10 @@
<span class="compose-type-icon">💿</span>
<span class="compose-type-name">Админка</span>
</a>
<a href="{% url "badge_generator" %}" class="compose-type">
<span class="compose-type-icon">🪪</span>
<span class="compose-type-name">Генератор бейджиков</span>
</a>
</div>
</div>
{% endblock %}

View File

@ -6,6 +6,7 @@
}
.profile-card {
break-inside: avoid;
vertical-align: middle;
color: var(--opposite-text-color);
background-color: var(--opposite-bg-color);
@ -35,8 +36,8 @@
.profile-user-avatar {
display: block;
width: 200px;
height: 200px;
width: 100%;
aspect-ratio: 1 / 1;
margin: 0 auto;
}

View File

@ -8,6 +8,7 @@ from django.http import Http404
from django.shortcuts import render, redirect
from authn.decorators.auth import require_auth
from badges.models import UserBadge
from club.exceptions import AccessDenied
from landing.forms import GodmodeNetworkSettingsEditForm, GodmodeDigestEditForm, GodmodeInviteForm
from landing.models import GodSettings
@ -141,3 +142,30 @@ def godmode_invite(request):
form = GodmodeInviteForm()
return render(request, "admin/simple_form.html", {"form": form})
@require_auth
def badge_generator(request):
requested_users = request.POST.get("users")
if requested_users:
requested_users = requested_users.split(",")
else:
requested_users = [request.me.slug]
users = User.registered_members().filter(slug__in=requested_users)
for user in users:
user.badges = UserBadge.user_badges_grouped(user=user)
repeat = int(request.POST.get("repeat") or 1)
if repeat > 1:
users = [u for u in users for _ in range(repeat)]
return render(request, "admin/badge_generator.html", {
"users": users,
"requested_users": ",".join(requested_users),
"hide_bio": request.POST.get("hide_bio"),
"hide_stats": request.POST.get("hide_stats"),
"hide_badges": request.POST.get("hide_badges"),
"repeat": repeat,
})