added image support

This commit is contained in:
2ManyProjects 2025-03-26 12:18:40 -05:00
parent 65ed1548a7
commit 15fc3944b4
8 changed files with 255 additions and 187 deletions

2
.gitignore vendored
View file

@ -1 +1,3 @@
node_modules
env
.env

13
package-lock.json generated
View file

@ -4513,9 +4513,9 @@
}
},
"dotenv": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
"version": "16.4.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ=="
},
"dotenv-expand": {
"version": "5.1.0",
@ -10368,6 +10368,13 @@
"webpack-dev-server": "^4.6.0",
"webpack-manifest-plugin": "^4.0.2",
"workbox-webpack-plugin": "^6.4.1"
},
"dependencies": {
"dotenv": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
}
}
},
"read-cache": {

View file

@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"dotenv": "^16.4.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1"

View file

@ -17,9 +17,7 @@ function App() {
setSelectedProjectId(null);
};
const selectedProject = selectedProjectId
? projects.find(p => p.id === selectedProjectId)
: null;
const selectedProject = selectedProjectId ? projects.find(p => p.id === selectedProjectId) : null;
return (
<div className="app">

View file

@ -2,44 +2,63 @@ import React, { useState, useEffect } from 'react';
const ImageCarousel = ({ projectId }) => {
const [images, setImages] = useState([]);
const [highResImages, setHighResImages] = useState([]);
const [fileIds, setFileIds] = useState([]);
const [currentImageIndex, setCurrentImageIndex] = useState(0);
const [loading, setLoading] = useState(true);
const [viewMode, setViewMode] = useState('thumbnail');
const getDirectDownloadUrl = (fileId) => {
return `https://lh3.google.com/u/0/d/${fileId}`
};
const getThumbnailUrl = (fileId) => {
return `https://drive.google.com/thumbnail?id=${fileId}&sz=w300`;
};
useEffect(() => {
const loadImages = async () => {
try {
const apiKey = process.env.REACT_APP_GOOGLE_API_KEY;
const importAll = (r) => r.keys().map(r);
let imageContext = null;
try {
switch(projectId){
case "mycology-lab":
imageContext = require.context(`../assets/mycology-lab`, false, /\.(png|jpe?g|svg)$/);
break
case "loanterra":
imageContext = require.context(`../assets/loanterra`, false, /\.(png|jpe?g|svg)$/);
break
case "orchard-market":
imageContext = require.context(`../assets/orchard-market`, false, /\.(png|jpe?g|svg)$/);
break
case "fecal-vision-model":
imageContext = require.context(`../assets/fecal-vision-model`, false, /\.(png|jpe?g|svg)$/);
break
default:
imageContext = require.context(`../assets/mycology-lab`, false, /\.(png|jpe?g|svg)$/);
if (!apiKey) {
throw new Error("Google API key not found in environment variables");
}
} catch (e) {
console.log("Error", e);
let folderId = "1kLdnnm47c7GkmKgiyIbv2QXh7sqFZ6p4";
let query = encodeURIComponent(`'${folderId}' in parents and trashed=false`);
let driveResponse = await fetch(
`https://www.googleapis.com/drive/v3/files?q=${query}&fields=files(id,name,mimeType)&key=${apiKey}`
);
if (!driveResponse.ok) {
throw new Error(`Google Drive API error: ${driveResponse.status}`);
}
if(imageContext){
const imageFiles = importAll(imageContext);
setImages(imageFiles);
const folderData = await driveResponse.json();
let foundFolder = folderData.files.filter(file => file.mimeType.startsWith('application/')).find(item => item.name === projectId);
if (foundFolder) {
folderId = foundFolder.id;
query = encodeURIComponent(`'${folderId}' in parents and trashed=false`);
driveResponse = await fetch(
`https://www.googleapis.com/drive/v3/files?q=${query}&fields=files(id,name,mimeType)&key=${apiKey}`
);
const fileData = await driveResponse.json();
const ids = fileData.files
.filter(file => file.mimeType.startsWith('image/'))
.map(file => file.id);
setFileIds(ids);
const thumbnailUrls = ids.map(id => getThumbnailUrl(id));
setImages(thumbnailUrls);
}
} catch (error) {
console.error("Error loading images:", error);
setImages([]);
} finally {
setLoading(false);
@ -47,17 +66,40 @@ const ImageCarousel = ({ projectId }) => {
};
loadImages();
setCurrentImageIndex(0);
setViewMode('thumbnail');
}, [projectId]);
const toggleViewMode = () => {
if (viewMode === 'thumbnail') {
setViewMode('highres');
setHighResImages([]);
setLoading(true);
const highResUrls = fileIds.map(id => getDirectDownloadUrl(id));
setHighResImages(highResUrls);
setLoading(false);
} else {
setViewMode('thumbnail');
setImages([]);
setLoading(true);
const thumbnailUrls = fileIds.map(id => getThumbnailUrl(id));
setImages(thumbnailUrls);
setLoading(false);
}
};
const nextImage = () => {
if(viewMode === 'highres')
toggleViewMode();
setCurrentImageIndex((prevIndex) =>
prevIndex === images.length - 1 ? 0 : prevIndex + 1
);
};
const prevImage = () => {
if(viewMode === 'highres')
toggleViewMode();
setCurrentImageIndex((prevIndex) =>
prevIndex === 0 ? images.length - 1 : prevIndex - 1
);
@ -70,7 +112,10 @@ const ImageCarousel = ({ projectId }) => {
if (images.length === 0) {
return <div className="carousel-empty">No images available</div>;
}
const addDefaultImg = ev => {
// ev.target.src = images[currentImageIndex]
ev.target.src = 'https://upload.wikimedia.org/wikipedia/commons/1/14/No_Image_Available.jpg'
}
return (
<div className="carousel">
<button
@ -83,12 +128,25 @@ const ImageCarousel = ({ projectId }) => {
<div className="carousel-image-container">
<img
src={images[currentImageIndex]}
src={viewMode === "thumbnail" ? images[currentImageIndex] : highResImages[currentImageIndex]}
alt={`Project ${projectId} - ${currentImageIndex + 1}`}
className="carousel-image"
onClick={toggleViewMode}
onError={(e) => addDefaultImg}
style={{
width: '100%',
height: 'auto'
}}
/>
<div className="carousel-counter">
{currentImageIndex + 1} / {images.length}
{viewMode === 'thumbnail' && (
<span className="image-quality-indicator"> [SD](Click Image for HD)</span>
)}
{viewMode === 'highres' && (
<span className="image-quality-indicator"> [HD](Click Image for SD)</span>
)}
</div>
</div>
@ -103,4 +161,6 @@ const ImageCarousel = ({ projectId }) => {
);
};
export default ImageCarousel;