Improve mobile responsiveness and fix particle field calculations

This commit is contained in:
ulve
2026-04-04 11:20:33 +02:00
parent a75ccc47a9
commit 2c97aa70dc
3 changed files with 70 additions and 11 deletions
+13 -7
View File
@@ -403,9 +403,9 @@ class ParticleField {
constructor(canvas) { constructor(canvas) {
this.canvas = canvas; this.canvas = canvas;
this.ctx = canvas.getContext('2d'); this.ctx = canvas.getContext('2d');
this.COLS = 100; this.COLS = 0;
this.ROWS = 4; this.ROWS = 4;
this.N = this.COLS * this.ROWS; this.N = 0;
this.targetProgress = 0; this.targetProgress = 0;
this.currentProgress = 0; this.currentProgress = 0;
this.cardState = 'active'; this.cardState = 'active';
@@ -420,6 +420,16 @@ class ParticleField {
this.canvas.height = rect.height * devicePixelRatio; this.canvas.height = rect.height * devicePixelRatio;
this.canvas.style.width = rect.width + 'px'; this.canvas.style.width = rect.width + 'px';
this.canvas.style.height = rect.height + 'px'; this.canvas.style.height = rect.height + 'px';
const dpr = devicePixelRatio;
const radius = 4 * dpr;
const gap = 2 * dpr;
const step = radius * 2 + gap;
// Calculate how many columns fit with 32px padding on each side
const padding = 32 * dpr;
this.COLS = Math.max(1, Math.floor((this.canvas.width - padding * 2) / step));
this.N = this.COLS * this.ROWS;
} }
update(progress, cardState) { update(progress, cardState) {
@@ -429,6 +439,7 @@ class ParticleField {
draw(_ts) { draw(_ts) {
const { ctx, canvas, COLS, ROWS, N } = this; const { ctx, canvas, COLS, ROWS, N } = this;
if (N === 0) return;
const w = canvas.width; const w = canvas.width;
const h = canvas.height; const h = canvas.height;
ctx.clearRect(0, 0, w, h); ctx.clearRect(0, 0, w, h);
@@ -639,11 +650,6 @@ function rebuildCards() {
const id = card.id.replace('card-', ''); const id = card.id.replace('card-', '');
const canvas = card.querySelector('canvas'); const canvas = card.querySelector('canvas');
if (!canvas) return; if (!canvas) return;
const rect = card.getBoundingClientRect();
canvas.width = rect.width * devicePixelRatio;
canvas.height = rect.height * devicePixelRatio;
canvas.style.width = rect.width + 'px';
canvas.style.height = rect.height + 'px';
particleFields[id] = new ParticleField(canvas); particleFields[id] = new ParticleField(canvas);
}); });
+2 -2
View File
@@ -16,12 +16,12 @@
<label class="toggle" id="workModeLabel"> <label class="toggle" id="workModeLabel">
<input type="checkbox" id="workMode"> <input type="checkbox" id="workMode">
<span class="track"></span> <span class="track"></span>
<span class="toggle-label">Work time</span> <span class="toggle-label"><span>Work time</span></span>
</label> </label>
<label class="toggle" id="bridgeDaysLabel"> <label class="toggle" id="bridgeDaysLabel">
<input type="checkbox" id="bridgeDays"> <input type="checkbox" id="bridgeDays">
<span class="track"></span> <span class="track"></span>
<span class="toggle-label">Bridge days</span> <span class="toggle-label"><span>Bridge days</span></span>
</label> </label>
<button id="editToggle" aria-label="Edit timers">✎</button> <button id="editToggle" aria-label="Edit timers">✎</button>
<button id="themeToggle" aria-label="Toggle theme"></button> <button id="themeToggle" aria-label="Toggle theme"></button>
+55 -2
View File
@@ -20,7 +20,6 @@ html, body {
font-family: 'Inter', system-ui, sans-serif; font-family: 'Inter', system-ui, sans-serif;
font-weight: 300; font-weight: 300;
color: var(--text); color: var(--text);
overflow: hidden;
} }
/* ── Header ─────────────────────────────────────── */ /* ── Header ─────────────────────────────────────── */
@@ -31,6 +30,16 @@ header {
justify-content: space-between; justify-content: space-between;
padding: 0 32px; padding: 0 32px;
border-bottom: 1px solid var(--border); border-bottom: 1px solid var(--border);
position: sticky;
top: 0;
background: var(--bg);
z-index: 10;
}
@media (max-width: 600px) {
header {
padding: 0 16px;
}
} }
#week-number { #week-number {
@@ -45,6 +54,12 @@ header {
align-items: center; align-items: center;
} }
@media (max-width: 600px) {
.toggles {
gap: 12px;
}
}
.toggle { .toggle {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -92,6 +107,18 @@ header {
font-size: 12px; font-size: 12px;
letter-spacing: 0.04em; letter-spacing: 0.04em;
color: var(--text-secondary); color: var(--text-secondary);
display: flex;
align-items: center;
gap: 4px;
}
#workModeLabel .toggle-label::before { content: '⚒'; filter: grayscale(100%); opacity: 0.7; }
#bridgeDaysLabel .toggle-label::before { content: '🏖'; filter: grayscale(100%); opacity: 0.7; }
@media (max-width: 600px) {
.toggle-label span {
display: none;
}
} }
#bridgeDaysLabel { #bridgeDaysLabel {
@@ -107,7 +134,7 @@ header {
/* ── Cards ───────────────────────────────────────── */ /* ── Cards ───────────────────────────────────────── */
#cards { #cards {
height: calc(100vh - var(--header-height)); min-height: calc(100vh - var(--header-height));
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
@@ -115,6 +142,7 @@ header {
.card { .card {
position: relative; position: relative;
flex: 1; flex: 1;
min-height: 80px;
border-bottom: 1px solid rgba(0, 0, 0, 0.12); border-bottom: 1px solid rgba(0, 0, 0, 0.12);
overflow: hidden; overflow: hidden;
} }
@@ -140,6 +168,12 @@ header {
pointer-events: none; pointer-events: none;
} }
@media (max-width: 600px) {
.card-content {
padding: 8px 12px 0;
}
}
.card-name { .card-name {
font-size: 11px; font-size: 11px;
font-weight: 400; font-weight: 400;
@@ -149,6 +183,12 @@ header {
transition: color 0.4s ease; transition: color 0.4s ease;
} }
@media (max-width: 600px) {
.card-name, .card-ends, .card-remaining {
font-size: 10px;
}
}
.card-ends { .card-ends {
font-size: 11px; font-size: 11px;
font-weight: 300; font-weight: 300;
@@ -279,6 +319,19 @@ header {
gap: 10px; gap: 10px;
} }
@media (max-width: 600px) {
.add-timer-form {
flex-direction: column;
padding: 20px 0;
gap: 12px;
}
.add-timer-form input[type="text"],
.add-timer-form input[type="date"] {
width: 200px !important;
}
}
.add-timer-form input[type="text"], .add-timer-form input[type="text"],
.add-timer-form input[type="date"] { .add-timer-form input[type="date"] {
background: none; background: none;