ios projects fix attempt 1
This commit is contained in:
parent
bcd933d87b
commit
6dc95b67f9
2 changed files with 194 additions and 149 deletions
|
@ -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 @ 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>
|
|
||||||
</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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue