Added option for grouping by year (for handling events that span multiple years)

This commit is contained in:
Franco Speziali 2022-06-14 18:40:47 +02:00
parent 1d848131a3
commit a936de4285
8 changed files with 119 additions and 10 deletions

View File

@ -4,7 +4,7 @@ This is a plugin for the [Joplin](https://joplinapp.org/) note-taking app.
It creates a calendar view of events that have been specified using the [YAML](https://yaml.org/) syntax within a fenced block.
- Organises events into "groupings"; you can group events by **day**, **week** or by **month**
- Organises events into "groupings"; you can group events by **day**, **week**, **month** or **year**
- Focus is on readability and simplicity of content, which is why the **YAML** is simple in structure
###### Example Day view
@ -13,10 +13,11 @@ It creates a calendar view of events that have been specified using the [YAML](h
## Features
- A grouping that contains no events will show the **date** (day grouping), **week number** (week grouping), or **month** (month grouping)
- A grouping that contains no events will show the **date** (day grouping), **week number** (week grouping), **month** (month grouping), or **year** (year grouping)
- If a grouping falls under the **current date**, it is highlighted in yellow
- Events can be specified in **any order**
- Events can be assigned an **icon** 🎁 such as an emoji
- Events without an icon will use the first 2 characters from the title
## How to use
@ -40,7 +41,7 @@ Events are specified using the YAML syntax, with the following keys:
> Sets the grouping for the view
> - _**optional**_
> - **default** `day`
> - **accepts** : `day`, `week`, `month`, `d`, `w`, `m`
> - **accepts** : `day`, `week`, `month`, `year`, `d`, `w`, `m`, `y`
### events:
> Each individual event is a list with its own properties

View File

@ -1,7 +1,17 @@
import { GroupTypes } from "../types";
import Events from "../Events/";
import { DayGrouping, WeekGrouping, MonthGrouping } from "../EventGrouping";
import { DayRenderer, WeekRenderer, MonthRenderer } from "../HtmlRenderer";
import {
DayGrouping,
MonthGrouping,
WeekGrouping,
YearGrouping,
} from "../EventGrouping";
import {
DayRenderer,
MonthRenderer,
WeekRenderer,
YearRenderer,
} from "../HtmlRenderer";
export default class Calendar {
public readonly jsonContent: object;
@ -30,6 +40,10 @@ export default class Calendar {
return new MonthRenderer(
new MonthGrouping(this.events.sortedEvents)
).render();
case GroupTypes.Year:
return new YearRenderer(
new YearGrouping(this.events.sortedEvents)
).render();
}
}
}

View File

@ -0,0 +1,42 @@
import EventGrouping from "./EventGrouping";
import { Event, Groups } from "../types";
import {
add,
differenceInCalendarYears,
isThisYear as dateFnsIsThisYear,
} from "date-fns";
export default class YearGrouping extends EventGrouping {
static isThisYear(date: Date): boolean {
return dateFnsIsThisYear(date);
}
constructor(sortedEvents: Event[]) {
super(sortedEvents);
this.groups = this.group();
}
group(): Groups {
const numberOfGroups = differenceInCalendarYears(
this.lastEvent.date,
this.firstEvent.date
);
return this.sortedEvents.reduce((prev, event) => {
const groupNumber = differenceInCalendarYears(
event.date,
this.firstEvent.date
);
prev[groupNumber].push(event);
return prev;
}, this.generateEmptyGroups(numberOfGroups));
}
public getDateFromGroupIndex(index: number): Date {
const startDate = this.firstEvent.date;
return add(startDate, { years: index });
}
}

View File

@ -1,5 +1,6 @@
import DayGrouping from "./DayGrouping";
import WeekGrouping from "./WeekGrouping";
import MonthGrouping from "./MonthGrouping";
import YearGrouping from "./YearGrouping";
export { DayGrouping, WeekGrouping, MonthGrouping };
export { DayGrouping, WeekGrouping, MonthGrouping, YearGrouping };

View File

@ -0,0 +1,30 @@
import { Event } from "../../types";
import { YearGrouping } from "../../EventGrouping";
import GroupRenderer from "../Abstract/GroupRenderer";
export default class GroupYearRenderer extends GroupRenderer {
constructor(group: Event[], groupDate: Date, groupIndex: number) {
super(group, groupDate, groupIndex);
if (YearGrouping.isThisYear(groupDate)) {
this.highlightGroup();
}
}
protected renderDateAsIcon(eventDate, groupIndex): HTMLSpanElement {
const html = document.createElement("span");
html.className = "icon";
html.textContent = eventDate.toLocaleDateString(undefined, {
year: "numeric",
});
html.className += " primary";
if (YearGrouping.isThisYear(eventDate)) {
html.className += " highlighted";
}
return html;
}
}

View File

@ -0,0 +1,19 @@
import { Event } from "../../types";
import { YearGrouping } from "../../EventGrouping";
import Renderer from "../Abstract/Renderer";
import GroupYearRenderer from "./GroupYearRenderer";
export default class YearRenderer extends Renderer {
constructor(eventGrouping: YearGrouping) {
super(eventGrouping);
this.container.className += " scale-year";
}
protected renderGroups(
group: Event[],
groupDate: Date,
groupIndex: number
): HTMLDivElement {
return new GroupYearRenderer(group, groupDate, groupIndex).render();
}
}

View File

@ -1,5 +1,6 @@
import DayRenderer from "./Day/";
import WeekRenderer from "./Week/";
import MonthRenderer from "./Month/";
import DayRenderer from "./Day";
import WeekRenderer from "./Week";
import MonthRenderer from "./Month";
import YearRenderer from "./Year";
export { DayRenderer, WeekRenderer, MonthRenderer };
export { DayRenderer, WeekRenderer, MonthRenderer, YearRenderer };

View File

@ -2,6 +2,7 @@ export enum GroupTypes {
Day = "D",
Week = "W",
Month = "M",
Year = "Y",
}
export interface Event {