aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-09-04 13:05:17 -0400
committerbobzel <zzzman@gmail.com>2024-09-04 13:05:17 -0400
commit0b77229000231869695a6211e216d5b1755f53f7 (patch)
tree70bc7018a861c07a93cb855ce6ac55d449991ee8 /src
parent158d501642b0183b286913eb396c396922166435 (diff)
made calendarBox work
Diffstat (limited to 'src')
-rw-r--r--src/ClientUtils.ts3
-rw-r--r--src/client/views/collections/CollectionCalendarView.tsx4
-rw-r--r--src/client/views/collections/CollectionCardDeckView.scss18
-rw-r--r--src/client/views/nodes/calendarBox/CalendarBox.scss18
-rw-r--r--src/client/views/nodes/calendarBox/CalendarBox.tsx172
5 files changed, 131 insertions, 84 deletions
diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts
index 55801df81..51ad55c07 100644
--- a/src/ClientUtils.ts
+++ b/src/ClientUtils.ts
@@ -650,6 +650,7 @@ export function DivWidth(ele: HTMLElement | null): number {
export function dateRangeStrToDates(dateStr: string) {
// dateStr in yyyy-mm-dd format
const dateRangeParts = dateStr.split('|'); // splits into from and to date
+ if (dateRangeParts.length < 2) return { startDate: new Date(), endDate: new Date() };
const fromParts = dateRangeParts[0].split('-');
const toParts = dateRangeParts[1].split('-');
@@ -661,7 +662,7 @@ export function dateRangeStrToDates(dateStr: string) {
const toMonth = parseInt(toParts[1]) - 1;
const toDay = parseInt(toParts[2]);
- return [new Date(fromYear, fromMonth, fromDay), new Date(toYear, toMonth, toDay)];
+ return { startDate: new Date(fromYear, fromMonth, fromDay), endDate: new Date(toYear, toMonth, toDay) };
}
function replaceCanvases(oldDiv: HTMLElement, newDiv: HTMLElement) {
diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx
index 9eb16917b..c1f0b314b 100644
--- a/src/client/views/collections/CollectionCalendarView.tsx
+++ b/src/client/views/collections/CollectionCalendarView.tsx
@@ -38,8 +38,8 @@ export class CollectionCalendarView extends CollectionSubView() {
const aDateRangeStr = StrCast(DocListCast(calendarA.data).lastElement()?.date_range);
const bDateRangeStr = StrCast(DocListCast(calendarB.data).lastElement()?.date_range);
- const [aFromDate, aToDate] = dateRangeStrToDates(aDateRangeStr);
- const [bFromDate, bToDate] = dateRangeStrToDates(bDateRangeStr);
+ const { startDate: aFromDate, endDate: aToDate } = dateRangeStrToDates(aDateRangeStr);
+ const { startDate: bFromDate, endDate: bToDate } = dateRangeStrToDates(bDateRangeStr);
if (aFromDate > bFromDate) {
return -1; // a comes first
diff --git a/src/client/views/collections/CollectionCardDeckView.scss b/src/client/views/collections/CollectionCardDeckView.scss
index a089b248d..cc797d0bd 100644
--- a/src/client/views/collections/CollectionCardDeckView.scss
+++ b/src/client/views/collections/CollectionCardDeckView.scss
@@ -6,6 +6,15 @@
position: relative;
background-color: white;
overflow: hidden;
+
+ button {
+ width: 35px;
+ height: 35px;
+ border-radius: 50%;
+ background-color: $dark-gray;
+ // border-color: $medium-blue;
+ margin: 5px; // transform: translateY(-50px);
+ }
}
.card-wrapper {
@@ -34,15 +43,6 @@
justify-content: start; /* Centers buttons horizontally */
}
-button {
- width: 35px;
- height: 35px;
- border-radius: 50%;
- background-color: $dark-gray;
- // border-color: $medium-blue;
- margin: 5px; // transform: translateY(-50px);
-}
-
// button:hover {
// transform: translateY(-50px);
// }
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.scss b/src/client/views/nodes/calendarBox/CalendarBox.scss
new file mode 100644
index 000000000..8eee47e42
--- /dev/null
+++ b/src/client/views/nodes/calendarBox/CalendarBox.scss
@@ -0,0 +1,18 @@
+.calendarBox {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ .calendarBox-wrapper {
+ width: 100%;
+ height: 100%;
+ .fc-col-header {
+ width: 100% !important;
+ }
+ .fc-daygrid-body {
+ width: 100% !important;
+ .fc-scrollgrid-sync-table {
+ width: 100% !important;
+ }
+ }
+ }
+}
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index bd66941c3..ca35d85b3 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -1,16 +1,17 @@
import { Calendar, EventSourceInput } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import multiMonthPlugin from '@fullcalendar/multimonth';
-import { makeObservable } from 'mobx';
+import { action, computed, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { dateRangeStrToDates } from '../../../../ClientUtils';
-import { Doc } from '../../../../fields/Doc';
-import { StrCast } from '../../../../fields/Types';
+import { Doc, DocListCast } from '../../../../fields/Doc';
+import { NumCast, StrCast } from '../../../../fields/Types';
import { DocumentType } from '../../../documents/DocumentTypes';
import { Docs } from '../../../documents/Documents';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { FieldView, FieldViewProps } from '../FieldView';
+import './CalendarBox.scss';
type CalendarView = 'month' | 'multi-month' | 'week';
@@ -20,108 +21,135 @@ export class CalendarBox extends ViewBoxBaseComponent<FieldViewProps>() {
return FieldView.LayoutString(CalendarBox, fieldKey);
}
+ _calendarRef: HTMLDivElement | null = null;
+ _calendar: Calendar | undefined;
+ _oldWheel: HTMLElement | null = null;
+ _observer: ResizeObserver | undefined;
+
constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
- componentDidMount(): void {}
+ @observable _multiMonth = 0;
- componentWillUnmount(): void {}
+ componentDidMount(): void {
+ reaction(
+ () => this.calendarEvents,
+ events => {
+ this._calendar?.setOption('events', events);
+ },
+ { fireImmediately: true }
+ );
+ }
- _calendarRef = React.createRef<HTMLElement>();
+ @computed get calendarEvents(): EventSourceInput | undefined {
+ return this.childDocs.map(doc => {
+ const { startDate: start, endDate: end } = dateRangeStrToDates(StrCast(doc.date_range));
+
+ return {
+ title: StrCast(doc.title),
+ start,
+ end,
+ startEditable: true,
+ endEditable: true,
+ allDay: false,
+ classNames: ['mother'], // will determine the style
+ editable: true, // subject to change in the future
+ backgroundColor: this.eventToColor(doc),
+ color: 'white',
+ extendedProps: {
+ description: StrCast(doc.description),
+ },
+ };
+ });
+ }
- get dateRangeStr() {
- return StrCast(this.Document.date_range);
+ @computed get dateRangeStrDates() {
+ return dateRangeStrToDates(StrCast(this.Document.date_range));
}
// Choose a calendar view based on the date range
- get calendarViewType(): CalendarView {
- const [fromDate, toDate] = dateRangeStrToDates(this.dateRangeStr);
+ @computed get calendarViewType(): CalendarView {
+ const { startDate, endDate } = this.dateRangeStrDates;
- if (fromDate.getFullYear() !== toDate.getFullYear() || fromDate.getMonth() !== toDate.getMonth()) return 'multi-month';
+ if (startDate.getFullYear() !== endDate.getFullYear() || startDate.getMonth() !== endDate.getMonth()) return 'multi-month';
- if (Math.abs(fromDate.getDay() - toDate.getDay()) > 7) return 'month';
+ if (Math.abs(startDate.getDay() - endDate.getDay()) > 7) return 'month';
return 'week';
}
-
- get calendarStartDate() {
- return this.dateRangeStr.split('|')[0];
- }
-
- get calendarToDate() {
- return this.dateRangeStr.split('|')[1];
+ @computed get childDocs() {
+ return DocListCast(this.dataDoc[this.fieldKey]);
}
- get childDocs(): Doc[] {
- return this.childDocs; // get all sub docs for a calendar
- }
-
- docBackgroundColor(type: string): string {
+ eventToColor(event: Doc): string {
// TODO: Return a different color based on the event type
- console.log(type);
+ console.log(event.title);
return 'blue';
}
- get calendarEvents(): EventSourceInput | undefined {
- if (this.childDocs.length === 0) return undefined;
- return this.childDocs.map(doc => {
- const docTitle = StrCast(doc.title);
- const docDateRange = StrCast(doc.date_range);
- const [startDate, endDate] = dateRangeStrToDates(docDateRange);
- const docType = doc.type;
- const docDescription = doc.description ? StrCast(doc.description) : '';
-
- return {
- title: docTitle,
- start: startDate,
- end: endDate,
- allDay: false,
- classNames: [StrCast(docType)], // will determine the style
- editable: false, // subject to change in the future
- backgroundColor: this.docBackgroundColor(StrCast(doc.type)),
- color: 'white',
- extendedProps: {
- description: docDescription,
- },
- };
- });
- }
-
handleEventClick = (/* arg: EventClickArg */) => {
// TODO: open popover with event description, option to open CalendarManager and change event date, delete event, etc.
};
- calendarEl: HTMLElement = document.getElementById('calendar-box-v1')!;
-
// https://fullcalendar.io
- get calendar() {
- return new Calendar(this.calendarEl, {
- plugins: [this.calendarViewType === 'multi-month' ? multiMonthPlugin : dayGridPlugin],
- headerToolbar: {
- left: 'prev,next today',
- center: 'title',
- right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek',
- },
- initialDate: this.calendarStartDate,
- navLinks: true,
- editable: false,
- displayEventTime: false,
- displayEventEnd: false,
- events: this.calendarEvents,
- eventClick: this.handleEventClick,
- });
- }
+ renderCalendar = () => {
+ const cal = !this._calendarRef
+ ? null
+ : (this._calendar = new Calendar(this._calendarRef, {
+ plugins: [multiMonthPlugin, dayGridPlugin],
+ headerToolbar: {
+ left: 'prev,next today',
+ center: 'title',
+ right: 'dayGridMonth multiMonth', // timeGridWeek timeGridDay listWeek',
+ },
+ initialDate: this.dateRangeStrDates.startDate,
+ navLinks: true,
+ editable: false,
+ displayEventTime: false,
+ displayEventEnd: false,
+ aspectRatio: NumCast(this.Document.width) / NumCast(this.Document.height),
+ events: this.calendarEvents,
+ eventClick: this.handleEventClick,
+ }));
+ cal?.render();
+ };
+ onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
render() {
+ this._multiMonth;
return (
- <div className="calendar-box-conatiner">
- <div id="calendar-box-v1" />
+ <div
+ key={this._multiMonth}
+ className="calendarBox"
+ onPointerDown={action(e =>
+ setTimeout(() => {
+ if ((e.nativeEvent.target as HTMLButtonElement)?.className?.includes('multiMonth-button')) {
+ this._multiMonth = this._multiMonth + 1;
+ }
+ })
+ )}
+ ref={r => {
+ this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
+ this._oldWheel = r;
+ // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
+ r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+
+ 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();
+ }
+ }}>
+ <div className="calendarBox-wrapper" ref={r => (this._calendarRef = r)} />
</div>
);
}
}
Docs.Prototypes.TemplateMap.set(DocumentType.CALENDAR, {
layout: { view: CalendarBox, dataField: 'data' },
- options: { acl: '' },
+ options: { acl: '', _layout_nativeDimEditable: true, _layout_reflowHorizontal: true, _layout_reflowVertical: true },
});