ios projects fix attempt 1

This commit is contained in:
chark1es 2025-03-08 14:29:35 -08:00
parent bcd933d87b
commit 6dc95b67f9
2 changed files with 194 additions and 149 deletions

View file

@ -3,29 +3,52 @@ import { LiaDotCircle } from "react-icons/lia";
import ProjectSection from "./ProjectSection.astro"; import ProjectSection from "./ProjectSection.astro";
--- ---
<div class="text-white md:mt-[15%] mt-[25%] mb-[30%] mx-[10%] relative"> <div class="text-white md:mt-[15%] mt-[25%] mb-[30%] mx-[10%] relative">
<div class="flex items-center md:text-[2.7vw] text-[4.5vw] mb-[7%]"> <div class="flex items-center md:text-[2.7vw] text-[4.5vw] mb-[7%]">
<LiaDotCircle className=" mr-[1vw] pt-[0.5%]"/> <LiaDotCircle className=" mr-[1vw] pt-[0.5%]" />
<p> <p>Annual Projects</p>
Annual Projects </div>
</p>
</div>
<p class="md:text-[1.2vw] text-[2vw] mt-[5%] mb-[3%] md:ml-[10%] ml-[5%] font-light"> <p
Join in the fray of internationally-recognized competition through Robocup, Signal Processing, Supercomputing, and Micromouse at IEEE @ UCSD! Participate in an intensive collaborative environment that challenges hard skills of hardware and software. class="md:text-[1.2vw] text-[2vw] mt-[5%] mb-[3%] md:ml-[10%] ml-[5%] font-light"
>
Join in the fray of internationally-recognized competition through Robocup,
Signal Processing, Supercomputing, and Micromouse at IEEE @ UCSD!
Participate in an intensive collaborative environment that challenges hard
skills of hardware and software.
</p>
<div
class="flex items-center md:text-[1.2vw] text-[2vw] font-light mb-[7%] justify-between md:ml-[10%]"
>
<LiaDotCircle className="md:text-[2vw] text-[3vw] pt-[0.5%]" />
<p class="md:text-[2vw] text-[3vw] mr-[2vw]">Skills & Requirements</p>
<p class="w-3/5">
IEEE @ UCSD's annual projects are intended for students with intermediate
experience with hardware or software. Participation on teams assemble an
array of skills and talents of soft and hard skills.
</p> </p>
</div>
<div class="flex items-center md:text-[1.2vw] text-[2vw] font-light mb-[7%] justify-between md:ml-[10%]"> <div class="project-section-container">
<LiaDotCircle className="md:text-[2vw] text-[3vw] pt-[0.5%]"/>
<p class="md:text-[2vw] text-[3vw] mr-[2vw]">
Skills & Requirements
</p>
<p class="w-3/5">
IEEE @ UCSDs annual projects are intended for students with intermediate experience with hardware or software. Participation on teams assemble an array of skills and talents of soft and hard skills.
</p>
</div>
<ProjectSection /> <ProjectSection />
</div>
</div> </div>
<style>
/* iOS-specific fixes */
@supports (-webkit-touch-callout: none) {
.project-section-container {
width: 100%;
overflow-x: hidden;
padding-bottom: 10vw;
}
}
@media screen and (max-width: 767px) {
.project-section-container {
width: 100%;
margin-left: -5%;
}
}
</style>

View file

@ -7,152 +7,174 @@ import { Image } from "astro:assets";
--- ---
<div <div
class="md:flex md:gap-[1.5vw] md:h-[30vw] md:w-auto w-[70vw] mt-[20%] md:mt-0 ml-[5%] md:ml-0" class="md:flex md:gap-[1.5vw] md:h-[30vw] md:w-auto w-[70vw] mt-[20%] md:mt-0 ml-[5%] md:ml-0"
> >
{ {
Object.entries(annualProjects).map(([title, project], index) => ( Object.entries(annualProjects).map(([title, project], index) => (
<a <a
href={project.url || "#"} href={project.url || "#"}
class={`project-card group relative flex-1 rounded-[1.5vw] overflow-hidden transition-all duration-500 ease-in-out md:hover:flex-[2] cursor-pointer ${index === 0 ? "expanded" : ""}`} class={`project-card group relative flex-1 rounded-[1.5vw] overflow-hidden transition-all duration-500 ease-in-out md:hover:flex-[2] cursor-pointer ${index === 0 ? "expanded" : ""}`}
data-project={index + 1} data-project={index + 1}
target={title === "Supercomputing" ? "_blank" : "_self"} target={title === "Supercomputing" ? "_blank" : "_self"}
> >
<div class="skeleton absolute inset-0 rounded-[1.5vw] z-0" /> <div class="skeleton absolute inset-0 rounded-[1.5vw] z-0" />
<Image <Image
src={project.image} src={project.image}
alt={`${title} Project`} alt={`${title} Project`}
width={668} width={668}
height={990} height={990}
class="opacity-70 w-full md:h-full h-[30vw] object-cover rounded-[1.5vw] aspect-[2/3] transition-transform duration-500 ease-in-out md:group-hover:scale-110 my-[2vw] md:my-0" class="opacity-70 w-full md:h-full h-[30vw] object-cover rounded-[1.5vw] aspect-[2/3] transition-transform duration-500 ease-in-out md:group-hover:scale-110 my-[2vw] md:my-0"
/> />
<div class="absolute flex items-end bottom-0 left-0 px-[5%] pb-[5%] md:pt-[17%] bg-gradient-to-b from-transparent to-black via-black rounded-b-[1.5vw] text-white z-10 w-full transition-transform duration-300 md:[.expanded_&]:pb-[5%]"> <div class="absolute flex items-end bottom-0 left-0 px-[5%] pb-[5%] md:pt-[17%] bg-gradient-to-b from-transparent to-black via-black rounded-b-[1.5vw] text-white z-10 w-full transition-transform duration-300 md:[.expanded_&]:pb-[5%]">
<div class="md:w-full w-[70vw]"> <div class="md:w-full w-[70vw]">
<p class="py-[1.5%] px-[8%] w-fit border-[0.1vw] border-white rounded-full text-nowrap md:text-[1.2vw] text-[2vw] font-light mb-[5%]"> <p class="py-[1.5%] px-[8%] w-fit border-[0.1vw] border-white rounded-full text-nowrap md:text-[1.2vw] text-[2vw] font-light mb-[5%]">
{title} {title}
</p> </p>
<p class="text-[2vw] md:text-[1.3vw] md:hidden md:[.expanded_&]:contents transition-all duration-300 overflow-hidden"> <p class="text-[2vw] md:text-[1.3vw] md:hidden md:[.expanded_&]:contents transition-all duration-300 overflow-hidden">
{project.description} {project.description}
</p> </p>
<div class="w-full flex justify-end md:invisible visible md:[.expanded_&]:visible h-0 md:[.expanded_&]:h-auto"> <div class="w-full flex justify-end md:invisible visible md:[.expanded_&]:visible h-0 md:[.expanded_&]:h-auto">
<div class="flex items-center md:text-[1.3vw] text-[2vw] md:[.expanded_&]:mt-[5%]"> <div class="flex items-center md:text-[1.3vw] text-[2vw] md:[.expanded_&]:mt-[5%]">
more details more details
<IoIosArrowDroprightCircle className="ml-[0.5vw] text-[1.4vw]" /> <IoIosArrowDroprightCircle className="ml-[0.5vw] text-[1.4vw]" />
</div> </div>
</div> </div>
</div> </div>
<GoArrowDownRight className="text-[3.2vw] [.expanded_&]:text-[0px] pt-[2%]" /> <GoArrowDownRight className="text-[3.2vw] [.expanded_&]:text-[0px] pt-[2%]" />
</div> </div>
<div class="bg-white w-fit rounded-full aspect-square p-[0.5vw] text-ieee-black md:text-[2vw] text-[3vw] absolute top-[3%] right-[5%]"> <div class="bg-white w-fit rounded-full aspect-square p-[0.5vw] text-ieee-black md:text-[2vw] text-[3vw] absolute top-[3%] right-[5%]">
<FaGear <FaGear
data-inview data-inview
className="in-view:rotate-[500deg] duration-[3000ms] group-hover:rotate-[750deg]" className="in-view:rotate-[500deg] duration-[3000ms] group-hover:rotate-[750deg]"
/> />
</div> </div>
</a> </a>
)) ))
} }
</div> </div>
<style> <style>
.project-card {
background-size: cover;
background-position: center;
}
.project-card img {
transition: transform 0.3s ease-in-out;
}
/* iOS-specific fixes */
@supports (-webkit-touch-callout: none) {
.project-card { .project-card {
background-size: cover; height: auto;
background-position: center; min-height: 30vw;
} }
.project-card img { .project-card img {
transition: transform 0.3s ease-in-out; height: auto;
min-height: 30vw;
}
}
@media (min-width: 768px) {
.project-card.expanded {
flex: 2;
} }
@media (min-width: 768px) { .project-card.expanded img {
.project-card.expanded { transform: scale(1.1);
flex: 2;
}
.project-card.expanded img {
transform: scale(1.1);
}
.project-card.expanded p {
opacity: 1;
}
} }
.project-card.expanded p {
opacity: 1;
}
}
/* Fix for iOS Safari */
@media screen and (max-width: 767px) {
.project-card {
width: 100%;
margin-bottom: 5vw;
}
}
</style> </style>
<script> <script>
function initializeProjectCards() { function initializeProjectCards() {
const projectCards = document.querySelectorAll(".project-card"); const projectCards = document.querySelectorAll(".project-card");
const STORAGE_KEY = "lastExpandedCardIndex"; const STORAGE_KEY = "lastExpandedCardIndex";
// Function to remove expanded class from all cards // Function to remove expanded class from all cards
function removeExpandedFromAll() { function removeExpandedFromAll() {
projectCards.forEach((card) => { projectCards.forEach((card) => {
card.classList.remove("expanded"); card.classList.remove("expanded");
}); });
}
// Function to expand a card by index
function expandCard(index: number) {
if (window.innerWidth >= 768) {
removeExpandedFromAll();
projectCards[index]?.classList.add("expanded");
localStorage.setItem(STORAGE_KEY, index.toString());
}
}
// Get the last expanded card index from localStorage
// Prevents bug where the expanded card breaks upon page reload
const lastExpandedIndex = parseInt(
localStorage.getItem(STORAGE_KEY) || "0"
);
expandCard(lastExpandedIndex);
// Add hover listeners to each card
projectCards.forEach((card, index) => {
card.addEventListener("mouseenter", () => {
expandCard(index);
});
});
// Handle window resize
window.addEventListener("resize", () => {
const currentIndex = parseInt(
localStorage.getItem(STORAGE_KEY) || "0"
);
expandCard(currentIndex);
});
} }
initializeProjectCards(); // Function to expand a card by index
function expandCard(index: number) {
document.addEventListener("astro:page-load", initializeProjectCards); if (window.innerWidth >= 768) {
removeExpandedFromAll();
// Image loading handler projectCards[index]?.classList.add("expanded");
function handleImageLoading() { localStorage.setItem(STORAGE_KEY, index.toString());
const projectImages = document.querySelectorAll(".project-card img"); }
projectImages.forEach((image, index) => {
// Ensure the image is fully loaded, even if it's already in cache
if (image.complete) {
image.style.opacity = "1";
const skeleton = image.previousElementSibling;
if (skeleton && skeleton.classList.contains("skeleton")) {
skeleton.style.display = "none";
}
} else {
image.addEventListener("load", () => {
image.style.opacity = "1";
const skeleton = image.previousElementSibling;
if (skeleton && skeleton.classList.contains("skeleton")) {
skeleton.style.display = "none";
}
});
}
});
} }
// Ensure images are loaded after a short delay // Get the last expanded card index from localStorage
setTimeout(handleImageLoading, 100); // Prevents bug where the expanded card breaks upon page reload
handleImageLoading(); const lastExpandedIndex = parseInt(
document.addEventListener("astro:page-load", handleImageLoading); localStorage.getItem(STORAGE_KEY) || "0",
);
expandCard(lastExpandedIndex);
// Add hover listeners to each card
projectCards.forEach((card, index) => {
card.addEventListener("mouseenter", () => {
expandCard(index);
});
});
// Handle window resize
window.addEventListener("resize", () => {
const currentIndex = parseInt(localStorage.getItem(STORAGE_KEY) || "0");
expandCard(currentIndex);
});
}
initializeProjectCards();
document.addEventListener("astro:page-load", initializeProjectCards);
// Image loading handler
function handleImageLoading() {
const projectImages = document.querySelectorAll(".project-card img");
projectImages.forEach((img) => {
// Type assertion to fix TypeScript errors
const image = img as HTMLImageElement;
// Ensure the image is fully loaded, even if it's already in cache
if (image.complete) {
image.style.opacity = "1";
const skeleton = image.previousElementSibling as HTMLElement;
if (skeleton && skeleton.classList.contains("skeleton")) {
skeleton.style.display = "none";
}
} else {
image.addEventListener("load", () => {
image.style.opacity = "1";
const skeleton = image.previousElementSibling as HTMLElement;
if (skeleton && skeleton.classList.contains("skeleton")) {
skeleton.style.display = "none";
}
});
}
});
}
// Ensure images are loaded after a short delay
setTimeout(handleImageLoading, 100);
handleImageLoading();
document.addEventListener("astro:page-load", handleImageLoading);
</script> </script>