fix(period): [ and ] snap odd ranges to calendar months, fresh visit opens the current period
This commit is contained in:
1 parent
741e5a49ba
commit
92db7d4093
2 files changed
+47
-8
No files matched your search
+40
-1
@@ -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);
|
const unit = unitOf(range, view);
|
||||||
if (unit) {
|
if (unit) {
|
||||||
const anchor = dir === 1 ? periodOf(range.start, unit).end : range.start;
|
const anchor = dir === 1 ? periodOf(range.start, unit).end : range.start;
|
||||||
return periodOf(addDays(anchor, dir), unit);
|
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;
|
const days = daysBetween(range.start, range.end) + 1;
|
||||||
return {
|
return {
|
||||||
end: addDays(range.end, dir * days),
|
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 {
|
export function daysBetween(a: string, b: string): number {
|
||||||
return Math.round((parse(b).getTime() - parse(a).getTime()) / 86_400_000);
|
return Math.round((parse(b).getTime() - parse(a).getTime()) / 86_400_000);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
isDynamic,
|
isDynamic,
|
||||||
periodOf,
|
periodOf,
|
||||||
type Range,
|
type Range,
|
||||||
shiftPeriod,
|
stepPeriod,
|
||||||
today,
|
today,
|
||||||
type ViewRange,
|
type ViewRange,
|
||||||
} from "#lib/dates.js";
|
} from "#lib/dates.js";
|
||||||
@@ -23,7 +23,7 @@ export interface Preset {
|
|||||||
|
|
||||||
function stored(): Range | null {
|
function stored(): Range | null {
|
||||||
try {
|
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)
|
return ISO_DATE.test(value?.start) && ISO_DATE.test(value?.end)
|
||||||
? value
|
? value
|
||||||
: null;
|
: null;
|
||||||
@@ -71,7 +71,7 @@ class Period {
|
|||||||
const range = rangeFromUrl(url) ?? stored() ?? periodOf(today(), view);
|
const range = rangeFromUrl(url) ?? stored() ?? periodOf(today(), view);
|
||||||
this.start = range.start;
|
this.start = range.start;
|
||||||
this.end = range.end;
|
this.end = range.end;
|
||||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(range));
|
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(range));
|
||||||
this.ready = true;
|
this.ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,11 +97,11 @@ class Period {
|
|||||||
}
|
}
|
||||||
this.start = range.start;
|
this.start = range.start;
|
||||||
this.end = range.end;
|
this.end = range.end;
|
||||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(range));
|
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(range));
|
||||||
}
|
}
|
||||||
|
|
||||||
shift(dir: 1 | -1) {
|
shift(dir: 1 | -1) {
|
||||||
this.set(shiftPeriod(this.range, this.view, dir));
|
this.set(stepPeriod(this.range, this.view, dir));
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
@@ -113,8 +113,8 @@ class Period {
|
|||||||
const { view } = this;
|
const { view } = this;
|
||||||
const presets: Preset[] = [];
|
const presets: Preset[] = [];
|
||||||
if (!isDynamic(view)) {
|
if (!isDynamic(view)) {
|
||||||
const prev = shiftPeriod(this.range, view, -1);
|
const prev = stepPeriod(this.range, view, -1);
|
||||||
const next = shiftPeriod(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(prev, view), range: prev });
|
||||||
presets.push({ hint: "]", label: periodLabel(next, view), range: next });
|
presets.push({ hint: "]", label: periodLabel(next, view), range: next });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user