Compare commits
11 Commits
22c4d28b42
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a1c494ade | ||
| d9b2c5ee22 | |||
| 57c5f4e054 | |||
| 3c0ca7843f | |||
| a135746e37 | |||
| 56ecfaad54 | |||
| 1ad1d96cb2 | |||
| 1a2dc295e1 | |||
| 9d34d648d8 | |||
| 7e52e1768b | |||
| 3dc9bdcc21 |
31
.replit
Normal file
31
.replit
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
modules = ["bun-1.3"]
|
||||||
|
[agent]
|
||||||
|
expertMode = true
|
||||||
|
|
||||||
|
[workflows]
|
||||||
|
runButton = "Project"
|
||||||
|
|
||||||
|
[[workflows.workflow]]
|
||||||
|
name = "Project"
|
||||||
|
mode = "parallel"
|
||||||
|
author = "agent"
|
||||||
|
|
||||||
|
[[workflows.workflow.tasks]]
|
||||||
|
task = "workflow.run"
|
||||||
|
args = "Start application"
|
||||||
|
|
||||||
|
[[workflows.workflow]]
|
||||||
|
name = "Start application"
|
||||||
|
author = "agent"
|
||||||
|
|
||||||
|
[[workflows.workflow.tasks]]
|
||||||
|
task = "shell.exec"
|
||||||
|
args = "PORT=5000 bun --hot run src/server.ts"
|
||||||
|
waitForPort = 5000
|
||||||
|
|
||||||
|
[workflows.workflow.metadata]
|
||||||
|
outputType = "webview"
|
||||||
|
|
||||||
|
[[ports]]
|
||||||
|
localPort = 5000
|
||||||
|
externalPort = 80
|
||||||
@@ -178,7 +178,7 @@
|
|||||||
<span class="side-hint">SEC</span>
|
<span class="side-hint">SEC</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tog-row">
|
<div class="tog-row">
|
||||||
<div class="lbl">TIMER</div>
|
<div class="lbl">LINK TIMER</div>
|
||||||
<label class="tog">
|
<label class="tog">
|
||||||
<input type="checkbox" id="timer-tog" onchange="toggleTimerFromSwitch()" /><span class="tog-track"></span>
|
<input type="checkbox" id="timer-tog" onchange="toggleTimerFromSwitch()" /><span class="tog-track"></span>
|
||||||
</label>
|
</label>
|
||||||
@@ -232,7 +232,7 @@
|
|||||||
<div id="tab-buzzer">
|
<div id="tab-buzzer">
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<div class="panel-title">BUZZ ORDER</div>
|
<div class="panel-title">BUZZ ORDER</div>
|
||||||
<div class="empty" id="mod-bz-empty">No buzzes — open a round to begin.</div>
|
<div class="empty" id="mod-bz-empty">No buzzes</div>
|
||||||
<div class="buzz-list" id="mod-bz-list"></div>
|
<div class="buzz-list" id="mod-bz-list"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -86,6 +86,11 @@ function handle(msg){
|
|||||||
room=msg.room;
|
room=msg.room;
|
||||||
if(role==='mod'){renderMod();renderRoundButtons();}
|
if(role==='mod'){renderMod();renderRoundButtons();}
|
||||||
else{renderPlayerBuzzer();startPlayerTimer();}
|
else{renderPlayerBuzzer();startPlayerTimer();}
|
||||||
|
// If timer is enabled and this is a fresh open, load the timer
|
||||||
|
if(room.settings.timerSeconds>0 && modTimerRemaining===0 && !modTimerRunning){
|
||||||
|
modTimerRemaining=room.settings.timerSeconds;
|
||||||
|
renderModTimerDisplay();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'round_closed':
|
case 'round_closed':
|
||||||
room=msg.room;
|
room=msg.room;
|
||||||
@@ -96,15 +101,6 @@ function handle(msg){
|
|||||||
room=msg.room;
|
room=msg.room;
|
||||||
if(role==='mod'){renderMod();renderRoundButtons();}else renderPlayerBuzzer();
|
if(role==='mod'){renderMod();renderRoundButtons();}else renderPlayerBuzzer();
|
||||||
break;
|
break;
|
||||||
case 'round_closed':
|
|
||||||
room=msg.room;
|
|
||||||
if(role==='mod')renderMod();
|
|
||||||
else{renderPlayerBuzzer();stopPlayerTimer();toast('ROUND CLOSED','warn');}
|
|
||||||
break;
|
|
||||||
case 'buzzer_reset':
|
|
||||||
room=msg.room;
|
|
||||||
if(role==='mod')renderMod();else renderPlayerBuzzer();
|
|
||||||
break;
|
|
||||||
case 'buzz_event':
|
case 'buzz_event':
|
||||||
room=msg.room;
|
room=msg.room;
|
||||||
if(role==='mod'){renderMod();renderRoundButtons();}else{renderPlayerBuzzer();addFeed(msg);}
|
if(role==='mod'){renderMod();renderRoundButtons();}else{renderPlayerBuzzer();addFeed(msg);}
|
||||||
@@ -303,13 +299,11 @@ function modTimerToggle(){
|
|||||||
if(modTimerRunning){
|
if(modTimerRunning){
|
||||||
clearInterval(modTimerInterval);modTimerRunning=false;
|
clearInterval(modTimerInterval);modTimerRunning=false;
|
||||||
document.getElementById('btn-timer-ss').textContent='START';
|
document.getElementById('btn-timer-ss').textContent='START';
|
||||||
document.getElementById('timer-tog').checked=false;
|
|
||||||
broadcastTimerToPlayers(modTimerRemaining,false);
|
broadcastTimerToPlayers(modTimerRemaining,false);
|
||||||
} else {
|
} else {
|
||||||
if(modTimerRemaining<=0)modTimerLoad();
|
if(modTimerRemaining<=0)modTimerLoad();
|
||||||
modTimerRunning=true;
|
modTimerRunning=true;
|
||||||
document.getElementById('btn-timer-ss').textContent='PAUSE';
|
document.getElementById('btn-timer-ss').textContent='PAUSE';
|
||||||
document.getElementById('timer-tog').checked=true;
|
|
||||||
broadcastTimerToPlayers(modTimerRemaining,true);
|
broadcastTimerToPlayers(modTimerRemaining,true);
|
||||||
modTimerInterval=setInterval(()=>{
|
modTimerInterval=setInterval(()=>{
|
||||||
modTimerRemaining--;
|
modTimerRemaining--;
|
||||||
@@ -318,7 +312,37 @@ function modTimerToggle(){
|
|||||||
if(modTimerRemaining<=0){
|
if(modTimerRemaining<=0){
|
||||||
clearInterval(modTimerInterval);modTimerRunning=false;
|
clearInterval(modTimerInterval);modTimerRunning=false;
|
||||||
document.getElementById('btn-timer-ss').textContent='START';
|
document.getElementById('btn-timer-ss').textContent='START';
|
||||||
document.getElementById('timer-tog').checked=false;
|
ws_send({type:'close_round'});
|
||||||
|
toast('TIME UP — round closed','warn');
|
||||||
|
if(typeof gsap!=='undefined'){
|
||||||
|
gsap.to('#mod-timer-disp',{scale:1.08,duration:0.1,yoyo:true,repeat:3,ease:'power2.inOut'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleTimer(){
|
||||||
|
modTimerToggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
function modTimerToggle(){
|
||||||
|
if(modTimerRunning){
|
||||||
|
clearInterval(modTimerInterval);modTimerRunning=false;
|
||||||
|
document.getElementById('btn-timer-ss').textContent='START';
|
||||||
|
broadcastTimerToPlayers(modTimerRemaining,false);
|
||||||
|
} else {
|
||||||
|
if(modTimerRemaining<=0)modTimerLoad();
|
||||||
|
modTimerRunning=true;
|
||||||
|
document.getElementById('btn-timer-ss').textContent='PAUSE';
|
||||||
|
broadcastTimerToPlayers(modTimerRemaining,true);
|
||||||
|
modTimerInterval=setInterval(()=>{
|
||||||
|
modTimerRemaining--;
|
||||||
|
renderModTimerDisplay();
|
||||||
|
broadcastTimerToPlayers(modTimerRemaining,true);
|
||||||
|
if(modTimerRemaining<=0){
|
||||||
|
clearInterval(modTimerInterval);modTimerRunning=false;
|
||||||
|
document.getElementById('btn-timer-ss').textContent='START';
|
||||||
ws_send({type:'close_round'});
|
ws_send({type:'close_round'});
|
||||||
toast('TIME UP — round closed','warn');
|
toast('TIME UP — round closed','warn');
|
||||||
if(typeof gsap!=='undefined'){
|
if(typeof gsap!=='undefined'){
|
||||||
@@ -338,23 +362,20 @@ function renderModTimerDisplay(){
|
|||||||
const s=modTimerRemaining;
|
const s=modTimerRemaining;
|
||||||
el.textContent=fmtTime(s);
|
el.textContent=fmtTime(s);
|
||||||
el.className='timer-digits'+(s<=5?' danger':s<=10?' warn':'');
|
el.className='timer-digits'+(s<=5?' danger':s<=10?' warn':'');
|
||||||
const tog=document.getElementById('timer-tog');
|
|
||||||
if(tog)tog.checked=modTimerRunning;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function modTimerLoad(){
|
function modTimerLoad(){
|
||||||
modTimerRemaining=Math.max(5,parseInt(document.getElementById('mod-timer-set').value)||30);
|
const sec=parseInt(document.getElementById('mod-timer-set').value)||30;
|
||||||
|
modTimerRemaining=sec;
|
||||||
modTimerRunning=false;
|
modTimerRunning=false;
|
||||||
clearInterval(modTimerInterval);
|
clearInterval(modTimerInterval);
|
||||||
document.getElementById('btn-timer-ss').textContent='START';
|
document.getElementById('btn-timer-ss').textContent='START';
|
||||||
document.getElementById('timer-tog').checked=false;
|
|
||||||
renderModTimerDisplay();
|
renderModTimerDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
function modTimerReset(){
|
function modTimerReset(){
|
||||||
clearInterval(modTimerInterval);
|
clearInterval(modTimerInterval);
|
||||||
modTimerRunning=false;
|
modTimerRunning=false;
|
||||||
document.getElementById('timer-tog').checked=false;
|
|
||||||
modTimerRemaining=Math.max(5,parseInt(document.getElementById('mod-timer-set').value)||30);
|
modTimerRemaining=Math.max(5,parseInt(document.getElementById('mod-timer-set').value)||30);
|
||||||
renderModTimerDisplay();
|
renderModTimerDisplay();
|
||||||
broadcastTimerToPlayers(modTimerRemaining,false);
|
broadcastTimerToPlayers(modTimerRemaining,false);
|
||||||
@@ -372,19 +393,59 @@ function broadcastTimerToPlayers(sec,running){
|
|||||||
// MOD ROUND CONTROL
|
// MOD ROUND CONTROL
|
||||||
// ══════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════
|
||||||
function toggleRound(){
|
function toggleRound(){
|
||||||
// Toggle: Open if closed, Close if open
|
|
||||||
if(room.buzzerState.roundOpen){
|
if(room.buzzerState.roundOpen){
|
||||||
ws_send({type:'close_round'});
|
ws_send({type:'close_round'});
|
||||||
|
// If linked (toggle ON) and timer running, pause it
|
||||||
|
if(document.getElementById('timer-tog').checked && modTimerRunning){
|
||||||
|
modTimerToggle();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ws_send({type:'open_round'});
|
ws_send({type:'open_round'});
|
||||||
|
// If linked (toggle ON) and timer stopped, reset and start it
|
||||||
|
if(document.getElementById('timer-tog').checked && !modTimerRunning){
|
||||||
|
modTimerLoad();
|
||||||
|
modTimerRunning=true;
|
||||||
|
document.getElementById('btn-timer-ss').textContent='PAUSE';
|
||||||
|
modTimerInterval=setInterval(()=>{
|
||||||
|
modTimerRemaining--;
|
||||||
|
renderModTimerDisplay();
|
||||||
|
broadcastTimerToPlayers(modTimerRemaining,true);
|
||||||
|
if(modTimerRemaining<=0){
|
||||||
|
clearInterval(modTimerInterval);modTimerRunning=false;
|
||||||
|
document.getElementById('btn-timer-ss').textContent='START';
|
||||||
|
ws_send({type:'close_round'});
|
||||||
|
toast('TIME UP — round closed','warn');
|
||||||
|
}
|
||||||
|
},1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resumeRound(){
|
function resumeRound(){
|
||||||
// Open round WITHOUT clearing existing buzzes (for accidental close recovery)
|
|
||||||
ws_send({type:'resume_round'});
|
ws_send({type:'resume_round'});
|
||||||
|
// If linked (toggle ON) and timer stopped, resume it (preserve current value)
|
||||||
|
if(document.getElementById('timer-tog').checked && !modTimerRunning){
|
||||||
|
modTimerRunning=true;
|
||||||
|
document.getElementById('btn-timer-ss').textContent='PAUSE';
|
||||||
|
broadcastTimerToPlayers(modTimerRemaining,true);
|
||||||
|
modTimerInterval=setInterval(()=>{
|
||||||
|
modTimerRemaining--;
|
||||||
|
renderModTimerDisplay();
|
||||||
|
broadcastTimerToPlayers(modTimerRemaining,true);
|
||||||
|
if(modTimerRemaining<=0){
|
||||||
|
clearInterval(modTimerInterval);modTimerRunning=false;
|
||||||
|
document.getElementById('btn-timer-ss').textContent='START';
|
||||||
|
ws_send({type:'close_round'});
|
||||||
|
toast('TIME UP — round closed','warn');
|
||||||
|
}
|
||||||
|
},1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ══════════════════════════════════════════════════════
|
||||||
|
// TIMER
|
||||||
|
// ══════════════════════════════════════════════════════
|
||||||
|
|
||||||
function renderRoundButtons(){
|
function renderRoundButtons(){
|
||||||
const btn=document.getElementById('mod-round-btn');
|
const btn=document.getElementById('mod-round-btn');
|
||||||
const resumeBtn=document.getElementById('mod-resume-btn');
|
const resumeBtn=document.getElementById('mod-resume-btn');
|
||||||
|
|||||||
Reference in New Issue
Block a user