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]);
+};