fix(period): [ and ] snap odd ranges to calendar months, fresh visit opens the current period

This commit is contained in:
hh committed 2026-10-25 23:26:06 +00:00
1 parent 741e5a49ba
commit 92db7d4093
2 files changed
+47 -8

No files matched your search

+40 -1
View File
@@ -130,12 +130,39 @@ function unitOf(range: Range, view: ViewRange): ViewRange | null {
);
}
export function shiftPeriod(range: Range, view: ViewRange, dir: 1 | -1): Range {
function wholeMonths(range: Range): number {
const after = addDays(range.end, 1);
if (!(range.start.endsWith("-01") && after.endsWith("-01"))) {
return 0;
}
const months = (value: string) =>
Number(value.slice(0, 4)) * 12 + Number(value.slice(5, 7));
return months(after) - months(range.start);
}
function calendarShift(
range: Range,
view: ViewRange,
dir: 1 | -1
): Range | null {
const unit = unitOf(range, view);
if (unit) {
const anchor = dir === 1 ? periodOf(range.start, unit).end : range.start;
return periodOf(addDays(anchor, dir), unit);
}
const months = wholeMonths(range);
if (months === 0) {
return null;
}
const start = addMonths(range.start, dir * months);
return { end: addDays(addMonths(start, months), -1), start };
}
export function shiftPeriod(range: Range, view: ViewRange, dir: 1 | -1): Range {
const calendar = calendarShift(range, view, dir);
if (calendar) {
return calendar;
}
const days = daysBetween(range.start, range.end) + 1;
return {
end: addDays(range.end, dir * days),
@@ -143,6 +170,18 @@ export function shiftPeriod(range: Range, view: ViewRange, dir: 1 | -1): Range {
};
}
export function stepPeriod(range: Range, view: ViewRange, dir: 1 | -1): Range {
const calendar = calendarShift(range, view, dir);
if (calendar) {
return calendar;
}
const unit = isDynamic(view) ? "1M" : view;
const edge = dir === 1 ? range.end : range.start;
const own = periodOf(edge, unit);
const reached = (dir === 1 ? own.end : own.start) === edge;
return reached ? periodOf(addDays(edge, dir), unit) : own;
}
export function daysBetween(a: string, b: string): number {
return Math.round((parse(b).getTime() - parse(a).getTime()) / 86_400_000);
}
+7 -7
View File
@@ -5,7 +5,7 @@ import {
isDynamic,
periodOf,
type Range,
shiftPeriod,
stepPeriod,
today,
type ViewRange,
} from "#lib/dates.js";
@@ -23,7 +23,7 @@ export interface Preset {
function stored(): Range | null {
try {
const value = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? "null");
const value = JSON.parse(sessionStorage.getItem(STORAGE_KEY) ?? "null");
return ISO_DATE.test(value?.start) && ISO_DATE.test(value?.end)
? value
: null;
@@ -71,7 +71,7 @@ class Period {
const range = rangeFromUrl(url) ?? stored() ?? periodOf(today(), view);
this.start = range.start;
this.end = range.end;
localStorage.setItem(STORAGE_KEY, JSON.stringify(range));
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(range));
this.ready = true;
}
@@ -97,11 +97,11 @@ class Period {
}
this.start = range.start;
this.end = range.end;
localStorage.setItem(STORAGE_KEY, JSON.stringify(range));
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(range));
}
shift(dir: 1 | -1) {
this.set(shiftPeriod(this.range, this.view, dir));
this.set(stepPeriod(this.range, this.view, dir));
}
reset() {
@@ -113,8 +113,8 @@ class Period {
const { view } = this;
const presets: Preset[] = [];
if (!isDynamic(view)) {
const prev = shiftPeriod(this.range, view, -1);
const next = shiftPeriod(this.range, view, 1);
const prev = stepPeriod(this.range, view, -1);
const next = stepPeriod(this.range, view, 1);
presets.push({ hint: "[", label: periodLabel(prev, view), range: prev });
presets.push({ hint: "]", label: periodLabel(next, view), range: next });
}