diff --git a/public/app.js b/public/app.js new file mode 100644 index 0000000..88afdb5 --- /dev/null +++ b/public/app.js @@ -0,0 +1,28 @@ +fetch("/images") + .then(response => { + if (!response.ok) throw new Error("Failed to fetch images."); + return response.json(); + }) + .then(images => { + const gallery = document.getElementById("gallery"); + images.forEach(img => { + const imgContainer = document.createElement("div"); + imgContainer.className = "image-container"; + imgContainer.innerHTML = ` + + ${img.name} + + + `; + const copyBtn = imgContainer.querySelector('.copy-btn'); + copyBtn.addEventListener('click', (e) => { + e.preventDefault(); + navigator.clipboard.writeText(img.url).then(() => { + copyBtn.textContent = 'Copied!'; + setTimeout(() => copyBtn.textContent = 'Copy URL', 1200); + }); + }); + gallery.appendChild(imgContainer); + }); + }) + .catch(error => console.error("Error loading images:", error)); diff --git a/public/index.html b/public/index.html index 65268f7..7c908e7 100644 --- a/public/index.html +++ b/public/index.html @@ -4,37 +4,14 @@ PictShare Gallery - +

PictShare Gallery

- + diff --git a/public/style.css b/public/style.css new file mode 100644 index 0000000..68bb669 --- /dev/null +++ b/public/style.css @@ -0,0 +1,62 @@ +body { font-family: Arial, sans-serif; text-align: center; margin: 0; padding: 0; } + +h1 { margin-top: 1.5rem; } + + +#gallery { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 22px; + justify-items: center; + align-items: start; + /* max-width: 1400px; */ + margin: auto 10rem; + padding: 0 1rem; +} + + +.image-container { + width: 200px; + aspect-ratio: 1 / 1; + background: #fafafa; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0,0,0,0.07); + transition: transform 0.15s; + position: relative; + overflow: hidden; + display: flex; + flex-direction: column; +} + +.image-container:hover { + transform: scale(1.04); + box-shadow: 0 4px 16px rgba(0,0,0,0.12); +} + +.copy-btn { + position: absolute; + top: 8px; + right: 8px; + background: rgba(0,0,0,0.7); + color: #fff; + border: none; + border-radius: 4px; + padding: 4px 8px; + font-size: 0.9rem; + opacity: 0; + cursor: pointer; + transition: opacity 0.2s; + z-index: 2; +} + +.image-container:hover .copy-btn { + opacity: 1; +} + +.image-container img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 8px 8px 0 0; + display: block; +} diff --git a/src/app.js b/src/app.js index 21a8fa3..1509029 100644 --- a/src/app.js +++ b/src/app.js @@ -1,9 +1,13 @@ const express = require("express"); +const path = require("path"); const galleryRoutes = require("./galleryRoutes"); const app = express(); const PORT = process.env.PORT || 3000; +// Serve static files from public directory +app.use(express.static(path.join(__dirname, "../public"))); + app.use(galleryRoutes); module.exports = app; diff --git a/src/galleryRoutes.js b/src/galleryRoutes.js index 2cedbaf..0e8b803 100644 --- a/src/galleryRoutes.js +++ b/src/galleryRoutes.js @@ -1,13 +1,14 @@ const express = require("express"); + const getImages = require("./getImages"); -const renderGallery = require("./renderGallery"); const router = express.Router(); -// Route: Serve Image Gallery at `/` + +// Serve static index.html for the root route +const path = require("path"); router.get("/", (req, res) => { - const images = getImages(); - res.send(renderGallery(images)); + res.sendFile(path.join(__dirname, "../public/index.html")); }); // API Route: Return JSON List of Images @@ -15,4 +16,5 @@ router.get("/images", (req, res) => { res.json(getImages()); }); + module.exports = router; diff --git a/src/renderGallery.js b/src/renderGallery.js deleted file mode 100644 index b87d4a0..0000000 --- a/src/renderGallery.js +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = function renderGallery(images) { - return ` - - - - - - PictShare Gallery - - - - -

PictShare Gallery

- - - - - `; -}; diff --git a/uploads/sha1.csv b/uploads/sha1.csv index f4c4335..84f09db 100644 --- a/uploads/sha1.csv +++ b/uploads/sha1.csv @@ -1,3 +1,26 @@ -0799fec84a8ace495e1cb631db19f944dadb330b;rkijhb.png -c8155c5afce62d096283fc3a7d5dc09e46714ffe;u71mru.png -443e983d9dd5ce40a42eb4be98a0facd8e080888;qojsy0.png + +0799fec84a8ace495e1cb631db19f944dadb330b;000001.png +c8155c5afce62d096283fc3a7d5dc09e46714ffe;000002.png +443e983d9dd5ce40a42eb4be98a0facd8e080888;000003.png +e1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1;000004.png +f2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2;000005.png +03c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3;000006.png +14d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4;000007.png +25e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5;000008.png +36f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6;000009.png +4707070707070707070707070707070707070707;000010.png +5818181818181818181818181818181818181818;000011.png +6929292929292929292929292929292929292929;000012.png +7a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3;000013.png +8b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4;000014.png +9c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5;000015.png +ad6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6;000016.png +be7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7;000017.png +cf8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8;000018.png +d0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a;000019.png +e1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b;000020.png +f2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c;000021.png +03d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d;000022.png +14e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e;000023.png +25f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f;000024.png +3606060606060606060606060606060606060606;000025.png