Skip to content

Commit 513fb6d

Browse files
authored
Update index.html
1 parent 31da71b commit 513fb6d

1 file changed

Lines changed: 55 additions & 80 deletions

File tree

index.html

Lines changed: 55 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=no">
66
<title>Flow</title>
7+
8+
<script>
9+
const savedTheme = localStorage.getItem('theme') || 'dark';
10+
document.documentElement.setAttribute('data-theme', savedTheme);
11+
</script>
12+
713
<style>
814
@import url('https://fonts.googleapis.com/css2?family=Fredoka:wght@500;600;700&display=swap');
915

@@ -20,47 +26,45 @@
2026
margin: 0; padding: 0; box-sizing: border-box;
2127
-webkit-font-smoothing: antialiased; font-family: 'Fredoka', sans-serif;
2228
-webkit-tap-highlight-color: transparent;
23-
user-select: none;
24-
outline: none;
29+
user-select: none; outline: none; touch-action: manipulation;
2530
}
2631

27-
::-webkit-scrollbar { display: none; }
28-
html { scrollbar-width: none; -ms-overflow-style: none; }
29-
3032
body {
3133
background: var(--bg); color: var(--text);
3234
height: 100dvh; display: flex; flex-direction: column; overflow: hidden;
33-
transition: background 0.4s ease;
35+
transition: background 0.4s ease, color 0.4s ease;
3436
padding: env(safe-area-inset-top) 10px env(safe-area-inset-bottom);
3537
}
3638

39+
/* UI ELEMENTS */
3740
.top-nav { height: 65px; display: flex; justify-content: space-between; align-items: center; z-index: 1000; flex-shrink: 0; padding: 0 10px; }
3841
.icon-btn { width: 46px; height: 46px; border-radius: 50%; border: none; background: var(--card); color: var(--text); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: 0.2s; }
3942
.icon-btn:active { transform: scale(0.9); }
4043

44+
/* CLOCK AREA */
4145
.stage { flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden; width: 100%; cursor: pointer; }
4246
.time-row { display: flex; align-items: baseline; justify-content: center; gap: 0.6vw; width: fit-content; max-width: 100%; pointer-events: none; }
4347
.digit-box { height: var(--digit-size); width: calc(var(--digit-size) * 0.62); overflow: hidden; display: flex; justify-content: center; align-items: center; }
44-
.digit { font-size: var(--digit-size); font-weight: 700; line-height: 1; }
48+
.digit { font-size: var(--digit-size); font-weight: 700; line-height: 1; transition: transform 0.4s var(--ease), opacity 0.2s; }
4549
.separator { font-size: calc(var(--digit-size) * 0.7); color: var(--sep-color); font-weight: 700; line-height: 1; }
4650

4751
.sec-group { display: none; align-items: baseline; opacity: 0.5; }
4852
.sec-group .digit-box { height: calc(var(--digit-size) * 0.6); width: calc(var(--digit-size) * 0.38); }
4953
.sec-group .digit { font-size: calc(var(--digit-size) * 0.6); }
5054

51-
body.has-seconds { --digit-size: clamp(50px, 13vw, 25vh); }
52-
body.has-ampm { --digit-size: clamp(50px, 14vw, 28vh); }
53-
body.has-seconds.has-ampm { --digit-size: clamp(45px, 11vw, 22vh); }
54-
55-
#ampm { font-size: clamp(0.9rem, 3.5vw, 1.5rem); font-weight: 700; color: var(--sep-color); margin-left: 8px; }
56-
55+
/* LANDSCAPE MODE (AUTO FULLSCREEN VIEW) */
5756
@media (orientation: landscape) and (max-height: 500px) {
5857
body.has-seconds { --digit-size: 52vh; }
5958
body:not(.has-seconds) { --digit-size: 75vh; }
6059
.top-nav, .dock { display: none !important; }
6160
body { padding: 0; }
6261
}
6362

63+
body.has-seconds { --digit-size: clamp(50px, 13vw, 25vh); }
64+
body.has-ampm { --digit-size: clamp(50px, 14vw, 28vh); }
65+
#ampm { font-size: clamp(0.9rem, 3.5vw, 1.5rem); font-weight: 700; color: var(--sep-color); margin-left: 8px; }
66+
67+
/* DOCK */
6468
.dock { width: 100%; max-width: 450px; margin: 0 auto; display: flex; flex-direction: column; gap: 12px; flex-shrink: 0; padding-bottom: 20px; }
6569
.segmented { background: var(--card); padding: 5px; border-radius: 100px; display: flex; }
6670
.seg-btn { flex: 1; border: none; background: transparent; color: var(--text); padding: 12px; border-radius: 100px; font-weight: 700; opacity: 0.3; font-size: 0.85rem; cursor: pointer; transition: 0.2s; }
@@ -69,24 +73,16 @@
6973
.btn { background: var(--card); color: var(--text); border: none; height: 64px; border-radius: 20px; display: flex; align-items: center; justify-content: center; flex: 1; cursor: pointer; transition: 0.2s; }
7074
.btn-main { flex: 2; background: var(--text); color: var(--bg); }
7175

76+
/* OVERLAYS */
7277
.overlay { position: fixed; inset: 0; background: var(--bg); display: none; z-index: 3000; flex-direction: column; animation: fadeIn 0.3s ease; }
7378
.overlay-close { position: absolute; top: 20px; left: 20px; z-index: 3001; }
7479
.overlay-content { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 30px; }
75-
76-
.edit-label { font-size: 0.8rem; font-weight: 700; text-transform: uppercase; letter-spacing: 1.5px; opacity: 0.4; margin-bottom: 20px; }
7780
.counter-group { background: var(--card); padding: 25px 35px; border-radius: 35px; display: flex; align-items: center; gap: 15px; }
78-
.timer-input { background: transparent; border: none; color: var(--text); font-size: 4rem; font-weight: 700; width: 2.2ch; text-align: center; outline: none; caret-color: #34c759; user-select: text; }
79-
.timer-input::-webkit-inner-spin-button, .timer-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
80-
81-
.step-btn {
82-
width: 52px; height: 52px; border: none; background: var(--bg); color: var(--text);
83-
border-radius: 18px; font-size: 1.4rem; cursor: pointer; display: flex;
84-
align-items: center; justify-content: center;
85-
}
86-
.step-btn:active { background: var(--text); color: var(--bg); }
87-
81+
.timer-input { background: transparent; border: none; color: var(--text); font-size: 4rem; font-weight: 700; width: 2.2ch; text-align: center; }
82+
.step-btn { width: 52px; height: 52px; border: none; background: var(--bg); color: var(--text); border-radius: 18px; font-size: 1.4rem; cursor: pointer; touch-action: none; }
8883
.confirm-btn { width: 100%; max-width: 300px; padding: 18px; border-radius: 100px; border: none; background: var(--text); color: var(--bg); font-weight: 700; margin-top: 40px; cursor: pointer; }
8984

85+
/* SETTINGS */
9086
.setting-item { width: 100%; max-width: 360px; display: flex; justify-content: space-between; align-items: center; background: var(--card); padding: 20px 24px; border-radius: 24px; margin-bottom: 10px; }
9187
.toggle { width: 48px; height: 26px; position: relative; }
9288
.toggle input { opacity: 0; width: 0; }
@@ -95,14 +91,14 @@
9591
input:checked + .slider { background: #34c759; }
9692
input:checked + .slider:before { transform: translateX(22px); }
9793

98-
#toast { position: fixed; top: 30px; left: 50%; transform: translate(-50%, -20px); background: var(--text); color: var(--bg); padding: 12px 24px; border-radius: 100px; font-weight: 700; opacity: 0; transition: 0.4s var(--ease); z-index: 5000; font-size: 0.85rem; }
94+
#toast { position: fixed; top: 30px; left: 50%; transform: translate(-50%, -20px); background: var(--text); color: var(--bg); padding: 12px 24px; border-radius: 100px; font-weight: 700; opacity: 0; transition: 0.4s var(--ease); z-index: 5000; font-size: 0.85rem; pointer-events: none; }
9995
#toast.show { opacity: 1; transform: translate(-50%, 0); }
10096

10197
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
10298
svg { fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; pointer-events: none; }
10399
</style>
104100
</head>
105-
<body onclick="handleGlobalClick(event)" oncontextmenu="return false;">
101+
<body onclick="handleGlobalClick(event)">
106102

107103
<div id="toast">THEME UPDATED</div>
108104

@@ -143,38 +139,17 @@
143139
<div id="edit-panel" class="overlay">
144140
<button class="icon-btn overlay-close" onclick="closeModal('edit-panel')"><svg width="20" height="20" viewBox="0 0 24 24"><path d="M18 6L6 18M6 6l12 12"/></svg></button>
145141
<div class="overlay-content">
146-
<div class="edit-label">Set Timer</div>
147142
<div class="counter-group">
148143
<div style="display:flex; flex-direction:column; align-items:center; gap:14px;">
149-
<button class="step-btn"
150-
onmousedown="hold(event, 'h-in', 1)"
151-
onmouseup="stopHold()"
152-
onmouseleave="stopHold()"
153-
ontouchstart="hold(event, 'h-in', 1)"
154-
ontouchend="stopHold()">+</button>
144+
<button class="step-btn" onpointerdown="hold(event, 'h-in', 1)" onpointerup="stopHold()" onpointerleave="stopHold()">+</button>
155145
<input type="number" id="h-in" class="timer-input" value="0">
156-
<button class="step-btn"
157-
onmousedown="hold(event, 'h-in', -1)"
158-
onmouseup="stopHold()"
159-
onmouseleave="stopHold()"
160-
ontouchstart="hold(event, 'h-in', -1)"
161-
ontouchend="stopHold()"></button>
146+
<button class="step-btn" onpointerdown="hold(event, 'h-in', -1)" onpointerup="stopHold()" onpointerleave="stopHold()"></button>
162147
</div>
163-
<div class="separator" style="margin-top:-5px; opacity:0.5;">:</div>
148+
<div class="separator" style="opacity:0.5;">:</div>
164149
<div style="display:flex; flex-direction:column; align-items:center; gap:14px;">
165-
<button class="step-btn"
166-
onmousedown="hold(event, 'm-in', 1)"
167-
onmouseup="stopHold()"
168-
onmouseleave="stopHold()"
169-
ontouchstart="hold(event, 'm-in', 1)"
170-
ontouchend="stopHold()">+</button>
150+
<button class="step-btn" onpointerdown="hold(event, 'm-in', 1)" onpointerup="stopHold()" onpointerleave="stopHold()">+</button>
171151
<input type="number" id="m-in" class="timer-input" value="25">
172-
<button class="step-btn"
173-
onmousedown="hold(event, 'm-in', -1)"
174-
onmouseup="stopHold()"
175-
onmouseleave="stopHold()"
176-
ontouchstart="hold(event, 'm-in', -1)"
177-
ontouchend="stopHold()"></button>
152+
<button class="step-btn" onpointerdown="hold(event, 'm-in', -1)" onpointerup="stopHold()" onpointerleave="stopHold()"></button>
178153
</div>
179154
</div>
180155
<button class="confirm-btn" onclick="saveEdit()">Apply Changes</button>
@@ -195,7 +170,7 @@
195170
const chime = new Audio('https://actions.google.com/sounds/v1/alarms/beep_short.ogg');
196171

197172
window.onload = () => {
198-
app.s_sec = localStorage.getItem('s_sec') === 'true';
173+
app.s_sec = localStorage.getItem('s_sec') !== 'false';
199174
app.s_ampm = localStorage.getItem('s_ampm') === 'true';
200175
document.getElementById('tog-sec').checked = app.s_sec;
201176
document.getElementById('tog-ampm').checked = app.s_ampm;
@@ -204,10 +179,20 @@
204179
};
205180

206181
function handleGlobalClick(e) {
207-
if (window.innerHeight < 500 && e.target.id === 'main-stage') {
208-
toggleTimer();
209-
} else if (!document.fullscreenElement && !['INPUT', 'BUTTON', 'A'].includes(e.target.tagName)) {
210-
document.documentElement.requestFullscreen().catch(() => {});
182+
183+
if (e.target.closest('.stage')) {
184+
185+
if (window.innerHeight < 500) {
186+
toggleTimer();
187+
}
188+
}
189+
}
190+
191+
function toggleFS() {
192+
if (!document.fullscreenElement) {
193+
document.documentElement.requestFullscreen().catch(()=>{});
194+
} else {
195+
document.exitFullscreen().catch(()=>{});
211196
}
212197
}
213198

@@ -220,19 +205,21 @@
220205
h = h % 12 || 12;
221206
document.getElementById('c-sec').style.display = app.s_sec ? 'flex' : 'none';
222207
document.getElementById('p-sec').style.display = 'none';
223-
document.title = "Flow Clock";
224208
} else {
225209
if (app.active && app.left > 0) {
226210
app.left--;
227-
if (app.left === 0) { chime.play(); app.active = false; updateIcon(); }
211+
if (app.left === 0) {
212+
app.active = false; updateIcon(); chime.play().catch(()=>{});
213+
if (app.mode === 'focus') { showToast("FOCUS DONE!"); setTimeout(()=>setMode('break'), 1500); }
214+
else { showToast("BREAK DONE!"); setTimeout(()=>setMode('focus'), 1500); }
215+
}
228216
}
229217
if (app.left >= 3600) { h = Math.floor(app.left/3600); m = Math.floor((app.left%3600)/60); isPomoHour=true; }
230218
else { h = Math.floor(app.left/60); m = app.left%60; }
231219
s = app.left % 60;
232220
document.getElementById('ampm').style.display = 'none';
233221
document.getElementById('c-sec').style.display = 'none';
234222
document.getElementById('p-sec').style.display = isPomoHour ? 'flex' : 'none';
235-
document.title = `[${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')}] Flow`;
236223
}
237224
updateScaling();
238225
render(h, m, s);
@@ -241,9 +228,8 @@
241228
function updateScaling() {
242229
const isClock = app.mode === 'clock';
243230
const showSec = (isClock && app.s_sec) || (!isClock && app.left >= 3600);
244-
const showAM = isClock && app.s_ampm;
245231
document.body.classList.toggle('has-seconds', showSec);
246-
document.body.classList.toggle('has-ampm', showAM);
232+
document.body.classList.toggle('has-ampm', isClock && app.s_ampm);
247233
}
248234

249235
function render(v1, v2, v3) {
@@ -281,22 +267,15 @@
281267
function closeModal(id) { document.getElementById(id).style.display = 'none'; }
282268

283269
function saveEdit() {
284-
const h = Math.min(99, parseInt(document.getElementById('h-in').value) || 0);
285-
const m = Math.min(59, parseInt(document.getElementById('m-in').value) || 0);
286-
const total = (h * 3600) + (m * 60);
287-
if (app.mode === 'focus') app.f = total; else app.b = total;
270+
app.f = (parseInt(document.getElementById('h-in').value) || 0) * 3600 + (parseInt(document.getElementById('m-in').value) || 0) * 60;
288271
closeModal('edit-panel'); resetTimer();
289272
}
290273

291-
function step(id, d) { let i = document.getElementById(id); i.value = Math.max(0, parseInt(i.value)+d); }
292-
293-
function hold(e, id, d) {
294-
if (e.cancelable) e.preventDefault(); // Stop mobile "double-tap" count
274+
function hold(e, id, d) {
295275
clearInterval(app.h_int);
296-
step(id, d);
297-
app.h_int = setInterval(() => step(id, d), 150);
276+
const step = () => { let i = document.getElementById(id); i.value = Math.max(0, parseInt(i.value)+d); };
277+
step(); app.h_int = setInterval(step, 150);
298278
}
299-
300279
function stopHold() { clearInterval(app.h_int); }
301280

302281
function syncPrefs() {
@@ -311,17 +290,13 @@
311290
const cur = document.documentElement.getAttribute('data-theme');
312291
const next = themes[(themes.indexOf(cur) + 1) % themes.length];
313292
document.documentElement.setAttribute('data-theme', next);
293+
localStorage.setItem('theme', next);
314294
showToast(`${next.toUpperCase()} THEME`);
315295
}
316296

317297
function showToast(m) {
318298
const t = document.getElementById('toast'); t.textContent = m;
319-
t.classList.add('show'); setTimeout(()=>t.classList.remove('show'), 1800);
320-
}
321-
322-
function toggleFS() {
323-
if (!document.fullscreenElement) document.documentElement.requestFullscreen();
324-
else document.exitFullscreen();
299+
t.classList.add('show'); setTimeout(()=>t.classList.remove('show'), 2000);
325300
}
326301
</script>
327302
</body>

0 commit comments

Comments
 (0)