mirror of
https://github.com/zadam/trilium.git
synced 2025-12-04 22:44:25 +01:00
chore(react/launch_bar): get calendar to render days
This commit is contained in:
parent
604488b166
commit
5c8445f3fe
@ -8,7 +8,6 @@ import options from "../../services/options.js";
|
||||
import { Dropdown } from "bootstrap";
|
||||
import type { EventData } from "../../components/app_context.js";
|
||||
import { dayjs, type Dayjs } from "@triliumnext/commons";
|
||||
import "../../stylesheets/calendar.css";
|
||||
import type { AttributeRow, OptionDefinitions } from "@triliumnext/commons";
|
||||
|
||||
const MONTHS = [
|
||||
@ -28,12 +27,6 @@ const MONTHS = [
|
||||
|
||||
const DROPDOWN_TPL = `
|
||||
<div class="calendar-dropdown-widget">
|
||||
<style>
|
||||
.calendar-dropdown-widget {
|
||||
width: 400px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="calendar-header">
|
||||
<div class="calendar-month-selector">
|
||||
<button class="calendar-btn tn-tool-button bx bx-chevron-left" data-calendar-toggle="previous"></button>
|
||||
@ -61,7 +54,6 @@ const DROPDOWN_TPL = `
|
||||
</div>
|
||||
|
||||
<div class="calendar-week"></div>
|
||||
<div class="calendar-body" data-calendar-area="month"></div>
|
||||
</div>`;
|
||||
|
||||
const DAYS_OF_WEEK = [
|
||||
@ -74,9 +66,7 @@ const DAYS_OF_WEEK = [
|
||||
t("calendar.sat")
|
||||
];
|
||||
|
||||
interface DateNotesForMonth {
|
||||
[date: string]: string;
|
||||
}
|
||||
|
||||
|
||||
interface WeekCalculationOptions {
|
||||
firstWeekType: number;
|
||||
@ -228,9 +218,6 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
|
||||
|
||||
// Store firstDayOfWeek as ISO (1–7)
|
||||
manageFirstDayOfWeek() {
|
||||
const rawFirstDayOfWeek = options.getInt("firstDayOfWeek") || 0;
|
||||
this.firstDayOfWeekISO = rawFirstDayOfWeek === 0 ? 7 : rawFirstDayOfWeek;
|
||||
|
||||
let localeDaysOfWeek = [...DAYS_OF_WEEK];
|
||||
const shifted = localeDaysOfWeek.splice(0, rawFirstDayOfWeek);
|
||||
localeDaysOfWeek = ['', ...localeDaysOfWeek, ...shifted];
|
||||
@ -244,34 +231,13 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
|
||||
};
|
||||
}
|
||||
|
||||
getWeekStartDate(date: Dayjs): Dayjs {
|
||||
const currentISO = date.isoWeekday();
|
||||
const diff = (currentISO - this.firstDayOfWeekISO + 7) % 7;
|
||||
return date.clone().subtract(diff, "day").startOf("day");
|
||||
}
|
||||
|
||||
getWeekNumber(date: Dayjs): number {
|
||||
const weekStart = this.getWeekStartDate(date);
|
||||
return weekStart.isoWeek();
|
||||
}
|
||||
|
||||
async dropdownShown() {
|
||||
await this.getWeekNoteEnable();
|
||||
this.weekNotes = await server.get<string[]>(`attribute-values/weekNote`);
|
||||
this.init(appContext.tabManager.getActiveContextNote()?.getOwnedLabelValue("dateNote") ?? null);
|
||||
this.init( ?? null);
|
||||
}
|
||||
|
||||
init(activeDate: string | null) {
|
||||
this.activeDate = activeDate ? dayjs(`${activeDate}T12:00:00`) : null;
|
||||
this.todaysDate = dayjs();
|
||||
this.date = dayjs(this.activeDate || this.todaysDate).startOf('month');
|
||||
this.createMonth();
|
||||
}
|
||||
|
||||
createDay(dateNotesForMonth: DateNotesForMonth, num: number) {
|
||||
const $newDay = $("<a>")
|
||||
.addClass("calendar-date")
|
||||
.attr("data-calendar-date", this.date.local().format('YYYY-MM-DD'));
|
||||
createDay() {
|
||||
const $date = $("<span>").html(String(num));
|
||||
const dateNoteId = dateNotesForMonth[this.date.local().format('YYYY-MM-DD')];
|
||||
|
||||
@ -304,105 +270,6 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
|
||||
return $newWeekNumber;
|
||||
}
|
||||
|
||||
// Use isoWeekday() consistently
|
||||
private getPrevMonthDays(firstDayISO: number): { weekNumber: number, dates: Dayjs[] } {
|
||||
const prevMonthLastDay = this.date.subtract(1, 'month').endOf('month');
|
||||
const daysToAdd = (firstDayISO - this.firstDayOfWeekISO + 7) % 7;
|
||||
const dates: Dayjs[] = [];
|
||||
|
||||
const firstDay = this.date.startOf('month');
|
||||
const weekNumber = this.getWeekNumber(firstDay);
|
||||
|
||||
// Get dates from previous month
|
||||
for (let i = daysToAdd - 1; i >= 0; i--) {
|
||||
dates.push(prevMonthLastDay.subtract(i, 'day'));
|
||||
}
|
||||
|
||||
return { weekNumber, dates };
|
||||
}
|
||||
|
||||
private getNextMonthDays(lastDayISO: number): Dayjs[] {
|
||||
const nextMonthFirstDay = this.date.add(1, 'month').startOf('month');
|
||||
const dates: Dayjs[] = [];
|
||||
|
||||
const lastDayOfUserWeek = ((this.firstDayOfWeekISO + 6 - 1) % 7) + 1; // ISO wrap
|
||||
const daysToAdd = (lastDayOfUserWeek - lastDayISO + 7) % 7;
|
||||
|
||||
for (let i = 0; i < daysToAdd; i++) {
|
||||
dates.push(nextMonthFirstDay.add(i, 'day'));
|
||||
}
|
||||
return dates;
|
||||
}
|
||||
|
||||
async createMonth() {
|
||||
const month = this.date.format('YYYY-MM');
|
||||
const dateNotesForMonth: DateNotesForMonth = await server.get(`special-notes/notes-for-month/${month}`);
|
||||
|
||||
this.$month.empty();
|
||||
|
||||
const firstDay = this.date.startOf('month');
|
||||
const firstDayISO = firstDay.isoWeekday();
|
||||
|
||||
// Previous month filler
|
||||
if (firstDayISO !== this.firstDayOfWeekISO) {
|
||||
const { weekNumber, dates } = this.getPrevMonthDays(firstDayISO);
|
||||
const prevMonth = this.date.subtract(1, 'month').format('YYYY-MM');
|
||||
const dateNotesForPrevMonth: DateNotesForMonth = await server.get(`special-notes/notes-for-month/${prevMonth}`);
|
||||
|
||||
const $weekNumber = this.createWeekNumber(weekNumber);
|
||||
this.$month.append($weekNumber);
|
||||
|
||||
dates.forEach(date => {
|
||||
const tempDate = this.date;
|
||||
this.date = date;
|
||||
const $day = this.createDay(dateNotesForPrevMonth, date.date());
|
||||
$day.addClass('calendar-date-prev-month');
|
||||
this.$month.append($day);
|
||||
this.date = tempDate;
|
||||
});
|
||||
}
|
||||
|
||||
const currentMonth = this.date.month();
|
||||
|
||||
// Main month
|
||||
while (this.date.month() === currentMonth) {
|
||||
const weekNumber = this.getWeekNumber(this.date);
|
||||
if (this.date.isoWeekday() === this.firstDayOfWeekISO) {
|
||||
const $weekNumber = this.createWeekNumber(weekNumber);
|
||||
this.$month.append($weekNumber);
|
||||
}
|
||||
|
||||
const $day = this.createDay(dateNotesForMonth, this.date.date());
|
||||
this.$month.append($day);
|
||||
this.date = this.date.add(1, 'day');
|
||||
}
|
||||
// while loop trips over and day is at 30/31, bring it back
|
||||
this.date = this.date.startOf('month').subtract(1, 'month');
|
||||
|
||||
// Add dates from next month
|
||||
const lastDayOfMonth = this.date.endOf('month');
|
||||
const lastDayISO = lastDayOfMonth.isoWeekday();
|
||||
const lastDayOfUserWeek = ((this.firstDayOfWeekISO + 6 - 1) % 7) + 1;
|
||||
|
||||
if (lastDayISO !== lastDayOfUserWeek) {
|
||||
const dates = this.getNextMonthDays(lastDayISO);
|
||||
const nextMonth = this.date.add(1, 'month').format('YYYY-MM');
|
||||
const dateNotesForNextMonth: DateNotesForMonth = await server.get(`special-notes/notes-for-month/${nextMonth}`);
|
||||
|
||||
dates.forEach(date => {
|
||||
const tempDate = this.date;
|
||||
this.date = date;
|
||||
const $day = this.createDay(dateNotesForNextMonth, date.date());
|
||||
$day.addClass('calendar-date-next-month');
|
||||
this.$month.append($day);
|
||||
this.date = tempDate;
|
||||
});
|
||||
}
|
||||
|
||||
this.$monthSelect.text(MONTHS[this.date.month()]);
|
||||
this.$yearSelect.val(this.date.year());
|
||||
}
|
||||
|
||||
async entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
|
||||
const WEEK_OPTIONS: (keyof OptionDefinitions)[] = [
|
||||
"firstDayOfWeek",
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import CalendarWidget from "../buttons/calendar.js";
|
||||
import SyncStatusWidget from "../sync_status.js";
|
||||
import BasicWidget, { wrapReactWidgets } from "../basic_widget.js";
|
||||
import utils, { isMobile } from "../../services/utils.js";
|
||||
@ -16,6 +15,7 @@ import QuickSearchWidget from "../quick_search.js";
|
||||
import { ParentComponent } from "../react/react_utils.jsx";
|
||||
import { useContext, useEffect, useMemo, useState } from "preact/hooks";
|
||||
import { LaunchBarActionButton, useLauncherIconAndTitle } from "../launch_bar/launch_bar_widgets.jsx";
|
||||
import CalendarWidget from "../launch_bar/CalendarWidget.jsx";
|
||||
|
||||
interface InnerWidget extends BasicWidget {
|
||||
settings?: {
|
||||
@ -98,7 +98,7 @@ export default class LauncherWidget extends BasicWidget {
|
||||
const builtinWidget = note.getLabelValue("builtinWidget");
|
||||
switch (builtinWidget) {
|
||||
case "calendar":
|
||||
return new CalendarWidget(note.title, note.getIcon());
|
||||
return <CalendarWidget launcherNote={note} />
|
||||
case "spacer":
|
||||
// || has to be inside since 0 is a valid value
|
||||
const baseSize = parseInt(note.getLabelValue("baseSize") || "40");
|
||||
|
||||
159
apps/client/src/widgets/launch_bar/CalendarWidget.tsx
Normal file
159
apps/client/src/widgets/launch_bar/CalendarWidget.tsx
Normal file
@ -0,0 +1,159 @@
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import FNote from "../../entities/fnote";
|
||||
import { LaunchBarDropdownButton, useLauncherIconAndTitle } from "./launch_bar_widgets";
|
||||
import { Dayjs, dayjs } from "@triliumnext/commons";
|
||||
import appContext from "../../components/app_context";
|
||||
import { useTriliumOptionInt } from "../react/hooks";
|
||||
import { VNode } from "preact";
|
||||
import clsx from "clsx";
|
||||
import "./CalendarWidget.css";
|
||||
import server from "../../services/server";
|
||||
|
||||
interface DateNotesForMonth {
|
||||
[date: string]: string;
|
||||
}
|
||||
|
||||
export default function CalendarWidget({ launcherNote }: { launcherNote: FNote }) {
|
||||
const { title, icon } = useLauncherIconAndTitle(launcherNote);
|
||||
const [ date, setDate ] = useState<Dayjs>();
|
||||
const [ rawFirstDayOfWeek ] = useTriliumOptionInt("firstDayOfWeek") ?? 0;
|
||||
const firstDayOfWeekISO = (rawFirstDayOfWeek === 0 ? 7 : rawFirstDayOfWeek);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
})
|
||||
|
||||
return (
|
||||
<LaunchBarDropdownButton
|
||||
icon={icon} title={title}
|
||||
onShown={() => {
|
||||
const dateNote = appContext.tabManager.getActiveContextNote()?.getOwnedLabelValue("dateNote");
|
||||
const activeDate = dateNote ? dayjs(`${dateNote}T12:00:00`) : null;
|
||||
const todaysDate = dayjs();
|
||||
const date = dayjs(activeDate || todaysDate).startOf('month');
|
||||
setDate(date);
|
||||
}}
|
||||
>
|
||||
{date && <div className="calendar-dropdown-widget" style={{ width: 400 }}>
|
||||
<Calendar date={date} firstDayOfWeekISO={firstDayOfWeekISO} />
|
||||
</div>}
|
||||
</LaunchBarDropdownButton>
|
||||
)
|
||||
}
|
||||
|
||||
function Calendar({ date, firstDayOfWeekISO }: { date: Dayjs, firstDayOfWeekISO: number }) {
|
||||
const month = date.format('YYYY-MM');
|
||||
const firstDay = date.startOf('month');
|
||||
const firstDayISO = firstDay.isoWeekday();
|
||||
|
||||
return (
|
||||
<div className="calendar-body" data-calendar-area="month">
|
||||
{firstDayISO !== firstDayOfWeekISO && <PreviousMonthDays date={date} firstDayISO={firstDayISO} firstDayOfWeekISO={firstDayOfWeekISO} />}
|
||||
<CurrentMonthDays date={date} firstDayOfWeekISO={firstDayOfWeekISO} />
|
||||
<NextMonthDays date={date} firstDayOfWeekISO={firstDayOfWeekISO} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function PreviousMonthDays({ date, firstDayISO, firstDayOfWeekISO }: { date: Dayjs, firstDayISO: number, firstDayOfWeekISO: number }) {
|
||||
const prevMonth = date.subtract(1, 'month').format('YYYY-MM');
|
||||
const { weekNumber, dates } = getPrevMonthDays(date, firstDayISO, firstDayOfWeekISO);
|
||||
const [ dateNotesForPrevMonth, setDateNotesForPrevMonth ] = useState<DateNotesForMonth>();
|
||||
|
||||
useEffect(() => {
|
||||
server.get<DateNotesForMonth>(`special-notes/notes-for-month/${prevMonth}`).then(setDateNotesForPrevMonth);
|
||||
}, [ date ]);
|
||||
|
||||
return dates.map(date => (
|
||||
<CalendarDay date={date} dateNotesForMonth={dateNotesForPrevMonth} className="calendar-date-prev-month" />
|
||||
));
|
||||
}
|
||||
|
||||
function CurrentMonthDays({ date, firstDayOfWeekISO }: { date: Dayjs, firstDayOfWeekISO: number }) {
|
||||
const dates = getCurMonthDays(date, firstDayOfWeekISO);
|
||||
|
||||
return dates.map(date => (
|
||||
<CalendarDay date={date} dateNotesForMonth={{}} />
|
||||
));
|
||||
}
|
||||
|
||||
function NextMonthDays({ date, firstDayOfWeekISO }: { date: Dayjs, firstDayOfWeekISO: number }) {
|
||||
const lastDayOfMonth = date.endOf('month');
|
||||
const lastDayISO = lastDayOfMonth.isoWeekday();
|
||||
const lastDayOfUserWeek = ((firstDayOfWeekISO + 6 - 1) % 7) + 1;
|
||||
const nextMonth = date.add(1, 'month').format('YYYY-MM');
|
||||
const [ dateNotesForNextMonth, setDateNotesForNextMonth ] = useState<DateNotesForMonth>();
|
||||
|
||||
useEffect(() => {
|
||||
server.get<DateNotesForMonth>(`special-notes/notes-for-month/${nextMonth}`).then(setDateNotesForNextMonth);
|
||||
}, [ date ]);
|
||||
|
||||
const dates = lastDayISO !== lastDayOfUserWeek ? getNextMonthDays(date, lastDayISO, firstDayOfWeekISO) : [];
|
||||
return dates.map(date => (
|
||||
<CalendarDay date={date} dateNotesForMonth={dateNotesForNextMonth} className="calendar-date-next-month" />
|
||||
));
|
||||
}
|
||||
|
||||
function CalendarDay({ date, dateNotesForMonth, className }: { date: Dayjs, dateNotesForMonth?: DateNotesForMonth, className?: string }) {
|
||||
return (
|
||||
<a
|
||||
className={clsx("calendar-date", className)}
|
||||
data-calendar-date={date.local().format("YYYY-MM-DD")}
|
||||
>
|
||||
<span>
|
||||
{date.date()}
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
function getPrevMonthDays(date: Dayjs, firstDayISO: number, firstDayOfWeekISO: number): { weekNumber: number, dates: Dayjs[] } {
|
||||
const prevMonthLastDay = date.subtract(1, 'month').endOf('month');
|
||||
const daysToAdd = (firstDayISO - firstDayOfWeekISO + 7) % 7;
|
||||
const dates: Dayjs[] = [];
|
||||
|
||||
const firstDay = date.startOf('month');
|
||||
const weekNumber = getWeekNumber(firstDay, firstDayOfWeekISO);
|
||||
|
||||
// Get dates from previous month
|
||||
for (let i = daysToAdd - 1; i >= 0; i--) {
|
||||
dates.push(prevMonthLastDay.subtract(i, 'day'));
|
||||
}
|
||||
|
||||
return { weekNumber, dates };
|
||||
}
|
||||
|
||||
function getCurMonthDays(date: Dayjs, firstDayOfWeekISO: number) {
|
||||
let dateCursor = date;
|
||||
const currentMonth = date.month();
|
||||
const dates: Dayjs[] = [];
|
||||
while (dateCursor.month() === currentMonth) {
|
||||
dates.push(dateCursor);
|
||||
dateCursor = dateCursor.add(1, "day");
|
||||
}
|
||||
return dates;
|
||||
}
|
||||
|
||||
function getNextMonthDays(date: Dayjs, lastDayISO: number, firstDayOfWeekISO): Dayjs[] {
|
||||
const nextMonthFirstDay = date.add(1, 'month').startOf('month');
|
||||
const dates: Dayjs[] = [];
|
||||
|
||||
const lastDayOfUserWeek = ((firstDayOfWeekISO + 6 - 1) % 7) + 1; // ISO wrap
|
||||
const daysToAdd = (lastDayOfUserWeek - lastDayISO + 7) % 7;
|
||||
|
||||
for (let i = 0; i < daysToAdd; i++) {
|
||||
dates.push(nextMonthFirstDay.add(i, 'day'));
|
||||
}
|
||||
return dates;
|
||||
}
|
||||
|
||||
function getWeekNumber(date: Dayjs, firstDayOfWeekISO: number): number {
|
||||
const weekStart = getWeekStartDate(date, firstDayOfWeekISO);
|
||||
return weekStart.isoWeek();
|
||||
}
|
||||
|
||||
function getWeekStartDate(date: Dayjs, firstDayOfWeekISO: number): Dayjs {
|
||||
const currentISO = date.isoWeekday();
|
||||
const diff = (currentISO - firstDayOfWeekISO + 7) % 7;
|
||||
return date.clone().subtract(diff, "day").startOf("day");
|
||||
}
|
||||
@ -20,7 +20,7 @@ export function LaunchBarActionButton(props: Omit<ActionButtonProps, "className"
|
||||
)
|
||||
}
|
||||
|
||||
export function LaunchBarDropdownButton({ children, icon, ...props }: Pick<DropdownProps, "title" | "children"> & { icon: string }) {
|
||||
export function LaunchBarDropdownButton({ children, icon, ...props }: Pick<DropdownProps, "title" | "children" | "onShown"> & { icon: string }) {
|
||||
return (
|
||||
<Dropdown
|
||||
className="right-dropdown-widget"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user