added project gallery behavior

This commit is contained in:
Hunter W.
2026-05-31 09:44:59 -04:00
parent 59e7589a29
commit 28a672c82b
8 changed files with 1053 additions and 640 deletions

View File

@@ -2,13 +2,94 @@
import { PROJECTS } from "@/data/content";
import { useStaggerReveal } from "@/hooks/useAnimations";
import ProjectCard from "./ProjectCard";
import React, { useState, useCallback } from 'react';
import ProjectCard from "@/components/ProjectCard";
import { Layout, Responsive, useContainerWidth, horizontalCompactor, verticalCompactor, DefaultBreakpoints } from "react-grid-layout";
import "react-grid-layout/css/styles.css";
import "react-resizable/css/styles.css";
export default function Projects() {
const visible = useStaggerReveal(PROJECTS.length, 100);
const rowHeight = 250;
const defaultExpandedHeightUnits = 2;
const visible = useStaggerReveal(PROJECTS.length, 100);
const [selectedProject, setSelectedProject] = useState<number>(1);
const { width, containerRef, mounted } = useContainerWidth();
const [topCellHeight, setTopCellHeight] = useState(defaultExpandedHeightUnits);
const [layouts, setLayouts] = useState<Record<DefaultBreakpoints, Layout>>(updateLayout(1));
function setExpandedHeight(height: number) {
const gridUnits = height === 0 ? defaultExpandedHeightUnits : Math.ceil(height / rowHeight);
setTopCellHeight(gridUnits);
setLayouts(updateLayout(selectedProject, gridUnits)); // pass both
}
function setSelectedHandler(projectId: number) {
const id = Number(projectId);
setSelectedProject(id);
setLayouts(updateLayout(id, topCellHeight)); // pass both
}
function updateLayout(activeId: number, cellHeight?: number) : Record<DefaultBreakpoints, Layout> {
const currentSelected = activeId ?? selectedProject;
const currentCellHeight = cellHeight ?? topCellHeight;
let isSelected = (projectId: number) => projectId === currentSelected;
return {
"sm": PROJECTS.map((project, i) => {
return {
i: project.id.toString(),
x: isSelected(project.id) ? 0 : (i % 2) + 1,
y: isSelected(project.id) ? 0 : Math.floor(i / 2) + (!isSelected(project.id) ? 1 : 0),
w: isSelected(project.id) ? 2 : 1,
h: project.images && project.images.length > 0 ? currentCellHeight : 1
};
}),
"xs": PROJECTS.map((project, i) => {
return {
i: project.id.toString(),
x: 0,
y: i,
w: 2,
h: project.images && project.images.length > 0 ? currentCellHeight : 1
};
}),
"xxs": PROJECTS.map((project, i) => {
return {
i: project.id.toString(),
x: 0,
y: i,
w: 2,
h: project.images && project.images.length > 0 ? currentCellHeight : 1
};
}),
"md": PROJECTS.map((project, i) => {
return {
i: project.id.toString(),
x: isSelected(project.id) ? 0 : (i % 2) + 1,
y: isSelected(project.id) ? 0 : Math.floor(i / 2) + (!isSelected(project.id) ? 1 : 0),
w: isSelected(project.id) ? 2 : 1,
h: project.images && project.images.length > 0 ? currentCellHeight : 1
};
}),
"lg": PROJECTS.map((project, i) => {
return {
i: project.id.toString(),
x: isSelected(project.id) ? 0 : (i % 2) + 1,
y: isSelected(project.id) ? 0 : Math.floor(i / 2) + (!isSelected(project.id) ? 1 : 0),
w: isSelected(project.id) ? 2 : 1,
h: project.images && project.images.length > 0 ? currentCellHeight : 1
};
}),
};
};
return (
<div style={{ padding: "48px 0" }}>
<div style={{ padding: "48px 0"}}>
<div
style={{
marginBottom: 8,
@@ -33,21 +114,33 @@ export default function Projects() {
>
{"Things I've built"}
</h2>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(320px, 1fr))",
gap: 16,
}}
>
<div ref={containerRef}>
{mounted && (<Responsive
layouts={layouts}
breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
cols={{ lg: 2, md: 2, sm: 2, xs: 2, xxs: 2 }}
width={width}
compactor={horizontalCompactor}
rowHeight={rowHeight}
dragConfig={{enabled:false}}
>
{PROJECTS.map((project, i) => (
<ProjectCard
key={project.id}
<div key={project.id} style={{pointerEvents: "none"}}>
<ProjectCard
project={project}
visible={visible.has(i)}
selected={selectedProject === project.id}
setSelected={setSelectedHandler}
setExpandedHeight={setExpandedHeight}
/>
</div>
))}
</Responsive>)}
</div>
</div>
);
}