alpha-base3_pass2

This commit is contained in:
Flatlogic Bot 2026-03-06 18:57:50 +00:00
parent c7011b706f
commit 9f4d000c39
2 changed files with 74 additions and 8 deletions

View File

@ -27,6 +27,9 @@ const app = {
// Relay State
currentParticipant: 1,
participantNames: [],
relayParticipantStartTime: 0,
relayParticipantElapsed: 0,
relayColors: ['#3b82f6', '#10b981', '#ef4444', '#f59e0b', '#8b5cf6', '#ec4899', '#06b6d4', '#f97316', '#14b8a6', '#6366f1', '#a855f7', '#d946ef'],
// Custom State
customActivities: [
@ -63,6 +66,7 @@ const app = {
landingClock: document.getElementById('landing-clock'),
mainTimer: document.getElementById('main-timer'),
subTimer: document.getElementById('sub-timer'),
relayParticipantTimer: document.getElementById('relay-participant-timer'),
viewLanding: document.getElementById('view-landing'),
viewTimer: document.getElementById('view-timer'),
timerTitle: document.getElementById('timer-title'),
@ -135,6 +139,7 @@ const app = {
init() {
console.log('Timer App Initializing...');
this.initDarkMode();
this.shuffleRelayColors();
this.updateLandingClock();
this.bindEvents();
this.renderCustomBuilder();
@ -143,6 +148,13 @@ const app = {
this.bindKeyboardShortcuts();
},
shuffleRelayColors() {
for (let i = this.relayColors.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[this.relayColors[i], this.relayColors[j]] = [this.relayColors[j], this.relayColors[i]];
}
},
bindKeyboardShortcuts() {
document.addEventListener('keydown', (e) => {
if (this.currentView !== 'timer' || !this.currentMode) return;
@ -155,10 +167,18 @@ const app = {
if (e.key === ' ' || e.code === 'Space') {
e.preventDefault();
if (!this.isRunning || this.isPaused) {
this.handleStartClick();
if (this.currentMode === 'lap') {
if (!this.isRunning || this.isPaused) {
this.handleStartClick();
} else {
this.recordLap();
}
} else {
this.pauseTimer();
if (!this.isRunning || this.isPaused) {
this.handleStartClick();
} else {
this.pauseTimer();
}
}
} else if (e.key === 'Escape' || e.code === 'Escape') {
e.preventDefault();
@ -232,7 +252,15 @@ const app = {
}
});
this.el.toggleDisplayMode.addEventListener('change', () => this.updateDisplay());
this.el.toggleDisplayMode.addEventListener('change', () => {
const label = this.el.displayModeContainer.querySelector('label');
if (this.el.toggleDisplayMode.checked) {
label.textContent = 'Activity Progress';
} else {
label.textContent = 'Timer Progress';
}
this.updateDisplay();
});
},
updateLandingClock() {
@ -286,6 +314,10 @@ const app = {
this.el.savedTimersContainer.classList.remove('d-none');
this.el.relayConfig.classList.add('d-none');
this.el.displayModeContainer.classList.remove('d-none');
// Set initial label based on toggle state
const label = this.el.displayModeContainer.querySelector('label');
label.textContent = this.el.toggleDisplayMode.checked ? 'Activity Progress' : 'Timer Progress';
} else if (mode.hasRelay) {
this.el.customBuilder.classList.add('d-none');
this.el.relayConfig.classList.remove('d-none');
@ -310,6 +342,7 @@ const app = {
this.el.restAlertContainer.classList.toggle('d-none', !mode.isCustom);
this.el.activeActivityName.classList.add('d-none');
this.el.relayActiveParticipantContainer.classList.add('d-none');
this.el.relayParticipantTimer.classList.add('d-none');
// Options Dropdown visibility logic
this.el.optionsDropdown.classList.toggle('d-none', modeKey === 'time-watch');
@ -367,9 +400,8 @@ const app = {
this.el.participantCount.value = count;
let html = '';
const colors = ['#3b82f6', '#10b981', '#ef4444', '#f59e0b', '#8b5cf6', '#ec4899', '#06b6d4', '#f97316', '#14b8a6', '#6366f1', '#a855f7', '#d946ef'];
for (let i = 1; i <= count; i++) {
const defaultColor = colors[(i - 1) % colors.length];
const defaultColor = this.relayColors[(i - 1) % this.relayColors.length];
html += `
<div class="input-group input-group-sm">
<span class="input-group-text fs-tiny">#${i}</span>
@ -482,13 +514,23 @@ const app = {
this.el.relayActiveParticipantContainer.classList.remove('d-none');
this.el.relayParticipantCountBox.classList.add('d-none');
this.updateRelayActiveDisplay();
this.relayParticipantStartTime = now;
this.relayParticipantElapsed = 0;
this.el.relayParticipantTimer.classList.add('d-none');
}
if (this.isPaused) {
const offset = (isCountdownMode) ? (this.countdownStartValue - this.elapsedTime) : this.elapsedTime;
this.startTime = now - offset;
if (mode.hasRelay) {
this.relayParticipantStartTime = now - this.relayParticipantElapsed;
}
} else {
this.startTime = now;
if (mode.hasRelay) {
this.relayParticipantStartTime = now;
}
}
this.isRunning = true;
@ -520,6 +562,9 @@ const app = {
pauseTimer() {
if (!this.isRunning || this.isPaused) return;
const mode = this.modes[this.currentMode];
if (mode && !mode.allowPause) return;
this.isPaused = true;
this.pausedTime = this.elapsedTime;
@ -551,6 +596,7 @@ const app = {
this.el.btnReset.disabled = false;
this.el.mainTimer.classList.remove('timer-alert');
this.el.relayActiveParticipantContainer.classList.add('d-none');
this.el.relayParticipantTimer.classList.add('d-none');
if (this.currentMode === 'countdown') {
this.el.countdownInputs.classList.remove('d-none');
@ -584,6 +630,8 @@ const app = {
this.currentParticipant = 1;
this.currentActivityIndex = 0;
this.lastPlayedSecond = -1;
this.relayParticipantStartTime = 0;
this.relayParticipantElapsed = 0;
this.el.listBody.innerHTML = '';
this.el.mainTimer.classList.remove('timer-finish');
@ -598,6 +646,7 @@ const app = {
this.el.btnRelaySplit.disabled = false;
this.el.activeActivityName.classList.add('d-none');
this.el.relayActiveParticipantContainer.classList.add('d-none');
this.el.relayParticipantTimer.classList.add('d-none');
this.el.relayParticipantCountBox.classList.remove('d-none');
this.el.sessionTitle.disabled = false;
@ -697,6 +746,10 @@ const app = {
} else {
// Standard count up
this.elapsedTime = now - this.startTime;
if (mode.hasRelay) {
this.relayParticipantElapsed = now - this.relayParticipantStartTime;
}
}
this.updateDisplay();
@ -782,6 +835,10 @@ const app = {
this.el.mainTimer.textContent = this.formatTime(ms, format);
}
this.el.subTimer.classList.add('d-none');
if (this.currentMode === 'relay' && !this.el.relayParticipantTimer.classList.contains('d-none')) {
this.el.relayParticipantTimer.textContent = this.formatTime(this.relayParticipantElapsed, 'hh:mm:ss.ms');
}
},
getTotalProgress() {
@ -854,6 +911,7 @@ const app = {
const maxParticipants = parseInt(this.el.participantCount.value) || 1;
if (this.currentParticipant > maxParticipants) {
this.el.relayActiveParticipantContainer.classList.add('d-none');
this.el.relayParticipantTimer.classList.add('d-none');
return;
}
@ -882,6 +940,11 @@ const app = {
const colorInput = document.querySelector(`.participant-color-input[data-index="${this.currentParticipant}"]`);
const color = colorInput ? colorInput.value : '#3b82f6';
// Show secondary timer after first split
if (this.history.length >= 0) {
this.el.relayParticipantTimer.classList.remove('d-none');
}
// If it's the last participant, mark as final but keep their name
if (this.currentParticipant === maxParticipants) {
isFinal = true;
@ -901,6 +964,8 @@ const app = {
if (!isFinal) {
this.currentParticipant++;
this.updateRelayActiveDisplay();
this.relayParticipantStartTime = performance.now();
this.relayParticipantElapsed = 0;
} else {
this.stopTimer();
this.el.btnRelaySplit.disabled = true;
@ -1283,4 +1348,4 @@ const app = {
};
// Start the app
document.addEventListener('DOMContentLoaded', () => app.init());
document.addEventListener('DOMContentLoaded', () => app.init());

View File

@ -293,13 +293,14 @@ $projectImage = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
</div>
<div class="timer-display font-tabular mb-2" id="main-timer">00:00:00</div>
<div class="timer-relay-participant font-tabular mb-4 d-none" id="relay-participant-timer" style="font-size: 2.5rem; opacity: 0.8;">00:00:00.00</div>
<div class="timer-sub-display font-tabular mb-4 d-none" id="sub-timer">00:00:00</div>
<!-- Controls -->
<!-- Toggle Display Mode -->
<div id="display-mode-container" class="form-check form-switch d-flex justify-content-center mb-3 d-none">
<input class="form-check-input me-2" type="checkbox" id="toggle-display-mode">
<label class="form-check-label small text-muted text-uppercase tracking-wider" for="toggle-display-mode">Show Total Progress</label>
<label class="form-check-label small text-muted text-uppercase tracking-wider" for="toggle-display-mode">Activity Progress</label>
</div>
<div class="d-flex justify-content-center flex-wrap gap-2 mb-5">
<button id="btn-start" class="btn btn-primary btn-precise px-4">Start</button>