Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
1e1fa8a
120s
wangpatrick57 Jun 14, 2025
708484e
distractions
wangpatrick57 Jun 14, 2025
51cfb77
text
wangpatrick57 Jun 14, 2025
4681247
email in first screen
wangpatrick57 Jun 14, 2025
7786acb
modularized popup
wangpatrick57 Jun 14, 2025
d0e1ad6
moved distraction
wangpatrick57 Jun 14, 2025
9665a22
moved style to component
wangpatrick57 Jun 15, 2025
8d7acfe
script out of body
wangpatrick57 Jun 15, 2025
d74dd41
now appearing at 115s
wangpatrick57 Jun 15, 2025
a15295a
120
wangpatrick57 Jun 15, 2025
4d71016
no more gray blocking bg
wangpatrick57 Jun 15, 2025
74b6b58
load in random location
wangpatrick57 Jun 15, 2025
fefcf1c
moved logic and made it periodic
wangpatrick57 Jun 15, 2025
a109374
buffer and stop
wangpatrick57 Jun 15, 2025
e6ee675
now shows multiple emails
wangpatrick57 Jun 15, 2025
bf6202d
now behind
wangpatrick57 Jun 15, 2025
bb49d0b
closing now only closes yourself
wangpatrick57 Jun 15, 2025
1abd2a9
120
wangpatrick57 Jun 15, 2025
aba9075
now randomizing email contents
wangpatrick57 Jun 15, 2025
6de2359
no repeated emails
wangpatrick57 Jun 15, 2025
0d9f761
more emails
wangpatrick57 Jun 15, 2025
9e5bf24
moved email to js
wangpatrick57 Jun 15, 2025
7f8aeb0
email index persists across pages
wangpatrick57 Jun 15, 2025
c8de818
del to and time
wangpatrick57 Jun 15, 2025
84c9d78
id now based on index
wangpatrick57 Jun 15, 2025
94704f4
emails persist across screens
wangpatrick57 Jun 15, 2025
28cb06b
now showing popups at fixed times
wangpatrick57 Jun 15, 2025
127b8e6
email styling
wangpatrick57 Jun 15, 2025
70ea0bc
larger email
wangpatrick57 Jun 15, 2025
f68db0b
added sounds
wangpatrick57 Jun 15, 2025
28d4389
times up sd
wangpatrick57 Jun 15, 2025
8e3913a
time sounds
wangpatrick57 Jun 15, 2025
269dd05
thresholds
wangpatrick57 Jun 15, 2025
efad95d
Merge branch 'main' into demo-popups
wangpatrick57 Jul 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions demo/components/distractionEmail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<style>
/* Popup and email component styles */
.email-popup-overlay {
display: none;
position: fixed;
top: 0; left: 0;
width: 100vw; height: 100vh;
z-index: 1000;
pointer-events: none;
}
.email-popup-content {
background: #fff;
border-radius: 16px;
box-shadow: 0 4px 20px rgba(0,0,0,0.2);
padding: 0;
max-width: 800px;
width: 90vw;
position: absolute;
font-family: Arial, sans-serif;
border: 1px solid #d3d3d3;
pointer-events: auto;
}
.popup-close {
position: absolute;
top: 20px; right: 24px;
font-size: 36px;
color: #666;
cursor: pointer;
}
.email-header {
background: #ffebee;
border-bottom: 1px solid #ffcdd2;
padding: 36px 64px 24px 64px;
border-radius: 16px 16px 0 0;
}
.email-subject {
font-weight: bold;
font-size: 32px;
margin-bottom: 12px;
color: #c62828;
}
.email-meta {
font-family: 'Fira Mono', 'Consolas', 'Menlo', monospace;
font-size: 20px;
color: #d32f2f;
margin-bottom: 8px;
}
.email-body {
padding: 36px 64px 24px 64px;
color: #222;
font-size: 24px;
line-height: 1.6;
}
.email-signature {
padding: 0 64px 36px 64px;
color: #666;
font-size: 20px;
font-style: italic;
}
.email-link {
color: #d32f2f;
text-decoration: underline;
}
</style>

<div class="email-popup-overlay" id="distractionPopup" style="display:none;">
<div class="email-popup-content" id="distractionPopupContent">
<span class="popup-close" onclick="this.closest('.email-popup-overlay').style.display='none'">&times;</span>
<div class="email-header">
<div class="email-subject">{{subject}}</div>
<div class="email-meta">From: {{from}}</div>
</div>
<div class="email-body">
<p>{{body}}</p>
</div>
<div class="email-signature">
{{signature}}
</div>
</div>
</div>
22 changes: 11 additions & 11 deletions demo/components/timesUpPopup.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
<div id="timesUpPopup" class="popup-overlay" style="display: none;">
<div class="popup-content">
<h1>Time is Up!</h1>
<!-- Every file needs to implement saveToUserData() -->
<button id="timesUpPopupSubmitButton" onclick="saveToUserData(); window.location.href='submission.html';">Submit</button>
</div>
</div>

<style>
.popup-overlay {
.times-up-popup-overlay {
position: fixed;
top: 0;
left: 0;
Expand All @@ -20,9 +12,17 @@ <h1>Time is Up!</h1>
z-index: 1000;
}

.popup-content {
.times-up-popup-content {
color: white;
font-size: 2em;
text-align: center;
}
</style>
</style>

<div id="timesUpPopup" class="times-up-popup-overlay" style="display: none;">
<div class="times-up-popup-content">
<h1>Time is Up!</h1>
<!-- Every file needs to implement saveToUserData() -->
<button id="timesUpPopupSubmitButton" onclick="saveToUserData(); window.location.href='submission.html';">Submit</button>
</div>
</div>
191 changes: 191 additions & 0 deletions demo/js/distractionEmail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
// Global array of distraction emails
let distractionEmails = [
{
subject: "HELP! Database broken!",
from: "[email protected]",
body: "I think I broke the database... all the queries are slow. Should I turn it off and on again?",
signature: "- The Intern",
sound: new Audio("../sounds/youve-got-mail.mp3")
},
{
subject: "URGENT: Database Crisis",
from: "[email protected]",
body: "Fix the database now or you're fired. Customers are leaving.",
signature: "- Your CTO",
sound: new Audio("../sounds/futuristic-ding.mp3")
},
{
subject: "We need to talk about Alex",
from: "[email protected]",
body: "I've been seeing a lot of messages from someone named Alex. Who is this person? Are you hiding something from me?",
signature: "- Your Spouse",
sound: new Audio("../sounds/four-bells.mp3")
},
{
subject: "Your Replacement is Being Hired",
from: "[email protected]",
body: "I've already posted your job on LinkedIn. Better hurry up with that database fix if you want to keep it.",
signature: "- Your CTO",
sound: new Audio("../sounds/email.mp3")
},
{
subject: "Taking Over Database Fix",
from: "[email protected]",
body: "Hey, I've started working on the database fix. The CTO says I'll get your job if I solve it first. Just FYI 😉",
signature: "- Your 'Friend' at Work",
sound: new Audio("../sounds/boing.mp3")
},
{
subject: "Intern's Gone, You're Next",
from: "[email protected]",
body: "Just fired the intern for breaking the database. You're the only one left to blame. Clock is ticking.",
signature: "- Your CTO",
sound: new Audio("../sounds/tune.mp3")
}
];

// Initialize the email index from localStorage or default to 0
let currentEmailIndex = parseInt(localStorage.getItem('currentEmailIndex')) || 0;

// Get active popups from localStorage or initialize empty array
let activePopups = JSON.parse(localStorage.getItem('activePopups')) || [];

// Get shown thresholds from localStorage or initialize empty array
let shownThresholds = JSON.parse(localStorage.getItem('shownThresholds')) || [];

// Shared function to create and display a popup
function createPopup(popupInfo, position = null) {
// Play notification sound for new emails (not for restored ones)
if (!position) {
popupInfo.email.sound.play().catch(error => console.error("Error playing sound:", error));
}

return fetch('../components/distractionEmail.html')
.then(response => response.text())
.then(data => {
// Replace the static IDs with unique ones
data = data.replace('id="distractionPopup"', `id="${popupInfo.overlayId}"`);
data = data.replace('id="distractionPopupContent"', `id="${popupInfo.contentId}"`);

// Replace the email content
data = data.replace('{{subject}}', popupInfo.email.subject);
data = data.replace('{{from}}', popupInfo.email.from);
data = data.replace('{{body}}', popupInfo.email.body);
data = data.replace('{{signature}}', popupInfo.email.signature);

// Insert the popup
const timesUpContainer = document.getElementById('timesUpPopupContainer');
if (timesUpContainer) {
timesUpContainer.insertAdjacentHTML('beforebegin', data);
} else {
document.body.innerHTML += data;
}

// Show the popup
const overlay = document.getElementById(popupInfo.overlayId);
const popup = document.getElementById(popupInfo.contentId);
overlay.style.display = 'block';

// Position the popup
if (position) {
popup.style.left = position.left + 'px';
popup.style.top = position.top + 'px';
} else {
// Get viewport size
const vw = window.innerWidth;
const vh = window.innerHeight;

// Get popup size (after display:block)
popup.style.left = '0px';
popup.style.top = '0px';
const rect = popup.getBoundingClientRect();
const pw = rect.width;
const ph = rect.height;

// Add buffer zone (50px from edges)
const buffer = 50;
const maxLeft = Math.max(buffer, vw - pw - buffer);
const maxTop = Math.max(buffer, vh - ph - buffer);
const left = Math.random() * (maxLeft - buffer) + buffer;
const top = Math.random() * (maxTop - buffer) + buffer;

popup.style.left = left + 'px';
popup.style.top = top + 'px';

// Update position in popupInfo
popupInfo.position = { left, top };
localStorage.setItem('activePopups', JSON.stringify(activePopups));
}

// Add close handler
const closeBtn = overlay.querySelector('.popup-close');
closeBtn.onclick = function() {
overlay.style.display = 'none';
activePopups = activePopups.filter(p => p.id !== popupInfo.id);
localStorage.setItem('activePopups', JSON.stringify(activePopups));
};
})
.catch(error => console.error("Error creating popup:", error));
}

function showDistractionPopup() {
// Get the next email in sequence
const email = distractionEmails[currentEmailIndex];
currentEmailIndex = (currentEmailIndex + 1) % distractionEmails.length;
localStorage.setItem('currentEmailIndex', currentEmailIndex.toString());

// Generate unique IDs for this popup instance
const uniqueId = 'distraction_' + currentEmailIndex;
const overlayId = uniqueId + '_overlay';
const contentId = uniqueId + '_content';

// Store popup info in activePopups
const popupInfo = {
id: uniqueId,
overlayId: overlayId,
contentId: contentId,
email: email,
position: null
};
activePopups.push(popupInfo);
localStorage.setItem('activePopups', JSON.stringify(activePopups));

// Create and show the popup
createPopup(popupInfo);
}

// Function to restore active popups
function restoreActivePopups() {
activePopups.forEach(popupInfo => {
createPopup(popupInfo, popupInfo.position);
});
}

// Start showing popups based on remaining time
window.addEventListener('DOMContentLoaded', function() {
// Restore any existing popups first
restoreActivePopups();

// Check timer every second
const checkInterval = setInterval(() => {
const timerDisplay = document.getElementById('timerDisplay');
const timeText = timerDisplay.innerText;
const remainingTime = parseFloat(timeText);

if (remainingTime <= 0) {
clearInterval(checkInterval);
return;
}

// Show popups at specific time thresholds (85s, 70s, etc.)
const thresholds = [110, 90, 70, 50, 30, 10];
// const thresholds = [118, 116, 114, 112, 110, 108];
thresholds.forEach(threshold => {
if (remainingTime <= threshold && !shownThresholds.includes(threshold)) {
showDistractionPopup();
shownThresholds.push(threshold);
localStorage.setItem('shownThresholds', JSON.stringify(shownThresholds));
}
});
}, 500);
});
56 changes: 52 additions & 4 deletions demo/js/timer.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,41 @@
// Constant for the total timer duration in seconds
// Remember to update welcome.html to match this value
const TIMER_DURATION = 60;
const TIMER_DURATION = 120;

let timerInterval;
let hasPlayedSound = false;
let clockSound = null;
const timesUpSound = new Audio('../sounds/times-up.mp3');

// Add CSS for flashing animation
const style = document.createElement('style');
style.textContent = `
@keyframes flash {
0% { color: white; }
50% { color: red; }
100% { color: white; }
}
.flashing {
animation: flash 1s infinite;
}
`;
document.head.appendChild(style);

function startClockSound() {
if (!clockSound) {
clockSound = new Audio('../sounds/clock.mp3');
clockSound.loop = true;
clockSound.play().catch(error => console.error("Error playing clock sound:", error));
}
}

function stopClockSound() {
if (clockSound) {
clockSound.pause();
clockSound.currentTime = 0;
clockSound = null;
}
}

function startTimer() {
const startTime = Date.now();
Expand Down Expand Up @@ -30,14 +63,29 @@ function clearTimer() {
function setText(startTime) {
if (!startTime) {
document.getElementById('timerDisplay').innerText = `${TIMER_DURATION}.0s Remaining`;
document.getElementById('timerDisplay').classList.remove('flashing');
stopClockSound();
} else {
const elapsedTime = (Date.now() - startTime) / 1000; // in seconds
const remainingTime = Math.max(0, TIMER_DURATION - elapsedTime);
document.getElementById('timerDisplay').innerText = `${remainingTime.toFixed(1)}s Remaining`;
const timerDisplay = document.getElementById('timerDisplay');
timerDisplay.innerText = `${remainingTime.toFixed(1)}s Remaining`;

// Add flashing effect and clock sound when 10 seconds or less remain
if (remainingTime <= 10 && remainingTime > 0) {
timerDisplay.classList.add('flashing');
startClockSound();
} else {
timerDisplay.classList.remove('flashing');
stopClockSound();
}

// Show the popup when time is up
if (remainingTime <= 0) {
// Show the popup and play sound when time is up
if (remainingTime <= 0 && !hasPlayedSound) {
document.getElementById('timesUpPopup').style.display = 'flex';
timesUpSound.play().catch(error => console.error("Error playing sound:", error));
hasPlayedSound = true;
stopClockSound();
}
}
}
Expand Down
Loading
Loading