Improve mobile responsiveness and fix particle field calculations
This commit is contained in:
+13
-7
@@ -403,9 +403,9 @@ class ParticleField {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
this.ctx = canvas.getContext('2d');
|
||||
this.COLS = 100;
|
||||
this.COLS = 0;
|
||||
this.ROWS = 4;
|
||||
this.N = this.COLS * this.ROWS;
|
||||
this.N = 0;
|
||||
this.targetProgress = 0;
|
||||
this.currentProgress = 0;
|
||||
this.cardState = 'active';
|
||||
@@ -420,6 +420,16 @@ class ParticleField {
|
||||
this.canvas.height = rect.height * devicePixelRatio;
|
||||
this.canvas.style.width = rect.width + '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) {
|
||||
@@ -429,6 +439,7 @@ class ParticleField {
|
||||
|
||||
draw(_ts) {
|
||||
const { ctx, canvas, COLS, ROWS, N } = this;
|
||||
if (N === 0) return;
|
||||
const w = canvas.width;
|
||||
const h = canvas.height;
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
@@ -639,11 +650,6 @@ function rebuildCards() {
|
||||
const id = card.id.replace('card-', '');
|
||||
const canvas = card.querySelector('canvas');
|
||||
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);
|
||||
});
|
||||
|
||||
|
||||
+2
-2
@@ -16,12 +16,12 @@
|
||||
<label class="toggle" id="workModeLabel">
|
||||
<input type="checkbox" id="workMode">
|
||||
<span class="track"></span>
|
||||
<span class="toggle-label">Work time</span>
|
||||
<span class="toggle-label"><span>Work time</span></span>
|
||||
</label>
|
||||
<label class="toggle" id="bridgeDaysLabel">
|
||||
<input type="checkbox" id="bridgeDays">
|
||||
<span class="track"></span>
|
||||
<span class="toggle-label">Bridge days</span>
|
||||
<span class="toggle-label"><span>Bridge days</span></span>
|
||||
</label>
|
||||
<button id="editToggle" aria-label="Edit timers">✎</button>
|
||||
<button id="themeToggle" aria-label="Toggle theme"></button>
|
||||
|
||||
+55
-2
@@ -20,7 +20,6 @@ html, body {
|
||||
font-family: 'Inter', system-ui, sans-serif;
|
||||
font-weight: 300;
|
||||
color: var(--text);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Header ─────────────────────────────────────── */
|
||||
@@ -31,6 +30,16 @@ header {
|
||||
justify-content: space-between;
|
||||
padding: 0 32px;
|
||||
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 {
|
||||
@@ -45,6 +54,12 @@ header {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.toggles {
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -92,6 +107,18 @@ header {
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.04em;
|
||||
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 {
|
||||
@@ -107,7 +134,7 @@ header {
|
||||
|
||||
/* ── Cards ───────────────────────────────────────── */
|
||||
#cards {
|
||||
height: calc(100vh - var(--header-height));
|
||||
min-height: calc(100vh - var(--header-height));
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -115,6 +142,7 @@ header {
|
||||
.card {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
min-height: 80px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -140,6 +168,12 @@ header {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.card-content {
|
||||
padding: 8px 12px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-name {
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
@@ -149,6 +183,12 @@ header {
|
||||
transition: color 0.4s ease;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.card-name, .card-ends, .card-remaining {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-ends {
|
||||
font-size: 11px;
|
||||
font-weight: 300;
|
||||
@@ -279,6 +319,19 @@ header {
|
||||
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="date"] {
|
||||
background: none;
|
||||
|
||||
Reference in New Issue
Block a user