248 lines
10 KiB
Vue
248 lines
10 KiB
Vue
<!-- components/forms/KhitanForm.vue -->
|
||
<template>
|
||
<div class="h-screen w-full relative bg-gradient-to-br from-blue-900 via-blue-800 to-blue-900 overflow-hidden">
|
||
<!-- Background Pattern -->
|
||
<div class="absolute inset-0 bg-pattern opacity-30"></div>
|
||
|
||
<!-- Decorative Lanterns -->
|
||
<div class="absolute top-8 left-8 animate-sway">
|
||
<div class="w-16 h-20 relative">
|
||
<!-- Lantern Chain -->
|
||
<div class="absolute top-0 left-1/2 w-0.5 h-8 bg-yellow-400 transform -translate-x-1/2"></div>
|
||
<!-- Lantern Body -->
|
||
<div class="absolute bottom-0 w-full">
|
||
<svg viewBox="0 0 64 80" class="w-full h-full">
|
||
<defs>
|
||
<linearGradient id="lanternGradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||
<stop offset="0%" style="stop-color:#FFD700"/>
|
||
<stop offset="50%" style="stop-color:#FFA500"/>
|
||
<stop offset="100%" style="stop-color:#FFD700"/>
|
||
</linearGradient>
|
||
</defs>
|
||
<ellipse cx="32" cy="15" rx="28" ry="12" fill="url(#lanternGradient)"/>
|
||
<rect x="8" y="12" width="48" height="40" rx="24" fill="url(#lanternGradient)" opacity="0.9"/>
|
||
<ellipse cx="32" cy="55" rx="28" ry="12" fill="url(#lanternGradient)"/>
|
||
<rect x="20" y="20" width="24" height="4" rx="2" fill="#1e40af" opacity="0.6"/>
|
||
<rect x="20" y="30" width="24" height="4" rx="2" fill="#1e40af" opacity="0.6"/>
|
||
<rect x="20" y="40" width="24" height="4" rx="2" fill="#1e40af" opacity="0.6"/>
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="absolute top-8 right-8 animate-sway animation-delay-1000">
|
||
<div class="w-16 h-20 relative">
|
||
<!-- Lantern Chain -->
|
||
<div class="absolute top-0 left-1/2 w-0.5 h-8 bg-yellow-400 transform -translate-x-1/2"></div>
|
||
<!-- Lantern Body -->
|
||
<div class="absolute bottom-0 w-full">
|
||
<svg viewBox="0 0 64 80" class="w-full h-full">
|
||
<!-- pakai gradient yang sama -->
|
||
<use href="#lanternGradient"></use>
|
||
<ellipse cx="32" cy="15" rx="28" ry="12" fill="url(#lanternGradient)"/>
|
||
<rect x="8" y="12" width="48" height="40" rx="24" fill="url(#lanternGradient)" opacity="0.9"/>
|
||
<ellipse cx="32" cy="55" rx="28" ry="12" fill="url(#lanternGradient)"/>
|
||
<rect x="20" y="20" width="24" height="4" rx="2" fill="#1e40af" opacity="0.6"/>
|
||
<rect x="20" y="30" width="24" height="4" rx="2" fill="#1e40af" opacity="0.6"/>
|
||
<rect x="20" y="40" width="24" height="4" rx="2" fill="#1e40af" opacity="0.6"/>
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Main Content -->
|
||
<div class="relative z-10 h-full flex items-center justify-center px-6">
|
||
<div class="text-center max-w-6xl mx-auto">
|
||
|
||
<!-- Bismillah -->
|
||
<div class="mb-8 animate-fade-in-down">
|
||
<h1 class="text-yellow-400 text-2xl md:text-3xl font-bold mb-6 arabic-text">
|
||
بِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ
|
||
</h1>
|
||
</div>
|
||
|
||
<!-- Event Description -->
|
||
<div class="mb-8 animate-fade-in-up animation-delay-300">
|
||
<p class="text-white text-base md:text-lg leading-relaxed max-w-4xl mx-auto mb-6">
|
||
Dengan memohon rahmat dan ridho Allah Subhanahu wa Ta'ala, kami<br>
|
||
mengundang Bapak/Ibu/Saudara/i untuk hadir dan berbagi kebahagiaan<br>
|
||
dalam acara Khitanan putra kami tercinta, yang insya Allah akan<br>
|
||
diselenggarakan pada :
|
||
</p>
|
||
</div>
|
||
|
||
<!-- Event Details Container -->
|
||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8">
|
||
|
||
<!-- Date & Countdown -->
|
||
<div class="animate-fade-in-left animation-delay-600">
|
||
<div class="bg-white/10 backdrop-blur-sm rounded-2xl p-8 border border-yellow-400/30">
|
||
<h3 class="text-yellow-400 text-2xl font-bold mb-6 font-script">
|
||
Jum'at/Sabtu
|
||
</h3>
|
||
|
||
<div class="text-white text-3xl md:text-4xl font-bold mb-8">
|
||
{{ eventDate }}
|
||
</div>
|
||
|
||
<!-- Countdown Timer -->
|
||
<div class="grid grid-cols-4 gap-4 mb-6">
|
||
<div
|
||
v-for="(item, index) in countdownItems"
|
||
:key="index"
|
||
class="bg-blue-800/50 rounded-lg p-4 text-center border border-yellow-400/20"
|
||
>
|
||
<div class="text-yellow-400 text-2xl md:text-3xl font-bold">
|
||
{{ item.value }}
|
||
</div>
|
||
<div class="text-white text-sm uppercase tracking-wider">
|
||
{{ item.label }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Add to Calendar Button -->
|
||
<button
|
||
@click="addToCalendar"
|
||
class="bg-yellow-400 hover:bg-yellow-500 text-blue-900 px-6 py-3 rounded-full font-semibold transition-all duration-300 transform hover:scale-105"
|
||
>
|
||
Add to Calendar
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Location & Map -->
|
||
<div class="animate-fade-in-right animation-delay-600">
|
||
<div class="bg-white/10 backdrop-blur-sm rounded-2xl p-8 border border-yellow-400/30">
|
||
<div class="text-white mb-6">
|
||
<p class="text-lg mb-2">Pukul {{ eventTime }}</p>
|
||
<p class="text-lg mb-2">{{ eventLocation }}</p>
|
||
<p class="text-base opacity-80">{{ eventAddress }}</p>
|
||
</div>
|
||
|
||
<!-- Map Placeholder -->
|
||
<div class="bg-gray-300 rounded-lg h-32 mb-6 relative overflow-hidden">
|
||
<div class="absolute inset-0 bg-gradient-to-r from-blue-400 to-blue-600 opacity-50"></div>
|
||
<div class="absolute inset-0 flex items-center justify-center">
|
||
<Icon name="lucide:map-pin" class="w-8 h-8 text-white" />
|
||
</div>
|
||
<img
|
||
src="https://via.placeholder.com/400x200/4299e1/ffffff?text=Map+Preview"
|
||
alt="Location Map"
|
||
class="w-full h-full object-cover opacity-80"
|
||
/>
|
||
</div>
|
||
|
||
<!-- Direction Button -->
|
||
<button
|
||
@click="openMap"
|
||
class="bg-yellow-400 hover:bg-yellow-500 text-blue-900 px-6 py-3 rounded-full font-semibold transition-all duration-300 transform hover:scale-105"
|
||
>
|
||
Direction
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Decorative Elements -->
|
||
<div class="absolute inset-0 pointer-events-none overflow-hidden">
|
||
<div class="absolute top-0 left-1/2 transform -translate-x-1/2">
|
||
<svg viewBox="0 0 200 100" class="w-48 h-24 text-yellow-400 opacity-20">
|
||
<path d="M100 20 Q120 0 140 20 Q160 40 140 60 Q120 40 100 60 Q80 40 60 60 Q40 40 60 20 Q80 0 100 20" fill="currentColor"/>
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted, onUnmounted, computed } from 'vue'
|
||
|
||
// Props
|
||
const props = defineProps({
|
||
data: {
|
||
type: Object,
|
||
default: () => ({})
|
||
}
|
||
})
|
||
|
||
// computed agar template tidak merah
|
||
const eventDate = computed(() => props.data.eventDate || '20-21 Juni 2025')
|
||
const eventTime = computed(() => props.data.eventTime || '09.00 WIB s.d Selesai')
|
||
const eventLocation = computed(() => props.data.eventLocation || 'TMC Mangrove, Tanjung Pasir')
|
||
const eventAddress = computed(() => props.data.eventAddress || 'Desa Tanjung Pasir')
|
||
|
||
const childPhoto = computed(() => props.data.childPhoto || '/images/khitan/child-photo.jpg')
|
||
const childName = computed(() => props.data.childName || 'Satria Huda Dinata')
|
||
const childTitle = computed(() => props.data.childTitle || 'SATRIA HUDA DINATA')
|
||
const childSubtitle = computed(() => props.data.childSubtitle || 'Putra Ke Dua Dari')
|
||
const fatherName = computed(() => props.data.fatherName || 'Bpk H. Munawar Huda, S.H.')
|
||
const motherName = computed(() => props.data.motherName || 'Ibu Hj. Dinah, A.M.Keb')
|
||
|
||
// countdown
|
||
const countdown = ref({ days: 7, hours: 11, minutes: 21, seconds: 45 })
|
||
let countdownInterval = null
|
||
|
||
const countdownItems = computed(() => [
|
||
{ value: String(countdown.value.days).padStart(2, '0'), label: 'D' },
|
||
{ value: String(countdown.value.hours).padStart(2, '0'), label: 'H' },
|
||
{ value: String(countdown.value.minutes).padStart(2, '0'), label: 'M' },
|
||
{ value: String(countdown.value.seconds).padStart(2, '0'), label: 'S' }
|
||
])
|
||
|
||
const updateCountdown = () => {
|
||
const eventDateObj = new Date('2025-06-20T09:00:00')
|
||
const now = new Date()
|
||
const diff = eventDateObj.getTime() - now.getTime()
|
||
if (diff > 0) {
|
||
countdown.value = {
|
||
days: Math.floor(diff / (1000 * 60 * 60 * 24)),
|
||
hours: Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)),
|
||
minutes: Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)),
|
||
seconds: Math.floor((diff % (1000 * 60)) / 1000)
|
||
}
|
||
} else {
|
||
countdown.value = { days: 0, hours: 0, minutes: 0, seconds: 0 }
|
||
if (countdownInterval) clearInterval(countdownInterval)
|
||
}
|
||
}
|
||
|
||
const addToCalendar = () => {
|
||
const eventDetails = {
|
||
title: `Tasyakuran Khitan ${childName.value}`,
|
||
start: '20250620T090000Z',
|
||
end: '20250621T170000Z',
|
||
description: 'Undangan Tasyakuran Khitan',
|
||
location: eventLocation.value
|
||
}
|
||
const url = `https://calendar.google.com/calendar/render?action=TEMPLATE&text=${encodeURIComponent(eventDetails.title)}&dates=${eventDetails.start}/${eventDetails.end}&details=${encodeURIComponent(eventDetails.description)}&location=${encodeURIComponent(eventDetails.location)}`
|
||
window.open(url, '_blank')
|
||
}
|
||
|
||
const openMap = () => {
|
||
const location = encodeURIComponent(eventLocation.value)
|
||
window.open(`https://maps.google.com/maps?q=${location}`, '_blank')
|
||
}
|
||
|
||
const handleImageError = (e) => {
|
||
e.target.src = 'https://via.placeholder.com/128x128/4299e1/ffffff?text=Photo'
|
||
}
|
||
|
||
onMounted(() => {
|
||
updateCountdown()
|
||
countdownInterval = setInterval(updateCountdown, 1000)
|
||
})
|
||
|
||
onUnmounted(() => {
|
||
if (countdownInterval) clearInterval(countdownInterval)
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* ... tetap sama dengan punyamu, kecuali hapus selector .grid-cols-1.lg\:grid-cols-2 */
|
||
</style>
|