Fix layout scaling when resizing.

This commit is contained in:
Jake Runyan 2024-12-25 13:16:32 -10:00
parent 898eafcb89
commit 2625c9c78e
5 changed files with 110 additions and 2 deletions

View File

@ -10,6 +10,7 @@ npx create-react-app portfolio
``` ```
npm install web-vitals npm install web-vitals
npm install react-router-dom npm install react-router-dom
npm install masonry-layout
``` ```
3. Test changes/fixes with 3. Test changes/fixes with
``` ```

49
package-lock.json generated
View File

@ -9,6 +9,7 @@
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"cra-template": "1.2.0", "cra-template": "1.2.0",
"masonry-layout": "^4.2.2",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-router-dom": "^7.1.1", "react-router-dom": "^7.1.1",
@ -6407,6 +6408,12 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/desandro-matches-selector": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/desandro-matches-selector/-/desandro-matches-selector-2.0.2.tgz",
"integrity": "sha512-+1q0nXhdzg1IpIJdMKalUwvvskeKnYyEe3shPRwedNcWtnhEKT3ZxvFjzywHDeGcKViIxTCAoOYQWP1qD7VNyg==",
"license": "MIT"
},
"node_modules/destroy": { "node_modules/destroy": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
@ -7625,6 +7632,12 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/ev-emitter": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ev-emitter/-/ev-emitter-1.1.1.tgz",
"integrity": "sha512-ipiDYhdQSCZ4hSbX4rMW+XzNKMD1prg/sTvoVmSLkuQ1MVlwjJQQA+sW8tMYR3BLUr9KjodFV4pvzunvRhd33Q==",
"license": "MIT"
},
"node_modules/eventemitter3": { "node_modules/eventemitter3": {
"version": "4.0.7", "version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
@ -7993,6 +8006,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/fizzy-ui-utils": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/fizzy-ui-utils/-/fizzy-ui-utils-2.0.7.tgz",
"integrity": "sha512-CZXDVXQ1If3/r8s0T+v+qVeMshhfcuq0rqIFgJnrtd+Bu8GmDmqMjntjUePypVtjHXKJ6V4sw9zeyox34n9aCg==",
"license": "MIT",
"dependencies": {
"desandro-matches-selector": "^2.0.0"
}
},
"node_modules/flat-cache": { "node_modules/flat-cache": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
@ -8347,6 +8369,12 @@
"node": ">=8.0.0" "node": ">=8.0.0"
} }
}, },
"node_modules/get-size": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/get-size/-/get-size-2.0.3.tgz",
"integrity": "sha512-lXNzT/h/dTjTxRbm9BXb+SGxxzkm97h/PCIKtlN/CBCxxmkkIVV21udumMS93MuVTDX583gqc94v3RjuHmI+2Q==",
"license": "MIT"
},
"node_modules/get-stream": { "node_modules/get-stream": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
@ -11047,6 +11075,16 @@
"tmpl": "1.0.5" "tmpl": "1.0.5"
} }
}, },
"node_modules/masonry-layout": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/masonry-layout/-/masonry-layout-4.2.2.tgz",
"integrity": "sha512-iGtAlrpHNyxaR19CvKC3npnEcAwszXoyJiI8ARV2ePi7fmYhIud25MHK8Zx4P0LCC4d3TNO9+rFa1KoK1OEOaA==",
"license": "MIT",
"dependencies": {
"get-size": "^2.0.2",
"outlayer": "^2.1.0"
}
},
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -11634,6 +11672,17 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/outlayer": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/outlayer/-/outlayer-2.1.1.tgz",
"integrity": "sha512-+GplXsCQ3VrbGujAeHEzP9SXsBmJxzn/YdDSQZL0xqBmAWBmortu2Y9Gwdp9J0bgDQ8/YNIPMoBM13nTwZfAhw==",
"license": "MIT",
"dependencies": {
"ev-emitter": "^1.0.0",
"fizzy-ui-utils": "^2.0.0",
"get-size": "^2.0.2"
}
},
"node_modules/p-limit": { "node_modules/p-limit": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",

View File

@ -4,6 +4,7 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"cra-template": "1.2.0", "cra-template": "1.2.0",
"masonry-layout": "^4.2.2",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-router-dom": "^7.1.1", "react-router-dom": "^7.1.1",

23
src/components/Home.css Normal file
View File

@ -0,0 +1,23 @@
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* Responsive columns */
margin: 0 auto; /* Adjust for spacing */
}
.gallery-photo {
margin: 4px; /* Vertical padding between items */
margin-left: 4px; /* Horizontal padding between items */
margin-right: 4px; /* Horizontal padding between items */
border-radius: 8px; /* Optional: Add rounded corners */
display: block; /* Ensure images are block elements */
height: auto; /* Maintain aspect ratio */
max-width: 30vw;
object-fit: cover; /* Ensure images cover the area without distortion */
}
/* Responsive adjustments */
@media (max-width: 768px) {
.gallery-photo {
width: calc(100% - 10px); /* Single column on smaller screens */
}
}

View File

@ -1,6 +1,10 @@
import React from 'react'; import React, { useEffect, useRef } from 'react';
import Masonry from 'masonry-layout';
import './Home.css'; // Global styles
const Home = () => { const Home = () => {
const masonryRef = useRef(null);
// Use require.context to load all images from the static/photos directory // Use require.context to load all images from the static/photos directory
const importAll = (r) => { const importAll = (r) => {
let images = {}; let images = {};
@ -10,8 +14,38 @@ const Home = () => {
const images = importAll(require.context('../../static/photos', false, /\.(png|jpe?g|svg)$/)); const images = importAll(require.context('../../static/photos', false, /\.(png|jpe?g|svg)$/));
useEffect(() => {
// Initialize Masonry after images have loaded
const masonry = new Masonry(masonryRef.current, {
itemSelector: '.gallery-photo',
columnWidth: '.gallery-photo',
percentPosition: true,
horizontalOrder: true,
});
// Layout Masonry after all images have loaded
const imgLoad = images => {
const imgLoad = images.map(img => {
return new Promise((resolve) => {
const imgElement = new Image();
imgElement.src = img;
imgElement.onload = resolve;
});
});
return Promise.all(imgLoad);
};
imgLoad(Object.values(images)).then(() => {
masonry.layout();
});
return () => {
masonry.destroy(); // Cleanup on unmount
};
}, [images]);
return ( return (
<div className="gallery"> <div className="gallery" ref={masonryRef}>
{Object.keys(images).map((key, index) => ( {Object.keys(images).map((key, index) => (
<img key={index} src={images[key]} alt={`Jake Runyan ${index + 1}`} className="gallery-photo" /> <img key={index} src={images[key]} alt={`Jake Runyan ${index + 1}`} className="gallery-photo" />
))} ))}