Feature: Timer-Schalter im Admin-Menü (v1.1.2)
Timer kann chapter-weit deaktiviert werden – Display-Ring, Countdown und Zeitbadges werden ausgeblendet. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
27
index.html
27
index.html
@@ -1219,9 +1219,11 @@
|
|||||||
<div class="status-dot dot-idle" id="sync-dot" title="Display-Verbindung"></div>
|
<div class="status-dot dot-idle" id="sync-dot" title="Display-Verbindung"></div>
|
||||||
<button class="btn btn-secondary btn-sm" onclick="resetMeeting()">↺ Neu starten</button>
|
<button class="btn btn-secondary btn-sm" onclick="resetMeeting()">↺ Neu starten</button>
|
||||||
<button class="btn btn-secondary btn-sm" onclick="openPdfImport()">📄 PDF importieren</button>
|
<button class="btn btn-secondary btn-sm" onclick="openPdfImport()">📄 PDF importieren</button>
|
||||||
|
<div id="ctrl-timer-controls" style="display:flex;gap:4px;">
|
||||||
<button class="btn btn-secondary btn-sm" onclick="editDefaultTimer()" title="Standard-Redezeit anpassen" style="font-variant-numeric:tabular-nums;">⏱ <span id="ctrl-timer-default">1:00</span></button>
|
<button class="btn btn-secondary btn-sm" onclick="editDefaultTimer()" title="Standard-Redezeit anpassen" style="font-variant-numeric:tabular-nums;">⏱ <span id="ctrl-timer-default">1:00</span></button>
|
||||||
<button class="btn btn-secondary btn-sm" id="ctrl-timer-toggle" onclick="toggleTimer()" style="font-variant-numeric:tabular-nums;min-width:80px;">▶ Start</button>
|
<button class="btn btn-secondary btn-sm" id="ctrl-timer-toggle" onclick="toggleTimer()" style="font-variant-numeric:tabular-nums;min-width:80px;">▶ Start</button>
|
||||||
<button class="btn btn-secondary btn-sm" id="ctrl-timer-reset" onclick="resetTimer()" title="Timer zurücksetzen">↺ <span id="ctrl-timer-display" style="min-width:36px;display:inline-block;"></span></button>
|
<button class="btn btn-secondary btn-sm" id="ctrl-timer-reset" onclick="resetTimer()" title="Timer zurücksetzen">↺ <span id="ctrl-timer-display" style="min-width:36px;display:inline-block;"></span></button>
|
||||||
|
</div>
|
||||||
<button class="btn btn-secondary btn-sm" onclick="openMemberSync()">🔄 Mitglieder aktualisieren</button>
|
<button class="btn btn-secondary btn-sm" onclick="openMemberSync()">🔄 Mitglieder aktualisieren</button>
|
||||||
<button class="btn btn-secondary btn-sm" onclick="openImportExport()">⬇ Import / Export</button>
|
<button class="btn btn-secondary btn-sm" onclick="openImportExport()">⬇ Import / Export</button>
|
||||||
<button class="btn btn-secondary btn-sm" onclick="window.open(location.href.split('#')[0] + '#display', '_blank', 'noopener')">🖥 Anzeige öffnen</button>
|
<button class="btn btn-secondary btn-sm" onclick="window.open(location.href.split('#')[0] + '#display', '_blank', 'noopener')">🖥 Anzeige öffnen</button>
|
||||||
@@ -1711,7 +1713,7 @@
|
|||||||
// ============================================================
|
// ============================================================
|
||||||
// CONSTANTS & CHAPTER CONFIG
|
// CONSTANTS & CHAPTER CONFIG
|
||||||
// ============================================================
|
// ============================================================
|
||||||
const APP_VERSION = '1.1.0';
|
const APP_VERSION = '1.1.2';
|
||||||
const GITEA_RAW = 'http://72.60.134.73:3000/api/v1/repos/cheubaum/BNI-Vorstellungsrunde/raw';
|
const GITEA_RAW = 'http://72.60.134.73:3000/api/v1/repos/cheubaum/BNI-Vorstellungsrunde/raw';
|
||||||
const GITEA_API = 'http://72.60.134.73:3000/api/v1/repos/cheubaum/BNI-Vorstellungsrunde';
|
const GITEA_API = 'http://72.60.134.73:3000/api/v1/repos/cheubaum/BNI-Vorstellungsrunde';
|
||||||
function giteaUrl(path) { return `${GITEA_RAW}/${path}?ref=main`; }
|
function giteaUrl(path) { return `${GITEA_RAW}/${path}?ref=main`; }
|
||||||
@@ -1758,6 +1760,7 @@ function defaultState() {
|
|||||||
mode: 'members', // 'members' | 'absent-summary' | 'visitors'
|
mode: 'members', // 'members' | 'absent-summary' | 'visitors'
|
||||||
defaultTimer: 60, // seconds (standard speaking time)
|
defaultTimer: 60, // seconds (standard speaking time)
|
||||||
memberTimers: {}, // { memberId: customSeconds }
|
memberTimers: {}, // { memberId: customSeconds }
|
||||||
|
showTimer: true, // false = timer completely hidden
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3947,12 +3950,17 @@ function timerCls(rem, total) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateTimerDisplays() {
|
function updateTimerDisplays() {
|
||||||
|
const timerOn = state.showTimer !== false;
|
||||||
const s = _t.remaining;
|
const s = _t.remaining;
|
||||||
const tot = _t.total;
|
const tot = _t.total;
|
||||||
const cls = tot > 0 ? timerCls(s, tot) : '';
|
const cls = tot > 0 ? timerCls(s, tot) : '';
|
||||||
const txt = tot > 0 ? fmtSecs(s) : '';
|
const txt = tot > 0 ? fmtSecs(s) : '';
|
||||||
const CIRC = 729; // 2 * PI * 116
|
const CIRC = 729; // 2 * PI * 116
|
||||||
|
|
||||||
|
// Control timer buttons visibility
|
||||||
|
const tc = document.getElementById('ctrl-timer-controls');
|
||||||
|
if (tc) tc.style.display = timerOn ? 'flex' : 'none';
|
||||||
|
|
||||||
// SVG ring
|
// SVG ring
|
||||||
const ring = document.getElementById('timer-ring-progress');
|
const ring = document.getElementById('timer-ring-progress');
|
||||||
const ringEl = document.getElementById('timer-ring-svg');
|
const ringEl = document.getElementById('timer-ring-svg');
|
||||||
@@ -3960,7 +3968,7 @@ function updateTimerDisplays() {
|
|||||||
const offset = tot > 0 ? CIRC * (1 - s / tot) : 0;
|
const offset = tot > 0 ? CIRC * (1 - s / tot) : 0;
|
||||||
ring.style.strokeDashoffset = offset;
|
ring.style.strokeDashoffset = offset;
|
||||||
ring.className = 'timer-ring-progress' + (cls ? ' ' + cls : '');
|
ring.className = 'timer-ring-progress' + (cls ? ' ' + cls : '');
|
||||||
ringEl.style.display = tot > 0 ? 'block' : 'none';
|
ringEl.style.display = (timerOn && tot > 0) ? 'block' : 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display timer text
|
// Display timer text
|
||||||
@@ -3968,7 +3976,7 @@ function updateTimerDisplays() {
|
|||||||
if (dt) {
|
if (dt) {
|
||||||
dt.textContent = txt;
|
dt.textContent = txt;
|
||||||
dt.className = cls;
|
dt.className = cls;
|
||||||
dt.style.display = tot > 0 ? 'block' : 'none';
|
dt.style.display = (timerOn && tot > 0) ? 'block' : 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Control timer display (live countdown)
|
// Control timer display (live countdown)
|
||||||
@@ -4000,6 +4008,7 @@ function stopTimer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toggleTimer() {
|
function toggleTimer() {
|
||||||
|
if (state.showTimer === false) return;
|
||||||
if (_t.running || _t.pending) {
|
if (_t.running || _t.pending) {
|
||||||
stopTimer();
|
stopTimer();
|
||||||
} else {
|
} else {
|
||||||
@@ -4016,6 +4025,7 @@ function resetTimer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function scheduleTimer(seconds) {
|
function scheduleTimer(seconds) {
|
||||||
|
if (state.showTimer === false) return;
|
||||||
stopTimer();
|
stopTimer();
|
||||||
_t.total = seconds; _t.remaining = seconds;
|
_t.total = seconds; _t.remaining = seconds;
|
||||||
updateTimerDisplays();
|
updateTimerDisplays();
|
||||||
@@ -4037,6 +4047,7 @@ function getPresenterSeconds(presenter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderTimerBadge(memberId) {
|
function renderTimerBadge(memberId) {
|
||||||
|
if (state.showTimer === false) return '';
|
||||||
const def = state.defaultTimer || 60;
|
const def = state.defaultTimer || 60;
|
||||||
const custom = state.memberTimers && state.memberTimers[memberId];
|
const custom = state.memberTimers && state.memberTimers[memberId];
|
||||||
const secs = custom > 0 ? custom : def;
|
const secs = custom > 0 ? custom : def;
|
||||||
@@ -4459,6 +4470,15 @@ function renderAdminPanel() {
|
|||||||
<div style="font-size:0.78rem;color:var(--muted);margin-bottom:16px;">Letzter Download: ${lastSync}</div>
|
<div style="font-size:0.78rem;color:var(--muted);margin-bottom:16px;">Letzter Download: ${lastSync}</div>
|
||||||
<a href="admin.html" target="_blank" class="btn btn-primary btn-sm" style="width:100%;display:block;text-align:center;text-decoration:none;margin-bottom:16px;">⚙ Admin-Panel öffnen</a>
|
<a href="admin.html" target="_blank" class="btn btn-primary btn-sm" style="width:100%;display:block;text-align:center;text-decoration:none;margin-bottom:16px;">⚙ Admin-Panel öffnen</a>
|
||||||
` : `<div style="color:var(--muted);font-size:0.88rem;margin-bottom:20px;">Kein Chapter aktiviert.</div>`}
|
` : `<div style="color:var(--muted);font-size:0.88rem;margin-bottom:20px;">Kein Chapter aktiviert.</div>`}
|
||||||
|
<div style="border-top:1px solid var(--border);padding-top:14px;margin-bottom:14px;">
|
||||||
|
<div style="font-size:0.78rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:1px;margin-bottom:10px;">Einstellungen</div>
|
||||||
|
<label style="display:flex;align-items:center;gap:10px;cursor:pointer;font-size:0.88rem;">
|
||||||
|
<input type="checkbox" id="admin-show-timer" ${state.showTimer !== false ? 'checked' : ''}
|
||||||
|
onchange="state.showTimer=this.checked;saveState();updateTimerDisplays();renderMemberQueue();renderVisitorQueue();renderVisitorsList();"
|
||||||
|
style="width:16px;height:16px;cursor:pointer;">
|
||||||
|
Zeitanzeige aktiv
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<div style="border-top:1px solid var(--border);padding-top:14px;">
|
<div style="border-top:1px solid var(--border);padding-top:14px;">
|
||||||
<button class="btn btn-ghost btn-sm" style="width:100%;" onclick="confirmSwitchChapter()">↔ Chapter wechseln</button>
|
<button class="btn btn-ghost btn-sm" style="width:100%;" onclick="confirmSwitchChapter()">↔ Chapter wechseln</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -4478,6 +4498,7 @@ function confirmSwitchChapter() {
|
|||||||
initChannel();
|
initChannel();
|
||||||
if (activeChapter) applyChapterUI(activeChapter.config);
|
if (activeChapter) applyChapterUI(activeChapter.config);
|
||||||
renderCurrentView();
|
renderCurrentView();
|
||||||
|
updateTimerDisplays();
|
||||||
checkLicenseAndUpdates();
|
checkLicenseAndUpdates();
|
||||||
|
|
||||||
// Keyboard shortcut hint
|
// Keyboard shortcut hint
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"version": "1.1.1",
|
"version": "1.1.2",
|
||||||
"notes": "Chapter Lumora und Callisto ergänzt"
|
"notes": "Timer-Schalter im Admin-Menü, DigiSeed-Logo Fix"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user