Skip to content

Commit

Permalink
feat: usePrefersColorScheme
Browse files Browse the repository at this point in the history
  • Loading branch information
mathhulk committed Apr 24, 2024
1 parent b768c75 commit eac8a91
Show file tree
Hide file tree
Showing 35 changed files with 721 additions and 424 deletions.
2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"@apollo/client": "^3.9.5",
"@floating-ui/dom": "^1.6.3",
"@mapbox/mapbox-gl-directions": "^4.3.0",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-hover-card": "^1.0.7",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-tooltip": "^1.0.7",
"@shopify/draggable": "^1.1.3",
Expand Down
16 changes: 8 additions & 8 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { RouterProvider, createBrowserRouter } from "react-router-dom";

import About from "@/app/About";
import Catalog from "@/app/Catalog";
import Explore from "@/app/Explore";
import Landing from "@/app/Landing";
import Layout from "@/app/Layout";
import Layout from "@/components/Layout";
import Plan from "@/app/Plan";
import Schedules from "@/app/Schedules";
import Search from "@/app/Search";
import AccountProvider from "@/components/AccountProvider";

const router = createBrowserRouter([
Expand All @@ -20,8 +20,8 @@ const router = createBrowserRouter([
index: true,
},
{
element: <Search />,
path: "search",
element: <Explore />,
path: "explore",
},
],
},
Expand All @@ -30,7 +30,7 @@ const router = createBrowserRouter([
children: [
{
element: <About />,
path: "/about",
path: "about",
},
],
},
Expand All @@ -39,15 +39,15 @@ const router = createBrowserRouter([
children: [
{
element: <Catalog />,
path: "/catalog/:year?/:semester?/:subject?/:courseNumber?/:classNumber?",
path: "catalog/:year?/:semester?/:subject?/:courseNumber?/:classNumber?",
},
{
element: <Schedules />,
path: "/schedules",
path: "schedules",
},
{
element: <Plan />,
path: "/plan",
path: "plan",
},
],
},
Expand Down
30 changes: 1 addition & 29 deletions frontend/src/app/Catalog/Class/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export default function Class({
[partialCurrentCourse, currentClassNumber]
);

const currentClass = useMemo(() => data?.class, [data?.class]);
const currentClass = useMemo(() => data?.class, [data]);

const Component = useMemo(() => views[view].Component, [view]);

Expand All @@ -112,34 +112,6 @@ export default function Class({
</IconButton>
</div>
<div className={styles.group}>
{/* TODO: Previously offered
<Select.Root defaultValue={`${currentSemester} ${currentYear}`}>
<Select.Trigger asChild>
<Button secondary>
<Select.Value />
<Select.Icon asChild>
<ArrowSeparateVertical />
</Select.Icon>
</Button>
</Select.Trigger>
<Select.Portal>
<Select.Content
position="popper"
className={styles.content}
align="end"
>
{currentClass?.course?.classes.map(
({ year, semester }, index) => (
<Select.Item key={index} value={`${semester} ${year}`}>
<Select.ItemText>
{semester} {year}
</Select.ItemText>
</Select.Item>
)
)}
</Select.Content>
</Select.Portal>
</Select.Root>*/}
{currentClass && (
<IconButton
as="a"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@

.view {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-columns: repeat(auto-fill, minmax(288px, 1fr));
gap: 12px;
flex-grow: 1;

.course {
border-radius: 8px;
Expand Down Expand Up @@ -84,17 +85,6 @@
gap: 16px;
box-shadow: 0 4px 8px rgba(0 0 0 / 10%);

.placeholder {
color: var(--slate-500);
position: absolute;
top: 50%;
left: 16px;
transform: translateY(-50%);
pointer-events: none;
font-size: 16px;
line-height: 1;
}

.input:not(:placeholder-shown) + .placeholder {
display: none;
}
Expand All @@ -103,7 +93,7 @@
color: var(--slate-900);
height: 56px;
font-size: 16px;
line-height: 1.5;
line-height: 1;

&::placeholder {
color: var(--slate-500);
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/app/Explore/Placeholder/Placeholder.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.root {
color: var(--slate-500);
position: absolute;
top: 50%;
left: 16px;
transform: translateY(-50%);
pointer-events: none;
font-size: 16px;
line-height: 1;
}
57 changes: 57 additions & 0 deletions frontend/src/app/Explore/Placeholder/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { useEffect, useRef, useState } from "react";

import classNames from "classnames";

import styles from "./Placeholder.module.scss";

const values = [
"Explore courses...",
"Computational methods for science and engineering",
"Environmental policy and resource management",
"Bioinformatics and computational biology",
"Quantum mechanics and mathematical physics",
"Public health epidemiology and data analysis",
];

interface PlaceholderProps {
className?: string;
}

export default function Placeholder({ className }: PlaceholderProps) {
const [text, setText] = useState(values[0]);
const positionRef = useRef(values[0].length - 1);
const indexRef = useRef(0);

useEffect(() => {
let timeoutId: ReturnType<typeof setTimeout>;

const update = () => {
let position = positionRef.current + 1;

if (position === values[indexRef.current].length * 2) {
indexRef.current = (indexRef.current + 1) % values.length;

position = 0;
}

positionRef.current = position;

const value = values[indexRef.current];

const end =
position > value.length ? -(position % value.length) : position;

const _text = values[indexRef.current].slice(0, end);

setText(_text);

timeoutId = setTimeout(update, _text.length === value.length ? 1000 : 75);
};

timeoutId = setTimeout(update, 100);

return () => clearInterval(timeoutId);
}, []);

return <p className={classNames(styles.root, className)}>{text}</p>;
}
147 changes: 147 additions & 0 deletions frontend/src/app/Explore/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { FormEvent, useState } from "react";

import { useApolloClient } from "@apollo/client";
import { ArrowRight, Calendar } from "iconoir-react";

import AverageGrade from "@/components/AverageGrade";
import Button from "@/components/Button";
import Container from "@/components/Container";
import Footer from "@/components/Footer";
import NavigationBar from "@/components/NavigationBar";
import Units from "@/components/Units";
import { GET_COURSE, ICourse, Semester } from "@/lib/api";

import styles from "./Explore.module.scss";
import Placeholder from "./Placeholder";

export default function Explore() {
const [input, setInput] = useState("");
const [courses, setCourses] = useState<ICourse[]>([]);
const apolloClient = useApolloClient();

const getCourse = async (name: string) => {
const [subject, courseNumber] = name.split(" ");

const { data } = await apolloClient.query<{ course: ICourse }>({
query: GET_COURSE,
variables: { subject, courseNumber },
});

if (!data) return;

return data.course;
};

const handleSubmit = async (event: FormEvent) => {
event.preventDefault();

const response = await fetch(
`http://localhost:3002/query?input=${encodeURIComponent(input)}&topK=24`
);

if (!response.ok) return;

const { matches } = (await response.json()) as {
matches: { id: string }[];
};

const courses = await Promise.all(
matches.map(({ id: name }) => getCourse(name))
);

setCourses(
courses.filter(
(course) => course && course.classes.length !== 0
) as ICourse[]
);
};

return (
<div className={styles.root}>
<div className={styles.header}>
<NavigationBar invert />
<div className={styles.container}>
<form className={styles.form} onSubmit={handleSubmit}>
<input
className={styles.input}
value={input}
// Required to display the placeholder conditionally
placeholder=""
onChange={(event) => setInput(event.target.value)}
/>
<Placeholder className={styles.placeholder} />
<Button className={styles.button}>
Search
<ArrowRight />
</Button>
</form>
</div>
</div>
<Container>
<div className={styles.body}>
<div className={styles.sideBar}></div>
<div className={styles.view}>
{courses
.sort((a, b) => {
const score = {
[Semester.Fall]: 3,
[Semester.Summer]: 2,
[Semester.Spring]: 1,
};

const getTerm = (course: ICourse) => {
return [...course.classes].sort(
(a, b) =>
a.year - b.year || score[a.semester] - score[b.semester]
)[0];
};

return (
getTerm(b).year - getTerm(a).year ||
score[getTerm(b).semester] - score[getTerm(a).semester]
);
})
.map((course) => {
const score = {
[Semester.Fall]: 3,
[Semester.Summer]: 2,
[Semester.Spring]: 1,
};

const { year, semester } = [...course.classes].sort(
(a, b) =>
a.year - b.year || score[a.semester] - score[b.semester]
)[0];

const { unitsMax, unitsMin } = course.classes.reduce(
(acc, { unitsMax, unitsMin }) => ({
unitsMax: Math.max(acc.unitsMax, unitsMax),
unitsMin: Math.min(acc.unitsMin, unitsMin),
}),
{ unitsMax: 0, unitsMin: 0 }
);

return (
<div className={styles.course} key={course.number}>
<p className={styles.title}>
{course.subject} {course.number}
</p>
<p className={styles.description}>{course.title}</p>
<div className={styles.row}>
<AverageGrade gradeAverage={course.gradeAverage} />
<div className={styles.badge}>
<Calendar />
{semester} {year}
</div>
<Units unitsMax={unitsMax} unitsMin={unitsMin} />
</div>
</div>
);
})}
</div>
</div>
</Container>
<Footer />
</div>
);
}
4 changes: 2 additions & 2 deletions frontend/src/app/Landing/Hero/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { FormEvent, useEffect, useMemo, useRef, useState } from "react";
import { ArrowRight, Clock } from "iconoir-react";

import Button from "@/components/Button";
import Header from "@/components/Header";
import NavigationBar from "@/components/NavigationBar";

import styles from "./Hero.module.scss";
import afternoon from "./afternoon.svg";
Expand Down Expand Up @@ -95,7 +95,7 @@ export default function Hero() {

return (
<div className={styles.root} ref={root}>
<Header invert />
<NavigationBar invert />
<div className={styles.container}>
<div className={styles.text}>
<h1 className={styles.heading}>
Expand Down
6 changes: 0 additions & 6 deletions frontend/src/app/Layout/Layout.module.scss

This file was deleted.

Loading

0 comments on commit eac8a91

Please sign in to comment.