Initial commit: Waypoint Obsidian plugin with calendar, recent files, and bookmarks

This commit is contained in:
2026-06-03 20:26:23 -04:00
commit fbdc42b4a3
16 changed files with 3400 additions and 0 deletions
+149
View File
@@ -0,0 +1,149 @@
// ── Date utilities ──
// Uses moment.js which is bundled with Obsidian.
// Period format helpers following O-vault conventions.
import { moment } from 'obsidian';
export interface PeriodInfo {
day: string; // yyyy-MM-dd
week: string; // GGGG-[W]WW
month: string; // yyyy-MM
quarter: string; // yyyy-[Q]Q
year: string; // yyyy
}
export interface CalendarDay {
date: moment.Moment;
dayOfMonth: number;
isToday: boolean;
isCurrentMonth: boolean;
isoWeekNumber: number;
}
export interface CalendarWeek {
weekNumber: number;
days: CalendarDay[];
}
/**
* Get period info for a given date.
*/
export function getPeriodInfo(date: moment.Moment): PeriodInfo {
return {
day: date.format('YYYY-MM-DD'),
week: date.format('GGGG-[W]WW'),
month: date.format('YYYY-MM'),
quarter: date.format('YYYY-[Q]Q'),
year: date.format('YYYY'),
};
}
/**
* Get quarter string from a moment date (e.g. "2026-Q3").
*/
export function getQuarterString(date: moment.Moment): string {
return date.format('YYYY-[Q]Q');
}
/**
* Get the current date's period info.
*/
export function getTodayPeriod(): PeriodInfo {
return getPeriodInfo(moment());
}
/**
* Build a month grid as an array of weeks.
* Each week has 7 days, starting on the configured first day of week.
* ISO week numbers are calculated from the Monday of that week row.
*/
export function getMonthGrid(
year: number,
month: number, // 0-indexed (0 = January)
firstDayOfWeek: number, // 0 = Sunday, 1 = Monday
): CalendarWeek[] {
const firstOfMonth = moment({ year, month, day: 1 });
const lastOfMonth = moment(firstOfMonth).endOf('month');
// Find the first day to display (may go back into previous month)
const startDate = moment(firstOfMonth)
.subtract((firstOfMonth.day() - firstDayOfWeek + 7) % 7, 'days');
const today = moment().startOf('day');
const weeks: CalendarWeek[] = [];
let currentDay = moment(startDate);
while (currentDay.isBefore(lastOfMonth) || currentDay.month() === month) {
const weekDays: CalendarDay[] = [];
for (let i = 0; i < 7; i++) {
weekDays.push({
date: moment(currentDay),
dayOfMonth: currentDay.date(),
isToday: currentDay.isSame(today, 'day'),
isCurrentMonth: currentDay.month() === month,
isoWeekNumber: currentDay.isoWeek(),
});
currentDay.add(1, 'day');
}
weeks.push({
weekNumber: weekDays[0].isoWeekNumber,
days: weekDays,
});
// Safety: break after 6 weeks
if (weeks.length >= 6) break;
}
return weeks;
}
/**
* Format a date label for the breadcrumb (e.g. "June 1st, 2026").
*/
export function formatDateLabel(date: moment.Moment): string {
return date.format('MMMM Do, YYYY');
}
/**
* Format a month label (e.g. "June 2026").
*/
export function formatMonthLabel(date: moment.Moment): string {
return date.format('MMMM YYYY');
}
/**
* Get readable quarter label (e.g. "Q3 2026").
*/
export function formatQuarterLabel(date: moment.Moment): string {
return date.format('[Q]Q YYYY');
}
/**
* Navigate a date by a given period and amount.
*/
export function navigateDate(
date: moment.Moment,
period: 'day' | 'week' | 'month' | 'quarter' | 'year',
delta: number,
): moment.Moment {
if (period === 'quarter') {
return moment(date).add(delta * 3, 'months');
}
return moment(date).add(delta, period);
}
/**
* Create a note filename from a date using the given format string.
*/
export function formatPeriodName(date: moment.Moment, format: string): string {
return date.format(format);
}
/**
* Get ISO week number for a given date.
*/
export function getISOWeek(date: moment.Moment): number {
return date.isoWeek();
}