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
All checks were successful
CI / build (push) Successful in 30s
This commit is contained in:
28
public/app.js
Normal file
28
public/app.js
Normal 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));
|
||||
@@ -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
62
public/style.css
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user