<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<script type="module" src="https://cdnjs.cloudflare.com/ajax/libs/ionicons/7.1.0/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://cdnjs.cloudflare.com/ajax/libs/ionicons/7.1.0/ionicons/ionicons.js"></script>
<div class="gallery-container">
<!-- Page Header -->
<div class="page-header">
<h1>Lightbox Gallery</h1>
<p>Click on any image to view in fullscreen lightbox</p>
</div>
<!-- Filter Buttons -->
<div class="filter-buttons">
<button class="filter-btn active" data-filter="all">All</button>
<button class="filter-btn" data-filter="nature">Nature</button>
<button class="filter-btn" data-filter="architecture">Architecture</button>
<button class="filter-btn" data-filter="people">People</button>
<button class="filter-btn" data-filter="abstract">Abstract</button>
</div>
<!-- Gallery Grid -->
<div class="gallery-grid" id="gallery">
<!-- Images will be generated by JavaScript -->
</div>
</div>
<!-- Lightbox Modal -->
<div class="modal fade lightbox-modal" id="lightboxModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body">
<button class="lightbox-close" data-bs-dismiss="modal">
<ion-icon name="close"></ion-icon>
</button>
<button class="lightbox-nav prev" onclick="navigateImage(-1)">
<ion-icon name="chevron-back"></ion-icon>
</button>
<button class="lightbox-nav next" onclick="navigateImage(1)">
<ion-icon name="chevron-forward"></ion-icon>
</button>
<div class="lightbox-image-container">
<img id="lightboxImage" src="" alt="">
</div>
<div class="lightbox-counter" id="lightboxCounter"></div>
<div class="lightbox-info">
<div class="lightbox-info-header">
<h3 id="lightboxTitle"></h3>
<span class="lightbox-info-category" id="lightboxCategory"></span>
</div>
<p id="lightboxDescription"></p>
</div>
<div class="lightbox-thumbnails" id="lightboxThumbnails"></div>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
* {
font-family: 'Roboto', sans-serif;
}
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 60px 20px;
}
.gallery-container {
max-width: 1200px;
margin: 0 auto;
}
/* Page Header */
.page-header {
text-align: center;
color: white;
margin-bottom: 50px;
}
.page-header h1 {
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 15px;
}
.page-header p {
font-size: 1.1rem;
opacity: 0.9;
}
/* Filter Buttons */
.filter-buttons {
display: flex;
justify-content: center;
gap: 15px;
margin-bottom: 40px;
flex-wrap: wrap;
}
.filter-btn {
background: white;
color: #2c3e50;
border: 2px solid white;
padding: 10px 25px;
border-radius: 50px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.filter-btn:hover {
background: transparent;
color: white;
transform: translateY(-2px);
}
.filter-btn.active {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
border-color: transparent;
color: white;
}
/* Gallery Grid */
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
margin-bottom: 40px;
}
.gallery-item {
position: relative;
border-radius: 15px;
overflow: hidden;
cursor: pointer;
aspect-ratio: 1;
transition: all 0.3s ease;
}
.gallery-item.hide {
display: none;
}
.gallery-item:hover {
transform: translateY(-10px);
}
.gallery-image {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.gallery-item:hover .gallery-image {
transform: scale(1.15);
}
.gallery-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to bottom, transparent 0%, rgba(0,0,0,0.8) 100%);
display: flex;
flex-direction: column;
justify-content: flex-end;
padding: 20px;
opacity: 0;
transition: opacity 0.3s ease;
}
.gallery-item:hover .gallery-overlay {
opacity: 1;
}
.gallery-title {
color: white;
font-size: 1.1rem;
font-weight: 700;
margin-bottom: 5px;
}
.gallery-category {
color: white;
font-size: 0.9rem;
opacity: 0.9;
}
.gallery-zoom-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60px;
height: 60px;
background: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
color: #667eea;
opacity: 0;
transition: all 0.3s ease;
}
.gallery-item:hover .gallery-zoom-icon {
opacity: 1;
transform: translate(-50%, -50%) scale(1.1);
}
/* Lightbox Modal */
.lightbox-modal .modal-dialog {
max-width: 90vw;
margin: 20px auto;
}
.lightbox-modal .modal-content {
background: rgba(0, 0, 0, 0.95);
border: none;
border-radius: 0;
}
.lightbox-modal .modal-body {
padding: 0;
position: relative;
}
.lightbox-image-container {
display: flex;
align-items: center;
justify-content: center;
min-height: 400px;
max-height: 80vh;
padding: 20px;
}
.lightbox-image-container img {
max-width: 100%;
max-height: 75vh;
border-radius: 10px;
box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}
/* Lightbox Controls */
.lightbox-close {
position: absolute;
top: 20px;
right: 20px;
width: 50px;
height: 50px;
background: white;
border-radius: 50%;
border: none;
font-size: 28px;
color: #2c3e50;
cursor: pointer;
transition: all 0.3s ease;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
}
.lightbox-close:hover {
transform: rotate(90deg);
background: #f5576c;
color: white;
}
.lightbox-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 50px;
height: 50px;
background: white;
border-radius: 50%;
border: none;
font-size: 28px;
color: #2c3e50;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
}
.lightbox-nav:hover {
background: #667eea;
color: white;
transform: translateY(-50%) scale(1.1);
}
.lightbox-nav.prev {
left: 20px;
}
.lightbox-nav.next {
right: 20px;
}
/* Lightbox Info */
.lightbox-info {
background: rgba(255, 255, 255, 0.95);
padding: 20px;
border-radius: 0 0 10px 10px;
}
.lightbox-info-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 10px;
}
.lightbox-info h3 {
font-size: 1.5rem;
font-weight: 700;
color: #2c3e50;
margin: 0;
}
.lightbox-info-category {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 5px 15px;
border-radius: 20px;
font-size: 0.85rem;
font-weight: 600;
}
.lightbox-info p {
color: #7f8c8d;
margin: 0;
}
.lightbox-counter {
text-align: center;
color: white;
padding: 15px;
font-size: 14px;
font-weight: 500;
}
/* Thumbnails */
.lightbox-thumbnails {
display: flex;
gap: 10px;
padding: 20px;
overflow-x: auto;
background: rgba(0, 0, 0, 0.5);
}
.lightbox-thumbnails::-webkit-scrollbar {
height: 6px;
}
.lightbox-thumbnails::-webkit-scrollbar-thumb {
background: #667eea;
border-radius: 10px;
}
.thumbnail-item {
width: 80px;
height: 80px;
border-radius: 8px;
overflow: hidden;
cursor: pointer;
flex-shrink: 0;
border: 3px solid transparent;
transition: all 0.3s ease;
}
.thumbnail-item:hover {
border-color: white;
}
.thumbnail-item.active {
border-color: #667eea;
}
.thumbnail-item img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* Loading Spinner */
.lightbox-loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.spinner {
border: 4px solid rgba(255, 255, 255, 0.3);
border-top: 4px solid white;
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Responsive */
@media (max-width: 768px) {
.gallery-grid {
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 15px;
}
.lightbox-nav {
width: 40px;
height: 40px;
font-size: 22px;
}
.lightbox-close {
width: 40px;
height: 40px;
font-size: 22px;
top: 10px;
right: 10px;
}
.lightbox-nav.prev {
left: 10px;
}
.lightbox-nav.next {
right: 10px;
}
.page-header h1 {
font-size: 2rem;
}
.lightbox-thumbnails {
padding: 10px;
}
.thumbnail-item {
width: 60px;
height: 60px;
}
}
// Gallery data
const galleryData = [
{ id: 1, category: 'nature', title: 'Mountain Landscape', description: 'Beautiful mountain scenery at sunset', color: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
{ id: 2, category: 'architecture', title: 'Modern Building', description: 'Contemporary architecture design', color: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)' },
{ id: 3, category: 'nature', title: 'Forest Path', description: 'Peaceful forest trail in autumn', color: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)' },
{ id: 4, category: 'people', title: 'Portrait', description: 'Professional portrait photography', color: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)' },
{ id: 5, category: 'abstract', title: 'Color Waves', description: 'Abstract colorful patterns', color: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)' },
{ id: 6, category: 'architecture', title: 'City Skyline', description: 'Urban cityscape at night', color: 'linear-gradient(135deg, #30cfd0 0%, #330867 100%)' },
{ id: 7, category: 'nature', title: 'Ocean View', description: 'Stunning ocean waves and beach', color: 'linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)' },
{ id: 8, category: 'abstract', title: 'Geometric Art', description: 'Modern geometric composition', color: 'linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%)' },
{ id: 9, category: 'people', title: 'Street Photography', description: 'Candid street moment captured', color: 'linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%)' },
{ id: 10, category: 'architecture', title: 'Historic Building', description: 'Classic architectural masterpiece', color: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
{ id: 11, category: 'nature', title: 'Waterfall', description: 'Majestic waterfall in the jungle', color: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)' },
{ id: 12, category: 'abstract', title: 'Light Trails', description: 'Long exposure light painting', color: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)' }
];
let currentImageIndex = 0;
let filteredImages = [...galleryData];
// Generate gallery
function generateGallery() {
const gallery = document.getElementById('gallery');
gallery.innerHTML = galleryData.map((item, index) => `
<div class="gallery-item" data-category="${item.category}" onclick="openLightbox(${index})">
<div style="width: 100%; height: 100%; background: ${item.color};"></div>
<div class="gallery-overlay">
<div class="gallery-title">${item.title}</div>
<div class="gallery-category">${item.category}</div>
</div>
<div class="gallery-zoom-icon">
<ion-icon name="expand"></ion-icon>
</div>
</div>
`).join('');
}
// Filter functionality
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', function() {
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
this.classList.add('active');
const filter = this.dataset.filter;
document.querySelectorAll('.gallery-item').forEach(item => {
if (filter === 'all' || item.dataset.category === filter) {
item.classList.remove('hide');
} else {
item.classList.add('hide');
}
});
});
});
// Open lightbox
function openLightbox(index) {
currentImageIndex = index;
updateLightbox();
const modal = new bootstrap.Modal(document.getElementById('lightboxModal'));
modal.show();
}
// Update lightbox content
function updateLightbox() {
const item = galleryData[currentImageIndex];
const imageDiv = document.createElement('div');
imageDiv.style.width = '600px';
imageDiv.style.height = '400px';
imageDiv.style.background = item.color;
imageDiv.style.borderRadius = '10px';
const container = document.querySelector('.lightbox-image-container');
container.innerHTML = '';
container.appendChild(imageDiv);
document.getElementById('lightboxTitle').textContent = item.title;
document.getElementById('lightboxCategory').textContent = item.category;
document.getElementById('lightboxDescription').textContent = item.description;
document.getElementById('lightboxCounter').textContent = `${currentImageIndex + 1} / ${galleryData.length}`;
// Update thumbnails
updateThumbnails();
}
// Update thumbnails
function updateThumbnails() {
const thumbnails = document.getElementById('lightboxThumbnails');
thumbnails.innerHTML = galleryData.map((item, index) => `
<div class="thumbnail-item ${index === currentImageIndex ? 'active' : ''}" onclick="currentImageIndex = ${index}; updateLightbox();">
<div style="width: 100%; height: 100%; background: ${item.color};"></div>
</div>
`).join('');
}
// Navigate images
function navigateImage(direction) {
currentImageIndex += direction;
if (currentImageIndex < 0) {
currentImageIndex = galleryData.length - 1;
} else if (currentImageIndex >= galleryData.length) {
currentImageIndex = 0;
}
updateLightbox();
}
// Keyboard navigation
document.addEventListener('keydown', (e) => {
const modal = document.getElementById('lightboxModal');
if (modal.classList.contains('show')) {
if (e.key === 'ArrowLeft') {
navigateImage(-1);
} else if (e.key === 'ArrowRight') {
navigateImage(1);
} else if (e.key === 'Escape') {
bootstrap.Modal.getInstance(modal).hide();
}
}
});
// Initialize gallery
generateGallery();
Login to leave a comment
Login
No comments yet. Be the first!