197 lines
4.9 KiB
Vue
197 lines
4.9 KiB
Vue
<template>
|
||
<section class="bg-transparent py-12 px-4">
|
||
<!-- Gallery Grid - Masonry Style -->
|
||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 max-w-6xl mx-auto px-4" data-aos="fade-up">
|
||
<img
|
||
v-for="(img, index) in displayImages"
|
||
:key="index"
|
||
:src="img"
|
||
alt="Gallery photo"
|
||
class="rounded-lg object-cover w-full shadow-lg hover:shadow-xl transition-shadow duration-300 cursor-pointer"
|
||
:class="getGridClass(index)"
|
||
@click="openLightbox(index)"
|
||
/>
|
||
</div>
|
||
|
||
<!-- Quote Section -->
|
||
<div class="max-w-3xl mx-auto mt-12 px-6 text-center" data-aos="fade-up" data-aos-delay="200">
|
||
<p class="text-gray-600 text-sm md:text-base leading-relaxed">
|
||
"And among His Signs is this, that He created for you mates from among yourselves,
|
||
that ye may dwell in tranquility with them, and He has put love and mercy between your (hearts):
|
||
verily in that are Signs for those who reflect."
|
||
</p>
|
||
<p class="mt-4 text-amber-600 font-semibold text-sm">- QS. Ar-Rum: 21 -</p>
|
||
</div>
|
||
|
||
<!-- Lightbox Modal -->
|
||
<Teleport to="body">
|
||
<div
|
||
v-if="lightboxOpen"
|
||
class="fixed inset-0 z-50 bg-black/90 flex items-center justify-center p-4"
|
||
@click="closeLightbox"
|
||
>
|
||
<button
|
||
class="absolute top-4 right-4 text-white text-4xl hover:text-amber-400 transition-colors"
|
||
@click="closeLightbox"
|
||
>
|
||
×
|
||
</button>
|
||
|
||
<button
|
||
v-if="currentImageIndex > 0"
|
||
class="absolute left-4 text-white text-4xl hover:text-amber-400 transition-colors"
|
||
@click.stop="prevImage"
|
||
>
|
||
‹
|
||
</button>
|
||
|
||
<img
|
||
:src="displayImages[currentImageIndex]"
|
||
class="max-w-full max-h-[90vh] object-contain rounded-lg"
|
||
@click.stop
|
||
/>
|
||
|
||
<button
|
||
v-if="currentImageIndex < displayImages.length - 1"
|
||
class="absolute right-4 text-white text-4xl hover:text-amber-400 transition-colors"
|
||
@click.stop="nextImage"
|
||
>
|
||
›
|
||
</button>
|
||
|
||
<div class="absolute bottom-4 text-white text-sm">
|
||
{{ currentImageIndex + 1 }} / {{ displayImages.length }}
|
||
</div>
|
||
</div>
|
||
</Teleport>
|
||
</section>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed } from 'vue'
|
||
|
||
const props = defineProps({
|
||
images: {
|
||
type: Array,
|
||
default: () => [
|
||
"/logo1.png",
|
||
"/logo2.png",
|
||
"/pria.jpg",
|
||
"/wanita.jpg",
|
||
"/iphone.png",
|
||
"/templat.jpg",
|
||
"/logo1.png",
|
||
"/logo2.png"
|
||
]
|
||
}
|
||
})
|
||
|
||
const lightboxOpen = ref(false)
|
||
const currentImageIndex = ref(0)
|
||
|
||
const displayImages = computed(() => {
|
||
const images = props.images && props.images.length > 0 ? props.images : [
|
||
"/images/logo1.png",
|
||
"/images/logo2.png",
|
||
"/images/pria.jpg",
|
||
"/images/wanita.jpg",
|
||
"/images/iphone.png",
|
||
"/images/templat.jpg",
|
||
"/images/logo1.png",
|
||
"/images/logo2.png"
|
||
]
|
||
console.log('displayImages:', images)
|
||
return images
|
||
})
|
||
|
||
// Masonry grid layout pattern
|
||
const getGridClass = (index) => {
|
||
const pattern = index % 8
|
||
|
||
switch (pattern) {
|
||
case 0:
|
||
return "col-span-1 row-span-2 h-[400px]" // Tall left
|
||
case 1:
|
||
return "col-span-1 h-[195px]" // Small top right
|
||
case 2:
|
||
return "col-span-1 h-[195px]" // Small middle
|
||
case 3:
|
||
return "col-span-2 h-[250px]" // Wide bottom
|
||
case 4:
|
||
return "col-span-1 h-[200px]" // Standard
|
||
case 5:
|
||
return "col-span-1 row-span-2 h-[400px]" // Tall right
|
||
case 6:
|
||
return "col-span-2 h-[195px]" // Wide top
|
||
case 7:
|
||
return "col-span-1 h-[200px]" // Standard
|
||
default:
|
||
return "h-[200px]"
|
||
}
|
||
}
|
||
|
||
const openLightbox = (index) => {
|
||
currentImageIndex.value = index
|
||
lightboxOpen.value = true
|
||
document.body.style.overflow = 'hidden'
|
||
}
|
||
|
||
const closeLightbox = () => {
|
||
lightboxOpen.value = false
|
||
document.body.style.overflow = ''
|
||
}
|
||
|
||
const nextImage = () => {
|
||
if (currentImageIndex.value < displayImages.value.length - 1) {
|
||
currentImageIndex.value++
|
||
}
|
||
}
|
||
|
||
const prevImage = () => {
|
||
if (currentImageIndex.value > 0) {
|
||
currentImageIndex.value--
|
||
}
|
||
}
|
||
|
||
// Keyboard navigation
|
||
const handleKeydown = (e) => {
|
||
if (!lightboxOpen.value) return
|
||
|
||
if (e.key === 'Escape') closeLightbox()
|
||
if (e.key === 'ArrowRight') nextImage()
|
||
if (e.key === 'ArrowLeft') prevImage()
|
||
}
|
||
|
||
if (typeof window !== 'undefined') {
|
||
window.addEventListener('keydown', handleKeydown)
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* Smooth transitions */
|
||
img {
|
||
transition: transform 0.3s ease, shadow 0.3s ease;
|
||
}
|
||
|
||
img:hover {
|
||
transform: scale(1.02);
|
||
}
|
||
|
||
/* Custom scrollbar for lightbox if needed */
|
||
::-webkit-scrollbar {
|
||
width: 8px;
|
||
}
|
||
|
||
::-webkit-scrollbar-track {
|
||
background: transparent;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb {
|
||
background: #f59e0b;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb:hover {
|
||
background: #d97706;
|
||
}
|
||
</style> |