192 lines
5.8 KiB
Vue
192 lines
5.8 KiB
Vue
<template>
|
|
<section
|
|
class="w-full bg-gradient-to-b from-yellow-300 to-yellow-100 py-12 px-4 text-center relative overflow-hidden">
|
|
<!-- Judul -->
|
|
<h1 class="text-3xl md:text-4xl font-extrabold text-orange-700 mb-10">
|
|
🎉 BIRTHDAY PARTY 🎉
|
|
</h1>
|
|
|
|
<div class="max-w-6xl mx-auto grid md:grid-cols-2 gap-8 bg-yellow-200/50 rounded-3xl p-8 shadow-xl relative z-10">
|
|
<!-- Kolom Kiri - Google Map -->
|
|
<div class="flex flex-col items-center justify-center">
|
|
<iframe v-if="mapEmbed" class="w-full h-72 rounded-2xl shadow-lg" :src="mapEmbed" allowfullscreen
|
|
loading="lazy"></iframe>
|
|
<button
|
|
class="mt-4 bg-orange-700 hover:bg-orange-800 text-white font-semibold py-2 px-6 rounded-full shadow-md transition"
|
|
@click="openMap">
|
|
Direction
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Kolom Kanan - Detail Acara -->
|
|
<div class="text-center">
|
|
<h2 class="text-2xl md:text-3xl font-extrabold text-blue-900 mb-4">
|
|
BIRTHDAY PARTY
|
|
</h2>
|
|
|
|
<!-- Tanggal dan Waktu -->
|
|
<div class="flex justify-center items-center gap-6 mb-4">
|
|
<div>
|
|
<p class="text-4xl font-extrabold text-orange-700">
|
|
{{ eventDateNum || '-' }}
|
|
</p>
|
|
<p class="text-sm font-bold text-orange-800 uppercase">
|
|
{{ eventDayName || 'TANGGAL TIDAK VALID' }}<br />
|
|
{{ eventMonthYear || '' }}
|
|
</p>
|
|
</div>
|
|
<div class="border-l-2 border-orange-500 h-10"></div>
|
|
<div class="text-left">
|
|
<p class="text-lg font-semibold text-orange-700">
|
|
{{ props.waktu || '00.00' }} WIB
|
|
</p>
|
|
<p class="text-sm text-orange-800 font-bold">S.D SELESAI</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Lokasi -->
|
|
<p class="text-orange-900 font-medium mb-6 leading-relaxed">
|
|
{{ props.alamat || 'Belum ada alamat' }}
|
|
</p>
|
|
|
|
|
|
<!-- Countdown -->
|
|
<div v-if="countdownValid" class="flex justify-center gap-4 mb-6 text-white font-bold">
|
|
<div v-for="(value, label) in countdownDisplay" :key="label"
|
|
class="bg-orange-700 rounded-xl px-4 py-3 text-center shadow-md w-16">
|
|
<p class="text-2xl">{{ value }}</p>
|
|
<p class="text-xs uppercase">{{ label }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tombol Kalender -->
|
|
<button
|
|
class="bg-orange-700 hover:bg-orange-800 text-white font-semibold py-2 px-6 rounded-full shadow-md transition"
|
|
@click="addToCalendar">
|
|
Add to Calendar
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Gambar di bawah -->
|
|
<img src="/ABBAUF.png" alt="Logo" class="mx-auto mt-10 w-56 md:w-64" />
|
|
</section>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, onMounted } from 'vue'
|
|
|
|
const props = defineProps({
|
|
hari_tanggal_acara: String,
|
|
waktu: String,
|
|
alamat: String,
|
|
link_gmaps: String,
|
|
hitung_mundur: String,
|
|
})
|
|
|
|
// --- Format tanggal agar tidak invalid ---
|
|
const eventDate = computed(() => {
|
|
let dateString = props.hari_tanggal_acara
|
|
if (!dateString) return null
|
|
// Tambahkan waktu default agar format valid di semua browser
|
|
if (!dateString.includes('T')) {
|
|
dateString += 'T00:00:00Z'
|
|
}
|
|
const d = new Date(dateString)
|
|
return isNaN(d) ? null : d
|
|
})
|
|
|
|
const eventDateNum = computed(() => eventDate.value?.getDate() || null)
|
|
const eventDayName = computed(() =>
|
|
eventDate.value
|
|
? eventDate.value
|
|
.toLocaleDateString('id-ID', { weekday: 'long' })
|
|
.toUpperCase()
|
|
: null
|
|
)
|
|
const eventMonthYear = computed(() =>
|
|
eventDate.value
|
|
? eventDate.value
|
|
.toLocaleDateString('id-ID', { month: 'long', year: 'numeric' })
|
|
.toUpperCase()
|
|
: null
|
|
)
|
|
|
|
// --- Google Map Embed ---
|
|
const mapEmbed = computed(() => {
|
|
if (!props.link_gmaps || props.link_gmaps.trim() === '') return null
|
|
if (props.link_gmaps.includes('/embed?')) return props.link_gmaps
|
|
return `https://www.google.com/maps?q=${encodeURIComponent(
|
|
props.link_gmaps
|
|
)}&output=embed`
|
|
})
|
|
|
|
const openMap = () => {
|
|
if (props.link_gmaps && props.link_gmaps.trim() !== '') {
|
|
window.open(props.link_gmaps, '_blank')
|
|
}
|
|
}
|
|
|
|
// --- Countdown ---
|
|
const countdown = ref({ days: 0, hours: 0, minutes: 0, seconds: 0 })
|
|
const countdownValid = ref(false)
|
|
|
|
onMounted(() => {
|
|
let targetString = props.hitung_mundur
|
|
if (!targetString) return
|
|
if (!targetString.includes('T')) {
|
|
targetString += 'T00:00:00'
|
|
}
|
|
const target = new Date(targetString)
|
|
if (isNaN(target)) return
|
|
|
|
countdownValid.value = true
|
|
setInterval(() => {
|
|
const now = new Date().getTime()
|
|
const diff = target.getTime() - now
|
|
if (diff <= 0) return
|
|
countdown.value = {
|
|
days: Math.floor(diff / (1000 * 60 * 60 * 24)),
|
|
hours: Math.floor((diff / (1000 * 60 * 60)) % 24),
|
|
minutes: Math.floor((diff / (1000 * 60)) % 60),
|
|
seconds: Math.floor((diff / 1000) % 60),
|
|
}
|
|
}, 1000)
|
|
})
|
|
|
|
const countdownDisplay = computed(() => ({
|
|
D: countdown.value.days,
|
|
H: countdown.value.hours,
|
|
M: countdown.value.minutes,
|
|
S: countdown.value.seconds,
|
|
}))
|
|
|
|
// --- Add to Calendar ---
|
|
const addToCalendar = () => {
|
|
const title = 'Birthday Party'
|
|
let dateString = props.hari_tanggal_acara
|
|
if (!dateString) return
|
|
if (!dateString.includes('T')) {
|
|
dateString += 'T00:00:00'
|
|
}
|
|
const startDate = new Date(dateString)
|
|
const endDate = new Date(startDate.getTime() + 2 * 60 * 60 * 1000) // +2 jam
|
|
|
|
const start = startDate.toISOString().replace(/-|:|\.\d+/g, '')
|
|
const end = endDate.toISOString().replace(/-|:|\.\d+/g, '')
|
|
|
|
const url = `https://calendar.google.com/calendar/render?action=TEMPLATE&text=${encodeURIComponent(
|
|
title
|
|
)}&dates=${start}/${end}&details=${encodeURIComponent(
|
|
'Acara Ulang Tahun di ' + (props.alamat || '')
|
|
)}`
|
|
window.open(url, '_blank')
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
section {
|
|
position: relative;
|
|
}
|
|
</style>
|