Initial commit: conference app with Flask
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ 'badges'|t }} - {{ event.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="badges-page">
|
||||
<div class="badges-header">
|
||||
<h1>{{ event.name }}</h1>
|
||||
<p>{{ 'attendee_badges'|t }}</p>
|
||||
<div class="header-actions">
|
||||
<a href="{{ url_for('event_scan', event_id=event.id) }}" class="btn btn-secondary">📷 {{ 'scan_qr_codes'|t }}</a>
|
||||
<button onclick="window.print()" class="btn btn-primary">{{ 'print_badges'|t }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="badges-grid">
|
||||
{% for attendee in attendees %}
|
||||
<div class="badge-card" data-first="{{ attendee.first_name }}" data-last="{{ attendee.last_name }}">
|
||||
<div class="badge-header">
|
||||
<h3 class="badge-name">
|
||||
<span class="first-name">{{ attendee.first_name }}</span><br>
|
||||
<span class="last-name">{{ attendee.last_name }}</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="badge-qr">
|
||||
<img src="{{ attendee.qr_code }}" alt="QR Code" width="100" height="100">
|
||||
</div>
|
||||
<div class="badge-body">
|
||||
<p class="badge-org">{{ (attendee.organisation)|spacify if attendee.organisation else '' }}</p>
|
||||
<p class="badge-role">{{ (attendee.role)|spacify if attendee.role else '' }}</p>
|
||||
{% if attendee.introduction %}
|
||||
<p class="badge-intro">{{ attendee.introduction[:80] }}{% if attendee.introduction|length > 80 %}...{% endif %}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="badge-footer">
|
||||
<span class="badge-id">#{{ attendee.id }}</span>
|
||||
<span class="badge-check {% if attendee.checked_in %}checked-in{% endif %}">
|
||||
{% if attendee.checked_in %}✓ {{ 'checked_in'|t }}{% else %}{{ 'pending'|t }}{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.badge-header h3 { margin: 0; font-size: 1rem; line-height: 1.2; }
|
||||
.badge-header h3 .first-name,
|
||||
.badge-header h3 .last-name { display: block; line-height: 1.1; }
|
||||
.badge-header h3 .last-name { font-size: 0.8rem; }
|
||||
@media print {
|
||||
.navbar, .footer, .badges-header .header-actions button, .flash-messages { display: none !important; }
|
||||
.badges-page { padding: 0; }
|
||||
.badges-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
|
||||
.badge-card { border: 2px solid #000; padding: 15px; page-break-inside: avoid; }
|
||||
.badge-header h3 { margin: 0; font-size: 1rem; line-height: 1.2; }
|
||||
.badge-header h3 .first-name,
|
||||
.badge-header h3 .last-name { display: block !important; line-height: 1.1; }
|
||||
.badge-header h3 .last-name { font-size: 0.8rem !important; }
|
||||
.badge-qr img { width: 80px !important; height: 80px !important; }
|
||||
.badge-body p { margin: 5px 0; }
|
||||
.badge-footer { display: flex; justify-content: space-between; margin-top: 10px; padding-top: 10px; border-top: 1px solid #ccc; }
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
(function() {
|
||||
// Create offscreen canvas for text measurement
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// Width limit for last name before it needs font reduction
|
||||
const LAST_NAME_WIDTH_LIMIT = 120;
|
||||
|
||||
function measureText(text, fontSize, fontFamily) {
|
||||
ctx.font = fontSize + 'px ' + (fontFamily || 'sans-serif');
|
||||
return ctx.measureText(text).width;
|
||||
}
|
||||
|
||||
function formatBadgeNames() {
|
||||
const cards = document.querySelectorAll('.badge-card');
|
||||
cards.forEach(card => {
|
||||
const lastName = card.dataset.last || '';
|
||||
const lastSpan = card.querySelector('.last-name');
|
||||
|
||||
// Measure last name at reduced size (0.8rem = 12.8px)
|
||||
const reducedFontSize = 12.8;
|
||||
const reducedLastWidth = measureText(lastName, reducedFontSize);
|
||||
|
||||
// If still too wide, reduce further
|
||||
if (reducedLastWidth > LAST_NAME_WIDTH_LIMIT) {
|
||||
lastSpan.style.fontSize = '0.7rem';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Run after DOM is ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', formatBadgeNames);
|
||||
} else {
|
||||
formatBadgeNames();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user