From b719a2c39183efaa7ab82a6cc87a5d2a56a6f243 Mon Sep 17 00:00:00 2001 From: Franco Speziali Date: Thu, 17 Mar 2022 14:48:10 +0100 Subject: [PATCH] Added EventGroupingHtmlRenderer initial concept --- src/EventGroupingHtmlRenderer/DayRenderer.ts | 27 +++++ .../MonthRenderer.ts | 32 ++++++ src/EventGroupingHtmlRenderer/Renderer.ts | 101 ++++++++++++++++++ src/EventGroupingHtmlRenderer/WeekRenderer.ts | 28 +++++ 4 files changed, 188 insertions(+) create mode 100644 src/EventGroupingHtmlRenderer/DayRenderer.ts create mode 100644 src/EventGroupingHtmlRenderer/MonthRenderer.ts create mode 100644 src/EventGroupingHtmlRenderer/Renderer.ts create mode 100644 src/EventGroupingHtmlRenderer/WeekRenderer.ts diff --git a/src/EventGroupingHtmlRenderer/DayRenderer.ts b/src/EventGroupingHtmlRenderer/DayRenderer.ts new file mode 100644 index 0000000..a5c152d --- /dev/null +++ b/src/EventGroupingHtmlRenderer/DayRenderer.ts @@ -0,0 +1,27 @@ +import EventGrouping from "../EventGrouping"; +import Renderer from "./Renderer"; + +export default class DayRenderer extends Renderer { + constructor(eventGrouping: EventGrouping) { + super(eventGrouping); + this.container.className += " scale-day"; + } + + protected renderDateAsIcon(eventDate, groupIndex): HTMLSpanElement { + const html = document.createElement("span"); + html.className = "event"; + + const dayInMonth = eventDate.getDate(); + + if (dayInMonth === 1) { + html.textContent = eventDate + .toLocaleDateString(undefined, { month: "long" }) + .slice(0, 3); + html.className += " primary"; + } else { + html.textContent = dayInMonth.toString(); + } + + return html; + } +} diff --git a/src/EventGroupingHtmlRenderer/MonthRenderer.ts b/src/EventGroupingHtmlRenderer/MonthRenderer.ts new file mode 100644 index 0000000..3e7e218 --- /dev/null +++ b/src/EventGroupingHtmlRenderer/MonthRenderer.ts @@ -0,0 +1,32 @@ +import EventGrouping from "../EventGrouping"; +import Renderer from "./Renderer"; + +export default class MonthRenderer extends Renderer { + constructor(eventGrouping: EventGrouping) { + super(eventGrouping); + this.container.className += " scale-month"; + } + + protected renderDateAsIcon(eventDate, groupIndex): HTMLSpanElement { + const html = document.createElement("span"); + html.className = "event"; + + // unlike getDate(), getMonth is 0 based + const month = eventDate.getMonth() + 1; + + if (month === 1) { + html.textContent = eventDate.toLocaleDateString(undefined, { + year: "numeric", + }); + html.className += " primary"; + } else { + html.textContent = eventDate + .toLocaleDateString(undefined, { + month: "long", + }) + .slice(0, 3); + } + + return html; + } +} diff --git a/src/EventGroupingHtmlRenderer/Renderer.ts b/src/EventGroupingHtmlRenderer/Renderer.ts new file mode 100644 index 0000000..bbe5863 --- /dev/null +++ b/src/EventGroupingHtmlRenderer/Renderer.ts @@ -0,0 +1,101 @@ +import { generateRandomColor } from "../utilities"; +import EventGrouping from "../EventGrouping"; +import { Event } from "../types"; + +export default abstract class Renderer { + protected abstract renderDateAsIcon( + eventDate: Date, + groupIndex: number + ): HTMLSpanElement; + + protected container: HTMLDivElement; + protected eventGrouping: EventGrouping; + + protected constructor(eventGrouping: EventGrouping) { + this.container = document.createElement("div"); + this.container.className = "event-calendar"; + this.eventGrouping = eventGrouping; + } + + protected renderGroups(): HTMLDivElement[] { + return this.eventGrouping.groups.map((group, index) => { + const html = document.createElement("div"); + html.className = "group"; + + if (group.length) { + const htmlHoverCard = this.renderHoverCard(group); + html.appendChild(htmlHoverCard); + } + + let htmlGroupIcon: HTMLSpanElement; + // only need to render icon from first event in group + const event = group[0]; + + if (event) { + htmlGroupIcon = this.renderIcon(event); + html.className += " icon"; + if (event.bgColor) { + html.style.backgroundColor = event.bgColor; + } else { + const randomColor = generateRandomColor(); + html.style.backgroundColor = `rgb(${randomColor.r}, ${randomColor.g}, ${randomColor.b})`; + } + } else { + const eventDate = this.eventGrouping.getDateFromGroupIndex(index); + htmlGroupIcon = this.renderDateAsIcon(eventDate, index); + } + + html.appendChild(htmlGroupIcon); + + return html; + }); + } + + protected renderHoverCard(events: Event[]): HTMLDivElement { + const htmlHoverCard = document.createElement("div"); + htmlHoverCard.className = "hover-card"; + + const cardDetails = events.map((event) => { + if (!event) { + return; + } + + const htmlEvent = document.createElement("div"); + const htmlDateText = document.createElement("p"); + htmlDateText.textContent = event.date.toLocaleDateString(); + const htmlEventTitle = document.createElement("p"); + htmlEventTitle.textContent = event.title; + const htmlEventText = document.createElement("p"); + htmlEventText.textContent = event.text; + + htmlEvent.appendChild(htmlDateText); + htmlEvent.appendChild(htmlEventTitle); + htmlEvent.appendChild(htmlEventText); + + return htmlEvent; + }); + + cardDetails.forEach((cardDetail) => htmlHoverCard.appendChild(cardDetail)); + + return htmlHoverCard; + } + + protected renderIcon(event: Event | undefined): HTMLSpanElement { + const html = document.createElement("span"); + html.className = "event"; + + if (event.icon) { + html.textContent = event.icon; + } + + return html; + } + + public render() { + const groups = this.renderGroups(); + + groups.forEach((group) => this.container.appendChild(group)); + + return this.container; + } +} diff --git a/src/EventGroupingHtmlRenderer/WeekRenderer.ts b/src/EventGroupingHtmlRenderer/WeekRenderer.ts new file mode 100644 index 0000000..4dce8a0 --- /dev/null +++ b/src/EventGroupingHtmlRenderer/WeekRenderer.ts @@ -0,0 +1,28 @@ +import { getWeek } from "date-fns"; +import EventGrouping from "../EventGrouping"; +import Renderer from "./Renderer"; + +export default class WeekRenderer extends Renderer { + constructor(eventGrouping: EventGrouping) { + super(eventGrouping); + this.container.className += " scale-week"; + } + + protected renderDateAsIcon(eventDate, groupIndex): HTMLSpanElement { + const html = document.createElement("span"); + html.className = "event"; + + const week = getWeek(eventDate); + + if (week === 1) { + html.textContent = eventDate.toLocaleDateString(undefined, { + year: "numeric", + }); + html.className += " primary"; + } else { + html.textContent = week.toString(); + } + + return html; + } +}