Implement image gallery with dynamic loading and copy URL functionality; add styles for improved layout and user interaction
All checks were successful
CI / build (push) Successful in 30s

This commit is contained in:
2025-07-23 20:12:47 +00:00
parent 2fc8bde6eb
commit 0a566797de
7 changed files with 128 additions and 62 deletions

28
public/app.js Normal file
View File

@@ -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 = `
<a href="${img.url}" target="_blank">
<img src="${img.url}" alt="${img.name}">
</a>
<button class="copy-btn" title="Copy URL">Copy URL</button>
`;
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));

View File

@@ -4,37 +4,14 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PictShare Gallery</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; }
#gallery { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.image-container { width: 150px; cursor: pointer; }
.image-container img { width: 100%; border-radius: 5px; }
</style>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>PictShare Gallery</h1>
<div id="gallery"></div>
<script>
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 = `<a href="${img.url}" target="_blank">
<img src="${img.url}" alt="${img.name}">
</a>`;
gallery.appendChild(imgContainer);
});
})
.catch(error => console.error("Error loading images:", error));
</script>
<script src="/app.js"></script>
</body>
</html>

62
public/style.css Normal file
View File

@@ -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;
}