Update
This commit is contained in:
@@ -373,6 +373,8 @@
|
||||
.admin-controls {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.35rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.join-window {
|
||||
@@ -384,6 +386,30 @@
|
||||
width: min(27rem, 92vw);
|
||||
}
|
||||
|
||||
.terminal-modal-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 72;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.terminal-window {
|
||||
width: min(46rem, 94vw);
|
||||
}
|
||||
|
||||
.terminal-window-content {
|
||||
padding: 0.55rem;
|
||||
}
|
||||
|
||||
.terminal-log-output {
|
||||
height: min(55vh, 30rem);
|
||||
overflow-y: auto;
|
||||
padding: 0.5rem;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.skeleton-line,
|
||||
.skeleton-board,
|
||||
.skeleton-table,
|
||||
|
||||
@@ -172,3 +172,27 @@ input[type="number"]::-webkit-inner-spin-button {
|
||||
40% { transform: scale(0.91); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
|
||||
.terminal-window .title-bar {
|
||||
background: #0f0f0f;
|
||||
color: #9dff9d;
|
||||
}
|
||||
|
||||
.terminal-window .title-bar-controls button {
|
||||
background: #1a1a1a;
|
||||
color: #9dff9d;
|
||||
border-color: #2e2e2e;
|
||||
}
|
||||
|
||||
.terminal-log-output {
|
||||
background: #020a02;
|
||||
color: #84ff84;
|
||||
border: 1px solid #0f4f0f;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.terminal-log-line {
|
||||
margin-bottom: 0.18rem;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,13 @@ const participantList = document.getElementById('participant-list');
|
||||
const adminControls = document.getElementById('admin-controls');
|
||||
const revealBtn = document.getElementById('reveal-btn');
|
||||
const resetBtn = document.getElementById('reset-btn');
|
||||
const terminalBtn = document.getElementById('terminal-btn');
|
||||
const shareLinkInput = document.getElementById('share-link');
|
||||
const shareAdminToggle = document.getElementById('share-admin-toggle');
|
||||
const roomStatus = document.getElementById('room-status');
|
||||
const terminalModalOverlay = document.getElementById('terminal-modal-overlay');
|
||||
const terminalCloseBtn = document.getElementById('terminal-close-btn');
|
||||
const terminalLogOutput = document.getElementById('terminal-log-output');
|
||||
|
||||
const joinPanel = document.getElementById('join-panel');
|
||||
const joinForm = document.getElementById('join-form');
|
||||
@@ -31,6 +35,7 @@ let participantID = params.get('participantId') || '';
|
||||
let adminToken = params.get('adminToken') || '';
|
||||
let eventSource = null;
|
||||
let latestLinks = { participantLink: '', adminLink: '' };
|
||||
let latestAdminLogs = [];
|
||||
|
||||
const savedUsername = localStorage.getItem(USERNAME_KEY) || '';
|
||||
joinUsernameInput.value = savedUsername;
|
||||
@@ -249,6 +254,42 @@ function renderCards(cards, participants, isRevealed) {
|
||||
});
|
||||
}
|
||||
|
||||
function formatLogTime(raw) {
|
||||
const parsed = new Date(raw);
|
||||
if (Number.isNaN(parsed.getTime())) {
|
||||
return raw || '-';
|
||||
}
|
||||
return parsed.toLocaleString();
|
||||
}
|
||||
|
||||
function renderTerminalLogs(logs) {
|
||||
terminalLogOutput.innerHTML = '';
|
||||
if (!Array.isArray(logs) || logs.length === 0) {
|
||||
const emptyLine = document.createElement('div');
|
||||
emptyLine.className = 'terminal-log-line';
|
||||
emptyLine.textContent = '[system] no activity recorded yet';
|
||||
terminalLogOutput.appendChild(emptyLine);
|
||||
return;
|
||||
}
|
||||
|
||||
logs.forEach((item) => {
|
||||
const line = document.createElement('div');
|
||||
line.className = 'terminal-log-line';
|
||||
line.textContent = `[${formatLogTime(item.at)}] ${item.message}`;
|
||||
terminalLogOutput.appendChild(line);
|
||||
});
|
||||
terminalLogOutput.scrollTop = terminalLogOutput.scrollHeight;
|
||||
}
|
||||
|
||||
function openTerminal() {
|
||||
terminalModalOverlay.classList.remove('hidden');
|
||||
renderTerminalLogs(latestAdminLogs);
|
||||
}
|
||||
|
||||
function closeTerminal() {
|
||||
terminalModalOverlay.classList.add('hidden');
|
||||
}
|
||||
|
||||
function renderState(state) {
|
||||
roomTitle.textContent = `${state.roomName} (${state.roomId})`;
|
||||
revealModeLabel.textContent = `Reveal mode: ${state.revealMode}`;
|
||||
@@ -263,8 +304,15 @@ function renderState(state) {
|
||||
|
||||
if (state.viewerIsAdmin) {
|
||||
adminControls.classList.remove('hidden');
|
||||
terminalBtn.classList.remove('hidden');
|
||||
} else {
|
||||
adminControls.classList.add('hidden');
|
||||
terminalBtn.classList.add('hidden');
|
||||
closeTerminal();
|
||||
}
|
||||
latestAdminLogs = Array.isArray(state.adminLogs) ? state.adminLogs : [];
|
||||
if (state.viewerIsAdmin && !terminalModalOverlay.classList.contains('hidden')) {
|
||||
renderTerminalLogs(latestAdminLogs);
|
||||
}
|
||||
|
||||
const votedCount = state.participants.filter((p) => p.connected && p.role === 'participant' && p.hasVoted).length;
|
||||
@@ -343,7 +391,19 @@ async function adminAction(action) {
|
||||
|
||||
revealBtn.addEventListener('click', () => adminAction('reveal'));
|
||||
resetBtn.addEventListener('click', () => adminAction('reset'));
|
||||
terminalBtn.addEventListener('click', openTerminal);
|
||||
terminalCloseBtn.addEventListener('click', closeTerminal);
|
||||
terminalModalOverlay.addEventListener('click', (event) => {
|
||||
if (event.target === terminalModalOverlay) {
|
||||
closeTerminal();
|
||||
}
|
||||
});
|
||||
shareAdminToggle.addEventListener('change', updateShareLink);
|
||||
window.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Escape') {
|
||||
closeTerminal();
|
||||
}
|
||||
});
|
||||
|
||||
joinForm.addEventListener('submit', async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
Reference in New Issue
Block a user