From da0616f4f3719f14ba6fd1a9580730a576e198e2 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 14 May 2025 23:31:31 -0400 Subject: fixed selecting allDay for calendar. fixed turning off allDay when moving calendar events. fixed undoing calendar drags. --- src/client/views/nodes/calendarBox/CalendarBox.tsx | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes/calendarBox') diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx index 2b20a666d..c1198f328 100644 --- a/src/client/views/nodes/calendarBox/CalendarBox.tsx +++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx @@ -17,6 +17,7 @@ import { ContextMenu } from '../../ContextMenu'; import { DocumentView } from '../DocumentView'; import { OpenWhere } from '../OpenWhere'; import './CalendarBox.scss'; +import { undoable } from '../../../util/UndoManager'; type CalendarView = 'multiMonth' | 'dayGridMonth' | 'timeGridWeek' | 'timeGridDay'; @@ -27,15 +28,15 @@ export class CalendarBox extends CollectionSubView() { _observer: ResizeObserver | undefined; _eventsDisposer: IReactionDisposer | undefined; _selectDisposer: IReactionDisposer | undefined; + _isMultiMonth: boolean | undefined; + + @observable _multiMonth = 0; constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } - @observable _multiMonth = 0; - isMultiMonth: boolean | undefined; - componentDidMount(): void { this._props.setContentViewBox?.(this); this._eventsDisposer = reaction( @@ -52,7 +53,7 @@ export class CalendarBox extends CollectionSubView() { type: 'CHANGE_DATE', dateMarker: state.dateEnv.createMarker(initialDate.start), }); - setTimeout(() => (initialDate.start.toISOString() !== initialDate.end.toISOString() ? this._calendar?.select(initialDate.start, initialDate.end) : this._calendar?.select(initialDate.start))); + setTimeout(() => initialDate.start.toISOString() !== initialDate.end.toISOString() && this._calendar?.select(initialDate.start, initialDate.end)); }, { fireImmediately: true } ); @@ -95,7 +96,7 @@ export class CalendarBox extends CollectionSubView() { // Choose a calendar view based on the date range @computed get calendarViewType(): CalendarView { if (this.dataDoc[this.fieldKey + '_calendarType']) return StrCast(this.dataDoc[this.fieldKey + '_calendarType']) as CalendarView; - if (this.isMultiMonth) return 'multiMonth'; + if (this._isMultiMonth) return 'multiMonth'; const { start, end } = this.dateRangeStrDates; if (start.getFullYear() !== end.getFullYear() || start.getMonth() !== end.getMonth()) return 'multiMonth'; if (Math.abs(start.getDay() - end.getDay()) > 7) return 'dayGridMonth'; @@ -122,10 +123,13 @@ export class CalendarBox extends CollectionSubView() { return false; }; - handleEventDrop = (arg: EventDropArg) => { + handleEventDrop = undoable((arg: EventDropArg) => { const doc = DocServer.GetCachedRefField(arg.event._def.groupId ?? ''); - doc && arg.event.start && (doc.date_range = arg.event.start?.toString() + '|' + (arg.event.end ?? arg.event.start).toString()); - }; + if (doc && arg.event.start) { + doc.$allDay = false; + doc.$date_range = arg.event.start?.toString() + '|' + (arg.event.end ?? arg.event.start).toString(); + } + }, 'change event date'); handleEventClick = (arg: EventClickArg) => { const doc = DocServer.GetCachedRefField(arg.event._def.groupId ?? ''); @@ -163,7 +167,7 @@ export class CalendarBox extends CollectionSubView() { displayEventEnd: false, select: info => { const start = dateRangeStrToDates(info.startStr).start.toISOString(); - const end = dateRangeStrToDates(info.endStr).start.toISOString(); + const end = info.allDay ? start : dateRangeStrToDates(info.endStr).start.toISOString(); this.dataDoc.date = start + '|' + end; }, aspectRatio: NumCast(this.Document.width) / NumCast(this.Document.height), -- cgit v1.2.3-70-g09d2 From 3f144d7bad65af2424d27e2e3a58eecd0d0e114b Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 15 May 2025 13:34:56 -0400 Subject: cleaned up calendarBox to have a more reactive UI and to fix some bugs with selecting and autoscroling. --- package-lock.json | 18 ++- package.json | 7 +- .../views/nodes/calendarBox/CalendarBox.scss | 3 +- src/client/views/nodes/calendarBox/CalendarBox.tsx | 141 ++++++++++++--------- 4 files changed, 102 insertions(+), 67 deletions(-) (limited to 'src/client/views/nodes/calendarBox') diff --git a/package-lock.json b/package-lock.json index 28b81dbc7..a8752cb5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,9 +28,10 @@ "@fortawesome/free-regular-svg-icons": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/react-fontawesome": "^0.2.2", - "@fullcalendar/core": "^6.1.15", - "@fullcalendar/daygrid": "^6.1.10", - "@fullcalendar/multimonth": "^6.1.10", + "@fullcalendar/core": "^6.1.17", + "@fullcalendar/daygrid": "^6.1.17", + "@fullcalendar/multimonth": "^6.1.17", + "@fullcalendar/react": "^6.1.17", "@fullcalendar/timegrid": "^6.1.15", "@internationalized/date": "^3.5.0", "@mozilla/readability": "^0.6.0", @@ -4581,6 +4582,17 @@ "@fullcalendar/core": "~6.1.17" } }, + "node_modules/@fullcalendar/react": { + "version": "6.1.17", + "resolved": "https://registry.npmjs.org/@fullcalendar/react/-/react-6.1.17.tgz", + "integrity": "sha512-AA8soHhlfRH5dUeqHnfAtzDiXa2vrgWocJSK/F5qzw/pOxc9MqpuoS/nQBROWtHHg6yQUg3DoGqOOhi7dmylXQ==", + "license": "MIT", + "peerDependencies": { + "@fullcalendar/core": "~6.1.17", + "react": "^16.7.0 || ^17 || ^18 || ^19", + "react-dom": "^16.7.0 || ^17 || ^18 || ^19" + } + }, "node_modules/@fullcalendar/timegrid": { "version": "6.1.17", "resolved": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-6.1.17.tgz", diff --git a/package.json b/package.json index 6a579efd2..382c71aed 100644 --- a/package.json +++ b/package.json @@ -112,9 +112,10 @@ "@fortawesome/free-regular-svg-icons": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/react-fontawesome": "^0.2.2", - "@fullcalendar/core": "^6.1.15", - "@fullcalendar/daygrid": "^6.1.10", - "@fullcalendar/multimonth": "^6.1.10", + "@fullcalendar/core": "^6.1.17", + "@fullcalendar/daygrid": "^6.1.17", + "@fullcalendar/multimonth": "^6.1.17", + "@fullcalendar/react": "^6.1.17", "@fullcalendar/timegrid": "^6.1.15", "@internationalized/date": "^3.5.0", "@mozilla/readability": "^0.6.0", diff --git a/src/client/views/nodes/calendarBox/CalendarBox.scss b/src/client/views/nodes/calendarBox/CalendarBox.scss index f8ac4b2d1..e3e0bae4b 100644 --- a/src/client/views/nodes/calendarBox/CalendarBox.scss +++ b/src/client/views/nodes/calendarBox/CalendarBox.scss @@ -3,7 +3,8 @@ width: 100%; height: 100%; transform-origin: top left; - .calendarBox-wrapper { + overflow: auto; + > div { width: 100%; height: 100%; .fc-timegrid-body { diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx index c1198f328..2d6c8c9a4 100644 --- a/src/client/views/nodes/calendarBox/CalendarBox.tsx +++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx @@ -3,13 +3,14 @@ import dayGridPlugin from '@fullcalendar/daygrid'; import interactionPlugin from '@fullcalendar/interaction'; import multiMonthPlugin from '@fullcalendar/multimonth'; import timeGrid from '@fullcalendar/timegrid'; -import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; +import FullCalendar from '@fullcalendar/react'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction, trace, untracked } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { dateRangeStrToDates } from '../../../../ClientUtils'; import { Doc } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; -import { BoolCast, NumCast, StrCast } from '../../../../fields/Types'; +import { BoolCast, StrCast } from '../../../../fields/Types'; import { DocServer } from '../../../DocServer'; import { DragManager } from '../../../util/DragManager'; import { CollectionSubView, SubCollectionViewProps } from '../../collections/CollectionSubView'; @@ -23,7 +24,7 @@ type CalendarView = 'multiMonth' | 'dayGridMonth' | 'timeGridWeek' | 'timeGridDa @observer export class CalendarBox extends CollectionSubView() { - _calendarRef: HTMLDivElement | null = null; + _calendarRef: FullCalendar | null = null; _calendar: Calendar | undefined; _observer: ResizeObserver | undefined; _eventsDisposer: IReactionDisposer | undefined; @@ -148,56 +149,85 @@ export class CalendarBox extends CollectionSubView() { }; // https://fullcalendar.io - renderCalendar = () => { - const cal = !this._calendarRef - ? null - : (this._calendar = new Calendar(this._calendarRef, { - plugins: [multiMonthPlugin, dayGridPlugin, timeGrid, interactionPlugin], - headerToolbar: { - left: 'prev,next today', - center: 'title', - right: 'multiMonth dayGridMonth timeGridWeek timeGridDay', - }, - selectable: true, - initialView: this.calendarViewType === 'multiMonth' ? undefined : this.calendarViewType, - initialDate: this.dateSelect.start, - navLinks: true, - editable: false, - displayEventTime: false, - displayEventEnd: false, - select: info => { - const start = dateRangeStrToDates(info.startStr).start.toISOString(); - const end = info.allDay ? start : dateRangeStrToDates(info.endStr).start.toISOString(); - this.dataDoc.date = start + '|' + end; - }, - aspectRatio: NumCast(this.Document.width) / NumCast(this.Document.height), - events: this.calendarEvents, - eventClick: this.handleEventClick, - eventDrop: this.handleEventDrop, - eventDidMount: arg => { - arg.el.addEventListener('pointerdown', ev => { - ev.button && ev.stopPropagation(); - }); - if (navigator.userAgent.includes('Macintosh')) { - arg.el.addEventListener('pointerup', ev => { - ev.button && ev.stopPropagation(); - ev.button && this.handleEventContextMenu(ev.pageX, ev.pageY, arg.event._def.groupId); - }); - } - arg.el.addEventListener('contextmenu', ev => { - if (!navigator.userAgent.includes('Macintosh')) { - this.handleEventContextMenu(ev.pageX, ev.pageY, arg.event._def.groupId); + @computed get renderCalendar() { + const availableWidth = this._props.PanelWidth() / (this._props.DocumentView?.().UIBtnScaling ?? 1); + const btn = (text: string, view: string | (() => void), hint: string) => ({ text, hint, click: typeof view === 'string' ? () => this._calendarRef?.getApi().changeView(view) : view }); + return ( + (this._calendarRef = r)} + customButtons={{ + nowBtn: btn('Now', () => this._calendarRef?.getApi().gotoDate(new Date()), 'Go to Today'), + multiBtn: btn('M+', 'multiMonth', 'Multiple Month View'), + monthBtn: btn('M', 'dayGridMonth', 'Month View'), + weekBtn: btn('W', 'timeGridWeek', 'Week View'), + dayBtn: btn('D', 'timeGridDay', 'Day View'), + }} + headerToolbar={ + availableWidth > 450 + ? { + left: 'prev,next nowBtn', + center: 'title', + right: 'multiBtn monthBtn weekBtn dayBtn', } - ev.stopPropagation(); - ev.preventDefault(); - }); - }, - })); - cal?.render(); - setTimeout(() => cal?.view.calendar.select(this.dateSelect.start, this.dateSelect.end)); - }; + : availableWidth > 300 + ? { + left: 'prev,next', + center: 'title', + right: '', + } + : { + left: '', + center: 'title', + right: '', + } + } + selectable={true} + initialView={this.calendarViewType === 'multiMonth' ? undefined : this.calendarViewType} + initialDate={untracked(() => this.dateSelect.start)} + navLinks={true} + editable={false} + // expandRows={true} + // handleWindowResize={true} + displayEventTime={false} + displayEventEnd={false} + plugins={[multiMonthPlugin, dayGridPlugin, timeGrid, interactionPlugin]} + aspectRatio={this._props.PanelWidth() / this._props.PanelHeight()} + weekends={false} + events={this.calendarEvents} + eventClick={this.handleEventClick} + eventDrop={this.handleEventDrop} + unselectAuto={false} + // unselect={() => {}} + select={info => { + const start = dateRangeStrToDates(info.startStr).start.toISOString(); + const end = info.allDay ? start : dateRangeStrToDates(info.endStr).start.toISOString(); + this.dataDoc.date = start + '|' + end; + }} + // eventContent={() => { + // return null; + // }} + eventDidMount={arg => { + arg.el.addEventListener('pointerdown', ev => ev.button && ev.stopPropagation()); + if (navigator.userAgent.includes('Macintosh')) { + arg.el.addEventListener('pointerup', ev => { + ev.button && ev.stopPropagation(); + ev.button && this.handleEventContextMenu(ev.pageX, ev.pageY, arg.event._def.groupId); + }); + } + arg.el.addEventListener('contextmenu', ev => { + if (!navigator.userAgent.includes('Macintosh')) { + this.handleEventContextMenu(ev.pageX, ev.pageY, arg.event._def.groupId); + } + ev.stopPropagation(); + ev.preventDefault(); + }); + }} + /> + ); + } render() { + trace(); return (
{ this.createDashEventsTarget(r); this.fixWheelEvents(r, this._props.isContentActive); - - if (r) { - this._observer?.disconnect(); - (this._observer = new ResizeObserver(() => { - this._calendar?.setOption('aspectRatio', NumCast(this.Document.width) / NumCast(this.Document.height)); - this._calendar?.updateSize(); - })).observe(r); - this.renderCalendar(); - } }}> -
(this._calendarRef = r)} /> + {this.renderCalendar}
); } -- cgit v1.2.3-70-g09d2 From 3741baee864a8bec757b4e50a58698a0064293be Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 15 May 2025 14:21:32 -0400 Subject: scroll wheel fixes for calendarBox --- src/client/views/nodes/calendarBox/CalendarBox.scss | 7 +++++++ src/client/views/nodes/calendarBox/CalendarBox.tsx | 5 ++--- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes/calendarBox') diff --git a/src/client/views/nodes/calendarBox/CalendarBox.scss b/src/client/views/nodes/calendarBox/CalendarBox.scss index e3e0bae4b..a607846df 100644 --- a/src/client/views/nodes/calendarBox/CalendarBox.scss +++ b/src/client/views/nodes/calendarBox/CalendarBox.scss @@ -1,3 +1,4 @@ +.calendarBox-interactive, .calendarBox { display: flex; width: 100%; @@ -5,6 +6,7 @@ transform-origin: top left; overflow: auto; > div { + pointer-events: none; width: 100%; height: 100%; .fc-timegrid-body { @@ -24,3 +26,8 @@ } } } +.calendarBox-interactive { + > div { + pointer-events: unset; + } +} diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx index 2d6c8c9a4..504dc2559 100644 --- a/src/client/views/nodes/calendarBox/CalendarBox.tsx +++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx @@ -4,7 +4,7 @@ import interactionPlugin from '@fullcalendar/interaction'; import multiMonthPlugin from '@fullcalendar/multimonth'; import timeGrid from '@fullcalendar/timegrid'; import FullCalendar from '@fullcalendar/react'; -import { IReactionDisposer, action, computed, makeObservable, observable, reaction, trace, untracked } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction, untracked } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { dateRangeStrToDates } from '../../../../ClientUtils'; @@ -227,11 +227,10 @@ export class CalendarBox extends CollectionSubView() { } render() { - trace(); return (
{ setTimeout( action(() => { -- cgit v1.2.3-70-g09d2