This commit is contained in:
chark1es 2025-03-08 14:52:03 -08:00
parent 9b226fd5e7
commit 790bea36b9

View file

@ -7,13 +7,13 @@ 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="flex flex-col md:flex-row md:gap-[1.5vw] md:h-[30vw] w-full max-w-[90vw] md:max-w-none mt-[10%] md:mt-0 mx-auto 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 mb-[5vw] md:mb-0 ${index === 0 ? "expanded" : ""}`}
data-project={index + 1} data-project={index + 1}
target={title === "Supercomputing" ? "_blank" : "_self"} target={title === "Supercomputing" ? "_blank" : "_self"}
> >
@ -23,24 +23,24 @@ import { Image } from "astro:assets";
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 h-[50vw] md:h-full object-cover rounded-[1.5vw] aspect-[2/3] transition-transform duration-500 ease-in-out md:group-hover:scale-110"
/> />
<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="w-full">
<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-[3vw] 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-[3vw] md:text-[1.3vw] block md:hidden md:[.expanded_&]:block transition-all duration-300 overflow-hidden mb-[3vw]">
{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-auto md: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-[3vw] md:[.expanded_&]:mt-[5%]">
more details more details
<IoIosArrowDroprightCircle className="ml-[0.5vw] text-[1.4vw]" /> <IoIosArrowDroprightCircle className="ml-[0.5vw] text-[3vw] md: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%] hidden md:block" />
</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%]">
@ -77,12 +77,20 @@ import { Image } from "astro:assets";
opacity: 1; opacity: 1;
} }
} }
@media (max-width: 767px) {
.project-card {
height: auto;
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";
const isMobile = window.innerWidth < 768;
// Function to remove expanded class from all cards // Function to remove expanded class from all cards
function removeExpandedFromAll() { function removeExpandedFromAll() {
@ -105,19 +113,32 @@ import { Image } from "astro:assets";
const lastExpandedIndex = parseInt( const lastExpandedIndex = parseInt(
localStorage.getItem(STORAGE_KEY) || "0", localStorage.getItem(STORAGE_KEY) || "0",
); );
expandCard(lastExpandedIndex);
// Only apply expanded state on desktop
if (!isMobile) {
expandCard(lastExpandedIndex);
}
// Add hover listeners to each card // Add hover listeners to each card
projectCards.forEach((card, index) => { projectCards.forEach((card, index) => {
card.addEventListener("mouseenter", () => { card.addEventListener("mouseenter", () => {
expandCard(index); if (!isMobile) {
expandCard(index);
}
}); });
}); });
// Handle window resize // Handle window resize
window.addEventListener("resize", () => { window.addEventListener("resize", () => {
const currentIndex = parseInt(localStorage.getItem(STORAGE_KEY) || "0"); const currentIndex = parseInt(localStorage.getItem(STORAGE_KEY) || "0");
expandCard(currentIndex); const isMobileNow = window.innerWidth < 768;
if (!isMobileNow) {
expandCard(currentIndex);
} else {
// On mobile, remove expanded class from all cards
removeExpandedFromAll();
}
}); });
} }
@ -129,20 +150,20 @@ import { Image } from "astro:assets";
function handleImageLoading() { function handleImageLoading() {
const projectImages = document.querySelectorAll(".project-card img"); const projectImages = document.querySelectorAll(".project-card img");
projectImages.forEach((image, index) => { projectImages.forEach((image) => {
// Ensure the image is fully loaded, even if it's already in cache // Ensure the image is fully loaded, even if it's already in cache
if (image.complete) { if ((image as HTMLImageElement).complete) {
image.style.opacity = "1"; (image as HTMLImageElement).style.opacity = "1";
const skeleton = image.previousElementSibling; const skeleton = image.previousElementSibling;
if (skeleton && skeleton.classList.contains("skeleton")) { if (skeleton && skeleton.classList.contains("skeleton")) {
skeleton.style.display = "none"; (skeleton as HTMLElement).style.display = "none";
} }
} else { } else {
image.addEventListener("load", () => { image.addEventListener("load", () => {
image.style.opacity = "1"; (image as HTMLImageElement).style.opacity = "1";
const skeleton = image.previousElementSibling; const skeleton = image.previousElementSibling;
if (skeleton && skeleton.classList.contains("skeleton")) { if (skeleton && skeleton.classList.contains("skeleton")) {
skeleton.style.display = "none"; (skeleton as HTMLElement).style.display = "none";
} }
}); });
} }