diff --git a/src/shared/util/colors.ts b/src/shared/util/colors.ts index 807a2c16..d6f7fdd6 100644 --- a/src/shared/util/colors.ts +++ b/src/shared/util/colors.ts @@ -42,9 +42,9 @@ export function pickFontColor(bgColor: string): 'text-white' | 'text-black' { * Get primary and secondary colors from a tailwind colorway * @param colorway the tailwind colorway ex. "emerald" */ -export function getCourseColors(colorway: keyof typeof theme.colors): CourseColors { +export function getCourseColors(colorway: keyof typeof theme.colors, index = 600, offset = 200): CourseColors { return { - primaryColor: theme.colors[colorway][600] as string, - secondaryColor: theme.colors[colorway][800] as string, + primaryColor: theme.colors[colorway][index] as string, + secondaryColor: theme.colors[colorway][index + offset] as string, }; } diff --git a/src/stories/components/CalendarCourseCell.stories.tsx b/src/stories/components/CalendarCourseCell.stories.tsx index 8203d74a..1e9d3c84 100644 --- a/src/stories/components/CalendarCourseCell.stories.tsx +++ b/src/stories/components/CalendarCourseCell.stories.tsx @@ -1,10 +1,9 @@ +import { Course, Status } from '@shared/types/Course'; +import { getCourseColors } from '@shared/util/colors'; import { Meta, StoryObj } from '@storybook/react'; +import CalendarCourseCell from '@views/components/common/CalendarCourseCell/CalendarCourseCell'; import React from 'react'; -import { Course, Status } from 'src/shared/types/Course'; -import { CourseMeeting, DAY_MAP } from 'src/shared/types/CourseMeeting'; -import { CourseSchedule } from 'src/shared/types/CourseSchedule'; -import Instructor from 'src/shared/types/Instructor'; -import CalendarCourseCell from 'src/views/components/common/CalendarCourseCell/CalendarCourseCell'; +import { exampleCourse } from './PopupCourseBlock.stories'; const meta = { title: 'Components/Common/CalendarCourseCell', @@ -16,52 +15,48 @@ const meta = { argTypes: { course: { control: 'object' }, meetingIdx: { control: 'number' }, - color: { control: 'color' }, + colors: { control: 'object' }, }, render: (args: any) => ( -
+
), + args: { + course: exampleCourse, + meetingIdx: 0, + colors: getCourseColors('emerald', 500), + }, } satisfies Meta; export default meta; type Story = StoryObj; -export const Default: Story = { - args: { - course: new Course({ - uniqueId: 123, - number: '311C', - fullName: "311C - Bevo's Default Course", - courseName: "Bevo's Default Course", - department: 'BVO', - creditHours: 3, - status: Status.WAITLISTED, - instructors: [new Instructor({ firstName: '', lastName: 'Bevo', fullName: 'Bevo' })], - isReserved: false, - url: '', - flags: [], - schedule: new CourseSchedule({ - meetings: [ - new CourseMeeting({ - days: [DAY_MAP.MON, DAY_MAP.WED, DAY_MAP.FRI], - startTime: 480, - endTime: 570, - location: { - building: 'UTC', - room: '123', - }, - }), - ], - }), - instructionMode: 'In Person', - semester: { - year: 2024, - season: 'Spring', - }, - }), - meetingIdx: 0, - color: 'red', - }, +export const Default: Story = {}; + +export const Variants: Story = { + render: props => ( +
+ + + + +
+ ), }; diff --git a/src/stories/components/CalendarGrid.stories.tsx b/src/stories/components/CalendarGrid.stories.tsx index 6d8861b9..26fa245e 100644 --- a/src/stories/components/CalendarGrid.stories.tsx +++ b/src/stories/components/CalendarGrid.stories.tsx @@ -1,19 +1,23 @@ -// Calendar.stories.tsx -import React from 'react'; -import Calendar from '@views/components/common/CalendarGrid/CalendarGrid'; -import type { Meta, StoryObj } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; +import CalendarGrid from 'src/views/components/common/CalendarGrid/CalendarGrid'; const meta = { - title: 'Components/Common/Calendar', - component: Calendar, - parameters: { - // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout - layout: 'centered', + title: 'Components/Common/CalendarGrid', + component: CalendarGrid, + parameters: { + layout: 'centered', + }, tags: ['autodocs'], - } -} satisfies Meta; - + argTypes: { + saturdayClass: { control: 'boolean' }, + }, +} satisfies Meta; export default meta; + type Story = StoryObj; -export const Default: Story = {}; \ No newline at end of file +export const Default: Story = { + args: { + saturdayClass: true, + }, +}; \ No newline at end of file diff --git a/src/stories/components/CalendarHeader.stories.tsx b/src/stories/components/CalendarHeader.stories.tsx new file mode 100644 index 00000000..6833b7b1 --- /dev/null +++ b/src/stories/components/CalendarHeader.stories.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { Meta, StoryObj } from '@storybook/react'; +import CalendarHeader from '@views/components/common/CalendarHeader/CalenderHeader'; + +const meta = { + title: 'Components/CalendarHeader', + component: CalendarHeader, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/src/stories/components/PopupCourseBlock.stories.tsx b/src/stories/components/PopupCourseBlock.stories.tsx index adda6062..0e60f9fe 100644 --- a/src/stories/components/PopupCourseBlock.stories.tsx +++ b/src/stories/components/PopupCourseBlock.stories.tsx @@ -1,13 +1,13 @@ import type { Meta, StoryObj } from '@storybook/react'; +import PopupCourseBlock from '@views/components/common/PopupCourseBlock/PopupCourseBlock'; import React from 'react'; import { Course, Status } from 'src/shared/types/Course'; import { CourseMeeting } from 'src/shared/types/CourseMeeting'; import Instructor from 'src/shared/types/Instructor'; -import PopupCourseBlock from '@views/components/common/PopupCourseBlock/PopupCourseBlock'; import { getCourseColors } from 'src/shared/util/colors'; import { theme } from 'unocss/preset-mini'; -const exampleCourse: Course = new Course({ +export const exampleCourse: Course = new Course({ courseName: 'ELEMS OF COMPTRS/PROGRAMMNG-WB', creditHours: 3, department: 'C S', @@ -103,7 +103,7 @@ export const test_colors = Object.keys(theme.colors) export const AllColors: Story = { render: props => ( -
+
{test_colors.map((color, i) => ( ))} diff --git a/src/views/components/common/CalendarCourseCell/CalendarCourseCell.tsx b/src/views/components/common/CalendarCourseCell/CalendarCourseCell.tsx index 27b2519e..505e5823 100644 --- a/src/views/components/common/CalendarCourseCell/CalendarCourseCell.tsx +++ b/src/views/components/common/CalendarCourseCell/CalendarCourseCell.tsx @@ -1,6 +1,8 @@ +import { Course, Status } from '@shared/types/Course'; +import { CourseMeeting } from '@shared/types/CourseMeeting'; +import clsx from 'clsx'; import React from 'react'; -import { Course, Status } from 'src/shared/types/Course'; -import { CourseMeeting } from 'src/shared/types/CourseMeeting'; +import { CourseColors, pickFontColor } from 'src/shared/util/colors'; import ClosedIcon from '~icons/material-symbols/lock'; import WaitlistIcon from '~icons/material-symbols/timelapse'; import CancelledIcon from '~icons/material-symbols/warning'; @@ -11,11 +13,14 @@ export interface CalendarCourseBlockProps { course: Course; /* index into course meeting array to display */ meetingIdx?: number; - /** The background color for the course. */ - color: string; + colors: CourseColors; } -const CalendarCourseBlock: React.FC = ({ course, meetingIdx }: CalendarCourseBlockProps) => { +const CalendarCourseBlock: React.FC = ({ + course, + meetingIdx, + colors, +}: CalendarCourseBlockProps) => { let meeting: CourseMeeting | null = meetingIdx !== undefined ? course.schedule.meetings[meetingIdx] : null; let rightIcon: React.ReactNode | null = null; if (course.status === Status.WAITLISTED) { @@ -26,20 +31,40 @@ const CalendarCourseBlock: React.FC = ({ course, meeti rightIcon = ; } + // whiteText based on secondaryColor + const fontColor = pickFontColor(colors.primaryColor); + return ( -
-
- +
+
+ {course.department} {course.number} - {course.instructors[0].lastName} - - {`${meeting.getTimeString({ separator: '–', capitalize: true })}${ - meeting.location ? ` – ${meeting.location.building}` : '' - }`} - + {meeting && ( + + {`${meeting.getTimeString({ separator: '–', capitalize: true })}${ + meeting.location ? ` – ${meeting.location.building}` : '' + }`} + + )}
{rightIcon && ( -
+
{rightIcon}
)} diff --git a/src/views/components/common/CalendarGrid/CalendarGrid.tsx b/src/views/components/common/CalendarGrid/CalendarGrid.tsx index 3d83ef9a..0bd85c10 100644 --- a/src/views/components/common/CalendarGrid/CalendarGrid.tsx +++ b/src/views/components/common/CalendarGrid/CalendarGrid.tsx @@ -2,7 +2,8 @@ import React from 'react'; import { DAY_MAP } from 'src/shared/types/CourseMeeting'; import styles from './CalendarGrid.module.scss'; import CalendarCell from '../CalendarGridCell/CalendarGridCell'; -import { CourseMeeting } from 'src/shared/types/CourseMeeting'; +import CalendarCourseCell from '../CalendarCourseCell/CalendarCourseCell'; +import { Chip } from '../Chip/Chip'; const daysOfWeek = Object.keys(DAY_MAP).filter(key => !['S', 'SU'].includes(key)); const hoursOfDay = Array.from({ length: 14 }, (_, index) => index + 8); @@ -22,15 +23,15 @@ for (let i = 0; i < 13; i++) { } interface Props { - CourseMeetingBlocks: CourseMeeting[]; + courseCells: any[]; + saturdayClass: boolean; } /** * Grid of CalendarGridCell components forming the user's course schedule calendar view * @param props */ -export function Calendar({ courseMeetingBlocks }: React.PropsWithChildren): JSX.Element { - +function CalendarGrid({ courseCells, saturdayClass }: React.PropsWithChildren ): JSX.Element { return (
@@ -54,16 +55,22 @@ export function Calendar({ courseMeetingBlocks }: React.PropsWithChildren {day}
))} - {grid.map((row, rowIndex) => row)} + {grid.map(row => row)}
- {courseMeetingBlocks.map((block: CourseMeeting, index: number) => ( -
- {block} + {/* courseCells.map((Block: typeof CalendarCourseCell) => ( +
+
- ))} + )) */}
); -}; +} -export default Calendar; +export default CalendarGrid; diff --git a/src/views/components/common/CalendarHeader/CalenderHeader.tsx b/src/views/components/common/CalendarHeader/CalenderHeader.tsx new file mode 100644 index 00000000..b5d07274 --- /dev/null +++ b/src/views/components/common/CalendarHeader/CalenderHeader.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { Status } from '@shared/types/Course'; +import Divider from '../Divider/Divider'; +import { Button } from '../Button/Button'; +import Text from '../Text/Text'; +import MenuIcon from '~icons/material-symbols/menu'; +import LogoIcon from '~icons/material-symbols/add-circle-outline'; +import UndoIcon from '~icons/material-symbols/undo'; +import RedoIcon from '~icons/material-symbols/redo'; +import SettingsIcon from '~icons/material-symbols/settings'; +import ScheduleTotalHoursAndCourses from '../ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses'; +import CourseStatus from '../CourseStatus/CourseStatus'; + +const CalendarHeader = () => ( +
+
+ +
+); + +export default CalendarHeader; diff --git a/src/views/components/common/List/List.tsx b/src/views/components/common/List/List.tsx index 8f2f24b5..c61314d4 100644 --- a/src/views/components/common/List/List.tsx +++ b/src/views/components/common/List/List.tsx @@ -135,8 +135,7 @@ const List: React.FC = ({ draggableElements, itemHeight, listHeight,
{items.map((item, index) => ( @@ -150,7 +149,9 @@ const List: React.FC = ({ draggableElements, itemHeight, listHeight, marginBottom: `${gap}px`, }} > - {React.cloneElement(item.content, { dragHandleProps: draggableProvided.dragHandleProps })} + {React.cloneElement(item.content, { + dragHandleProps: draggableProvided.dragHandleProps, + })}
)} diff --git a/src/views/components/common/PopupCourseBlock/PopupCourseBlock.tsx b/src/views/components/common/PopupCourseBlock/PopupCourseBlock.tsx index 2d703caa..0f70d025 100644 --- a/src/views/components/common/PopupCourseBlock/PopupCourseBlock.tsx +++ b/src/views/components/common/PopupCourseBlock/PopupCourseBlock.tsx @@ -1,8 +1,8 @@ -import clsx from 'clsx'; -import React, { useState } from 'react'; import { Course, Status } from '@shared/types/Course'; +import { CourseColors, pickFontColor } from '@shared/util/colors'; import { StatusIcon } from '@shared/util/icons'; -import { CourseColors, getCourseColors, pickFontColor } from '@shared/util/colors'; +import clsx from 'clsx'; +import React from 'react'; import DragIndicatorIcon from '~icons/material-symbols/drag-indicator'; import Text from '../Text/Text'; @@ -21,7 +21,12 @@ export interface PopupCourseBlockProps { * * @param props PopupCourseBlockProps */ -export default function PopupCourseBlock({ className, course, colors, dragHandleProps }: PopupCourseBlockProps): JSX.Element { +export default function PopupCourseBlock({ + className, + course, + colors, + dragHandleProps, +}: PopupCourseBlockProps): JSX.Element { // whiteText based on secondaryColor const fontColor = pickFontColor(colors.primaryColor); @@ -41,10 +46,7 @@ export default function PopupCourseBlock({ className, course, colors, dragHandle >
- + {course.uniqueId} {course.department} {course.number} –{' '} {course.instructors.length === 0 ? 'Unknown' : course.instructors.map(v => v.lastName)} diff --git a/src/views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses.tsx b/src/views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses.tsx index 72d7782a..fd91d1f7 100644 --- a/src/views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses.tsx +++ b/src/views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses.tsx @@ -15,27 +15,19 @@ export interface ScheduleTotalHoursAndCoursesProps { * * @param props ScheduleTotalHoursAndCoursesProps */ -export default function ScheduleTotalHoursAndCoursess({ scheduleName, totalHours, totalCourses }: ScheduleTotalHoursAndCoursesProps): JSX.Element { +export default function ScheduleTotalHoursAndCourses({ + scheduleName, + totalHours, + totalCourses, +}: ScheduleTotalHoursAndCoursesProps): JSX.Element { return ( -
- +
+ {`${scheduleName}: `} - + {`${totalHours} HOURS`} - + {`${totalCourses} courses`}