Skip to content

Commit 9c07658

Browse files
authored
1 parent 1e1e759 commit 9c07658

File tree

1 file changed

+179
-6
lines changed

1 file changed

+179
-6
lines changed

pomodoro.html

+179-6
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@
88
body {
99
font-family: Arial, sans-serif;
1010
display: flex;
11-
justify-content: center;
11+
flex-direction: column;
1212
align-items: center;
13-
height: 100vh;
14-
margin: 0;
13+
padding: 2rem;
1514
background-color: #f0f0f0;
1615
}
1716
.container {
@@ -20,12 +19,13 @@
2019
padding: 2rem;
2120
border-radius: 10px;
2221
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
22+
margin-bottom: 2rem;
2323
}
2424
#timer {
2525
font-size: 4rem;
2626
margin-bottom: 1rem;
2727
}
28-
button, select {
28+
button, select, input {
2929
font-size: 1rem;
3030
padding: 0.5rem 1rem;
3131
margin: 0.5rem;
@@ -41,11 +41,11 @@
4141
#startBtn:hover {
4242
background-color: #45a049;
4343
}
44-
#resetBtn {
44+
#resetBtn, #endBtn {
4545
background-color: #f44336;
4646
color: white;
4747
}
48-
#resetBtn:hover {
48+
#resetBtn:hover, #endBtn:hover {
4949
background-color: #da190b;
5050
}
5151
select {
@@ -55,11 +55,43 @@
5555
select:hover {
5656
background-color: #2980b9;
5757
}
58+
#goalInput {
59+
width: 100%;
60+
padding: 0.5rem;
61+
margin-bottom: 1rem;
62+
border: 1px solid #ccc;
63+
border-radius: 5px;
64+
}
65+
#sessionLog {
66+
width: 100%;
67+
max-width: 800px;
68+
margin-top: 2rem;
69+
overflow-x: auto;
70+
}
71+
#sessionLog table {
72+
width: 100%;
73+
border-collapse: collapse;
74+
}
75+
#sessionLog th, #sessionLog td {
76+
border: 1px solid #ddd;
77+
padding: 8px;
78+
text-align: left;
79+
}
80+
#sessionLog th {
81+
background-color: #f2f2f2;
82+
}
83+
#jsonOutput {
84+
width: 100%;
85+
height: 200px;
86+
margin-top: 2rem;
87+
font-family: monospace;
88+
}
5889
</style>
5990
</head>
6091
<body>
6192
<div class="container">
6293
<h1>Pomodoro Timer</h1>
94+
<input type="text" id="goalInput" placeholder="Enter your goal for this session" required>
6395
<div id="timer">25:00</div>
6496
<select id="durationSelect">
6597
<option value="5">5 minutes</option>
@@ -74,18 +106,81 @@ <h1>Pomodoro Timer</h1>
74106
<br>
75107
<button id="startBtn">Start</button>
76108
<button id="resetBtn">Reset</button>
109+
<button id="endBtn">End Session</button>
110+
</div>
111+
112+
<div id="sessionLog">
113+
<h2>Session Log</h2>
114+
<table>
115+
<thead>
116+
<tr>
117+
<th>Goal</th>
118+
<th>Start Time</th>
119+
<th>End Time</th>
120+
<th>Duration</th>
121+
<th>Pauses</th>
122+
</tr>
123+
</thead>
124+
<tbody id="sessionLogBody"></tbody>
125+
</table>
77126
</div>
78127

128+
<textarea id="jsonOutput" readonly></textarea>
129+
79130
<script>
80131
const timerDisplay = document.getElementById('timer');
81132
const startBtn = document.getElementById('startBtn');
82133
const resetBtn = document.getElementById('resetBtn');
134+
const endBtn = document.getElementById('endBtn');
83135
const durationSelect = document.getElementById('durationSelect');
136+
const goalInput = document.getElementById('goalInput');
137+
const sessionLogBody = document.getElementById('sessionLogBody');
138+
const jsonOutput = document.getElementById('jsonOutput');
84139

85140
let startTime;
86141
let timeLeft = 25 * 60; // Default to 25 minutes in seconds
87142
let isRunning = false;
88143
let duration = 25 * 60; // Default duration in seconds
144+
let currentSession = null;
145+
let sessions = [];
146+
147+
// Check if localStorage is available
148+
function isLocalStorageAvailable() {
149+
try {
150+
localStorage.setItem('test', 'test');
151+
localStorage.removeItem('test');
152+
return true;
153+
} catch (e) {
154+
return false;
155+
}
156+
}
157+
158+
// Load sessions from storage
159+
function loadSessions() {
160+
if (isLocalStorageAvailable()) {
161+
const storedSessions = localStorage.getItem('pomodoroSessions');
162+
if (storedSessions) {
163+
sessions = JSON.parse(storedSessions);
164+
}
165+
} else {
166+
console.warn('localStorage is not available. Session data will not persist.');
167+
}
168+
updateSessionLog();
169+
}
170+
171+
loadSessions();
172+
173+
function formatDate(date) {
174+
return new Date(date).toLocaleString('en-US', {
175+
year: 'numeric',
176+
month: '2-digit',
177+
day: '2-digit',
178+
hour: '2-digit',
179+
minute: '2-digit',
180+
second: '2-digit',
181+
hour12: true
182+
}).replace(',', '');
183+
}
89184

90185
function updateDisplay() {
91186
const minutes = Math.floor(timeLeft / 60);
@@ -95,14 +190,34 @@ <h1>Pomodoro Timer</h1>
95190

96191
function startTimer() {
97192
if (!isRunning) {
193+
if (!goalInput.value) {
194+
alert('Please enter a goal for this session.');
195+
return;
196+
}
98197
isRunning = true;
99198
startBtn.textContent = 'Pause';
100199
durationSelect.disabled = true;
200+
goalInput.disabled = true;
201+
if (!currentSession) {
202+
currentSession = {
203+
goal: goalInput.value,
204+
startTime: new Date().toISOString(),
205+
endTime: null,
206+
duration: 0,
207+
pauses: []
208+
};
209+
} else {
210+
currentSession.pauses[currentSession.pauses.length - 1].resumeTime = new Date().toISOString();
211+
}
101212
startTime = Date.now() - ((duration - timeLeft) * 1000);
102213
requestAnimationFrame(updateTimer);
103214
} else {
104215
isRunning = false;
105216
startBtn.textContent = 'Resume';
217+
currentSession.pauses.push({
218+
pauseTime: new Date().toISOString(),
219+
resumeTime: null
220+
});
106221
}
107222
}
108223

@@ -116,6 +231,8 @@ <h1>Pomodoro Timer</h1>
116231
isRunning = false;
117232
startBtn.textContent = 'Start';
118233
durationSelect.disabled = false;
234+
goalInput.disabled = false;
235+
endSession();
119236
alert('Pomodoro session complete!');
120237
} else {
121238
requestAnimationFrame(updateTimer);
@@ -132,6 +249,8 @@ <h1>Pomodoro Timer</h1>
132249
updateDisplay();
133250
startBtn.textContent = 'Start';
134251
durationSelect.disabled = false;
252+
goalInput.disabled = false;
253+
currentSession = null;
135254
}
136255

137256
function changeDuration() {
@@ -142,10 +261,64 @@ <h1>Pomodoro Timer</h1>
142261
}
143262
}
144263

264+
function endSession() {
265+
if (currentSession) {
266+
currentSession.endTime = new Date().toISOString();
267+
currentSession.duration = Math.round((new Date(currentSession.endTime) - new Date(currentSession.startTime)) / 1000);
268+
sessions.unshift(currentSession);
269+
updateSessionLog();
270+
saveSessions();
271+
resetTimer();
272+
}
273+
}
274+
275+
function updateSessionLog() {
276+
sessionLogBody.innerHTML = '';
277+
sessions.forEach(session => {
278+
const row = document.createElement('tr');
279+
row.innerHTML = `
280+
<td>${session.goal}</td>
281+
<td>${formatDate(session.startTime)}</td>
282+
<td>${session.endTime ? formatDate(session.endTime) : 'In progress'}</td>
283+
<td>${formatDuration(session.duration)}</td>
284+
<td>${formatPauses(session.pauses)}</td>
285+
`;
286+
sessionLogBody.appendChild(row);
287+
});
288+
jsonOutput.value = JSON.stringify(sessions, null, 2);
289+
}
290+
291+
function formatDuration(seconds) {
292+
const minutes = Math.floor(seconds / 60);
293+
const remainingSeconds = seconds % 60;
294+
return `${minutes}m ${remainingSeconds}s`;
295+
}
296+
297+
function formatPauses(pauses) {
298+
return pauses.map(pause =>
299+
`${formatDate(pause.pauseTime)} - ${pause.resumeTime ? formatDate(pause.resumeTime) : 'Not resumed'}`
300+
).join('<br>');
301+
}
302+
303+
function saveSessions() {
304+
if (isLocalStorageAvailable()) {
305+
localStorage.setItem('pomodoroSessions', JSON.stringify(sessions));
306+
}
307+
}
308+
145309
startBtn.addEventListener('click', startTimer);
146310
resetBtn.addEventListener('click', resetTimer);
311+
endBtn.addEventListener('click', endSession);
147312
durationSelect.addEventListener('change', changeDuration);
148313

314+
// Keyboard shortcut
315+
document.addEventListener('keydown', (e) => {
316+
if (e.code === 'Space' && document.activeElement !== goalInput) {
317+
e.preventDefault();
318+
startTimer();
319+
}
320+
});
321+
149322
updateDisplay();
150323
</script>
151324
</body>

0 commit comments

Comments
 (0)