Refactored entire rendering module; added new feature for "highlighting" a group, when the current date falls within that group
This commit is contained in:
parent
024abebf2a
commit
da62052e79
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
108
src/EventGroupingHtmlRenderer/GroupRenderer/GroupRenderer.ts
Normal file
108
src/EventGroupingHtmlRenderer/GroupRenderer/GroupRenderer.ts
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user