Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions client/public/ACMDev-logo-white.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/public/fonts/Gilroy-Bold.ttf
Binary file not shown.
Binary file added client/public/fonts/Gilroy-Light.ttf
Binary file not shown.
Binary file added client/public/fonts/Gilroy-Regular.ttf
Binary file not shown.
Binary file added client/public/fonts/Gilroy-SemiBold.ttf
Binary file not shown.
108 changes: 43 additions & 65 deletions client/src/components/Core.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { HeartTwoTone } from "@ant-design/icons";
import { Popover } from "antd";
import type { ReactNode } from "react";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import styled from "styled-components";
import SageAd from "./SageAd";

const Container = styled.div`
min-height: 100%;
Expand Down Expand Up @@ -38,65 +37,63 @@ const Footer = styled.div`
}
`;

const SageLink = styled.a`
background: linear-gradient(90deg, rgba(7,67,37,1) 0%, rgba(22,50,36,1) 100%);
display: inline-flex;
align-items: center;
gap: 0.25rem;
padding: 0.6rem 1.2rem;
margin-bottom: 0.3rem;
border-radius: 100rem;
color: #5AED86;
text-shadow: 0 0 4px rgb(0 0 0 / 0.6);
box-shadow: 0 2px 6px rgb(0 0 0 / 0.2);
transition: transform cubic-bezier(0.4, 0, 0.2, 1) 150ms, box-shadow cubic-bezier(0.4, 0, 0.2, 1) 150ms;
&:hover {
color: #5AED86;
box-shadow: 0 2px 8px rgb(0 0 0 / 0.2);
transform: scale(1.01);
}
`;

const SageText = styled.p`
line-height: 1.2rem;
margin-bottom: 0;
font-size: 0.9rem;
`;

const BuiltWithLove = styled.p`
/*const BuiltWithLove = styled.p`
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
font-size: 1rem;
margin: 0.3rem 0;
font-weight: 550;
`;

const SageLogo = styled.img`
height: 1.2rem;
margin-right: 0.4rem;
filter: drop-shadow(0 0 4px rgb(0 0 0 / 0.6));
`;

const SageTextMark = styled.img`
height: 1.2rem;
`
`;*/

const CreditsText = styled.p`
font-size: 0.9rem;
font-family: 'Gilroy-Bold', sans-serif;
color: var(--muted-text);
margin: 0.2rem 0;

@media (max-width: 768px) {
display: none;
}
`;

const GitHubLink = styled.a`
color: var(--link-color) !important;
text-decoration: none;

&:hover {
text-decoration: underline;
}
`;

interface CoreProps {
children: ReactNode;
showSageAd?: boolean;
}

function Core({ children }: CoreProps) {
function Core({ children, showSageAd = false }: CoreProps) {
const [, setTheme] = useState<"light" | "dark" | null>(null);

// Initialize theme on start
useEffect(() => {
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
const theme = prefersDark ? "dark" : "light";
setTheme(theme);
document.documentElement.setAttribute("data-theme", theme);
}, []);

useEffect(() => {
const handleThemeChange = (e: StorageEvent) => {
if ((e.newValue === "light" || e.newValue === "dark")) {
setTheme(e.newValue);
document.documentElement.setAttribute("data-theme", e.newValue);
}
};

window.addEventListener("storage", handleThemeChange);
return () => window.removeEventListener("storage", handleThemeChange);
}, []);

useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
const target = event.target as HTMLElement | null;
Expand Down Expand Up @@ -148,40 +145,21 @@ function Core({ children }: CoreProps) {
window.removeEventListener("keydown", handleKeyDown);
};
}, []);
const donors = (
<div style={{ width: "300px" }}>
<p>
Thank you to the following people for donating and making this possible (in order of most
monetary support): Anthony-Tien Huynh, Adam Butcher, Paul Denino, Thomas Sowders, Xavier
Brown, Enza Denino, David Garvin, Alastair Feille, Andrew Vaccaro and other anonymous
donors.
</p>
</div>
);

return (
<Container>
<Body>{children}</Body>
<Footer>
<SageLink href="https://utdsage.com/" target={"blank"}>
<SageLogo src="/SAGE-Logo.svg" />
<SageText>Get AI-powered UTD advising with </SageText>
<SageTextMark src="/SAGE-Textmark.svg" />
</SageLink>
<BuiltWithLove>
Built with <HeartTwoTone twoToneColor="#eb2f96" /> by{" "}
<a href="https://www.acmutd.co" target={"blank"}>ACM Dev</a>
</BuiltWithLove>
{showSageAd && <SageAd />}
<CreditsText>
Designed by <a href="https://www.arimilli.io" target={"blank"}>Bharat Arimilli</a>. Thanks to{" "}
{/*Designed by <a href="https://www.arimilli.io" target={"blank"}>Bharat Arimilli</a>. Thanks to{" "}
<a href="https://garrettgu.com/" target={"blank"}>Garrett Gu</a>,{" "}
<a href="https://jeffw.xyz/" target={"blank"}>Jeffrey Wang</a>,{" "}
<a href="https://www.linkedin.com/in/josephwickline/" target={"blank"}>Joseph Wickline</a> and our{" "}
<Popover content={donors}>
<span style={{ textDecoration: "underline" }}>donors</span>.
</Popover>

<a href="https://github.com/acmutd/utd-grades/tree/master/raw_data" target={"blank"}> Raw data available for download</a>
</Popover>*/}
See the full source code on our <GitHubLink href="https://github.com/acmutd/utd-grades" target="_blank">GitHub</GitHubLink>

</CreditsText>
</Footer>
Expand Down
135 changes: 117 additions & 18 deletions client/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,28 @@ import { HomeOutlined } from "@ant-design/icons";
import { Button, Row } from "antd";
import Image from "next/image";
import Router from "next/router";
import React from "react";
import React, { useEffect, useState } from "react";
import styled from "styled-components";

const Menu = styled(Row)`
padding: 30px;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
`;

const Back = styled(Button) <{ $dummy?: boolean }>`
background: none;
outline: none;
border: none;
cursor: pointer;
outline: none;
border: none;
box-shadow: none;
color: var(--text-color);
svg {
color: inherit;
}
visibility: ${(props) => (props.$dummy ? "hidden" : "visible")};

&:hover,
&:focus,
&:active {
Expand All @@ -35,15 +38,83 @@ const Back = styled(Button) <{ $dummy?: boolean }>`
}
`;

const ThemeToggle = styled.button`
position: absolute;
top: 20px;
right: 20px;
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 9999px;
border: 1px solid var(--toggle-border, #e4e4e7);
background: var(--toggle-bg);
color: var(--text-color);
cursor: pointer;
transition: all 0.2s ease;

&:hover {
background: var(--toggle-hover-bg);
color: var(--toggle-hover-color, #333333);
}

svg {
width: 16px;
height: 16px;
}

@media (prefers-color-scheme: light) {
border-color: rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.05);

&:hover {
background: rgba(255, 255, 255, 0.1);
color: #727272;
}
}
`;

const SunIcon = () => (
<svg
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"
/>
</svg>
);

const MoonIcon = () => (
<svg
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"
/>
</svg>
);



const HeaderText = styled.a`
margin-right: auto;
margin-left: auto;
position: absolute;
left: 50%;
transform: translateX(-50%);
display: block;

& h2 {
font-family: var(--font-family);
text-transform: uppercase;
color: rgb(78, 78, 78);
color: var(--header-color);
font-weight: 300;
letter-spacing: 2px;
font-size: 24px;
Expand All @@ -54,16 +125,42 @@ const HeaderText = styled.a`
}
`;


const HeaderBold = styled.span`
font-family: 'Gilroy-Bold', sans-serif;
font-weight: 700;
`;

const HeaderLight = styled.span`
font-family: 'Gilroy-Light', sans-serif;
`;

const Logo = {
height: "36px",
width: "36px",
};

export default function Header() {
const [theme, setTheme] = useState<"light" | "dark">(() => {
if (typeof window === "undefined") return "light";
const saved = localStorage.getItem("theme");
if (saved === "light" || saved === "dark") return saved;
return "light";
});

const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === "dark" ? "light" : "dark"));
};

useEffect(() => {
try {
document.documentElement.setAttribute("data-theme", theme);
localStorage.setItem("theme", theme);
} catch (e) {
// ignore during SSR
}
}, [theme]);

function goHome() {
(async function () {
await Router.push("/");
Expand All @@ -75,17 +172,19 @@ export default function Header() {
<Back onClick={goHome} type="ghost" icon={<HomeOutlined />} shape="circle" size="large" />
<HeaderText href="#" onClick={goHome}>
<h2>
<Image src="/ACMDev-logo.svg" alt="ACM Dev Logo" width={24} height={24} style={Logo} /> <HeaderBold>UTD</HeaderBold> Grades
<Image
src={theme === "light" ? "/ACMDev-logo.svg" : "/ACMDev-logo-white.svg"}
alt="ACM Dev Logo"
width={24}
height={24}
style={Logo}
/>
<HeaderBold>UTD</HeaderBold> <HeaderLight>GRADES</HeaderLight>
</h2>
</HeaderText>
<Back
$dummy
onClick={goHome}
type="ghost"
icon={<HomeOutlined />}
shape="circle"
size="large"
/>
<ThemeToggle onClick={toggleTheme} aria-label="Toggle Dark Mode">
{theme === "dark" ? <SunIcon /> : <MoonIcon />}
</ThemeToggle>
</Menu>
);
}
Loading