Theme
This commit is contained in:
@@ -33,12 +33,13 @@ const joinAdminTokenInput = document.getElementById('join-admin-token');
|
||||
const joinError = document.getElementById('join-error');
|
||||
let participantID = params.get('participantId') || '';
|
||||
let adminToken = params.get('adminToken') || '';
|
||||
const prefillUsername = params.get('username') || '';
|
||||
let eventSource = null;
|
||||
let latestLinks = { participantLink: '', adminLink: '' };
|
||||
let latestAdminLogs = [];
|
||||
|
||||
const savedUsername = localStorage.getItem(USERNAME_KEY) || '';
|
||||
joinUsernameInput.value = savedUsername;
|
||||
joinUsernameInput.value = prefillUsername || savedUsername;
|
||||
joinAdminTokenInput.value = adminToken;
|
||||
|
||||
if (!window.CardUI || typeof window.CardUI.appendFace !== 'function') {
|
||||
@@ -59,6 +60,8 @@ function setJoinError(message) {
|
||||
|
||||
function updateURL() {
|
||||
const next = new URL(window.location.href);
|
||||
next.searchParams.delete('username');
|
||||
|
||||
if (participantID) {
|
||||
next.searchParams.set('participantId', participantID);
|
||||
} else {
|
||||
@@ -103,6 +106,7 @@ async function joinRoom({ username, role, password, participantIdOverride }) {
|
||||
localStorage.setItem(USERNAME_KEY, data.username);
|
||||
updateURL();
|
||||
setJoinError('');
|
||||
return data;
|
||||
}
|
||||
|
||||
function renderParticipants(participants, isRevealed) {
|
||||
@@ -114,12 +118,14 @@ function renderParticipants(participants, isRevealed) {
|
||||
item.className = 'participant-item';
|
||||
|
||||
const name = document.createElement('span');
|
||||
name.className = 'participant-name';
|
||||
let label = participant.username;
|
||||
if (participant.id === participantID) {
|
||||
label += ' (You)';
|
||||
}
|
||||
if (participant.isAdmin) {
|
||||
label += ' [Admin]';
|
||||
name.classList.add('is-admin');
|
||||
}
|
||||
name.textContent = label;
|
||||
|
||||
@@ -247,6 +253,7 @@ function renderCards(cards, participants, isRevealed) {
|
||||
card.classList.remove('impact');
|
||||
void card.offsetWidth;
|
||||
card.classList.add('impact');
|
||||
spawnVoteParticles(card);
|
||||
castVote(value);
|
||||
});
|
||||
|
||||
@@ -254,6 +261,26 @@ function renderCards(cards, participants, isRevealed) {
|
||||
});
|
||||
}
|
||||
|
||||
function spawnVoteParticles(card) {
|
||||
const particleCount = 12;
|
||||
for (let i = 0; i < particleCount; i += 1) {
|
||||
const particle = document.createElement('span');
|
||||
particle.className = 'vote-particle';
|
||||
|
||||
const angle = (Math.PI * 2 * i) / particleCount + (Math.random() * 0.4 - 0.2);
|
||||
const distance = 18 + Math.random() * 26;
|
||||
const dx = Math.cos(angle) * distance;
|
||||
const dy = Math.sin(angle) * distance;
|
||||
|
||||
particle.style.setProperty('--tx', `${dx.toFixed(2)}px`);
|
||||
particle.style.setProperty('--ty', `${dy.toFixed(2)}px`);
|
||||
particle.style.setProperty('--hue', `${Math.floor(Math.random() * 80) + 90}`);
|
||||
|
||||
particle.addEventListener('animationend', () => particle.remove(), { once: true });
|
||||
card.appendChild(particle);
|
||||
}
|
||||
}
|
||||
|
||||
function formatLogTime(raw) {
|
||||
const parsed = new Date(raw);
|
||||
if (Number.isNaN(parsed.getTime())) {
|
||||
@@ -417,12 +444,17 @@ joinForm.addEventListener('submit', async (event) => {
|
||||
adminToken = joinAdminTokenInput.value.trim();
|
||||
|
||||
try {
|
||||
await joinRoom({
|
||||
const result = await joinRoom({
|
||||
username,
|
||||
role: joinRoleInput.value,
|
||||
password: joinPasswordInput.value,
|
||||
participantIdOverride: participantID,
|
||||
});
|
||||
if (result.isAdmin) {
|
||||
const adminRoomURL = `/room/${encodeURIComponent(roomID)}?participantId=${encodeURIComponent(participantID)}&adminToken=${encodeURIComponent(adminToken)}`;
|
||||
window.location.assign(adminRoomURL);
|
||||
return;
|
||||
}
|
||||
connectSSE();
|
||||
} catch (err) {
|
||||
if (participantID) {
|
||||
@@ -433,6 +465,27 @@ joinForm.addEventListener('submit', async (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
async function tryAutoJoinExistingParticipant() {
|
||||
if (!participantID) {
|
||||
return;
|
||||
}
|
||||
|
||||
const username = joinUsernameInput.value.trim() || prefillUsername || 'host';
|
||||
|
||||
try {
|
||||
await joinRoom({
|
||||
username,
|
||||
role: 'participant',
|
||||
password: joinPasswordInput.value,
|
||||
participantIdOverride: participantID,
|
||||
});
|
||||
connectSSE();
|
||||
} catch (_err) {
|
||||
participantID = '';
|
||||
updateURL();
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('pagehide', () => {
|
||||
if (!participantID) {
|
||||
return;
|
||||
@@ -441,3 +494,5 @@ window.addEventListener('pagehide', () => {
|
||||
const payload = JSON.stringify({ participantId: participantID });
|
||||
navigator.sendBeacon(`/api/rooms/${encodeURIComponent(roomID)}/leave`, new Blob([payload], { type: 'application/json' }));
|
||||
});
|
||||
|
||||
void tryAutoJoinExistingParticipant();
|
||||
|
||||
Reference in New Issue
Block a user