diff --git a/src/App.tsx b/src/App.tsx index 0d701f4..5529c31 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,10 +6,12 @@ import { HelpModal } from './components/HelpModal'; import { SearchForm } from './components/SearchForm'; import { useCoursesInfo } from './data/course-info'; import { useFirstTimeHelp } from './helpers/help-modal'; +import { useZoom } from './helpers/zoom'; export const App = () => { useCoursesInfo(); useFirstTimeHelp(); + useZoom(); return ( <> diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index dc8b792..dcd2713 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -7,7 +7,11 @@ import { create } from 'zustand'; import { WEEK_DAYS } from '../constants/week-days'; import { YEAR } from '../constants/year'; import { useCourseColor, useEnrolledCourse } from '../data/enrolled-courses'; -import { useCalendar, useOtherWeekCourseTimes } from '../helpers/calendar'; +import { + useCalendar, + useCalendarHourHeight, + useOtherWeekCourseTimes, +} from '../helpers/calendar'; import { calcHoursDuration } from '../helpers/hours-duration'; import type dayjs from '../lib/dayjs'; import type { DateTimeRange, WeekCourse, WeekCourses } from '../types/course'; @@ -176,6 +180,8 @@ const CalendarHeader = ({ const CalendarBg = ({ currentWeek }: { currentWeek: dayjs.Dayjs }) => { const { t } = useTranslation(); + const blockHeight = useCalendarHourHeight((s) => s.height); + return (
@@ -206,9 +212,10 @@ const CalendarBg = ({ currentWeek }: { currentWeek: dayjs.Dayjs }) => {
))}
@@ -216,8 +223,6 @@ const CalendarBg = ({ currentWeek }: { currentWeek: dayjs.Dayjs }) => { ); }; -const HOUR_HEIGHT = 4.5; - const getGridRow = (time: string) => { const t = timeToDayjs(time); return t.hour() * 2 + (t.minute() >= 30 ? 1 : 0) - 13; @@ -229,6 +234,8 @@ const CalendarCourses = ({ courses: WeekCourses; currentWeek: dayjs.Dayjs; }) => { + const blockHeight = useCalendarHourHeight((s) => s.height); + return (
{day.map((times, i) => @@ -240,7 +247,7 @@ const CalendarCourses = ({ gridColumnStart: i + 1, gridRowStart: getGridRow(time.time.start), gridRowEnd: getGridRow(time.time.end), - height: calcHoursDuration(time.time) * HOUR_HEIGHT + 'rem', + height: calcHoursDuration(time.time) * blockHeight + 'rem', zIndex: j, // TODO: Remove zIndex after implementing course conflicts #5 }} > @@ -310,6 +317,8 @@ const CalendarCourseOtherTimes = ({ }: { currentWeek: dayjs.Dayjs; }) => { + const blockHeight = useCalendarHourHeight((s) => s.height); + const course = useDraggingCourse((s) => s.course)!; const times = useOtherWeekCourseTimes({ courseId: course.id, @@ -329,7 +338,7 @@ const CalendarCourseOtherTimes = ({ gridColumnStart: i + 1, gridRowStart: getGridRow(time.time.start), gridRowEnd: getGridRow(time.time.end), - height: calcHoursDuration(time.time) * HOUR_HEIGHT + 'rem', + height: calcHoursDuration(time.time) * blockHeight + 'rem', }} > {time.classes.map((c) => ( diff --git a/src/helpers/calendar.ts b/src/helpers/calendar.ts index 2631195..764b8b5 100644 --- a/src/helpers/calendar.ts +++ b/src/helpers/calendar.ts @@ -1,4 +1,5 @@ import { useEffect, useState } from 'react'; +import { create } from 'zustand'; import { WEEK_DAYS } from '../constants/week-days'; import { useGetCourseClasses } from '../data/course-info'; @@ -219,3 +220,12 @@ export const useOtherWeekCourseTimes = ({ return times; }; + +export const useCalendarHourHeight = create<{ + height: number; + setHeight: (getNewHeight: (height: number) => number) => void; +}>()((set) => ({ + height: 4.5, + setHeight: (getNewHeight) => + set((state) => ({ height: getNewHeight(state.height) })), +})); diff --git a/src/helpers/zoom.ts b/src/helpers/zoom.ts new file mode 100644 index 0000000..20ce5d9 --- /dev/null +++ b/src/helpers/zoom.ts @@ -0,0 +1,33 @@ +import { useCallback, useEffect } from 'react'; + +import { useCalendarHourHeight } from './calendar'; + +const MIN_HEIGHT = 3; +const MAX_HEIGHT = 10; +const SPEED = 0.08; + +export const useZoom = () => { + const setCalendarHeight = useCalendarHourHeight((s) => s.setHeight); + + const onZoom = useCallback( + (e: WheelEvent) => { + // Check if user is scrolling + if (e.deltaY % 1 === 0) return; + e.preventDefault(); + e.stopPropagation(); + setCalendarHeight((previousHeight) => { + const newHeight = previousHeight - e.deltaY * SPEED; + const height = Math.min(Math.max(newHeight, MIN_HEIGHT), MAX_HEIGHT); + return height; + }); + }, + [setCalendarHeight], + ); + + useEffect(() => { + document.addEventListener('wheel', onZoom, { passive: false }); + return () => { + document.removeEventListener('wheel', onZoom); + }; + }, [onZoom]); +};