From 8246e5c690e6f8a722840884a0625151711be1f8 Mon Sep 17 00:00:00 2001 From: danieldeng2 <danieldeng223@gmail.com> Date: Sat, 5 Sep 2020 19:06:48 +0100 Subject: [PATCH] Refactor timeline grid into multiple components --- .../components/DayIndicatorGrid/index.tsx | 40 +++++ .../DayIndicatorGrid/style.module.scss | 16 ++ .../Timeline/components/EventGrid/index.tsx | 30 ++++ .../components/EventGrid/style.module.scss | 20 +++ .../Timeline/components/ModuleRows/index.tsx | 69 +++++++++ .../components/ModuleRows/style.module.scss | 43 ++++++ .../components/TermSwitcher/index.tsx | 46 +++--- .../components/TermSwitcher/style.module.scss | 17 +++ .../Timeline/components/WeekRow/index.tsx | 37 +++++ .../components/WeekRow/style.module.scss | 17 +++ src/components/pages/Timeline/index.tsx | 138 ++++-------------- .../pages/Timeline/style.module.scss | 119 +-------------- 12 files changed, 340 insertions(+), 252 deletions(-) create mode 100644 src/components/pages/Timeline/components/DayIndicatorGrid/index.tsx create mode 100644 src/components/pages/Timeline/components/DayIndicatorGrid/style.module.scss create mode 100644 src/components/pages/Timeline/components/EventGrid/index.tsx create mode 100644 src/components/pages/Timeline/components/EventGrid/style.module.scss create mode 100644 src/components/pages/Timeline/components/ModuleRows/index.tsx create mode 100644 src/components/pages/Timeline/components/ModuleRows/style.module.scss create mode 100644 src/components/pages/Timeline/components/WeekRow/index.tsx create mode 100644 src/components/pages/Timeline/components/WeekRow/style.module.scss diff --git a/src/components/pages/Timeline/components/DayIndicatorGrid/index.tsx b/src/components/pages/Timeline/components/DayIndicatorGrid/index.tsx new file mode 100644 index 000000000..e5ca7c8d7 --- /dev/null +++ b/src/components/pages/Timeline/components/DayIndicatorGrid/index.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import styles from "./style.module.scss"; +export interface ModuleHeadingprops { + numWeeks: number; + activeDay: Date; + termStart: Date; +} + +const DayIndicatorGrid: React.FC<ModuleHeadingprops> = ({ + numWeeks, + activeDay, + termStart, +}) => { + const activeColumn = + Math.ceil( + ((activeDay.getTime() - termStart.getTime()) / 86400000 / 7) * 6 + ) + 1; + + return ( + <div + className={styles.dayIndicatorGrid} + style={{ + gridTemplateColumns: `repeat(${numWeeks}, 3rem 3rem 3rem 3rem 3rem 0.625rem`, + }} + > + <div + className={styles.dayIndicatorColumn} + style={{ + visibility: + activeDay.getDay() === 6 || activeDay.getDay() === 0 + ? "hidden" + : "visible", + gridColumn: `${activeColumn} / ${activeColumn + 1}`, + }} + ></div> + </div> + ); +}; + +export default DayIndicatorGrid; diff --git a/src/components/pages/Timeline/components/DayIndicatorGrid/style.module.scss b/src/components/pages/Timeline/components/DayIndicatorGrid/style.module.scss new file mode 100644 index 000000000..c9501be6a --- /dev/null +++ b/src/components/pages/Timeline/components/DayIndicatorGrid/style.module.scss @@ -0,0 +1,16 @@ +.dayIndicatorGrid { + grid-area: background; + padding-top: 0.625rem; + z-index: 2; + display: grid; + grid-template-rows: auto; +} + +.dayIndicatorColumn { + grid-row: 1; + margin-right: 0.75rem; + margin-bottom: 0.625rem; + margin-left: 0.75rem; + background-color: var(--day-indicator-column); + border: 0.0625rem solid var(--border-color); +} \ No newline at end of file diff --git a/src/components/pages/Timeline/components/EventGrid/index.tsx b/src/components/pages/Timeline/components/EventGrid/index.tsx new file mode 100644 index 000000000..74532e8b3 --- /dev/null +++ b/src/components/pages/Timeline/components/EventGrid/index.tsx @@ -0,0 +1,30 @@ +import React from "react"; +import styles from "./style.module.scss"; +export interface EventGridProps { + numWeeks: number; + trackHeight: number; +} + +const EventGrid: React.FC<EventGridProps> = ({ numWeeks, trackHeight }) => { + return ( + <div + className={styles.timelineCardGrid} + style={{ + gridTemplateColumns: `repeat(${numWeeks}, 3rem 3rem 3rem 3rem 3rem 0.625rem)`, + gridTemplateRows: `${trackHeight}rem ${trackHeight}rem 0.3125rem repeat(${7}, ${trackHeight}rem ${trackHeight}rem 0.625rem) ${trackHeight}rem ${trackHeight}rem 0.3125rem`, + }} + > + <div className={styles.timelineEvent} style={{ gridColumn: `1 / 9` }}> + <span className={styles.eventTitle}>Title of the first event</span> + </div> + <div + className={styles.timelineEvent} + style={{ gridColumn: `3 / 24`, gridRow: `2` }} + > + <span className={styles.eventTitle}>Title of the second event</span> + </div> + </div> + ); +}; + +export default EventGrid; diff --git a/src/components/pages/Timeline/components/EventGrid/style.module.scss b/src/components/pages/Timeline/components/EventGrid/style.module.scss new file mode 100644 index 000000000..d384862be --- /dev/null +++ b/src/components/pages/Timeline/components/EventGrid/style.module.scss @@ -0,0 +1,20 @@ +.timelineCardGrid { + padding-top: 0.625rem; + display: grid; + grid-area: background; + z-index: 3; +} + +.timelineEvent { + background: red; + margin: 0.5rem; + border-radius: 0.5rem; + padding: 0.5rem; + display: flex; + align-items: center; +} + +.eventTitle { + color: var(--primary-text-color); + font-size: 1rem; +} diff --git a/src/components/pages/Timeline/components/ModuleRows/index.tsx b/src/components/pages/Timeline/components/ModuleRows/index.tsx new file mode 100644 index 000000000..42e5d8a6b --- /dev/null +++ b/src/components/pages/Timeline/components/ModuleRows/index.tsx @@ -0,0 +1,69 @@ +import React, { ReactElement } from "react"; +import styles from "./style.module.scss"; +import { ModuleTracks } from "../.."; +import ModuleHeading from "../ModuleHeading"; +import classNames from "classnames"; + +export interface ModuleRowsProps { + numWeeks: number; + trackHeight: number; + modulesList: any[]; + moduleTracks: ModuleTracks; +} + +const ModuleRows: React.FC<ModuleRowsProps> = ({ + numWeeks, + trackHeight, + modulesList, + moduleTracks, +}) => { + let timelineBackgrounds: ReactElement[] = []; + let moduleHeadings: ReactElement[] = []; + + for (let i = 0; i < modulesList.length; i++) { + const code = modulesList[i].code; + const tracks = moduleTracks[code]; + if (tracks) { + moduleHeadings.push( + <ModuleHeading + key={code} + style={{ height: `${tracks.length * trackHeight}rem` }} + moduleCode={code} + title={modulesList[i].title} + /> + ); + const timelineBackgroundsClass = classNames( + i % 2 === 0 + ? styles.timelineBackgroundEven + : styles.timelineBackgroundOdd, + i === 0 ? styles.timelineBackgroundFirst : "", + i === modulesList.length - 1 ? styles.timelineBackgroundLast : "" + ); + const offset = + i === modulesList.length - 1 || i === 0 ? 0.625 / 2 : 0.625; + for (let j = 0; j < numWeeks; j++) { + timelineBackgrounds.push( + <div + key={code + j} + style={{ height: `${tracks.length * trackHeight + offset}rem` }} + className={timelineBackgroundsClass} + ></div> + ); + } + } + } + + return ( + <> + <div className={styles.timelineModuleColumn}>{moduleHeadings}</div> + <div + className={styles.timelineWeekBackground} + style={{ gridTemplateColumns: `repeat(${numWeeks}, 15rem)` }} + > + {timelineBackgrounds} + </div> + </> + ); +}; + +export default ModuleRows; diff --git a/src/components/pages/Timeline/components/ModuleRows/style.module.scss b/src/components/pages/Timeline/components/ModuleRows/style.module.scss new file mode 100644 index 000000000..9f7e1ec46 --- /dev/null +++ b/src/components/pages/Timeline/components/ModuleRows/style.module.scss @@ -0,0 +1,43 @@ +.timelineModuleColumn { + grid-area: modules; + display: grid; + grid-gap: 0.625rem; + left: 0; + position: sticky; + padding-right: 1.25rem; + box-sizing: border-box; + padding-left: 0.625rem; + margin-bottom: 0.625rem; + background: var(--background-color); + padding-top: 0.625rem; + z-index: 4; +} + +.timelineWeekBackground { + padding-top: 0.625rem; + display: grid; + grid-area: background; + grid-template-rows: auto; + column-gap: 0.625rem; + row-gap: 0; + margin-bottom: 0.625rem; + z-index: 1; +} + +.timelineBackgroundEven { + background-color: var(--checker-even-color); +} + +.timelineBackgroundOdd { + background-color: var(--checker-odd-color); +} + +.timelineBackgroundFirst { + border-top-left-radius: 0.5rem; + border-top-right-radius: 0.5rem; +} + +.timelineBackgroundLast { + border-bottom-left-radius: 0.5rem; + border-bottom-right-radius: 0.5rem; +} \ No newline at end of file diff --git a/src/components/pages/Timeline/components/TermSwitcher/index.tsx b/src/components/pages/Timeline/components/TermSwitcher/index.tsx index 7460f9244..5763fd0dc 100644 --- a/src/components/pages/Timeline/components/TermSwitcher/index.tsx +++ b/src/components/pages/Timeline/components/TermSwitcher/index.tsx @@ -7,31 +7,27 @@ import { faLeaf, faSeedling, faSun } from "@fortawesome/free-solid-svg-icons"; const TermSwitcher: React.FC = () => { return ( - <> - <ButtonGroup style={{ float: "right" }}> - <Button - className={styles.termSwitch} - active={true} - variant="secondary" - > - <FontAwesomeIcon icon={faLeaf} fixedWidth/> - </Button> - <Button - className={styles.termSwitch} - active={false} - variant="secondary" - > - <FontAwesomeIcon icon={faSeedling} fixedWidth/> - </Button> - <Button - className={styles.termSwitch} - active={false} - variant="secondary" - > - <FontAwesomeIcon icon={faSun} fixedWidth/> - </Button> - </ButtonGroup> - </> + <div className={styles.timelineTermSwitcher}> + <ButtonGroup style={{ float: "right" }}> + <Button className={styles.termSwitch} active={true} variant="secondary"> + <FontAwesomeIcon icon={faLeaf} fixedWidth /> + </Button> + <Button + className={styles.termSwitch} + active={false} + variant="secondary" + > + <FontAwesomeIcon icon={faSeedling} fixedWidth /> + </Button> + <Button + className={styles.termSwitch} + active={false} + variant="secondary" + > + <FontAwesomeIcon icon={faSun} fixedWidth /> + </Button> + </ButtonGroup> + </div> ); }; diff --git a/src/components/pages/Timeline/components/TermSwitcher/style.module.scss b/src/components/pages/Timeline/components/TermSwitcher/style.module.scss index c0f047694..0ac65d83d 100644 --- a/src/components/pages/Timeline/components/TermSwitcher/style.module.scss +++ b/src/components/pages/Timeline/components/TermSwitcher/style.module.scss @@ -31,3 +31,20 @@ color: var(--primary-button-text); box-shadow: none !important; } + +.timelineTermSwitcher { + grid-area: switcher; + top: 0; + left: 0; + position: sticky; + z-index: 5; + background: var(--background-color); + padding-right: 1.25rem; + padding-left: 0.625rem; + height: 5.5rem !important; + padding-bottom: 0.625rem; +} + +.timelineTermSwitcher > * { + width: 100%; +} \ No newline at end of file diff --git a/src/components/pages/Timeline/components/WeekRow/index.tsx b/src/components/pages/Timeline/components/WeekRow/index.tsx new file mode 100644 index 000000000..f55c29395 --- /dev/null +++ b/src/components/pages/Timeline/components/WeekRow/index.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import styles from "./style.module.scss"; +import WeekHeading from "../WeekHeading"; +import { addDays } from "utils/functions"; + +export interface WeekRowProps { + numWeeks: number; + termStart: Date; + activeDay: Date; +} + + +const WeekRow: React.FC<WeekRowProps> = ({ + numWeeks, + termStart, + activeDay, +}) => { + return ( + <div + className={styles.timelineWeekRow} + style={{ gridTemplateColumns: `repeat(${numWeeks}, 15rem)` }} + > + {[...Array(numWeeks)].map((_, i) => ( + <div className={styles.weekHeading} key={i}> + <WeekHeading + weekNumber={i + 1} + dateRangeStart={addDays(termStart, i * 7)} + dateRangeEnd={addDays(termStart, i * 7 + 4)} + activeDay={activeDay} + /> + </div> + ))} + </div> + ); +}; + +export default WeekRow; \ No newline at end of file diff --git a/src/components/pages/Timeline/components/WeekRow/style.module.scss b/src/components/pages/Timeline/components/WeekRow/style.module.scss new file mode 100644 index 000000000..67413ed99 --- /dev/null +++ b/src/components/pages/Timeline/components/WeekRow/style.module.scss @@ -0,0 +1,17 @@ +.weekHeading { + height: 4.25rem !important; +} + +.timelineWeekRow { + grid-area: weeks; + display: grid; + grid-auto-flow: row; + grid-gap: 0.625rem; + padding-right: 0.625rem; + top: 0; + position: sticky; + background: var(--background-color); + padding-bottom: 0.625rem; + height: 5.5rem !important; + z-index: 4; +} \ No newline at end of file diff --git a/src/components/pages/Timeline/index.tsx b/src/components/pages/Timeline/index.tsx index be205e735..e3e625872 100644 --- a/src/components/pages/Timeline/index.tsx +++ b/src/components/pages/Timeline/index.tsx @@ -1,12 +1,12 @@ -import React, { ReactElement } from "react"; +import React from "react"; import MyBreadcrumbs from "components/atoms/MyBreadcrumbs"; import styles from "./style.module.scss"; import TermSwitcher from "./components/TermSwitcher"; -import ModuleHeading from "./components/ModuleHeading"; -import WeekHeading from "./components/WeekHeading"; import { modulesList } from "../ModuleList/list"; -import classNames from "classnames"; -import { addDays } from "utils/functions"; +import WeekRow from "./components/WeekRow"; +import ModuleRows from "./components/ModuleRows"; +import DayIndicatorGrid from "./components/DayIndicatorGrid"; +import EventGrid from "./components/EventGrid"; interface TimelineProps { initSideBar: () => void; @@ -17,7 +17,7 @@ interface Event { title: string; } -type ModuleTracks = { +export type ModuleTracks = { [index: string]: Event[][]; }; @@ -44,116 +44,36 @@ class Timeline extends React.Component<TimelineProps, TimelineState> { this.props.revertSideBar(); } - generateGridItems(numWeeks: number, trackHeight: number) { - let timelineBackgrounds: ReactElement[] = []; - let moduleHeadings: ReactElement[] = []; - - for (let i = 0; i < modulesList.length; i++) { - const code = modulesList[i].code; - const tracks = this.state.moduleTracks[code]; - if (tracks) { - moduleHeadings.push( - <ModuleHeading - key={code} - style={{ height: `${tracks.length * trackHeight}rem` }} - moduleCode={code} - title={modulesList[i].title} - /> - ); - const timelineBackgroundsClass = classNames( - i % 2 === 0 - ? styles.timelineBackgroundEven - : styles.timelineBackgroundOdd, - i === 0 ? styles.timelineBackgroundFirst : "", - i === modulesList.length - 1 ? styles.timelineBackgroundLast : "" - ); - const offset = - i === modulesList.length - 1 || i === 0 ? 0.625 / 2 : 0.625; - for (let j = 0; j < numWeeks; j++) { - timelineBackgrounds.push( - <div - key={code + j} - style={{ height: `${tracks.length * trackHeight + offset}rem` }} - className={timelineBackgroundsClass} - ></div> - ); - } - } - } - return [moduleHeadings, timelineBackgrounds]; - } - render() { const termStart = new Date("2020-09-28"); - const activeDay = new Date("2020-10-23"); + const activeDay = new Date("2020-10-12"); const numWeeks = 11; - const trackHeight = 4.25; - const [moduleHeadings, timelineBackgrounds] = this.generateGridItems( - numWeeks, - trackHeight - ); - const activeColumn = - Math.ceil( - ((activeDay.getTime() - termStart.getTime()) / 86400000 / 7) * 6 - ) + 1; - console.log(activeColumn); + const trackHeight = 4; + return ( <div className={styles.timelineContainer}> <MyBreadcrumbs /> <div className={styles.timelineGrid}> - <div className={styles.timelineTermSwitcher}> - <TermSwitcher /> - </div> - <div - className={styles.timelineWeekRow} - style={{ gridTemplateColumns: `repeat(${numWeeks}, 15rem)` }} - > - {[...Array(numWeeks)].map((_, i) => ( - <div className={styles.weekHeading} key={i}> - <WeekHeading - weekNumber={i + 1} - dateRangeStart={addDays(termStart, i * 7)} - dateRangeEnd={addDays(termStart, i * 7 + 4)} - activeDay={activeDay} - /> - </div> - ))} - </div> - <div className={styles.timelineModuleColumn}>{moduleHeadings}</div> - <div - className={styles.timelineWeekBackground} - style={{ gridTemplateColumns: `repeat(${numWeeks}, 15rem)` }} - > - {timelineBackgrounds} - </div> - <div - className={styles.dayIndicatorGrid} - style={{ - gridTemplateColumns: `repeat(${numWeeks}, 3rem 3rem 3rem 3rem 3rem 0.625rem`, - }} - > - <div - className={styles.dayIndicatorColumn} - style={{ - visibility: - activeDay.getDay() === 6 || activeDay.getDay() == 0 - ? "hidden" - : "visible", - gridColumn: `${activeColumn} / ${activeColumn + 1}`, - }} - ></div> - </div> - <div className={styles.timelineCardGrid} style={{ - gridTemplateColumns: `repeat(${numWeeks}, 3rem 3rem 3rem 3rem 3rem 0.625rem`, - gridTemplateRows: `4.25rem 4.25rem 0.3125rem repeat(${7}, 4.25rem 4.25rem 0.625rem) 4.25rem 4.25rem 0.3125rem` - }}> - <div className={styles.timelineEvent} style={{ gridColumn: `1 / 9`}}> - <span className={styles.eventTitle}>Title of the first event</span> - </div> - <div className={styles.timelineEvent} style={{ gridColumn: `3 / 24`, gridRow: `2`}}> - <span className={styles.eventTitle}>Title of the second event</span> - </div> - </div> + <TermSwitcher /> + <WeekRow + numWeeks={numWeeks} + termStart={termStart} + activeDay={activeDay} + /> + <ModuleRows + numWeeks={numWeeks} + trackHeight={trackHeight} + modulesList={modulesList} + moduleTracks={this.state.moduleTracks} + /> + + <DayIndicatorGrid + numWeeks={numWeeks} + activeDay={activeDay} + termStart={termStart} + /> + + <EventGrid numWeeks={numWeeks} trackHeight={trackHeight} /> </div> </div> ); diff --git a/src/components/pages/Timeline/style.module.scss b/src/components/pages/Timeline/style.module.scss index 3fed75846..16f595173 100644 --- a/src/components/pages/Timeline/style.module.scss +++ b/src/components/pages/Timeline/style.module.scss @@ -45,121 +45,4 @@ .timelineGrid:hover::-webkit-scrollbar-thumb { background-color: var(--scrollbar); -} - -.timelineTermSwitcher { - grid-area: switcher; - top: 0; - left: 0; - position: sticky; - z-index: 5; - background: var(--background-color); - padding-right: 1.25rem; - padding-left: 0.625rem; - height: 5.5rem !important; - padding-bottom: 0.625rem; -} - -.timelineTermSwitcher > * { - width: 100%; -} - -.timelineWeekRow { - grid-area: weeks; - display: grid; - grid-auto-flow: row; - grid-gap: 0.625rem; - padding-right: 0.625rem; - top: 0; - position: sticky; - background: var(--background-color); - padding-bottom: 0.625rem; - height: 5.5rem !important; - z-index: 4; -} - -.timelineModuleColumn { - grid-area: modules; - display: grid; - grid-gap: 0.625rem; - left: 0; - position: sticky; - padding-right: 1.25rem; - box-sizing: border-box; - padding-left: 0.625rem; - margin-bottom: 0.625rem; - background: var(--background-color); - padding-top: 0.625rem; - z-index: 4; -} - -.weekHeading { - height: 4.25rem !important; -} - -.timelineWeekBackground { - padding-top: 0.625rem; - display: grid; - grid-area: background; - grid-template-rows: auto; - column-gap: 0.625rem; - row-gap: 0; - margin-bottom: 0.625rem; - z-index: 1; -} - -.timelineBackgroundEven { - background-color: var(--checker-even-color); -} - -.timelineBackgroundOdd { - background-color: var(--checker-odd-color); -} - -.timelineBackgroundFirst { - border-top-left-radius: 0.5rem; - border-top-right-radius: 0.5rem; -} - -.timelineBackgroundLast { - border-bottom-left-radius: 0.5rem; - border-bottom-right-radius: 0.5rem; -} - -.dayIndicatorGrid { - grid-area: background; - padding-top: 0.625rem; - z-index: 2; - display: grid; - grid-template-rows: auto; -} - -.dayIndicatorColumn { - grid-row: 1; - margin-right: 0.75rem; - margin-bottom: 0.625rem; - margin-left: 0.75rem; - background-color: var(--day-indicator-column); - border: 0.0625rem solid var(--border-color); -} - -.timelineCardGrid { - padding-top: 0.625rem; - display: grid; - grid-area: background; - z-index: 3; -} - -.timelineEvent { - background: red; - margin: 0.5rem; - border-radius: 0.5rem; - padding: 0.5rem; - display: flex; - align-items: center; -} - -.eventTitle { - color: var(--primary-text-color); - font-size: 1rem; -} +} \ No newline at end of file -- GitLab