Merge branch 'main' into andy/reduce-flicker
BIN
bun.lockb
4
nixpacks.toml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[phases.setup]
|
||||||
|
nixPkgs = ["nodejs_18", "bun"]
|
||||||
|
aptPkgs = ["curl", "wget"]
|
||||||
|
|
BIN
public/404.png
Before Width: | Height: | Size: 2 MiB |
BIN
public/404.webp
Normal file
After Width: | Height: | Size: 431 KiB |
Before Width: | Height: | Size: 112 KiB |
BIN
public/calendar.webp
Normal file
After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 203 KiB |
BIN
public/halloween.webp
Normal file
After Width: | Height: | Size: 186 KiB |
Before Width: | Height: | Size: 308 KiB |
BIN
public/hardhack.webp
Normal file
After Width: | Height: | Size: 183 KiB |
BIN
public/map.png
Before Width: | Height: | Size: 74 KiB |
BIN
public/map.webp
Normal file
After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 1.3 MiB |
BIN
public/officers/akhil.webp
Normal file
After Width: | Height: | Size: 1,020 KiB |
Before Width: | Height: | Size: 1.1 MiB |
BIN
public/officers/allie.webp
Normal file
After Width: | Height: | Size: 987 KiB |
Before Width: | Height: | Size: 949 KiB |
BIN
public/officers/andy.webp
Normal file
After Width: | Height: | Size: 741 KiB |
Before Width: | Height: | Size: 1.4 MiB |
BIN
public/officers/anika.webp
Normal file
After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 1.5 MiB |
BIN
public/officers/anu.webp
Normal file
After Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 1.4 MiB |
BIN
public/officers/ashlee.webp
Normal file
After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 699 KiB |
BIN
public/officers/charles.webp
Normal file
After Width: | Height: | Size: 540 KiB |
Before Width: | Height: | Size: 1.5 MiB |
BIN
public/officers/christine.webp
Normal file
After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 1.8 MiB |
BIN
public/officers/dhruv.webp
Normal file
After Width: | Height: | Size: 1.6 MiB |
Before Width: | Height: | Size: 1.4 MiB |
BIN
public/officers/dihan.webp
Normal file
After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 1.2 MiB |
BIN
public/officers/emma.webp
Normal file
After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 1.3 MiB |
BIN
public/officers/erik.webp
Normal file
After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 1.2 MiB |
BIN
public/officers/jonathan.webp
Normal file
After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 1.3 MiB |
BIN
public/officers/lauren.webp
Normal file
After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 1.5 MiB |
BIN
public/officers/lisa.webp
Normal file
After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 1.5 MiB |
BIN
public/officers/philip.webp
Normal file
After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 1.2 MiB |
BIN
public/officers/pranav.webp
Normal file
After Width: | Height: | Size: 943 KiB |
Before Width: | Height: | Size: 1.1 MiB |
BIN
public/officers/rafaella.webp
Normal file
After Width: | Height: | Size: 987 KiB |
Before Width: | Height: | Size: 1.7 MiB |
BIN
public/officers/raymond.webp
Normal file
After Width: | Height: | Size: 1.5 MiB |
Before Width: | Height: | Size: 1 MiB |
BIN
public/officers/ridhi.webp
Normal file
After Width: | Height: | Size: 973 KiB |
Before Width: | Height: | Size: 2.1 MiB |
BIN
public/officers/rohil.webp
Normal file
After Width: | Height: | Size: 2.1 MiB |
Before Width: | Height: | Size: 1.4 MiB |
BIN
public/officers/shing.webp
Normal file
After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 1.4 MiB |
BIN
public/officers/shipra.webp
Normal file
After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 235 KiB |
BIN
public/officers/stella.webp
Normal file
After Width: | Height: | Size: 209 KiB |
Before Width: | Height: | Size: 82 KiB |
BIN
public/officers/steph.webp
Normal file
After Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 1.7 MiB |
BIN
public/officers/terri.webp
Normal file
After Width: | Height: | Size: 1.5 MiB |
Before Width: | Height: | Size: 205 KiB |
BIN
public/officers/zarif.webp
Normal file
After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 1.5 MiB |
BIN
public/project.webp
Normal file
After Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 4.2 MiB |
BIN
public/robocup.webp
Normal file
After Width: | Height: | Size: 122 KiB |
Before Width: | Height: | Size: 216 KiB |
BIN
public/signal.webp
Normal file
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 60 KiB |
BIN
public/supercomp.webp
Normal file
After Width: | Height: | Size: 42 KiB |
|
@ -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>
|
||||||
|
|
|
@ -2,32 +2,55 @@
|
||||||
import { FaGear } from "react-icons/fa6";
|
import { FaGear } from "react-icons/fa6";
|
||||||
import { MdEmail } from "react-icons/md";
|
import { MdEmail } from "react-icons/md";
|
||||||
import Link from "next/link";
|
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">
|
<div class="text-white">
|
||||||
<Link href="s1hung@ucsd.edu" className = "flex items-center ml-[3%] py-[0.5vh]">
|
<div class="text-ieee-yellow">
|
||||||
<MdEmail className = "text-[1.5vw] mr-[0.5%]"/>
|
<Link
|
||||||
<p class = "text-[0.8vw]">
|
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}
|
{email}
|
||||||
</p>
|
</p>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</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">
|
<div
|
||||||
<img src ={picture} alt = "officer" class = "w-[18vw] rounded-[10%] pt-[5%] pb-[3%] relative" >
|
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"
|
||||||
<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/>
|
<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>
|
||||||
<div class = "w-full flex justify-between px-[7%]">
|
<div
|
||||||
<p data-inview class = "opacity-0 in-view:animate-fade-right text-[2vw] font-light leading-[4.5vh]">
|
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}
|
{name}
|
||||||
</p>
|
</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}
|
{position}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
|
||||||
|
|
|
@ -1,43 +1,64 @@
|
||||||
---
|
---
|
||||||
import about from "../../images/about.png";
|
import about from "../../images/about.webp";
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
import neko from "../../images/neko.png";
|
import neko from "../../images/neko.webp";
|
||||||
import { LiaDotCircle } from "react-icons/lia";
|
import { LiaDotCircle } from "react-icons/lia";
|
||||||
import Officer from "../board/Officer.astro";
|
import Officer from "../board/Officer.astro";
|
||||||
|
import Filter from "../board/Filter.astro";
|
||||||
import officers from "../../data/officers.json";
|
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
|
||||||
<div data-inview class="relative w-[21vw] in-view:animate-fade-down">
|
class="text-white flex flex-col items-center md:mt-[5vw] mt-[10vw] mb-[10vh]"
|
||||||
<Image src={about} alt="About background image" />
|
>
|
||||||
<Image
|
<div
|
||||||
src={neko}
|
data-inview
|
||||||
alt="About image"
|
class="relative w-[40vw] md:w-[21vw] mb-[10vh] in-view:animate-fade-down"
|
||||||
class="absolute top-[10%] left-[16%] aspect-[399/491] object-cover w-[14vw] rounded-[2vw]"
|
>
|
||||||
/>
|
<Image src={about} alt="About background image" />
|
||||||
</div>
|
<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]">
|
<div class="text-[5vw] md:text-[2.5vw] flex items-center mt-[1vw]">
|
||||||
<LiaDotCircle className="mr-[1vw] pt-[0.5%]" />
|
<LiaDotCircle className="mr-[1vw] pt-[0.5%]" />
|
||||||
<p>MEET THE BOARD</p>
|
<p>MEET THE BOARD</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-[1.3vw] w-[56%] my-[3%] font-extralight text-center">
|
<p
|
||||||
Erat hendrerit tristique erat; parturient cursus fringilla feugiat. Eget
|
class="md:text-[1.3vw] text-[2.5vw] md:w-[56%] w-[70%] my-[3%] font-extralight text-center"
|
||||||
faucibus fames ridiculus nec egestas convallis cubilia malesuada. Tellus
|
>
|
||||||
nibh vivamus tempus molestie tristique quis
|
Our board comprises 31 students of varying majors, colleges, and interests!
|
||||||
</p>
|
Feel free to reach out for any questions about our position or experiences.
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="grid gap-[3vw] grid-cols-3 mt-[10vh]">
|
<Filter filters={types} currentFilter={currentFilter} />
|
||||||
{
|
|
||||||
officers.map((officer) => (
|
<div class="grid gap-[3vw] md:grid-cols-3 grid-cols-2 mt-[2vh]">
|
||||||
<Officer
|
{
|
||||||
name={officer.name}
|
officers.map((officer) => (
|
||||||
position={officer.position}
|
<div
|
||||||
picture={officer.picture}
|
data-officer
|
||||||
email={officer.email}
|
data-types={JSON.stringify(officer.type)}
|
||||||
/>
|
style="opacity: 0; visibility: hidden"
|
||||||
))
|
>
|
||||||
}
|
<Officer
|
||||||
</div>
|
name={officer.name}
|
||||||
|
position={officer.position}
|
||||||
|
picture={officer.picture}
|
||||||
|
email={officer.email}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,14 +4,14 @@ const {title, text} = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="flex flex-col items-center text-white my-[10%]">
|
<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%]"/>
|
<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">
|
<p class="text-transparent bg-clip-text bg-gradient-to-b from-white via-white to-ieee-black">
|
||||||
{title}
|
{title}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="w-[70%] text-[1.4vw] font-light ">
|
<p class="w-[70%] md:text-[1.4vw] text-[2vw] font-light ">
|
||||||
{text}
|
{text}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
|
@ -5,22 +5,22 @@ import whiteLogoHorizontal from "../../images/logos/white_logo_horizontal.svg";
|
||||||
import { IoHeart } from "react-icons/io5";
|
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
|
<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">
|
<Link href="/" className="hover:opacity-70 duration-300">
|
||||||
<Image
|
<Image
|
||||||
class="w-[15vw]"
|
class="md:w-[15vw] w-[35vw]"
|
||||||
src={whiteLogoHorizontal}
|
src={whiteLogoHorizontal}
|
||||||
alt="IEEE UCSD Logo"
|
alt="IEEE UCSD Logo"
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<div class="flex items-center">
|
<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
|
made by IEEE UCSD webmasters with
|
||||||
</p>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,146 +4,151 @@ import whiteLogoHorizontal from "../../images/logos/white_logo_horizontal.svg";
|
||||||
import pages from "../../data/pages.json";
|
import pages from "../../data/pages.json";
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="md:w-full w-fit fixed z-10">
|
<div class="w-full">
|
||||||
<div
|
<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]"
|
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 hidden md:flex">
|
<a href="/" class="hover:opacity-60 duration-300">
|
||||||
<Image
|
<Image
|
||||||
class="w-[15vw]"
|
class="w-[15vw] md:block hidden"
|
||||||
src={whiteLogoHorizontal}
|
src={whiteLogoHorizontal}
|
||||||
alt="IEEE UCSD Logo"
|
alt="IEEE UCSD Logo"
|
||||||
/>
|
/>
|
||||||
</a>
|
<Image
|
||||||
|
class="w-[40vw] md:hidden block"
|
||||||
|
src={whiteLogoHorizontal}
|
||||||
|
alt="IEEE UCSD Logo"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
|
||||||
<!-- Desktop Navigation -->
|
<!-- Desktop Navigation -->
|
||||||
<div class="hidden md:flex md:w-[55%] md:justify-between">
|
<div class="hidden md:flex md:w-[55%] md:justify-between">
|
||||||
{
|
{
|
||||||
pages.map((page) => (
|
pages.map((page) => (
|
||||||
<a
|
<a
|
||||||
href={page.path}
|
href={page.path}
|
||||||
class={`uppercase rounded-full duration-300 px-[1.5vw] py-[0.2vw] text-[1.2vw] text-nowrap
|
class={`uppercase rounded-full duration-300 px-[1.5vw] py-[0.2vw] text-[1.2vw] text-nowrap
|
||||||
${
|
${
|
||||||
page.name === "Online Store"
|
page.name === "Online Store"
|
||||||
? "bg-ieee-yellow text-black hover:opacity-70"
|
? "bg-ieee-yellow text-black hover:opacity-70"
|
||||||
: "text-white border-white hover:opacity-50 border-[0.1vw] font-light"
|
: "text-white border-white hover:opacity-50 border-[0.1vw] font-light"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{page.name}
|
{page.name}
|
||||||
</a>
|
</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>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Mobile Menu -->
|
<!-- Mobile Hamburger/Close Button -->
|
||||||
<div
|
<button
|
||||||
id="mobile-menu"
|
id="menu-btn"
|
||||||
class="fixed inset-0 z-[51] hidden xl:hidden motion-safe:transition-transform motion-safe:duration-300 translate-x-full"
|
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
|
<!-- Hamburger Icon -->
|
||||||
class="flex flex-col items-center h-[70vh] justify-evenly bg-black"
|
<svg
|
||||||
>
|
class="w-6 h-6 menu-icon"
|
||||||
{
|
fill="none"
|
||||||
pages.map((page) => (
|
stroke="currentColor"
|
||||||
<a
|
viewBox="0 0 24 24"
|
||||||
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
|
<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"
|
page.name === "Online Store"
|
||||||
? "bg-[#f3c135] text-black border-[#f3c135] hover:bg-[#dba923] hover:border-[#dba923]"
|
? "bg-[#f3c135] text-black border-[#f3c135] hover:bg-[#dba923] hover:border-[#dba923]"
|
||||||
: "text-white hover:text-gray-300 border-white"
|
: "text-white hover:text-gray-300 border-white border-2"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{page.name}
|
{page.name}
|
||||||
</a>
|
</a>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#mobile-menu.show {
|
#mobile-menu.show {
|
||||||
@apply translate-x-0;
|
@apply translate-x-0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const menuBtn = document.getElementById("menu-btn");
|
const menuBtn = document.getElementById("menu-btn");
|
||||||
const mobileMenu = document.getElementById("mobile-menu");
|
const mobileMenu = document.getElementById("mobile-menu");
|
||||||
const menuIcon = document.querySelector(".menu-icon");
|
const menuIcon = document.querySelector(".menu-icon");
|
||||||
const closeIcon = document.querySelector(".close-icon");
|
const closeIcon = document.querySelector(".close-icon");
|
||||||
|
|
||||||
function toggleMenu(show: boolean) {
|
function toggleMenu(show: boolean) {
|
||||||
if (show) {
|
if (show) {
|
||||||
mobileMenu?.classList.remove("hidden");
|
mobileMenu?.classList.remove("hidden");
|
||||||
menuIcon?.classList.add("hidden");
|
menuIcon?.classList.add("hidden");
|
||||||
closeIcon?.classList.remove("hidden");
|
closeIcon?.classList.remove("hidden");
|
||||||
document.body.style.overflow = "hidden";
|
document.body.style.overflow = "hidden";
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
mobileMenu?.classList.add("show");
|
mobileMenu?.classList.add("show");
|
||||||
}, 10);
|
}, 10);
|
||||||
} else {
|
} else {
|
||||||
mobileMenu?.classList.remove("show");
|
mobileMenu?.classList.remove("show");
|
||||||
menuIcon?.classList.remove("hidden");
|
menuIcon?.classList.remove("hidden");
|
||||||
closeIcon?.classList.add("hidden");
|
closeIcon?.classList.add("hidden");
|
||||||
document.body.style.overflow = "";
|
document.body.style.overflow = "";
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
mobileMenu?.classList.add("hidden");
|
mobileMenu?.classList.add("hidden");
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
menuBtn?.addEventListener("click", () => {
|
menuBtn?.addEventListener("click", () => {
|
||||||
const isMenuHidden = mobileMenu?.classList.contains("hidden") ?? true;
|
const isMenuHidden = mobileMenu?.classList.contains("hidden") ?? true;
|
||||||
toggleMenu(isMenuHidden);
|
toggleMenu(isMenuHidden);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close menu when clicking outside
|
// Close menu when clicking outside
|
||||||
document.addEventListener("click", (e) => {
|
document.addEventListener("click", (e) => {
|
||||||
if (
|
if (
|
||||||
!mobileMenu?.contains(e.target as Node) &&
|
!mobileMenu?.contains(e.target as Node) &&
|
||||||
!menuBtn?.contains(e.target as Node) &&
|
!menuBtn?.contains(e.target as Node) &&
|
||||||
!mobileMenu?.classList.contains("hidden")
|
!mobileMenu?.classList.contains("hidden")
|
||||||
) {
|
) {
|
||||||
toggleMenu(false);
|
toggleMenu(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
---
|
---
|
||||||
const {question, answer} = Astro.props;
|
const {question, answer} = Astro.props;
|
||||||
---
|
---
|
||||||
<div class = "text-white w-full flex flex-col mb-[2vh]">
|
<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-[1.4vw] mb-[2vh] font-semibold pl-[1vw]">
|
<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}
|
{question}
|
||||||
</p>
|
</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}
|
{answer}
|
||||||
</p>
|
</p>
|
||||||
<dev>
|
<dev>
|
||||||
|
|
|
@ -4,8 +4,8 @@ import { LiaDotCircle } from "react-icons/lia";
|
||||||
const {faq} = Astro.props;
|
const {faq} = Astro.props;
|
||||||
|
|
||||||
---
|
---
|
||||||
<div class = "text-white w-full h-[90vh] ml-[15vw] mb-[20%] mt-[10%]">
|
<div class = "text-white md:ml-[15vw] ml-[10vw] mb-[20%] mt-[10%]">
|
||||||
<div class = "text-[2.5vw] flex items-center my-[7vh]">
|
<div class = "text-[4.5vw] md:text-[2.5vw] flex items-center my-[7vh]">
|
||||||
<LiaDotCircle className = "mr-[1vw]" />
|
<LiaDotCircle className = "mr-[1vw]" />
|
||||||
<p>
|
<p>
|
||||||
Frequently Asked Questions
|
Frequently Asked Questions
|
||||||
|
|
|
@ -1,71 +1,79 @@
|
||||||
---
|
---
|
||||||
import { LiaDotCircle } from "react-icons/lia";
|
import { LiaDotCircle } from "react-icons/lia";
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
import evan from "../../images/evan.png";
|
import jellyfish from "../../images/jellyfish.webp";
|
||||||
import { FaDiscord, FaFacebook } from "react-icons/fa";
|
import { FaDiscord } from "react-icons/fa";
|
||||||
import { RiInstagramFill } from "react-icons/ri";
|
import { RiInstagramFill } from "react-icons/ri";
|
||||||
|
import { MdEmail } from "react-icons/md";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="text-white flex flex-col items-center h-[65vh] justify-between">
|
<div
|
||||||
<div class="flex items-center text-[2.5vw]">
|
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%]" />
|
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]" />
|
||||||
<p>Social Media</p>
|
<p>Social Media</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="w-1/3 text-center text-[1.2vw] pb-[5%]">
|
<p class="md:w-1/3 w-3/5 text-center text-[2vw] md:text-[1.2vw] pb-[5%]">
|
||||||
Lorem ipsum is placeholder text commonly used in the graphic, print, and
|
Stay connected with us on Discord, Facebook, and Instagram! We regularly
|
||||||
publishing industries f
|
post information on upcoming events and competitions.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div
|
<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">
|
<div
|
||||||
<Link
|
data-inview
|
||||||
href="https://discord.gg/XxfjqZSjca"
|
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"
|
||||||
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>
|
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href="https://www.instagram.com/ieee.ucsd"
|
href="https://www.instagram.com/ieee.ucsd"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="flex flex-col items-center"
|
className="flex flex-col items-center"
|
||||||
>
|
>
|
||||||
<div
|
<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 />
|
<RiInstagramFill />
|
||||||
</div>
|
</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>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<Image
|
<Image
|
||||||
data-inview
|
data-inview
|
||||||
src={evan}
|
src={jellyfish}
|
||||||
alt="cat placeholder"
|
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>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@ const {title} = Astro.props;
|
||||||
import { LiaDotCircle } from "react-icons/lia";
|
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%]"/>
|
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]"/>
|
||||||
<p>
|
<p>
|
||||||
{title}
|
{title}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
---
|
---
|
||||||
const {title} = Astro.props;
|
const { title } = Astro.props;
|
||||||
import { LiaDotCircle } from "react-icons/lia";
|
import { LiaDotCircle } from "react-icons/lia";
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="flex items-center text-[3vw] ml-[10%] pt-[10%] text-white font-semibold">
|
<div
|
||||||
<LiaDotCircle className=" mr-[1vw] text-[2.7vw]"/>
|
class="flex items-center md:text-[3vw] text-[4.5vw] ml-[10%] md:pt-[5%] pt-[10%] text-white font-semibold"
|
||||||
<p>
|
>
|
||||||
{title}
|
<LiaDotCircle className=" mr-[1vw] text-[2.7vw]" />
|
||||||
</p>
|
<p>
|
||||||
</div>
|
{title}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
358
src/components/events/Calendar.jsx
Normal 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;
|
170
src/components/events/EventList.jsx
Normal 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;
|
|
@ -1,20 +1,19 @@
|
||||||
---
|
---
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
import eventbg from "../../images/eventbg.png";
|
import eventbg from "../../images/eventbg.webp";
|
||||||
import { LiaDotCircle } from "react-icons/lia";
|
import { LiaDotCircle } from "react-icons/lia";
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="w-full pt-[25vh] flex justify-center relative">
|
<div class="w-full md:pt-[5vw] pt-[10vw] flex justify-center relative">
|
||||||
<Image
|
<Image
|
||||||
src={eventbg}
|
src={eventbg}
|
||||||
alt="Event Page Background"
|
alt="Event Page Background"
|
||||||
class="w-[45%] rounded-[2vw] aspect-[2/1] object-cover relative in-view:animate-fade-down opacity-0"
|
class="md:w-[45%] w-[80%] rounded-[2vw] aspect-[2/1] object-cover"
|
||||||
data-inview
|
/>
|
||||||
/>
|
<div
|
||||||
<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]"
|
||||||
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%]" />
|
||||||
<LiaDotCircle className=" mr-[2vw] pt-[0.5%]" />
|
<p>EVENTS</p>
|
||||||
<p>EVENTS</p>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,45 +1,28 @@
|
||||||
---
|
---
|
||||||
import UpcomingEvent from "./UpcomingEvent.astro";
|
|
||||||
import { LiaDotCircle } from "react-icons/lia";
|
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="flex ml-[15%] md:my-[10%] my-[20%]">
|
||||||
<div class="w-[6vw] h-[0.3vw] bg-ieee-yellow rounded-full"/>
|
<div class="md:w-1/4 w-[30%] text-white pr-[5%] mr-[10%]">
|
||||||
<div class="flex items-center text-[2vw] font-bold my-[10%]">
|
<div class="w-[6vw] h-[0.3vw] bg-ieee-yellow rounded-full"></div>
|
||||||
<LiaDotCircle className=" mr-[1vw] text-[2.5vw]"/>
|
<div class="flex items-center md:text-[2vw] text-[4vw] font-bold my-[10%]">
|
||||||
<p>
|
<LiaDotCircle className=" mr-[1vw] text-[2.5vw]" />
|
||||||
Upcoming <br/> Events
|
<p>
|
||||||
</p>
|
Upcoming <br /> Events
|
||||||
</div>
|
|
||||||
<p class="text-[1.3vw] font-light">
|
|
||||||
SCROLL DOWN TO SEE THE UPCOMING EVENTS FOR IEEE!
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<p class="md:text-[1.3vw] text-[2vw] font-light">
|
||||||
<UpcomingEvent
|
SCROLL DOWN TO SEE THE UPCOMING EVENTS FOR IEEE!
|
||||||
name="Beach Social"
|
</p>
|
||||||
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>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<EventList
|
||||||
|
client:load
|
||||||
|
CALENDAR_API_KEY={CALENDAR_API_KEY}
|
||||||
|
EVENT_CALENDAR_ID={EVENT_CALENDAR_ID}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -3,22 +3,32 @@ import Link from "next/link";
|
||||||
import { LiaDotCircle } from "react-icons/lia";
|
import { LiaDotCircle } from "react-icons/lia";
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="pt-[14vh] text-white w-full flex justify-center mb-[10vh]">
|
<div
|
||||||
<div class="w-3/4 h-[40vh] flex justify-between flex-col">
|
class="md:pt-[5vw] pt-[10vw] text-white w-full flex justify-center md:mb-[8vw] mb-[15vw]"
|
||||||
<div class="flex items-center text-[3vw] pl-[5%] pt-[5%]">
|
>
|
||||||
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]"/>
|
<div class="w-3/4 md:h-[25vw] h-[35vw] flex justify-between flex-col">
|
||||||
<p>
|
<div class="flex items-center md:text-[3vw] text-[4.5vw] pl-[5%] pt-[5%]">
|
||||||
Contact Us
|
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]" />
|
||||||
</p>
|
<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>
|
</div>
|
||||||
</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>
|
||||||
|
|
20
src/components/join/BuildingLocation.astro
Normal 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>
|
|
@ -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%]">
|
<div class="w-full flex flex-col md:flex-row items-center md:justify-evenly px-[10%]">
|
||||||
<OH title="Check out our calendar!" subtitle="Each officer has their own OAH" image="/calendar.png" />
|
<OAH />
|
||||||
<OH title="Check out our location!" subtitle="We are located in EBU1-4710" image="/map.png" />
|
<BuildingLocation />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,16 +6,16 @@ import { IoMdCalendar } from "react-icons/io";
|
||||||
import { RiRobot2Fill } from "react-icons/ri";
|
import { RiRobot2Fill } from "react-icons/ri";
|
||||||
const {image, text, link, delay} = Astro.props;
|
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"/>
|
<img src={image} alt="involvement background" class="opacity-70 aspect-[230/425] object-cover rounded-[2vw] group-hover:opacity-50 duration-300"/>
|
||||||
<Link
|
<Link
|
||||||
href={link}
|
href={link}
|
||||||
target={text==="H.A.R.D. HACK"? "_blank":"_self"}
|
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="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-[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 === "PROJECTS"? <RiRobot2Fill/>:
|
||||||
text === "EVENTS"? <IoMdCalendar/>:
|
text === "EVENTS"? <IoMdCalendar/>:
|
||||||
|
@ -24,16 +24,16 @@ const {image, text, link, delay} = Astro.props;
|
||||||
</div>
|
</div>
|
||||||
</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="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-[1.1vw] duration-300 flex w-full px-[3%] justify-between items-end">
|
<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">
|
<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}
|
{text}
|
||||||
</p>
|
</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>
|
</div>
|
||||||
|
|
||||||
{text === "H.A.R.D. HACK" &&
|
{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 Diego’s largest
|
UC San Diego’s largest
|
||||||
hardware focused hackathon
|
hardware focused hackathon
|
||||||
hold by IEEE UCSD, HKN, and TNT
|
hold by IEEE UCSD, HKN, and TNT
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
import Involvement from "./Involvement.astro";
|
import Involvement from "./Involvement.astro";
|
||||||
import involve from "../../data/involve.json";
|
import involve from "../../data/involve.json";
|
||||||
---
|
---
|
||||||
<div class="pl-[10%] pr-[6%] flex items-center mb-[10%]">
|
<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 w-3/5 justify-between">
|
<div class="flex md:w-3/5 w-[95%] justify-between">
|
||||||
{involve.map((item)=>(
|
{involve.map((item)=>(
|
||||||
<Involvement
|
<Involvement
|
||||||
text = {item.text}
|
text = {item.text}
|
||||||
|
@ -14,11 +14,11 @@ import involve from "../../data/involve.json";
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-2/5 flex flex-col px-[5%]">
|
<div class="md:w-2/5 w-4/5 flex flex-col px-[5%] pb-[10vw] md:pb-0">
|
||||||
<p class="text-ieee-yellow text-[1.2vw] mb-[5%]">
|
<p class="text-ieee-yellow md:text-[1.2vw] text-[2.5vw] mb-[5%]">
|
||||||
Get involve in international IEEE
|
Get involve in IEEE @ UCSD
|
||||||
</p>
|
</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
|
How To Keep Up With And Get Engaged With IEEE at UCSD
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,22 +3,35 @@ import Link from "next/link";
|
||||||
import { LiaDotCircle } from "react-icons/lia";
|
import { LiaDotCircle } from "react-icons/lia";
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="pt-[14vh] text-white w-full flex justify-center mb-[20vh]">
|
<div class="text-white w-full flex justify-center mb-[10vw]">
|
||||||
<div class="w-3/4 h-[40vh] flex justify-between flex-col">
|
<div class="w-3/4 md:h-[20vw] h-[40vw] flex justify-between flex-col">
|
||||||
<div data-inview class="flex items-center text-[3vw] pl-[5%] pt-[5%] in-view:animate-fade-right">
|
<div
|
||||||
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]"/>
|
data-inview
|
||||||
<p>
|
class="animate-ease-in-out flex items-center text-[6vw] md:text-[3vw] pl-[5%] pt-[5%] in-view:animate-fade-right"
|
||||||
Join Us
|
>
|
||||||
</p>
|
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]" />
|
||||||
</div>
|
<p>Join Us</p>
|
||||||
<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>
|
</div>
|
||||||
</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>
|
||||||
|
|
19
src/components/join/OAH.astro
Normal 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>
|
|
@ -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>
|
|
|
@ -2,19 +2,19 @@ import Link from "next/link";
|
||||||
|
|
||||||
const Resource = ({icon, title, text, link}) => {
|
const Resource = ({icon, title, text, link}) => {
|
||||||
return (
|
return (
|
||||||
<div class="text-white flex w-[30vw] 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-[6.5vw] aspect-square w-[12vw] flex justify-center 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}
|
{icon}
|
||||||
</div>
|
</div>
|
||||||
<div class="w-[24vw]">
|
<div class="md:w-[24vw] w-[27vw] ">
|
||||||
<p class = "text-[1.8vw] mb-[2vh] font-extralight">
|
<p class = "md:text-[1.8vw] text-[2.5vw] mb-[2vh] font-extralight">
|
||||||
{title}
|
{title}
|
||||||
</p>
|
</p>
|
||||||
<p class = "text-[1vw] mb-[1vh] font-light">
|
<p class = "md:text-[1vw] text-[1.8vw] mb-[1vh] font-light">
|
||||||
{text}
|
{text}
|
||||||
</p>
|
</p>
|
||||||
<div class="flex justify-end mt-[5%]">
|
<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
|
VIEW
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
import Resource from "./Resource.jsx"
|
import Resource from "./Resource.jsx"
|
||||||
import { LiaDotCircle } from "react-icons/lia";
|
import { LiaDotCircle } from "react-icons/lia";
|
||||||
import { RiSlideshowLine } from "react-icons/ri";
|
import { RiSlideshowLine } from "react-icons/ri";
|
||||||
import { BiMoviePlay } from "react-icons/bi";
|
import { IoMdGlobe } from "react-icons/io";
|
||||||
|
|
||||||
const Resources = () => {
|
const Resources = () => {
|
||||||
return (
|
return (
|
||||||
<div class = "text-white w-full flex flex-col items-center h-[55vh] justify-center">
|
<div class = "text-white w-full flex flex-col items-center justify-center mb-[20vw] md:mb-[5vw]">
|
||||||
<div class = "text-[2.5vw] flex items-center">
|
<div class = "text-[4.5vw] md:text-[2.5vw] flex items-center">
|
||||||
<LiaDotCircle className = "mr-[1vw] pt-[0.5%]" />
|
<LiaDotCircle className = "mr-[1vw] pt-[0.5%]" />
|
||||||
<p>
|
<p>
|
||||||
Member Resources
|
Member Resources
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class = " w-[90%] flex justify-evenly mt-[9vh]">
|
<div class = "md:w-[90%] w-full flex justify-evenly mt-[5vw]">
|
||||||
<Resource
|
<Resource
|
||||||
icon = <RiSlideshowLine/>
|
icon = <RiSlideshowLine/>
|
||||||
title = "Workshop Slides"
|
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"
|
link = "http://www.google.com"
|
||||||
/>
|
/>
|
||||||
<Resource
|
<Resource
|
||||||
icon = <BiMoviePlay/>
|
icon = <IoMdGlobe/>
|
||||||
title = "Workshop Videos"
|
title = "International IEEE"
|
||||||
text = "Hac at maecenas maximus faucibus venenatis blandit. Netus elit fusce a tortor"
|
text = "Our parent organization provides variety of events including project sponsorship, IEEE DataPort dataset database, and renowned student contests."
|
||||||
link = "http://www.google.com"
|
link = "https://www.ieee.org/"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|