PHP Classes

File: templates/bulletins.twig

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   templates/bulletins.twig   Download  
File: templates/bulletins.twig
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 5 days ago
Size: 5,003 bytes
 

Contents

Class file image Download
{% extends "base.twig" %} {% block title %}{{ t('ui.bulletins.title', {}, locale, ['common']) }} - {{ parent() }}{% endblock %} {% block head %} {{ parent() }} <style> .bulletin-viewer { max-width: 880px; margin: 0 auto; } .bulletin-body { min-height: 260px; } .bulletin-plain-body, .bulletin-viewer .message-preformatted { font-family: ui-monospace, 'Cascadia Code', 'Cascadia Mono', SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace; } .bulletin-plain-body { white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; font-size: 0.875rem; line-height: 1.5; } </style> {% endblock %} {% block content %} <div class="bulletin-viewer"> <div class="d-flex justify-content-between align-items-center mb-3"> <h5 class="mb-0"><i class="fas fa-clipboard-list me-2"></i>{{ t('ui.bulletins.title', {}, locale, ['common']) }}</h5> <span class="text-muted small" id="bulletinPosition"></span> </div> <div class="card"> <div class="card-header"> <h6 class="mb-0" id="bulletinTitle"></h6> </div> <div class="card-body bulletin-body" id="bulletinBody"></div> <div class="card-footer d-flex justify-content-between align-items-center gap-2"> <button type="button" class="btn btn-outline-secondary" id="prevBulletinBtn"> <i class="fas fa-chevron-left"></i> </button> <div class="btn-group"> <button type="button" class="btn btn-outline-secondary" id="skipAllBtn">{{ t('ui.bulletins.skip_all', {}, locale, ['common']) }}</button> <button type="button" class="btn btn-primary" id="nextBulletinBtn">{{ t('ui.bulletins.next', {}, locale, ['common']) }}</button> </div> </div> </div> </div> {% endblock %} {% block scripts %} <script src="/js/ansisys.js"></script> <script> const bulletins = {{ display_bulletins|json_encode|raw }}; const showUnreadOnly = {{ show_unread_only ? 'true' : 'false' }}; let bulletinIndex = 0; function uiT(key, fallback, params = {}) { return window.t ? window.t(key, params, fallback) : fallback.replace(/\{([^}]+)\}/g, (_, k) => params[k] ?? ''); } function markRead(ids) { return fetch('/api/bulletins/read-all', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ids }) }); } function renderBulletinBody(bulletin) { if ((bulletin.format || 'plain') !== 'plain' || typeof renderAnsiTerminal !== 'function') { return bulletin.body_html || ''; } return `<pre class="message-preformatted mb-0">${renderAnsiTerminal(bulletin.body || '', 80, 500)}</pre>`; } function showBulletin() { if (!bulletins.length) { document.querySelector('.bulletin-viewer').innerHTML = ` <div class="card"> <div class="card-body text-center py-5"> <h5>${showUnreadOnly ? uiT('ui.bulletins.no_new', 'No new bulletins') : uiT('ui.bulletins.none_available', 'No bulletins available')}</h5> <a class="btn btn-primary mt-3" href="/?skip_bulletins=1">${uiT('ui.bulletins.done', 'Done')}</a> </div> </div>`; return; } const current = bulletins[bulletinIndex]; document.getElementById('bulletinTitle').textContent = current.title || ''; document.getElementById('bulletinBody').innerHTML = renderBulletinBody(current); document.getElementById('bulletinPosition').textContent = uiT('ui.bulletins.count', 'Bulletin {current} of {total}', { current: bulletinIndex + 1, total: bulletins.length }); document.getElementById('prevBulletinBtn').disabled = bulletinIndex === 0; document.getElementById('nextBulletinBtn').textContent = bulletinIndex === bulletins.length - 1 ? uiT('ui.bulletins.done', 'Done') : uiT('ui.bulletins.next', 'Next'); } document.addEventListener('DOMContentLoaded', function() { document.getElementById('prevBulletinBtn').addEventListener('click', function() { if (bulletinIndex > 0) { bulletinIndex--; showBulletin(); } }); document.getElementById('nextBulletinBtn').addEventListener('click', function() { const current = bulletins[bulletinIndex]; fetch(`/api/bulletins/${current.id}/read`, { method: 'POST' }).finally(function() { if (bulletinIndex >= bulletins.length - 1) { window.location.href = '/?skip_bulletins=1'; return; } bulletinIndex++; showBulletin(); }); }); document.getElementById('skipAllBtn').addEventListener('click', function() { markRead(bulletins.map(b => b.id)).finally(function() { window.location.href = '/?skip_bulletins=1'; }); }); showBulletin(); }); </script> {% endblock %}