Db sync and tips
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,6 +1,6 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
step_competition.db
|
# step_competition.db
|
||||||
*.db
|
# *.db
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
|
|||||||
@@ -1,10 +1,38 @@
|
|||||||
const API_URL = window.location.origin;
|
const API_URL = window.location.origin;
|
||||||
|
|
||||||
|
// Humorous step tips
|
||||||
|
const STEP_TIPS = [
|
||||||
|
"Never underestimate a 5-minute dance break. Your step count (and mood) will thank you.",
|
||||||
|
"Don't let the high-stepping jet-setters get you down. Focus on crushing whoever's ranked right above you.",
|
||||||
|
"Pacing while on phone calls counts. Your colleagues will understand the extra enthusiasm.",
|
||||||
|
"Pro tip: Park in the farthest spot. It's not laziness, it's strategy.",
|
||||||
|
"Taking the stairs? That's just vertical stepping with extra credit.",
|
||||||
|
"Your fitness tracker thinks you're training for a marathon. Let's not disappoint it.",
|
||||||
|
"Remember: Every journey to the fridge and back is an opportunity for greatness.",
|
||||||
|
"Walking meetings are just step competitions in disguise. You're welcome.",
|
||||||
|
"Forgot something upstairs? That's not forgetfulness, that's bonus cardio.",
|
||||||
|
"Why run when you can aggressively walk? Same steps, less judgment.",
|
||||||
|
"Your dog wants a walk. Your step count wants a walk. It's basically a win-win-woof.",
|
||||||
|
"A monster a day keeps the last place away.",
|
||||||
|
"Reading this tip instead of walking? Bold strategy. Let's see how it plays out.",
|
||||||
|
"Pro tip about tips: They're less effective if you're sitting down while reading them.",
|
||||||
|
"Winners log their steps before noon. Legends log them before breakfast. -Mike (probably)",
|
||||||
|
"Infrastructure as a Service is down? Legs as a Service is always running.",
|
||||||
|
"Strapping the tracker to a ceiling fan was attempted in 2019. It didn't work then either.",
|
||||||
|
"Following your dog around the house may not be the most efficient way to get steps, but it's definitely the most confusing for the dog.",
|
||||||
|
"Dancing in the school pickup line may not be the most efficient way to get steps, but it's definitely the most embarrassing for your kids.",
|
||||||
|
"4 out of 5 dentists agree: this has nothing to do with teeth, but walking is still good.",
|
||||||
|
"Rumor has it the winner of the last competition was just trying to learn the latest Katseye choreo.",
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
// State
|
// State
|
||||||
let teams = [];
|
let teams = [];
|
||||||
let participants = [];
|
let participants = [];
|
||||||
let charts = {};
|
let charts = {};
|
||||||
let selectedParticipant = null;
|
let selectedParticipant = null;
|
||||||
|
let currentTipIndex = 0;
|
||||||
|
let tipRotationInterval = null;
|
||||||
|
|
||||||
// Initialize app
|
// Initialize app
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
@@ -14,6 +42,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
setDefaultDate();
|
setDefaultDate();
|
||||||
handleRouting();
|
handleRouting();
|
||||||
checkAdminMode();
|
checkAdminMode();
|
||||||
|
initializeTipRotation();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Admin mode
|
// Admin mode
|
||||||
@@ -918,3 +947,59 @@ function formatDate(dateStr) {
|
|||||||
day: 'numeric'
|
day: 'numeric'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tip rotation functionality
|
||||||
|
function shuffleTips(array) {
|
||||||
|
// Fisher-Yates shuffle algorithm for true randomization
|
||||||
|
const shuffled = [...array];
|
||||||
|
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
|
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
||||||
|
}
|
||||||
|
return shuffled;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeTipRotation() {
|
||||||
|
// Clear any existing interval to prevent duplicates
|
||||||
|
if (tipRotationInterval) {
|
||||||
|
clearInterval(tipRotationInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuffle the tips array for randomized order
|
||||||
|
window.shuffledTips = shuffleTips(STEP_TIPS);
|
||||||
|
currentTipIndex = 0;
|
||||||
|
|
||||||
|
// Display first tip
|
||||||
|
displayTip();
|
||||||
|
|
||||||
|
// Rotate every 20 seconds
|
||||||
|
tipRotationInterval = setInterval(rotateTip, 20000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayTip() {
|
||||||
|
const tipTextElement = document.getElementById('tip-text');
|
||||||
|
if (!tipTextElement || !window.shuffledTips) return;
|
||||||
|
|
||||||
|
tipTextElement.textContent = window.shuffledTips[currentTipIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
function rotateTip() {
|
||||||
|
const tipTextElement = document.getElementById('tip-text');
|
||||||
|
if (!tipTextElement || !window.shuffledTips) return;
|
||||||
|
|
||||||
|
// Fade out
|
||||||
|
tipTextElement.classList.add('fade-out');
|
||||||
|
|
||||||
|
// After fade out, change text and fade in
|
||||||
|
setTimeout(() => {
|
||||||
|
currentTipIndex = (currentTipIndex + 1) % window.shuffledTips.length;
|
||||||
|
|
||||||
|
// If we've completed a full cycle, re-shuffle for next cycle
|
||||||
|
if (currentTipIndex === 0) {
|
||||||
|
window.shuffledTips = shuffleTips(STEP_TIPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
tipTextElement.textContent = window.shuffledTips[currentTipIndex];
|
||||||
|
tipTextElement.classList.remove('fade-out');
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,6 +20,12 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
<!-- Tip Banner -->
|
||||||
|
<div id="tip-banner" class="tip-banner">
|
||||||
|
<span class="tip-icon">💡</span>
|
||||||
|
<span id="tip-text" class="tip-text"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Log Your Steps Tab -->
|
<!-- Log Your Steps Tab -->
|
||||||
<div id="log-tab" class="tab-content active">
|
<div id="log-tab" class="tab-content active">
|
||||||
<div class="two-column-layout">
|
<div class="two-column-layout">
|
||||||
|
|||||||
@@ -39,6 +39,40 @@ header h1 {
|
|||||||
letter-spacing: 2px;
|
letter-spacing: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tip Banner */
|
||||||
|
.tip-banner {
|
||||||
|
background: linear-gradient(135deg, #8a2be2 0%, #ff7700 100%);
|
||||||
|
padding: 15px 30px;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
border-bottom: 2px solid #ff7700;
|
||||||
|
box-shadow: 0 4px 15px rgba(138, 43, 226, 0.3);
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-icon {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-text {
|
||||||
|
color: white;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.4;
|
||||||
|
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.3);
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-text.fade-out {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.header-logo {
|
.header-logo {
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -720,6 +754,19 @@ nav {
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tip-banner {
|
||||||
|
padding: 12px 20px;
|
||||||
|
min-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-text {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-icon {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.stats-grid {
|
.stats-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user