andy/reduce-flicker #25

Merged
shing.hung merged 3 commits from andy/reduce-flicker into main 2025-02-07 04:45:50 +00:00
195 changed files with 3419 additions and 893 deletions
Showing only changes of commit fbc7feba56 - Show all commits

1483
bun.lock Normal file

File diff suppressed because it is too large Load diff

BIN
bun.lockb

Binary file not shown.

4
nixpacks.toml Normal file
View file

@ -0,0 +1,4 @@
[phases.setup]
nixPkgs = ["nodejs_18", "bun"]
aptPkgs = ["curl", "wget"]

Binary file not shown.

BIN
public/404.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 431 KiB

After

Width:  |  Height:  |  Size: 431 KiB

Binary file not shown.

BIN
public/calendar.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

BIN
public/halloween.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

BIN
public/hardhack.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

BIN
public/map.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

BIN
public/officers/akhil.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,020 KiB

After

Width:  |  Height:  |  Size: 1,020 KiB

Binary file not shown.

BIN
public/officers/allie.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 987 KiB

After

Width:  |  Height:  |  Size: 987 KiB

Binary file not shown.

BIN
public/officers/andy.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 741 KiB

After

Width:  |  Height:  |  Size: 741 KiB

Binary file not shown.

BIN
public/officers/anika.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

BIN
public/officers/anu.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

BIN
public/officers/ashlee.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 540 KiB

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

BIN
public/officers/dhruv.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

BIN
public/officers/dihan.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

BIN
public/officers/emma.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

BIN
public/officers/erik.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

BIN
public/officers/lauren.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

BIN
public/officers/lisa.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

BIN
public/officers/philip.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

BIN
public/officers/pranav.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 943 KiB

After

Width:  |  Height:  |  Size: 943 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 987 KiB

After

Width:  |  Height:  |  Size: 987 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

BIN
public/officers/ridhi.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 973 KiB

After

Width:  |  Height:  |  Size: 973 KiB

Binary file not shown.

BIN
public/officers/rohil.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

BIN
public/officers/shing.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

BIN
public/officers/shipra.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

BIN
public/officers/stella.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

BIN
public/officers/steph.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

BIN
public/officers/terri.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

BIN
public/officers/zarif.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

BIN
public/project.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

BIN
public/robocup.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

BIN
public/signal.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

BIN
public/supercomp.webp Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View file

@ -1,3 +1,166 @@
---
const { filters, currentFilter } = Astro.props;
---
---
<div class="inline-flex border border-white/20 rounded-full md:p-[0.2vw] p-[0.4vw] relative my-[3vw]">
<div
id="slider"
class="absolute h-[calc(100%-15%)] bg-[#FFB81C] rounded-full transition-none"
style="left: 1%;"
>
</div>
{
filters.map((filter) => (
<button
data-filter={filter}
class={`md:text-[1.3vw] text-[2.5vw] md:px-[1.8vw] px-[3vw] md:py-[0.2vw] py-[0.4vw] rounded-full transition-all relative z-10 ${
currentFilter === filter
? "text-black"
: "text-white hover:bg-white/10 hover:bg-opacity-50"
}`}
>
{filter}
</button>
))
}
</div>
<script>
const buttons = document.querySelectorAll("[data-filter]");
const officers = document.querySelectorAll("[data-officer]");
const container = officers[0]?.parentElement;
const slider = document.getElementById("slider");
// Define type order for consistent sorting
const typeOrder = ["Executives", "Internal", "Events", "Projects"];
function getTypeWeight(type) {
const index = typeOrder.indexOf(type);
return index === -1 ? typeOrder.length : index;
}
function sortOfficersByType() {
const officerArray = Array.from(officers);
officerArray.sort((a, b) => {
const aTypes = JSON.parse(a.getAttribute("data-types"));
const bTypes = JSON.parse(b.getAttribute("data-types"));
return getTypeWeight(aTypes[0]) - getTypeWeight(bTypes[0]);
});
officerArray.forEach((officer) => {
container.appendChild(officer);
});
}
function moveSlider(button) {
if (!slider) return;
const buttonRect = button.getBoundingClientRect();
const containerRect = button.parentElement.getBoundingClientRect();
slider.style.width = `${buttonRect.width}px`;
slider.style.left = `${buttonRect.left - containerRect.left}px`;
}
function updateFilter(selectedFilter, clickedButton) {
// Update button styles
buttons.forEach((btn) => {
const isSelected =
btn.getAttribute("data-filter") === selectedFilter;
btn.classList.toggle("text-black", isSelected);
btn.classList.toggle("text-white", !isSelected);
btn.classList.toggle("hover:bg-white/10", !isSelected);
btn.classList.toggle("hover:bg-opacity-50", !isSelected);
});
// move slider
moveSlider(clickedButton);
// fades out all officers
officers.forEach((officer) => {
officer.style.opacity = "0";
officer.style.transition = "opacity 300ms ease-out";
});
// waits, then removes and re-adds officers
setTimeout(() => {
// removes all officers from container
officers.forEach((officer) => {
officer.remove();
});
// filters officers and prepares them for re-insertion
const officersToShow = Array.from(officers).filter((officer) => {
const types = JSON.parse(
officer.getAttribute("data-types") || "[]"
);
return (
selectedFilter === "All" || types.includes(selectedFilter)
);
});
// sorts if needed
if (selectedFilter === "All") {
officersToShow.sort((a, b) => {
const aTypes = JSON.parse(a.getAttribute("data-types"));
const bTypes = JSON.parse(b.getAttribute("data-types"));
return getTypeWeight(aTypes[0]) - getTypeWeight(bTypes[0]);
});
}
// sets initial opacity to 0 for fade in
officersToShow.forEach((officer) => {
officer.style.opacity = "0";
officer.style.display = "";
container.appendChild(officer);
});
// triggers reflow and fades in
requestAnimationFrame(() => {
officersToShow.forEach((officer) => {
officer.style.opacity = "1";
});
});
}, 300); // matches fade-out duration
}
sortOfficersByType();
// init
const initialButton = Array.from(buttons).find(
(btn) => btn.getAttribute("data-filter") === "All"
);
// init
if (initialButton && slider) {
const buttonRect = initialButton.getBoundingClientRect();
slider.style.width = `${buttonRect.width}px`;
// turns on transitions
requestAnimationFrame(() => {
slider.classList.remove("transition-none");
slider.classList.add(
"transition-all",
"duration-300",
"ease-in-out"
);
});
}
// reveals officers after sorting with animation
requestAnimationFrame(() => {
officers.forEach((officer) => {
officer.style.transition = "opacity 300ms ease-out";
officer.style.visibility = "visible";
// triggers reflow
officer.offsetHeight;
officer.style.opacity = "1";
});
});
// addss click handlers
buttons.forEach((button) => {
button.addEventListener("click", () => {
const filterValue = button.getAttribute("data-filter");
updateFilter(filterValue, button);
});
});
</script>

View file

@ -2,32 +2,55 @@
import { FaGear } from "react-icons/fa6";
import { MdEmail } from "react-icons/md";
import Link from "next/link";
const {name, position, picture, email} = Astro.props;
import { Image } from "astro:assets";
const { name, position, picture, email } = Astro.props;
---
<div class = "text-white">
<div class = "text-ieee-yellow">
<Link href="s1hung@ucsd.edu" className = "flex items-center ml-[3%] py-[0.5vh]">
<MdEmail className = "text-[1.5vw] mr-[0.5%]"/>
<p class = "text-[0.8vw]">
<div class="text-white">
<div class="text-ieee-yellow">
<Link
href={`mailto:${email}`}
className="flex items-center ml-[3%] py-[0.5vh] group"
>
<MdEmail
className="md:text-[1.5vw] text-[2.5vw] mr-[0.5%] group-hover:scale-110 group-hover:opacity-70 duration-300"
/>
<p class="md:text-[0.8vw] text-[2vw]">
{email}
</p>
</Link>
</div>
<div class = "w-[20vw] aspect-[334/440] bg-gradient-to-t from-ieee-blue-100/5 to-ieee-blue-100/25 rounded-[10%] flex flex-col items-center">
<img src ={picture} alt = "officer" class = "w-[18vw] rounded-[10%] pt-[5%] pb-[3%] relative" >
<div class = "bg-white w-fit rounded-full aspect-square p-[0.4vw] text-ieee-black text-[1.8vw] absolute ml-[13.5vw] mt-[3vh]">
<FaGear/>
<div
class="md:w-[20vw] w-[35vw] aspect-[334/440] bg-gradient-to-t from-ieee-blue-100/5 to-ieee-blue-100/25 rounded-[10%] flex flex-col items-center relative"
>
<Image
src={picture}
alt="officer"
class="md:w-[18vw] w-[31vw] md:rounded-[1.5vw] rounded-[3vw] mt-[5%] mb-[3%]"
width={334}
height={440}
/>
<div
class="bg-white w-fit rounded-full aspect-square md:p-[0.4vw] p-[0.8vw] text-ieee-black md:text-[1.8vw] text-[3.5vw] absolute md:right-[1.5vw] md:top-[1.5vw] right-[2.5vw] top-[2.5vw]"
>
<FaGear />
</div>
<div class = "w-full flex justify-between px-[7%]">
<p data-inview class = "opacity-0 in-view:animate-fade-right text-[2vw] font-light leading-[4.5vh]">
<div
class="flex w-[85%] justify-between"
>
<p
data-inview
class="in-view:animate-fade-right md:text-[2vw] text-[3.5vw] font-light md:leading-[2.5vw] leading-[5vw] w-[10vw]"
>
{name}
</p>
<div data-inview class = "opacity-0 in-view:animate-fade-up text-[0.8vw] w-[8vw] border-[0.11vw] border-white/90 rounded-full p-[0.5%] h-fit text-center">
<div
data-inview
class="md:mt-[0.5vw] mt-[1.5vw] in-view:animate-fade-up md:text-[0.8vw] text-[1.5vw] w-fit border-[0.11vw] border-white/90 rounded-full px-[1vw] py-[0.1vw] h-fit text-center"
>
{position}
</div>
</div>
</div>
</div>

View file

@ -1,43 +1,64 @@
---
import about from "../../images/about.png";
import about from "../../images/about.webp";
import { Image } from "astro:assets";
import neko from "../../images/neko.png";
import neko from "../../images/neko.webp";
import { LiaDotCircle } from "react-icons/lia";
import Officer from "../board/Officer.astro";
import Filter from "../board/Filter.astro";
import officers from "../../data/officers.json";
// Get all unique types and add 'All' option
const typeOrder = ["Executives", "Internal", "Events", "Projects"];
const types = ["All", ...typeOrder];
const currentFilter = "All";
---
<div class="text-white flex flex-col items-center mt-[15vh] mb-[10vh]">
<div data-inview class="relative w-[21vw] in-view:animate-fade-down">
<Image src={about} alt="About background image" />
<Image
src={neko}
alt="About image"
class="absolute top-[10%] left-[16%] aspect-[399/491] object-cover w-[14vw] rounded-[2vw]"
/>
</div>
<div
class="text-white flex flex-col items-center md:mt-[5vw] mt-[10vw] mb-[10vh]"
>
<div
data-inview
class="relative w-[40vw] md:w-[21vw] mb-[10vh] in-view:animate-fade-down"
>
<Image src={about} alt="About background image" />
<Image
src={neko}
alt="About image"
class="absolute top-[10%] left-[16%] aspect-[399/491] object-cover w-[27vw] md:w-[14vw] rounded-[2vw]"
/>
</div>
<div class="text-[2.5vw] flex items-center mt-[2vh]">
<LiaDotCircle className="mr-[1vw] pt-[0.5%]" />
<p>MEET THE BOARD</p>
</div>
<div class="text-[5vw] md:text-[2.5vw] flex items-center mt-[1vw]">
<LiaDotCircle className="mr-[1vw] pt-[0.5%]" />
<p>MEET THE BOARD</p>
</div>
<p class="text-[1.3vw] w-[56%] my-[3%] font-extralight text-center">
Erat hendrerit tristique erat; parturient cursus fringilla feugiat. Eget
faucibus fames ridiculus nec egestas convallis cubilia malesuada. Tellus
nibh vivamus tempus molestie tristique quis
</p>
<p
class="md:text-[1.3vw] text-[2.5vw] md:w-[56%] w-[70%] my-[3%] font-extralight text-center"
>
Our board comprises 31 students of varying majors, colleges, and interests!
Feel free to reach out for any questions about our position or experiences.
</p>
<div class="grid gap-[3vw] grid-cols-3 mt-[10vh]">
{
officers.map((officer) => (
<Officer
name={officer.name}
position={officer.position}
picture={officer.picture}
email={officer.email}
/>
))
}
</div>
<Filter filters={types} currentFilter={currentFilter} />
<div class="grid gap-[3vw] md:grid-cols-3 grid-cols-2 mt-[2vh]">
{
officers.map((officer) => (
<div
data-officer
data-types={JSON.stringify(officer.type)}
style="opacity: 0; visibility: hidden"
>
<Officer
name={officer.name}
position={officer.position}
picture={officer.picture}
email={officer.email}
/>
</div>
))
}
</div>
</div>

View file

@ -4,14 +4,14 @@ const {title, text} = Astro.props;
---
<div class="flex flex-col items-center text-white my-[10%]">
<div class="flex items-center text-[2.5vw] mb-[3%]">
<div class="flex items-center text-[4.5vw] md:text-[2.5vw] mb-[3%]">
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]"/>
<p class="text-transparent bg-clip-text bg-gradient-to-b from-white via-white to-ieee-black">
{title}
</p>
</div>
<p class="w-[70%] text-[1.4vw] font-light ">
<p class="w-[70%] md:text-[1.4vw] text-[2vw] font-light ">
{text}
</p>
</div>

View file

@ -5,22 +5,22 @@ import whiteLogoHorizontal from "../../images/logos/white_logo_horizontal.svg";
import { IoHeart } from "react-icons/io5";
---
<div class="w-full py-[2%] flex justify-center">
<div class="w-full md:py-[2%] py-[3vw] flex justify-center">
<div
class="w-[95%] bg-black/40 py-[1%] px-[1.5%] rounded-[2vw] border-[0.1vw] flex justify-between"
class="w-[95%] bg-black/40 md:py-[1%] py-[2vw] px-[1.5%] rounded-[2vw] border-[0.1vw] flex justify-between"
>
<Link href="/" className="hover:opacity-70 duration-300">
<Image
class="w-[15vw]"
class="md:w-[15vw] w-[35vw]"
src={whiteLogoHorizontal}
alt="IEEE UCSD Logo"
/>
</Link>
<div class="flex items-center">
<p class="text-white text-[1.2vw]">
<p class="text-white md:text-[1.2vw] text-[2.7vw]">
made by IEEE UCSD webmasters with
</p>
<IoHeart className=" text-ieee-blue-100 ml-[1vw] text-[1.5vw]" />
<IoHeart className=" text-ieee-blue-100 ml-[1vw] md:text-[1.5vw] text-[4vw]" />
</div>
</div>
</div>

View file

@ -4,146 +4,151 @@ import whiteLogoHorizontal from "../../images/logos/white_logo_horizontal.svg";
import pages from "../../data/pages.json";
---
<div class="md:w-full w-fit fixed z-10">
<div
class="flex justify-between items-center bg-black my-[1%] mx-[2.5%] py-[0.5%] px-[1%] md:rounded-full md:border-[0.1vw]"
>
<a href="/" class="hover:opacity-60 duration-300 hidden md:flex">
<Image
class="w-[15vw]"
src={whiteLogoHorizontal}
alt="IEEE UCSD Logo"
/>
</a>
<div class="w-full">
<div
class="flex justify-between items-center bg-ieee-black my-[1%] mx-[2.5%] py-[0.5%] px-[1%] rounded-full md:border-[0.1vw]"
>
<a href="/" class="hover:opacity-60 duration-300">
<Image
class="w-[15vw] md:block hidden"
src={whiteLogoHorizontal}
alt="IEEE UCSD Logo"
/>
<Image
class="w-[40vw] md:hidden block"
src={whiteLogoHorizontal}
alt="IEEE UCSD Logo"
/>
</a>
<!-- Desktop Navigation -->
<div class="hidden md:flex md:w-[55%] md:justify-between">
{
pages.map((page) => (
<a
href={page.path}
class={`uppercase rounded-full duration-300 px-[1.5vw] py-[0.2vw] text-[1.2vw] text-nowrap
<!-- Desktop Navigation -->
<div class="hidden md:flex md:w-[55%] md:justify-between">
{
pages.map((page) => (
<a
href={page.path}
class={`uppercase rounded-full duration-300 px-[1.5vw] py-[0.2vw] text-[1.2vw] text-nowrap
${
page.name === "Online Store"
? "bg-ieee-yellow text-black hover:opacity-70"
: "text-white border-white hover:opacity-50 border-[0.1vw] font-light"
page.name === "Online Store"
? "bg-ieee-yellow text-black hover:opacity-70"
: "text-white border-white hover:opacity-50 border-[0.1vw] font-light"
}`}
>
{page.name}
</a>
))
}
</div>
<!-- Mobile Hamburger/Close Button -->
<button
id="menu-btn"
class="md:hidden text-white p-2 flex justify-center items-center focus:outline-none relative z-[60] scale-150"
aria-label="Toggle menu"
>
<!-- Hamburger Icon -->
<svg
class="w-6 h-6 menu-icon"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
<!-- Close Icon -->
<svg
class="w-6 h-6 close-icon hidden"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
>
{page.name}
</a>
))
}
</div>
<!-- Mobile Menu -->
<div
id="mobile-menu"
class="fixed inset-0 z-[51] hidden xl:hidden motion-safe:transition-transform motion-safe:duration-300 translate-x-full"
<!-- Mobile Hamburger/Close Button -->
<button
id="menu-btn"
class="md:hidden text-white p-2 flex justify-center items-center focus:outline-none relative z-[60] scale-150"
aria-label="Toggle menu"
>
<div
class="flex flex-col items-center h-[70vh] justify-evenly bg-black"
>
{
pages.map((page) => (
<a
href={page.path}
class={`block py-2 px-8 text-center rounded-[3rem] motion-safe:transition-colors motion-safe:duration-200 uppercase font-bold text-xl
<!-- Hamburger Icon -->
<svg
class="w-6 h-6 menu-icon"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
<!-- Close Icon -->
<svg
class="w-6 h-6 close-icon hidden"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<!-- Mobile Menu -->
<div
id="mobile-menu"
class="fixed inset-0 z-[51] hidden xl:hidden motion-safe:transition-transform motion-safe:duration-300 translate-x-full"
>
<div
class="flex flex-col items-center min-h-screen justify-center bg-black py-20 px-4 space-y-8"
>
{
pages.map((page) => (
<a
href={page.path}
class={`block py-4 px-12 text-center rounded-[3rem] motion-safe:transition-colors motion-safe:duration-200 uppercase font-bold text-2xl w-full max-w-md
${
page.name === "Online Store"
? "bg-[#f3c135] text-black border-[#f3c135] hover:bg-[#dba923] hover:border-[#dba923]"
: "text-white hover:text-gray-300 border-white"
page.name === "Online Store"
? "bg-[#f3c135] text-black border-[#f3c135] hover:bg-[#dba923] hover:border-[#dba923]"
: "text-white hover:text-gray-300 border-white border-2"
}`}
>
{page.name}
</a>
))
}
</div>
>
{page.name}
</a>
))
}
</div>
</div>
</div>
<style>
#mobile-menu.show {
@apply translate-x-0;
}
#mobile-menu.show {
@apply translate-x-0;
}
</style>
<script>
const menuBtn = document.getElementById("menu-btn");
const mobileMenu = document.getElementById("mobile-menu");
const menuIcon = document.querySelector(".menu-icon");
const closeIcon = document.querySelector(".close-icon");
const menuBtn = document.getElementById("menu-btn");
const mobileMenu = document.getElementById("mobile-menu");
const menuIcon = document.querySelector(".menu-icon");
const closeIcon = document.querySelector(".close-icon");
function toggleMenu(show: boolean) {
if (show) {
mobileMenu?.classList.remove("hidden");
menuIcon?.classList.add("hidden");
closeIcon?.classList.remove("hidden");
document.body.style.overflow = "hidden";
function toggleMenu(show: boolean) {
if (show) {
mobileMenu?.classList.remove("hidden");
menuIcon?.classList.add("hidden");
closeIcon?.classList.remove("hidden");
document.body.style.overflow = "hidden";
setTimeout(() => {
mobileMenu?.classList.add("show");
}, 10);
} else {
mobileMenu?.classList.remove("show");
menuIcon?.classList.remove("hidden");
closeIcon?.classList.add("hidden");
document.body.style.overflow = "";
setTimeout(() => {
mobileMenu?.classList.add("show");
}, 10);
} else {
mobileMenu?.classList.remove("show");
menuIcon?.classList.remove("hidden");
closeIcon?.classList.add("hidden");
document.body.style.overflow = "";
setTimeout(() => {
mobileMenu?.classList.add("hidden");
}, 100);
}
setTimeout(() => {
mobileMenu?.classList.add("hidden");
}, 100);
}
}
menuBtn?.addEventListener("click", () => {
const isMenuHidden = mobileMenu?.classList.contains("hidden") ?? true;
toggleMenu(isMenuHidden);
});
menuBtn?.addEventListener("click", () => {
const isMenuHidden = mobileMenu?.classList.contains("hidden") ?? true;
toggleMenu(isMenuHidden);
});
// Close menu when clicking outside
document.addEventListener("click", (e) => {
if (
!mobileMenu?.contains(e.target as Node) &&
!menuBtn?.contains(e.target as Node) &&
!mobileMenu?.classList.contains("hidden")
) {
toggleMenu(false);
}
});
// Close menu when clicking outside
document.addEventListener("click", (e) => {
if (
!mobileMenu?.contains(e.target as Node) &&
!menuBtn?.contains(e.target as Node) &&
!mobileMenu?.classList.contains("hidden")
) {
toggleMenu(false);
}
});
</script>

View file

@ -1,11 +1,11 @@
---
const {question, answer} = Astro.props;
---
<div class = "text-white w-full flex flex-col mb-[2vh]">
<p data-inview class = "in-view:animate-fade-right text-ieee-yellow text-[1.4vw] mb-[2vh] font-semibold pl-[1vw]">
<div class = "text-white w-full flex flex-col mb-[2vh] animate-ease-in-out">
<p data-inview class = "in-view:animate-fade-right text-ieee-yellow text-[2.5vw] md:text-[1.4vw] mb-[2vh] font-semibold pl-[1vw]">
{question}
</p>
<p data-inview class = "w-[60%] mb-[2vh] pl-[1vw] in-view:animate-fade-left">
<p data-inview class = "md:w-[70%] w-[80%] mb-[2vh] pl-[1vw] text-[2vw] md:text-[1.2vw] in-view:animate-fade-left animate-ease-in-out">
{answer}
</p>
<dev>

View file

@ -4,8 +4,8 @@ import { LiaDotCircle } from "react-icons/lia";
const {faq} = Astro.props;
---
<div class = "text-white w-full h-[90vh] ml-[15vw] mb-[20%] mt-[10%]">
<div class = "text-[2.5vw] flex items-center my-[7vh]">
<div class = "text-white md:ml-[15vw] ml-[10vw] mb-[20%] mt-[10%]">
<div class = "text-[4.5vw] md:text-[2.5vw] flex items-center my-[7vh]">
<LiaDotCircle className = "mr-[1vw]" />
<p>
Frequently Asked Questions

View file

@ -1,71 +1,79 @@
---
import { LiaDotCircle } from "react-icons/lia";
import { Image } from "astro:assets";
import evan from "../../images/evan.png";
import { FaDiscord, FaFacebook } from "react-icons/fa";
import jellyfish from "../../images/jellyfish.webp";
import { FaDiscord } from "react-icons/fa";
import { RiInstagramFill } from "react-icons/ri";
import { MdEmail } from "react-icons/md";
import Link from "next/link";
---
<div class="text-white flex flex-col items-center h-[65vh] justify-between">
<div class="flex items-center text-[2.5vw]">
<div
class="text-white flex flex-col items-center md:h-[35vw] h-[60vw] justify-between"
>
<div class="flex items-center text-[4.5vw] md:text-[2.5vw]">
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]" />
<p>Social Media</p>
</div>
<p class="w-1/3 text-center text-[1.2vw] pb-[5%]">
Lorem ipsum is placeholder text commonly used in the graphic, print, and
publishing industries f
<p class="md:w-1/3 w-3/5 text-center text-[2vw] md:text-[1.2vw] pb-[5%]">
Stay connected with us on Discord, Facebook, and Instagram! We regularly
post information on upcoming events and competitions.
</p>
<div
class="w-[85%] rounded-[3vw] bg-gradient-to-r from-ieee-blue-300 to-ieee-blue-100 relative h-[30vh] flex items-center text-white/90"
class="md:w-[85%] w-full rounded-[3vw] bg-gradient-to-r from-ieee-blue-300 to-ieee-blue-100 relative md:h-[15vw] h-[30vw] flex items-center text-white/90"
>
<div data-inview class="w-2/5 flex justify-evenly ml-[5%] in-view:animate-flip-up animate-duration-1000">
<Link
href="https://discord.gg/XxfjqZSjca"
target="_blank"
className="flex flex-col items-center"
>
<div
class="border-[0.15vw] rounded-full shadow-glow hover:scale-110 duration-300 p-[1vw] text-[2.2vw] text-ieee-black/80 border-ieee-blue-100 bg-gradient-radial from-white to-ieee-blue-100"
>
<FaDiscord />
</div>
<p class="text-[1.3vw] font-semibold">Discord</p>
</Link>
<Link
href="https://www.facebook.com/ieeeucsd"
target="_blank"
className="flex flex-col items-center"
>
<div
class="border-[0.15vw] rounded-full shadow-glow hover:scale-110 duration-300 p-[1vw] text-[2.2vw] text-ieee-black/80 border-ieee-blue-100 bg-gradient-radial from-white to-ieee-blue-100"
>
<FaFacebook />
</div>
<p class="text-[1.3vw] font-semibold">Facebook</p>
</Link>
<div
data-inview
class="md:w-2/5 w-1/2 flex justify-evenly ml-[5%] animate-ease-in-out in-view:animate-flip-up animate-duration-1000"
>
<Link
href="https://www.instagram.com/ieee.ucsd"
target="_blank"
className="flex flex-col items-center"
>
<div
class="border-[0.15vw] rounded-full shadow-glow hover:scale-110 duration-300 p-[1vw] text-[2.2vw] text-ieee-black/80 border-ieee-blue-100 bg-gradient-radial from-white to-ieee-blue-100"
class="border-[0.15vw] rounded-full shadow-glow hover:scale-110 duration-300 p-[1vw] text-[5vw] md:text-[2.2vw] text-ieee-black/80 border-ieee-blue-100 bg-gradient-radial from-white to-ieee-blue-100"
>
<RiInstagramFill />
</div>
<p class="text-[1.3vw] font-semibold">Instagram</p>
<p class="text-[2vw] md:text-[1.3vw] font-semibold">
Instagram
</p>
</Link>
<Link
href="https://discord.gg/XxfjqZSjca"
target="_blank"
className="flex flex-col items-center"
>
<div
class="border-[0.15vw] rounded-full shadow-glow hover:scale-110 duration-300 p-[1vw] text-[5vw] md:text-[2.2vw] text-ieee-black/80 border-ieee-blue-100 bg-gradient-radial from-white to-ieee-blue-100"
>
<FaDiscord />
</div>
<p class="text-[2vw] md:text-[1.3vw] font-semibold">Discord</p>
</Link>
<Link
href="mailto:ieee@ucsd.edu"
target="_blank"
className="flex flex-col items-center"
>
<div
class="border-[0.15vw] rounded-full shadow-glow hover:scale-110 duration-300 p-[1vw] text-[5vw] md:text-[2.2vw] text-ieee-black/80 border-ieee-blue-100 bg-gradient-radial from-white to-ieee-blue-100"
>
<MdEmail />
</div>
<p class="text-[2vw] md:text-[1.3vw] font-semibold">Email</p>
</Link>
</div>
<Image
data-inview
src={evan}
src={jellyfish}
alt="cat placeholder"
class="absolute -bottom-[10vh] w-[25vw] right-0 in-view:animate-wiggle"
class="absolute bottom-0 md:w-[25vw] w-[35vw] right-[4vw] animate-wiggle animate-infinite"
/>
</div>
</div>

View file

@ -3,7 +3,7 @@ const {title} = Astro.props;
import { LiaDotCircle } from "react-icons/lia";
---
<div class="flex items-center text-[2.5vw] mb-[5%]">
<div class="flex items-center md:text-[2.5vw] text-[4vw] mb-[5%]">
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]"/>
<p>
{title}

View file

@ -1,11 +1,13 @@
---
const {title} = Astro.props;
const { title } = Astro.props;
import { LiaDotCircle } from "react-icons/lia";
---
<div class="flex items-center text-[3vw] ml-[10%] pt-[10%] text-white font-semibold">
<LiaDotCircle className=" mr-[1vw] text-[2.7vw]"/>
<p>
{title}
</p>
<div
class="flex items-center md:text-[3vw] text-[4.5vw] ml-[10%] md:pt-[5%] pt-[10%] text-white font-semibold"
>
<LiaDotCircle className=" mr-[1vw] text-[2.7vw]" />
<p>
{title}
</p>
</div>

View file

@ -0,0 +1,358 @@
import React, { useState, useEffect } from "react";
const Calendar = ({ CALENDAR_API_KEY, EVENT_CALENDAR_ID }) => {
const [currentDate, setCurrentDate] = useState(new Date());
const [events, setEvents] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [hoveredEvent, setHoveredEvent] = useState(null);
const [tooltipPosition, setTooltipPosition] = useState({ x: 0, y: 0 });
const getDaysInMonth = (date) => {
const year = date.getFullYear();
const month = date.getMonth();
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
const daysInMonth = lastDay.getDate();
const startingDay = firstDay.getDay();
const endingDay = lastDay.getDay();
const days = [];
// Add empty slots for days before the first of the month
for (let i = 0; i < startingDay; i++) {
days.push(null);
}
// Add all days of the month
for (let i = 1; i <= daysInMonth; i++) {
days.push(new Date(year, month, i));
}
// Add empty slots for remaining days in the last week
const remainingDays = 6 - endingDay;
for (let i = 0; i < remainingDays; i++) {
days.push(null);
}
return days;
};
// Format date to match event dates
const formatDate = (date) => {
if (!date) return "";
return date.toISOString().split("T")[0];
};
// Get events for a specific day
const getEventsForDay = (day) => {
if (!day) return [];
const dayStr = formatDate(day);
return events.filter((event) => {
const eventDate = event.start.dateTime
? new Date(event.start.dateTime).toISOString().split("T")[0]
: event.start.date;
return eventDate === dayStr;
});
};
// Format time for display
const formatEventTime = (dateTimeStr) => {
if (!dateTimeStr) return "";
const date = new Date(dateTimeStr);
return date.toLocaleTimeString("en-US", {
hour: "numeric",
minute: "2-digit",
});
};
useEffect(() => {
const calendarId = EVENT_CALENDAR_ID;
const userTimeZone = "America/Los_Angeles";
const loadGapiAndListEvents = async () => {
try {
console.log("Starting to load events...");
if (typeof window.gapi === "undefined") {
console.log("Loading GAPI script...");
await new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = "https://apis.google.com/js/api.js";
document.body.appendChild(script);
script.onload = () => {
console.log("GAPI script loaded");
window.gapi.load("client", resolve);
};
script.onerror = () => {
console.error("Failed to load GAPI script");
reject(new Error("Failed to load the Google API script."));
};
});
}
console.log("Initializing GAPI client...");
await window.gapi.client.init({
apiKey: CALENDAR_API_KEY,
discoveryDocs: [
"https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest",
],
});
// Get first and last day of current month
const firstDay = new Date(
currentDate.getFullYear(),
currentDate.getMonth(),
1,
);
const lastDay = new Date(
currentDate.getFullYear(),
currentDate.getMonth() + 1,
0,
);
console.log("Fetching events...");
const response = await window.gapi.client.calendar.events.list({
calendarId: calendarId,
timeZone: userTimeZone,
singleEvents: true,
timeMin: firstDay.toISOString(),
timeMax: lastDay.toISOString(),
orderBy: "startTime",
});
console.log("Response received:", response);
if (response.result.items) {
setEvents(response.result.items);
}
} catch (error) {
console.error("Detailed Error: ", error);
setError(error.message || "Failed to load events");
} finally {
setLoading(false);
}
};
if (!CALENDAR_API_KEY) {
setError("API key is missing");
setLoading(false);
return;
}
setLoading(true);
loadGapiAndListEvents();
}, [CALENDAR_API_KEY, currentDate]);
const monthNames = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
const weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const changeMonth = (increment) => {
setCurrentDate(
new Date(
currentDate.getFullYear(),
currentDate.getMonth() + increment,
1,
),
);
};
const handleEventMouseEnter = (event, e) => {
const target = e.target;
setTooltipPosition({
x: e.clientX,
y: e.clientY,
});
setHoveredEvent({ event, target });
};
const handleEventMouseLeave = () => {
setHoveredEvent(null);
};
const handleMouseMove = (e) => {
if (hoveredEvent) {
// Check if the mouse is still over the event element
const rect = hoveredEvent.target.getBoundingClientRect();
const isStillHovering =
e.clientX >= rect.left &&
e.clientX <= rect.right &&
e.clientY >= rect.top &&
e.clientY <= rect.bottom;
if (!isStillHovering) {
setHoveredEvent(null);
} else {
setTooltipPosition({
x: e.clientX,
y: e.clientY,
});
}
}
};
useEffect(() => {
const handleScroll = () => {
if (hoveredEvent) {
const rect = hoveredEvent.target.getBoundingClientRect();
const mouseX = tooltipPosition.x - 15; // Subtract the offset added to the tooltip
const mouseY = tooltipPosition.y - 15;
const isStillHovering =
mouseX >= rect.left &&
mouseX <= rect.right &&
mouseY >= rect.top &&
mouseY <= rect.bottom;
if (!isStillHovering) {
setHoveredEvent(null);
}
}
};
window.addEventListener("scroll", handleScroll, true);
return () => window.removeEventListener("scroll", handleScroll, true);
}, [hoveredEvent, tooltipPosition]);
if (!CALENDAR_API_KEY) {
return (
<div className="text-white">
Error: Calendar API key is not configured
</div>
);
}
return (
<div
className="md:w-[90vw] w-[95vw] mx-auto p-[3vw] relative z-10"
onMouseMove={handleMouseMove}
>
{/* Hovering Calendar Header */}
<div className="flex justify-center mb-[2vw]">
<div className="bg-gradient-to-t from-ieee-blue-100/5 to-ieee-blue-100/25 rounded-[1.5vw] p-[1vw] backdrop-blur-sm w-[30vw] px-[2vw]">
<div className="flex items-center gap-[3vw]">
<button
onClick={() => changeMonth(-1)}
className="text-white hover:text-ieee-yellow transition-colors text-[2vw] bg-ieee-black/40 w-[4vw] h-[4vw] rounded-[1vw] flex items-center justify-center"
>
</button>
<h2 className="text-white text-[2.5vw] font-bold whitespace-nowrap">
{monthNames[currentDate.getMonth()]} {currentDate.getFullYear()}
</h2>
<button
onClick={() => changeMonth(1)}
className="text-white hover:text-gray transition-colors text-[2vw] bg-ieee-black/40 w-[4vw] h-[4vw] rounded-[1vw] flex items-center justify-center"
>
</button>
</div>
</div>
</div>
{/* Main Calendar Body */}
<div className="bg-gradient-to-t from-ieee-blue-100/5 to-ieee-blue-100/25 rounded-[1.5vw] p-[1vw] relative">
{/* Week Days Header */}
<div className="grid grid-cols-7 gap-[0.5vw] mb-[1vw]">
{weekDays.map((day, index) => (
<div key={day} className="flex justify-center w-full">
<div
className={`text-white text-center font-semibold p-[0.5vw] text-[1.2vw] bg-ieee-black/60 w-full h-[4vw] flex items-center justify-center
${
index === 0
? "rounded-tl-[2vw] rounded-[0.5vw]"
: index === 6
? "rounded-tr-[2vw] rounded-[0.5vw]"
: "rounded-[0.5vw]"
}`}
>
{day}
</div>
</div>
))}
</div>
{/* Calendar Grid */}
<div className="grid grid-cols-7 gap-[0.5vw] relative">
{getDaysInMonth(currentDate).map((day, index) => (
<div
key={index}
className={`min-h-[10vw] p-[0.5vw] rounded relative ${
day ? "bg-white/5" : "bg-transparent"
} border border-white/10`}
>
{day && (
<>
<div className="text-white mb-[0.5vw] text-[1vw]">
{day.getDate()}
</div>
<div className="space-y-[0.5vw]">
{getEventsForDay(day).map((event, eventIndex) => (
<div
key={eventIndex}
className="text-[0.8vw] border border-gray-300 text-white p-[0.5vw] rounded truncate cursor-pointer hover:bg-white/10 transition-colors relative"
onMouseEnter={(e) => handleEventMouseEnter(event, e)}
onMouseLeave={handleEventMouseLeave}
>
{event.summary}
</div>
))}
</div>
</>
)}
</div>
))}
</div>
{/* Tooltip */}
{hoveredEvent && (
<div
className="fixed z-[9999] bg-ieee-blue-100 text-white p-[1vw] rounded-[0.5vw] shadow-xl border border-white/20 min-w-[15vw]"
style={{
left: `${tooltipPosition.x + 15}px`,
top: `${tooltipPosition.y + 15}px`,
}}
>
<h3 className="text-[1vw] font-semibold mb-[0.5vw]">
{hoveredEvent.event.summary}
</h3>
{hoveredEvent.event.description && (
<p className="text-[0.8vw] mb-[0.5vw] text-white/80">
{hoveredEvent.event.description}
</p>
)}
<div className="text-[0.8vw] text-white/90">
{hoveredEvent.event.start.dateTime ? (
<>
<p>
Start: {formatEventTime(hoveredEvent.event.start.dateTime)}
</p>
<p>End: {formatEventTime(hoveredEvent.event.end.dateTime)}</p>
</>
) : (
<p>All day event</p>
)}
{hoveredEvent.event.location && (
<p className="mt-[0.3vw]">
Location: {hoveredEvent.event.location}
</p>
)}
</div>
</div>
)}
</div>
</div>
);
};
export default Calendar;

View file

@ -0,0 +1,170 @@
import React, { useEffect, useState } from "react";
const UpcomingEvent = ({ name, location, date, time, delay, description }) => (
<div className="text-white w-[40vw] pl-[8%] md:border-l-[0.3vw] border-l-[0.5vw] border-white/70 pb-[5%] relative">
<p
data-inview
className={`animate-duration-500 animate-delay-${delay * 200} in-view:animate-fade-left py-[0.2%] px-[2%] w-fit border-[0.1vw] font-light rounded-full md:text-[1.3vw] text-[2.3vw]`}
>
{name}
</p>
<div
data-inview
className={`animate-duration-500 animate-delay-${delay * 200 + 100} in-view:animate-fade-left flex justify-between items-center min-w-[70%] w-fit md:text-[1.2vw] text-[2vw] my-[2%]`}
>
Location: {location}
{date && (
<>
<div className="bg-white h-[0.5vw] w-[0.5vw] rounded-full mx-[0.5vw]" />
<p>{date}</p>
</>
)}
{time && (
<>
<div className="bg-white h-[0.5vw] w-[0.5vw] rounded-full mx-[0.5vw]" />
<p>{time}</p>
</>
)}
</div>
<p
data-inview
className={`animate-duration-500 animate-delay-${delay * 200 + 200} in-view:animate-fade-left md:text-[1vw] text-[1.8vw] text-white/60`}
>
{description}
</p>
<div className="bg-ieee-yellow md:h-[1.2vw] h-[1.5vw] md:w-[1.2vw] w-[1.5vw] rounded-full absolute -top-[1.5%] -left-[2%]" />
</div>
);
const EventList = ({ CALENDAR_API_KEY, EVENT_CALENDAR_ID }) => {
const [events, setEvents] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const apiKey = CALENDAR_API_KEY;
const calendarId = EVENT_CALENDAR_ID;
const userTimeZone = "America/Los_Angeles";
const loadGapiAndListEvents = async () => {
try {
console.log("Starting to load events...");
if (typeof window.gapi === "undefined") {
console.log("Loading GAPI script...");
await new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = "https://apis.google.com/js/api.js";
document.body.appendChild(script);
script.onload = () => {
console.log("GAPI script loaded");
window.gapi.load("client", resolve);
};
script.onerror = () => {
console.error("Failed to load GAPI script");
reject(new Error("Failed to load the Google API script."));
};
});
}
console.log("Initializing GAPI client...");
await window.gapi.client.init({
apiKey: apiKey,
discoveryDocs: [
"https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest",
],
});
console.log("Fetching events...");
const response = await window.gapi.client.calendar.events.list({
calendarId: calendarId,
timeZone: userTimeZone,
singleEvents: true,
timeMin: new Date().toISOString(),
maxResults: 3,
orderBy: "startTime",
});
console.log("Response received:", response);
if (response.result.items) {
setEvents(response.result.items);
}
} catch (error) {
console.error("Detailed Error: ", error);
setError(error.message || "Failed to load events");
} finally {
setLoading(false);
}
};
if (!CALENDAR_API_KEY) {
setError("API key is missing");
setLoading(false);
return;
}
setLoading(true);
loadGapiAndListEvents();
}, [CALENDAR_API_KEY]);
if (!CALENDAR_API_KEY) {
return (
<div className="text-white">
Error: Calendar API key is not configured
</div>
);
}
return (
<div>
{error && <p className="text-white">Error: {error}</p>}
{!loading && !error && events.length === 0 && (
<UpcomingEvent
name="No Upcoming Events!"
location="¯\_(ツ)_/¯"
date=""
time=""
delay={0}
description="There are no upcoming events! Check back again soon :)
...or just wait for the entire page to load. This is here by default LOL"
/>
)}
{!loading && !error && events.length > 0 && (
<div>
{events.map((event, index) => {
const startDate = new Date(
event.start.dateTime || event.start.date,
);
const day = startDate.toLocaleDateString("en-US", {
weekday: "short",
});
const date = startDate.toLocaleDateString("en-US", {
day: "numeric",
month: "short",
year: "numeric",
});
const time = startDate.toLocaleTimeString("en-US", {
hour: "numeric",
minute: "2-digit",
});
return (
<UpcomingEvent
key={index}
name={event.summary || "No Title"}
location={event.location || "No location provided"}
date={`${day} ${date}`}
time={time}
delay={index}
description={event.description || "No description available."}
/>
);
})}
</div>
)}
</div>
);
};
export default EventList;

View file

@ -1,20 +1,19 @@
---
import { Image } from "astro:assets";
import eventbg from "../../images/eventbg.png";
import eventbg from "../../images/eventbg.webp";
import { LiaDotCircle } from "react-icons/lia";
---
<div class="w-full pt-[25vh] flex justify-center relative">
<Image
src={eventbg}
alt="Event Page Background"
class="w-[45%] rounded-[2vw] aspect-[2/1] object-cover relative in-view:animate-fade-down opacity-0"
data-inview
/>
<div
class="absolute -bottom-[6%] left-[20%] flex items-center text-[3vw] py-[1.5%] px-[3%] text-white bg-ieee-black rounded-[2vw]"
>
<LiaDotCircle className=" mr-[2vw] pt-[0.5%]" />
<p>EVENTS</p>
</div>
<div class="w-full md:pt-[5vw] pt-[10vw] flex justify-center relative">
<Image
src={eventbg}
alt="Event Page Background"
class="md:w-[45%] w-[80%] rounded-[2vw] aspect-[2/1] object-cover"
/>
<div
class="absolute -bottom-[6%] md:left-[20%] left-[10%] flex items-center md:text-[3vw] text-[6vw] py-[1.5%] px-[3%] text-white bg-ieee-black rounded-[2vw]"
>
<LiaDotCircle className=" mr-[2vw] pt-[0.5%]" />
<p>EVENTS</p>
</div>
</div>

View file

@ -1,45 +1,28 @@
---
import UpcomingEvent from "./UpcomingEvent.astro";
import { LiaDotCircle } from "react-icons/lia";
import EventList from "./EventList.jsx";
const CALENDAR_API_KEY = import.meta.env.CALENDAR_API_KEY;
const EVENT_CALENDAR_ID = import.meta.env.EVENT_CALENDAR_ID;
---
<div class="flex ml-[15%] my-[10%]">
<div class="w-1/4 text-white pr-[5%] mr-[10%]">
<div class="w-[6vw] h-[0.3vw] bg-ieee-yellow rounded-full"/>
<div class="flex items-center text-[2vw] font-bold my-[10%]">
<LiaDotCircle className=" mr-[1vw] text-[2.5vw]"/>
<p>
Upcoming <br/> Events
</p>
</div>
<p class="text-[1.3vw] font-light">
SCROLL DOWN TO SEE THE UPCOMING EVENTS FOR IEEE!
<div class="flex ml-[15%] md:my-[10%] my-[20%]">
<div class="md:w-1/4 w-[30%] text-white pr-[5%] mr-[10%]">
<div class="w-[6vw] h-[0.3vw] bg-ieee-yellow rounded-full"></div>
<div class="flex items-center md:text-[2vw] text-[4vw] font-bold my-[10%]">
<LiaDotCircle className=" mr-[1vw] text-[2.5vw]" />
<p>
Upcoming <br /> Events
</p>
</div>
<div>
<UpcomingEvent
name="Beach Social"
location="La Jolla Cove"
date="Tue 9 Jun 2024"
time="2 pm"
delay="0"
description="Cursus nec orci pulvinar convallis mollis a diam. Nostra aptent praesent suscipit nisl dignissim consequat. Semper malesuada pharetra fusce; elementum maximus"
/>
<UpcomingEvent
name="Beach Social"
location="La Jolla Cove"
date="Tue 9 Jun 2024"
time="2 pm"
delay="300"
description="Cursus nec orci pulvinar convallis mollis a diam. Nostra aptent praesent suscipit nisl dignissim consequat. Semper malesuada pharetra fusce; elementum maximus"
/>
<UpcomingEvent
name="Beach Social"
location="La Jolla Cove"
date="Tue 9 Jun 2024"
time="2 pm"
delay="700"
description="Cursus nec orci pulvinar convallis mollis a diam. Nostra aptent praesent suscipit nisl dignissim consequat. Semper malesuada pharetra fusce; elementum maximus"
/>
</div>
<p class="md:text-[1.3vw] text-[2vw] font-light">
SCROLL DOWN TO SEE THE UPCOMING EVENTS FOR IEEE!
</p>
</div>
<div>
<EventList
client:load
CALENDAR_API_KEY={CALENDAR_API_KEY}
EVENT_CALENDAR_ID={EVENT_CALENDAR_ID}
/>
</div>
</div>

View file

@ -3,22 +3,32 @@ import Link from "next/link";
import { LiaDotCircle } from "react-icons/lia";
---
<div class="pt-[14vh] text-white w-full flex justify-center mb-[10vh]">
<div class="w-3/4 h-[40vh] flex justify-between flex-col">
<div class="flex items-center text-[3vw] pl-[5%] pt-[5%]">
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]"/>
<p>
Contact Us
</p>
</div>
<p class="text-[1.25vw]">
The <a class=" text-ieee-yellow underline" href="https://maps.app.goo.gl/y4RwNCkoKBEHGHsv6" target="_blank">IEEE Project Space</a> is an open-access, collaborative space located at EBU1-4710. Students can do homework or get access to basic electronic tools such as soldering stations, breadboard components, and Arduino and Raspberry PI parts!
</p>
<div class="flex justify-end">
<Link data-inview href="https://maps.app.goo.gl/y4RwNCkoKBEHGHsv6" target="_blank" className="in-view:animate-jump-in border-white/70 border-[0.1vw] py-[1%] px-[8%] rounded-[0.7vw] hover:text-ieee-yellow hover:border-ieee-yellow duration-300 text-[1.2vw]">
DISCORD
</Link>
</div>
<div
class="md:pt-[5vw] pt-[10vw] text-white w-full flex justify-center md:mb-[8vw] mb-[15vw]"
>
<div class="w-3/4 md:h-[25vw] h-[35vw] flex justify-between flex-col">
<div class="flex items-center md:text-[3vw] text-[4.5vw] pl-[5%] pt-[5%]">
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]" />
<p>Contact Us</p>
</div>
<p class="md:text-[1.25vw] text-[2vw]">
The <a
class="text-ieee-yellow underline"
href="https://maps.app.goo.gl/y4RwNCkoKBEHGHsv6"
target="_blank">IEEE Project Space</a
> is an open-access, collaborative space located at EBU1-4710. Students can
do homework or get access to basic electronic tools such as soldering stations,
breadboard components, and Arduino and Raspberry PI parts!
</p>
<div class="flex justify-end">
<Link
data-inview
href="https://maps.app.goo.gl/y4RwNCkoKBEHGHsv6"
target="_blank"
className="in-view:animate-jump-in border-white/70 border-[0.1vw] py-[1%] px-[8%] rounded-[0.7vw] hover:text-ieee-yellow hover:border-ieee-yellow duration-300 md:text-[1.2vw] text-[2vw]"
>
DISCORD
</Link>
</div>
</div>
</div>

View file

@ -0,0 +1,20 @@
---
---
<div
data-inview
class="flex flex-col items-center md:w-[40vw] w-[100vw] h-[100vw] md:h-[40vw] my-[10%] in-view:animate-fade-down"
>
<p class="text-ieee-yellow md:text-[1.2vw] text-[2.5vw]">Each officer has their own OAH</p>
<p class="text-white md:text-[2.5vw] text-[4.5vw] my-[2%]">Check out our calendar!</p>
<iframe
class="w-[90%] rounded-[1.5vw]"
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3350.627565860723!2d-117.23806952372503!3d32.881572078634505!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x80dc06c3689b4f99%3A0xdf55f97f07f34d4f!2sIrwin%20%26%20Joan%20Jacobs%20School%20of%20Engineering!5e0!3m2!1sen!2sus!4v1736755644414!5m2!1sen!2sus"
width="600"
height="450"
style="border:0;"
allowfullscreen=""
loading="lazy"
referrerpolicy="no-referrer-when-downgrade"></iframe>
</div>

View file

@ -1,8 +1,9 @@
---
import OH from "./OH.astro"
import OAH from "./OAH.astro";
import BuildingLocation from "./BuildingLocation.astro";
---
<div class="w-full flex justify-evenly px-[10%]">
<OH title="Check out our calendar!" subtitle="Each officer has their own OAH" image="/calendar.png" />
<OH title="Check out our location!" subtitle="We are located in EBU1-4710" image="/map.png" />
<div class="w-full flex flex-col md:flex-row items-center md:justify-evenly px-[10%]">
<OAH />
<BuildingLocation />
</div>

View file

@ -6,16 +6,16 @@ import { IoMdCalendar } from "react-icons/io";
import { RiRobot2Fill } from "react-icons/ri";
const {image, text, link, delay} = Astro.props;
---
<div data-inview class={`w-[15vw] relative group in-view:animate-fade-up animate-delay-${delay} animate-duration-1000`}>
<div data-inview class={` animate-ease-in-out md:w-[15vw] w-[24vw] relative group in-view:animate-fade-up animate-delay-${delay} animate-duration-1000`}>
<img src={image} alt="involvement background" class="opacity-70 aspect-[230/425] object-cover rounded-[2vw] group-hover:opacity-50 duration-300"/>
<Link
href={link}
target={text==="H.A.R.D. HACK"? "_blank":"_self"}
className="absolute top-0 w-[15vw] pt-[5%] aspect-[230/425] flex flex-col justify-between"
className="absolute top-0 md:w-[15vw] w-[25vw] pt-[5%] aspect-[230/425] flex flex-col justify-between"
>
<div class="w-full flex justify-end pr-[5%]">
<div class="bg-white w-fit rounded-full aspect-square p-[0.5vw] text-ieee-black text-[2vw]">
<div class="w-full flex justify-end md:pr-[5%] pr-[2vw]">
<div class="bg-white w-fit rounded-full aspect-square p-[0.5vw] text-ieee-black text-[4.5vw] md:text-[2vw]">
{
text === "PROJECTS"? <RiRobot2Fill/>:
text === "EVENTS"? <IoMdCalendar/>:
@ -24,16 +24,16 @@ const {image, text, link, delay} = Astro.props;
</div>
</div>
<div class="px-[3%] text-white w-full bg-gradient-to-t from-black via-black to-transparent rounded-b-[2vw] pt-[30%] pb-[5%]">
<div class="text-[1.1vw] duration-300 flex w-full px-[3%] justify-between items-end">
<div class="px-[3%] text-white w-full bg-gradient-to-t from-black via-black to-transparent rounded-b-[2vw] pt-[20vw] pb-[3vw] md:pt-[30%] md:pb-[5%]">
<div class="text-[2vw] md:text-[1.1vw] duration-300 flex w-full px-[3%] justify-between items-end">
<p class="pt-[3%] pb-[2%] px-[10%] border-[0.1vw] border-white rounded-full group-hover:text-ieee-yellow group-hover:border-ieee-yellow duration-300 font-light">
{text}
</p>
<GoArrowDownRight className="text-[3vw] leading-none group-hover:text-ieee-yellow"/>
<GoArrowDownRight className="text-[5vw] md:text-[3vw] leading-none group-hover:text-ieee-yellow"/>
</div>
{text === "H.A.R.D. HACK" &&
<p class="text-[1vw] text-center pt-[10%] group-hover:text-ieee-yellow duration-300">
<p class="text-[1.8vw] md:text-[1vw] text-center pt-[10%] group-hover:text-ieee-yellow duration-300">
UC San Diegos largest
hardware focused hackathon
hold by IEEE UCSD, HKN, and TNT

View file

@ -2,8 +2,8 @@
import Involvement from "./Involvement.astro";
import involve from "../../data/involve.json";
---
<div class="pl-[10%] pr-[6%] flex items-center mb-[10%]">
<div class="flex w-3/5 justify-between">
<div class="pl-[10%] pr-[6%] flex md:items-center md:mb-[10%] mb-[30vw] mt-[20vw] md:mt-0 flex-col-reverse md:flex-row">
<div class="flex md:w-3/5 w-[95%] justify-between">
{involve.map((item)=>(
<Involvement
text = {item.text}
@ -14,11 +14,11 @@ import involve from "../../data/involve.json";
))}
</div>
<div class="w-2/5 flex flex-col px-[5%]">
<p class="text-ieee-yellow text-[1.2vw] mb-[5%]">
Get involve in international IEEE
<div class="md:w-2/5 w-4/5 flex flex-col px-[5%] pb-[10vw] md:pb-0">
<p class="text-ieee-yellow md:text-[1.2vw] text-[2.5vw] mb-[5%]">
Get involve in IEEE @ UCSD
</p>
<p class="text-white text-[2vw] font-bold">
<p class="text-white md:text-[2vw] text-[3vw] font-bold">
How To Keep Up With And Get Engaged With IEEE at UCSD
</p>
</div>

View file

@ -3,22 +3,35 @@ import Link from "next/link";
import { LiaDotCircle } from "react-icons/lia";
---
<div class="pt-[14vh] text-white w-full flex justify-center mb-[20vh]">
<div class="w-3/4 h-[40vh] flex justify-between flex-col">
<div data-inview class="flex items-center text-[3vw] pl-[5%] pt-[5%] in-view:animate-fade-right">
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]"/>
<p>
Join Us
</p>
</div>
<p class="text-[1.25vw]">
The <a class=" text-ieee-yellow underline" href="https://maps.app.goo.gl/y4RwNCkoKBEHGHsv6" target="_blank">IEEE Project Space</a> is an open-access, collaborative space located at EBU1-4710. Students can do homework or get access to basic electronic tools such as soldering stations, breadboard components, and Arduino and Raspberry PI parts!
</p>
<div data-inview class="flex justify-end in-view:animate-fade-up">
<Link href="https://maps.app.goo.gl/y4RwNCkoKBEHGHsv6" target="_blank" className="text-[1.2vw] border-white/70 border-[0.1vw] py-[1%] px-[8%] rounded-[0.7vw] hover:text-ieee-yellow hover:border-ieee-yellow duration-300">
JOIN
</Link>
</div>
<div class="text-white w-full flex justify-center mb-[10vw]">
<div class="w-3/4 md:h-[20vw] h-[40vw] flex justify-between flex-col">
<div
data-inview
class="animate-ease-in-out flex items-center text-[6vw] md:text-[3vw] pl-[5%] pt-[5%] in-view:animate-fade-right"
>
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]" />
<p>Join Us</p>
</div>
<p class="text-[2.2vw] md:text-[1.25vw]">
The <a
class="text-ieee-yellow underline"
href="https://maps.app.goo.gl/y4RwNCkoKBEHGHsv6"
target="_blank">IEEE Project Space</a
> is an open-access, collaborative space located at EBU1-4710. Students can
do homework or get access to basic electronic tools such as soldering stations,
breadboard components, and Arduino and Raspberry PI parts!
</p>
<div
data-inview
class="animate-ease-in-out flex justify-end in-view:animate-fade-up"
>
<Link
href="https://maps.app.goo.gl/y4RwNCkoKBEHGHsv6"
target="_blank"
className="text-[2.5vw] md:text-[1.2vw] border-white/70 border-[0.1vw] py-[1%] px-[8%] rounded-[0.7vw] hover:text-ieee-yellow hover:border-ieee-yellow duration-300"
>
JOIN
</Link>
</div>
</div>
</div>

View file

@ -0,0 +1,19 @@
---
---
<div
data-inview
class="flex flex-col items-center md:w-[40vw] w-[100vw] h-[100vw] md:h-[40vw] my-[10%] in-view:animate-fade-down"
>
<p class="text-ieee-yellow md:text-[1.2vw] text-[2.5vw]">Each officer has their own OAH</p>
<p class="text-white md:text-[2.5vw] text-[4.5vw] my-[2%]">Check out our calendar!</p>
<iframe
class="w-[90%] rounded-[1.5vw]"
src="https://calendar.google.com/calendar/embed?src=c_62493071bab19c7c60d103460604dc7b3b569ffc1e58a42617978f626dff02ac%40group.calendar.google.com&ctz=America%2FLos_Angeles"
style="border: 0"
width="600"
height="450"
frameborder="0"
scrolling="no"></iframe>
</div>

View file

@ -1,13 +0,0 @@
---
const {title, subtitle, image} = Astro.props;
---
<div data-inview class="flex flex-col items-center w-[40vw] my-[10%] in-view:animate-fade-down">
<p class="text-ieee-yellow text-[1.2vw]">
{subtitle}
</p>
<p class="text-white text-[2.5vw] my-[2%]">
{title}
</p>
<img src={image} alt="Office hours" class="object-cover aspect-[620/408] w-[90%] rounded-[2vw]" />
</div>

View file

@ -2,19 +2,19 @@ import Link from "next/link";
const Resource = ({icon, title, text, link}) => {
return (
<div class="text-white flex w-[30vw] items-center">
<div class = "mr-[1vw] bg-gradient-radial from-ieee-blue-300 via-ieee-black to-ieee-black rounded-full text-[6.5vw] aspect-square w-[12vw] flex justify-center items-center">
<div class="text-white flex md:w-[30vw] w-[40vw] items-center">
<div class = "mr-[1vw] bg-gradient-radial from-ieee-blue-300 via-ieee-black to-ieee-black rounded-full text-[8vw] md:text-[6.5vw] aspect-square w-[12vw] flex justify-center items-center">
{icon}
</div>
<div class="w-[24vw]">
<p class = "text-[1.8vw] mb-[2vh] font-extralight">
<div class="md:w-[24vw] w-[27vw] ">
<p class = "md:text-[1.8vw] text-[2.5vw] mb-[2vh] font-extralight">
{title}
</p>
<p class = "text-[1vw] mb-[1vh] font-light">
<p class = "md:text-[1vw] text-[1.8vw] mb-[1vh] font-light">
{text}
</p>
<div class="flex justify-end mt-[5%]">
<Link href={link} target="_blank" className=" text-[1.1vw] font-extralight border-white/70 border-[0.1vw] py-[1%] px-[11%] rounded-[0.5vw] cursor-pointer hover:text-ieee-yellow hover:border-ieee-yellow duration-300">
<Link href={link} target="_blank" className=" md:text-[1.1vw] text-[2vw] font-extralight border-white/70 border-[0.1vw] py-[1%] px-[11%] rounded-[0.5vw] cursor-pointer hover:text-ieee-yellow hover:border-ieee-yellow duration-300">
VIEW
</Link>
</div>

View file

@ -1,29 +1,29 @@
import Resource from "./Resource.jsx"
import { LiaDotCircle } from "react-icons/lia";
import { RiSlideshowLine } from "react-icons/ri";
import { BiMoviePlay } from "react-icons/bi";
import { IoMdGlobe } from "react-icons/io";
const Resources = () => {
return (
<div class = "text-white w-full flex flex-col items-center h-[55vh] justify-center">
<div class = "text-[2.5vw] flex items-center">
<div class = "text-white w-full flex flex-col items-center justify-center mb-[20vw] md:mb-[5vw]">
<div class = "text-[4.5vw] md:text-[2.5vw] flex items-center">
<LiaDotCircle className = "mr-[1vw] pt-[0.5%]" />
<p>
Member Resources
</p>
</div>
<div class = " w-[90%] flex justify-evenly mt-[9vh]">
<div class = "md:w-[90%] w-full flex justify-evenly mt-[5vw]">
<Resource
icon = <RiSlideshowLine/>
title = "Workshop Slides"
text = "Hac at maecenas maximus faucibus venenatis blandit. Netus elit fusce a tortor"
text = "Find our database of workshop slides here."
link = "http://www.google.com"
/>
<Resource
icon = <BiMoviePlay/>
title = "Workshop Videos"
text = "Hac at maecenas maximus faucibus venenatis blandit. Netus elit fusce a tortor"
link = "http://www.google.com"
icon = <IoMdGlobe/>
title = "International IEEE"
text = "Our parent organization provides variety of events including project sponsorship, IEEE DataPort dataset database, and renowned student contests."
link = "https://www.ieee.org/"
/>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show more