Skip to content

Commit 7bcca04

Browse files
committed
feat: expand rolling window controls
1 parent 52c1d60 commit 7bcca04

3 files changed

Lines changed: 26 additions & 5 deletions

File tree

index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,9 @@
443443
.card.chart .plot {
444444
flex: 1 1 0;
445445
}
446+
.card.chart .plot.can-select-window {
447+
cursor: pointer;
448+
}
446449
/* Fixed so the strip's height never depends on whether its svg is present.
447450
Must match the height drawTrips() computes: PAD.t + 2 + barH + 26. */
448451
.card.strip .plot {

src/app.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,15 @@ interface Domain {
154154
if (Number.isInteger(day)) selectedWindowEnd = day;
155155
}
156156

157+
function syncRollingChartCursor(): void {
158+
el("plot1").classList.toggle("can-select-window", selectedWindowEnd === null);
159+
}
160+
157161
function selectWindowEndingOn(end: number): void {
158162
if (!rollingHover || !rollingTooltip) return;
159163
keepAlive();
160164
selectedWindowEnd = rollingHover.clampDate(end);
165+
syncRollingChartCursor();
161166
horizontalWheelRemainder = 0;
162167
saveSelectedWindow();
163168
rollingTooltip.innerHTML = rollingHover.show(selectedWindowEnd, true);
@@ -340,7 +345,7 @@ interface Domain {
340345
`<span class="muted">${over ? `${out - LIMIT} over the ${LIMIT}-day limit`
341346
: `${LIMIT - out} days of headroom`}</span>` +
342347
(selected
343-
? `<hr><span class="selection-help">ESC to dismiss selection; arrow keys to adjust window.</span>`
348+
? `<hr><span class="selection-help">ESC to dismiss selection; arrow keys or H/L adjust by day; hold Shift to adjust by week.</span>`
344349
: "");
345350
}
346351

@@ -843,6 +848,7 @@ interface Domain {
843848
drawTrips(el("plot2"), el("tt2"), A, dom, rolling);
844849
rollingHover = rolling;
845850
rollingTooltip = el("tt1");
851+
syncRollingChartCursor();
846852

847853
// Redraws caused by edits or resizing keep an active selection visible.
848854
if (selectedWindowEnd !== null) {
@@ -862,6 +868,7 @@ interface Domain {
862868
ev.preventDefault();
863869
keepAlive();
864870
selectedWindowEnd = null;
871+
syncRollingChartCursor();
865872
horizontalWheelRemainder = 0;
866873
lastTimelineTrip = null;
867874
nextTimelineAlignment = 0;
@@ -874,14 +881,19 @@ interface Domain {
874881
return;
875882
}
876883

877-
if (ev.key !== "ArrowLeft" && ev.key !== "ArrowRight") return;
884+
if (ev.altKey || ev.ctrlKey || ev.metaKey) return;
885+
const key = ev.key.toLowerCase();
886+
const direction = key === "arrowleft" || key === "h"
887+
? -1
888+
: key === "arrowright" || key === "l" ? 1 : 0;
889+
if (direction === 0) return;
878890
if (ev.defaultPrevented) return;
879891
const target = ev.target as HTMLElement | null;
880892
if (target && (target.matches("input, textarea, select, button") || target.isContentEditable)) return;
881893

882894
ev.preventDefault();
883895
keepAlive();
884-
const delta = ev.key === "ArrowLeft" ? -1 : 1;
896+
const delta = direction * (ev.shiftKey ? 7 : 1);
885897
moveSelectedWindowBy(delta);
886898
});
887899
}

test/app.test.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,16 @@ test("date fields stay unrestricted while invalid ranges are corrected", () => {
2929
test("rolling chart selection locks hover and supports keyboard control", () => {
3030
assert.match(appSource, /host\.onclick = \(ev: MouseEvent\) => \{/);
3131
assert.match(appSource, /if \(selectedWindowEnd !== null\) return;/);
32-
assert.match(appSource, /ev\.key === "ArrowLeft" \? -1 : 1/);
32+
assert.match(appSource, /classList\.toggle\("can-select-window", selectedWindowEnd === null\)/);
33+
assert.match(indexSource, /\.card\.chart \.plot\.can-select-window \{\s*cursor: pointer;/);
34+
assert.match(appSource, /const key = ev\.key\.toLowerCase\(\);/);
35+
assert.match(appSource, /if \(ev\.altKey \|\| ev\.ctrlKey \|\| ev\.metaKey\) return;/);
36+
assert.match(appSource, /key === "arrowleft" \|\| key === "h"/);
37+
assert.match(appSource, /key === "arrowright" \|\| key === "l"/);
38+
assert.match(appSource, /const delta = direction \* \(ev\.shiftKey \? 7 : 1\);/);
3339
assert.match(appSource, /if \(ev\.key === "Escape"\) \{/);
3440
assert.match(appSource, /selectedWindowEnd = null;/);
35-
assert.match(appSource, /ESC to dismiss selection; arrow keys to adjust window\./);
41+
assert.match(appSource, /ESC to dismiss selection; arrow keys or H\/L adjust by day; hold Shift to adjust by week\./);
3642
assert.match(appSource, /rollingHover\.show\(selectedWindowEnd, true\)/);
3743
assert.match(indexSource, /\.tt \.selection-help \{[\s\S]*?white-space: normal;/);
3844
assert.match(appSource, /host\.onwheel = \(ev: WheelEvent\) => moveSelectedWindowFromWheel\(ev, host\);/);

0 commit comments

Comments
 (0)