diff --git a/src/EventGroupingHtmlRenderer/DayRenderer.ts b/src/EventGroupingHtmlRenderer/DayRenderer.ts index 2c40bc0..bf1e180 100644 --- a/src/EventGroupingHtmlRenderer/DayRenderer.ts +++ b/src/EventGroupingHtmlRenderer/DayRenderer.ts @@ -1,5 +1,7 @@ +import { Event } from "../types"; import { DayGrouping } from "../EventGrouping"; import Renderer from "./Renderer"; +import GroupDayRenderer from "./GroupRenderer/GroupDayRenderer"; export default class DayRenderer extends Renderer { constructor(eventGrouping: DayGrouping) { @@ -7,21 +9,11 @@ export default class DayRenderer extends Renderer { this.container.className += " scale-day"; } - protected renderDateAsIcon(eventDate, groupIndex): HTMLSpanElement { - const html = document.createElement("span"); - html.className = "icon"; - - 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; + protected renderGroups( + group: Event[], + groupDate: Date, + groupIndex: number + ): HTMLDivElement { + return new GroupDayRenderer(group, groupDate, groupIndex).render(); } } diff --git a/src/EventGroupingHtmlRenderer/GroupRenderer/GroupDayRenderer.ts b/src/EventGroupingHtmlRenderer/GroupRenderer/GroupDayRenderer.ts new file mode 100644 index 0000000..8ffe374 --- /dev/null +++ b/src/EventGroupingHtmlRenderer/GroupRenderer/GroupDayRenderer.ts @@ -0,0 +1,32 @@ +import { Event } from "../../types"; +import { DayGrouping } from "../../EventGrouping"; + +import GroupRenderer from "./GroupRenderer"; + +export default class GroupDayRenderer extends GroupRenderer { + constructor(group: Event[], groupDate: Date, groupIndex: number) { + super(group, groupDate, groupIndex); + + if (DayGrouping.isToday(groupDate)) { + this.highlightGroup(); + } + } + + protected renderDateAsIcon(eventDate, groupIndex): HTMLSpanElement { + const html = document.createElement("span"); + html.className = "icon"; + + 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/GroupRenderer/GroupMonthRenderer.ts b/src/EventGroupingHtmlRenderer/GroupRenderer/GroupMonthRenderer.ts new file mode 100644 index 0000000..9167211 --- /dev/null +++ b/src/EventGroupingHtmlRenderer/GroupRenderer/GroupMonthRenderer.ts @@ -0,0 +1,37 @@ +import { Event } from "../../types"; +import { MonthGrouping } from "../../EventGrouping"; + +import GroupRenderer from "./GroupRenderer"; + +export default class GroupMonthRenderer extends GroupRenderer { + constructor(group: Event[], groupDate: Date, groupIndex: number) { + super(group, groupDate, groupIndex); + + if (MonthGrouping.isThisMonth(groupDate)) { + this.highlightGroup(); + } + } + + protected renderDateAsIcon(eventDate, groupIndex): HTMLSpanElement { + const html = document.createElement("span"); + html.className = "icon"; + + // 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/GroupRenderer/GroupRenderer.ts b/src/EventGroupingHtmlRenderer/GroupRenderer/GroupRenderer.ts new file mode 100644 index 0000000..cda8360 --- /dev/null +++ b/src/EventGroupingHtmlRenderer/GroupRenderer/GroupRenderer.ts @@ -0,0 +1,108 @@ +import { Event } from "../../types"; +import { generateRandomColor } from "../../utilities"; +import { format } from "date-fns"; + +export default abstract class GroupRenderer { + protected container: HTMLDivElement; + protected group: Event[]; + protected groupDate: Date; + protected groupIndex: number; + + protected abstract renderDateAsIcon( + eventDate: Date, + groupIndex: number + ): HTMLSpanElement; + + constructor(group: Event[], groupDate: Date, groupIndex: number) { + this.container = document.createElement("div"); + this.container.className = "group"; + this.group = group; + this.groupDate = groupDate; + this.groupIndex = groupIndex; + } + + highlightGroup(): void { + this.container.className += " highlight"; + } + + render(): HTMLDivElement { + if (this.group.length) { + const htmlHoverCard = this.renderHoverCard(this.group); + this.container.appendChild(htmlHoverCard); + } + + let htmlGroupIcon: HTMLSpanElement; + // only need to render icon from first event in group + const event = this.group[0]; + + if (event) { + htmlGroupIcon = this.renderIcon(event); + this.container.className += " icon"; + if (event.bgColor) { + this.container.style.backgroundColor = event.bgColor; + } else { + const randomColor = generateRandomColor(); + this.container.style.backgroundColor = `rgb(${randomColor.r}, ${randomColor.g}, ${randomColor.b})`; + } + } else { + htmlGroupIcon = this.renderDateAsIcon(this.groupDate, this.groupIndex); + } + + this.container.appendChild(htmlGroupIcon); + + return this.container; + } + + renderIcon(event: Event | undefined): HTMLSpanElement { + const html = document.createElement("span"); + html.className = "event"; + + if (event.icon) { + html.textContent = event.icon; + } + + return html; + } + + renderHoverCard(events: Event[]): HTMLDivElement { + const html = document.createElement("div"); + html.className = "hover-card"; + + const htmlMonthYear = document.createElement("p"); + htmlMonthYear.className = "month-year"; + htmlMonthYear.textContent = events[0].date.toLocaleDateString(undefined, { + year: "numeric", + month: "long", + }); + + html.appendChild(htmlMonthYear); + + const cardDetails = events.map((event) => { + if (!event) { + return; + } + + const htmlEvent = document.createElement("div"); + htmlEvent.className = "event"; + const htmlEventDate = document.createElement("p"); + htmlEventDate.className = "date"; + htmlEventDate.textContent = format(event.date, "EEEE do"); + const htmlEventTitle = document.createElement("p"); + htmlEventTitle.className = "title"; + htmlEventTitle.textContent = event.title; + const htmlEventText = document.createElement("p"); + htmlEventText.className = "text"; + htmlEventText.textContent = event.text; + + htmlEvent.appendChild(htmlEventDate); + htmlEvent.appendChild(htmlEventTitle); + htmlEvent.appendChild(htmlEventText); + + return htmlEvent; + }); + + cardDetails.forEach((cardDetail) => html.appendChild(cardDetail)); + + return html; + } +} diff --git a/src/EventGroupingHtmlRenderer/GroupRenderer/GroupWeekRenderer.ts b/src/EventGroupingHtmlRenderer/GroupRenderer/GroupWeekRenderer.ts new file mode 100644 index 0000000..523890f --- /dev/null +++ b/src/EventGroupingHtmlRenderer/GroupRenderer/GroupWeekRenderer.ts @@ -0,0 +1,36 @@ +import { Event } from "../../types"; +import { WeekGrouping } from "../../EventGrouping"; + +import GroupRenderer from "./GroupRenderer"; + +export default class GroupWeekRenderer extends GroupRenderer { + constructor(group: Event[], groupDate: Date, groupIndex: number) { + super(group, groupDate, groupIndex); + + if (WeekGrouping.isThisWeek(groupDate)) { + this.highlightGroup(); + } + } + + protected renderDateAsIcon(eventDate, groupIndex): HTMLSpanElement { + const html = document.createElement("span"); + html.className = "icon"; + + const week = WeekGrouping.getWeek(eventDate); + + if (week === 1) { + html.textContent = eventDate.toLocaleDateString(undefined, { + year: "numeric", + }); + html.className += " primary"; + } else { + html.textContent = week.toString(); + } + + if (WeekGrouping.isThisWeek(eventDate)) { + html.className += " highlighted"; + } + + return html; + } +} diff --git a/src/EventGroupingHtmlRenderer/MonthRenderer.ts b/src/EventGroupingHtmlRenderer/MonthRenderer.ts index cc89ec0..6af3334 100644 --- a/src/EventGroupingHtmlRenderer/MonthRenderer.ts +++ b/src/EventGroupingHtmlRenderer/MonthRenderer.ts @@ -1,5 +1,7 @@ +import { Event } from "../types"; import { MonthGrouping } from "../EventGrouping"; import Renderer from "./Renderer"; +import GroupMonthRenderer from "./GroupRenderer/GroupMonthRenderer"; export default class MonthRenderer extends Renderer { constructor(eventGrouping: MonthGrouping) { @@ -7,26 +9,13 @@ export default class MonthRenderer extends Renderer { this.container.className += " scale-month"; } - protected renderDateAsIcon(eventDate, groupIndex): HTMLSpanElement { - const html = document.createElement("span"); - html.className = "icon"; + protected renderGroups( + group: Event[], + groupDate: Date, + groupIndex: number + ): HTMLDivElement { + const monthGroup = new GroupMonthRenderer(group, groupDate, groupIndex); - // 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; + return monthGroup.render(); } } diff --git a/src/EventGroupingHtmlRenderer/Renderer.ts b/src/EventGroupingHtmlRenderer/Renderer.ts index 0fdb0a7..dfc6a69 100644 --- a/src/EventGroupingHtmlRenderer/Renderer.ts +++ b/src/EventGroupingHtmlRenderer/Renderer.ts @@ -1,13 +1,12 @@ -import { format } from "date-fns"; -import { generateRandomColor } from "../utilities"; import EventGrouping from "../EventGrouping/EventGrouping"; import { Event } from "../types"; export default abstract class Renderer { - protected abstract renderDateAsIcon( - eventDate: Date, + protected abstract renderGroups( + group: Event[], + groupDate: Date, groupIndex: number - ): HTMLSpanElement; + ): HTMLDivElement; protected container: HTMLDivElement; protected eventGrouping: EventGrouping; @@ -18,95 +17,16 @@ export default abstract class Renderer { this.eventGrouping = eventGrouping; } - protected renderGroups(): HTMLDivElement[] { - return this.eventGrouping.groups.map((group, index) => { - const html = document.createElement("div"); - html.className = "group"; + protected _renderGroups(): HTMLDivElement[] { + return this.eventGrouping.groups.map((group: Event[], index: number) => { + const groupDate = this.eventGrouping.getDateFromGroupIndex(index); - 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; + return this.renderGroups(group, groupDate, index); }); } - protected renderHoverCard(events: Event[]): HTMLDivElement { - const html = document.createElement("div"); - html.className = "hover-card"; - - const htmlMonthYear = document.createElement("p"); - htmlMonthYear.className = "month-year"; - htmlMonthYear.textContent = events[0].date.toLocaleDateString(undefined, { - year: "numeric", - month: "long", - }); - - html.appendChild(htmlMonthYear); - - const cardDetails = events.map((event) => { - if (!event) { - return; - } - - const htmlEvent = document.createElement("div"); - htmlEvent.className = "event"; - const htmlEventDate = document.createElement("p"); - htmlEventDate.className = "date"; - htmlEventDate.textContent = format(event.date, "EEEE do"); - const htmlEventTitle = document.createElement("p"); - htmlEventTitle.className = "title"; - htmlEventTitle.textContent = event.title; - const htmlEventText = document.createElement("p"); - htmlEventText.className = "text"; - htmlEventText.textContent = event.text; - - htmlEvent.appendChild(htmlEventDate); - htmlEvent.appendChild(htmlEventTitle); - htmlEvent.appendChild(htmlEventText); - - return htmlEvent; - }); - - cardDetails.forEach((cardDetail) => html.appendChild(cardDetail)); - - return html; - } - - 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(): HTMLDivElement { - const groups = this.renderGroups(); + const groups = this._renderGroups(); groups.forEach((group) => this.container.appendChild(group)); diff --git a/src/EventGroupingHtmlRenderer/WeekRenderer.ts b/src/EventGroupingHtmlRenderer/WeekRenderer.ts index 3c7da81..ddae6c5 100644 --- a/src/EventGroupingHtmlRenderer/WeekRenderer.ts +++ b/src/EventGroupingHtmlRenderer/WeekRenderer.ts @@ -1,7 +1,7 @@ -import { getWeek } from "date-fns"; - +import { Event } from "../types"; import { WeekGrouping } from "../EventGrouping"; import Renderer from "./Renderer"; +import GroupWeekRenderer from "./GroupRenderer/GroupWeekRenderer"; export default class WeekRenderer extends Renderer { constructor(eventGrouping: WeekGrouping) { @@ -9,21 +9,11 @@ export default class WeekRenderer extends Renderer { this.container.className += " scale-week"; } - protected renderDateAsIcon(eventDate, groupIndex): HTMLSpanElement { - const html = document.createElement("span"); - html.className = "icon"; - - const week = getWeek(eventDate); - - if (week === 1) { - html.textContent = eventDate.toLocaleDateString(undefined, { - year: "numeric", - }); - html.className += " primary"; - } else { - html.textContent = week.toString(); - } - - return html; + protected renderGroups( + group: Event[], + groupDate: Date, + groupIndex: number + ): HTMLDivElement { + return new GroupWeekRenderer(group, groupDate, groupIndex).render(); } } diff --git a/src/event-calendar.css b/src/event-calendar.css index f5dda4b..1acc8c2 100644 --- a/src/event-calendar.css +++ b/src/event-calendar.css @@ -8,13 +8,17 @@ width: 36px; height: 26px; margin: 0 4px 4px 0; - border-top: 10px solid rgba(255, 140, 140, 0.5); + border-top: 10px solid rgba(255, 140, 140, 1); border-right: 1px solid rgba(20, 20, 20, 0.7); border-bottom: 1px solid rgba(20, 20, 20, 0.7); border-left: 1px solid rgba(20, 20, 20, 0.2); border-radius: 4px; } +.event-calendar .group.highlight { + border-top: 10px solid rgba(255, 223, 65, 1); +} + .event-calendar .group .icon { font-size: 15px; text-align: center;