add annual projects component
This commit is contained in:
parent
4fb32cd112
commit
73bf65a640
1 changed files with 135 additions and 0 deletions
135
src/components/projects/ProjectSection.astro
Normal file
135
src/components/projects/ProjectSection.astro
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
---
|
||||||
|
import annualProjects from "../../data/annualProjects.json";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
width?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { width = "100%" } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<section class="w-full py-12">
|
||||||
|
<div class={`mx-auto`} style={`width: ${width}`}>
|
||||||
|
<div class="flex flex-col md:flex-row gap-6 md:h-[400px]">
|
||||||
|
{
|
||||||
|
Object.entries(annualProjects).map(
|
||||||
|
([title, project], index) => (
|
||||||
|
<a
|
||||||
|
href={project.url || "#"}
|
||||||
|
class={`project-card group relative h-[300px] md:h-auto flex-none md:flex-1 rounded-lg overflow-hidden transition-all duration-500 ease-in-out md:hover:flex-[2] cursor-pointer ${index === 0 ? "expanded" : ""}`}
|
||||||
|
data-project={index + 1}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={project.image}
|
||||||
|
alt={`${title} Project`}
|
||||||
|
class="w-full h-full object-cover rounded-lg transition-transform duration-500 ease-in-out md:group-hover:scale-110"
|
||||||
|
/>
|
||||||
|
<div class="absolute inset-0 bg-gradient-to-b from-transparent to-project_card_gradient/60 rounded-lg" />
|
||||||
|
<div class="absolute bottom-0 left-0 p-6 text-project_card_text z-10 w-full transition-transform duration-300 md:[.expanded_&]:translate-y-[-30px]">
|
||||||
|
<h3 class="text-xl font-bold mb-2 transition-transform duration-300">
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
|
<p class="md:opacity-0 md:[.expanded_&]:opacity-100 transition-all duration-300 max-h-0 md:[.expanded_&]:max-h-[200px] overflow-hidden">
|
||||||
|
{project.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="absolute bottom-2 right-2 bg-project_button_bg rounded-full p-2 shadow
|
||||||
|
md:opacity-0 md:[.expanded_&]:opacity-100 transition-opacity duration-300"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="h-6 w-6 text-project_button_color"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M7 7l10 10m0-10v10h-10"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.project-card {
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card img {
|
||||||
|
transition: transform 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.project-card.expanded {
|
||||||
|
flex: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card.expanded img {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card.expanded p {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function initializeProjectCards() {
|
||||||
|
const projectCards = document.querySelectorAll(".project-card");
|
||||||
|
const STORAGE_KEY = "lastExpandedCardIndex";
|
||||||
|
|
||||||
|
// Function to remove expanded class from all cards
|
||||||
|
function removeExpandedFromAll() {
|
||||||
|
projectCards.forEach((card) => {
|
||||||
|
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();
|
||||||
|
|
||||||
|
document.addEventListener("astro:page-load", initializeProjectCards);
|
||||||
|
</script>
|
Loading…
Reference in a new issue