210 lines
7.9 KiB
Vue
210 lines
7.9 KiB
Vue
<template>
|
||
<div class="min-h-screen bg-gradient-to-br from-rose-50 via-pink-50 to-purple-50 flex items-center justify-center p-4">
|
||
<!-- Main Card -->
|
||
<div class="max-w-lg w-full">
|
||
<!-- Floating Animation Container -->
|
||
<div class="animate-float">
|
||
<div class="relative bg-white rounded-3xl shadow-2xl overflow-hidden">
|
||
<!-- Decorative Top Wave -->
|
||
<div class="absolute top-0 left-0 right-0 h-32 bg-gradient-to-r from-rose-400 to-pink-400 opacity-10">
|
||
<svg class="absolute bottom-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320">
|
||
<path fill="#ffffff" fill-opacity="1" d="M0,96L48,112C96,128,192,160,288,160C384,160,480,128,576,112C672,96,768,96,864,112C960,128,1056,160,1152,160C1248,160,1344,128,1392,112L1440,96L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z"></path>
|
||
</svg>
|
||
</div>
|
||
|
||
<!-- Header Image Section -->
|
||
<div class="relative h-64 overflow-hidden">
|
||
<div class="absolute inset-0 bg-gradient-to-b from-transparent to-white z-10"></div>
|
||
<img
|
||
:src="imageUrl"
|
||
alt="Wedding Template"
|
||
class="w-full h-full object-cover transform hover:scale-110 transition-transform duration-700"
|
||
/>
|
||
<!-- Ornamental Corner -->
|
||
<div class="absolute top-4 left-4 w-16 h-16 border-l-4 border-t-4 border-rose-300 rounded-tl-2xl"></div>
|
||
<div class="absolute top-4 right-4 w-16 h-16 border-r-4 border-t-4 border-rose-300 rounded-tr-2xl"></div>
|
||
</div>
|
||
|
||
<!-- Content Section -->
|
||
<div class="relative px-8 py-10 space-y-8">
|
||
<!-- Divider Line -->
|
||
<div class="flex items-center justify-center mb-8">
|
||
<div class="h-px w-12 bg-gradient-to-r from-transparent to-rose-300"></div>
|
||
<div class="mx-4">
|
||
<svg class="w-8 h-8 text-rose-400" fill="currentColor" viewBox="0 0 20 20">
|
||
<path fill-rule="evenodd" d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z" clip-rule="evenodd"/>
|
||
</svg>
|
||
</div>
|
||
<div class="h-px w-12 bg-gradient-to-l from-transparent to-rose-300"></div>
|
||
</div>
|
||
|
||
<!-- Names -->
|
||
<div class="text-center space-y-2">
|
||
<h1 class="text-4xl md:text-5xl font-serif font-bold bg-gradient-to-r from-rose-600 to-pink-600 bg-clip-text text-transparent animate-fade-in">
|
||
{{ formData.nama_pengantin || 'Undangan Pernikahan' }}
|
||
</h1>
|
||
<p class="text-gray-500 text-sm tracking-widest uppercase">The Wedding Of</p>
|
||
</div>
|
||
|
||
<!-- Date Section -->
|
||
<div class="bg-gradient-to-r from-rose-50 to-pink-50 rounded-2xl p-6 shadow-inner transform hover:scale-105 transition-transform duration-300">
|
||
<div class="flex items-center justify-center space-x-3 mb-2">
|
||
<svg class="w-6 h-6 text-rose-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
|
||
</svg>
|
||
<h2 class="text-lg font-semibold text-gray-700">Save The Date</h2>
|
||
</div>
|
||
<p class="text-center text-2xl font-serif text-gray-800">
|
||
{{ formatDate(formData.tanggal_acara) || 'Tanggal belum ditentukan' }}
|
||
</p>
|
||
</div>
|
||
|
||
<!-- Location Section -->
|
||
<div class="bg-gradient-to-r from-purple-50 to-pink-50 rounded-2xl p-6 shadow-inner transform hover:scale-105 transition-transform duration-300">
|
||
<div class="flex items-center justify-center space-x-3 mb-2">
|
||
<svg class="w-6 h-6 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"/>
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"/>
|
||
</svg>
|
||
<h2 class="text-lg font-semibold text-gray-700">Lokasi Acara</h2>
|
||
</div>
|
||
<p class="text-center text-xl text-gray-800 font-medium">
|
||
{{ formData.lokasi || 'Lokasi belum ditentukan' }}
|
||
</p>
|
||
</div>
|
||
|
||
<!-- Decorative Quote -->
|
||
<div class="text-center py-4">
|
||
<p class="text-sm text-gray-400 italic font-serif">
|
||
"Cinta adalah persahabatan yang telah terbakar"
|
||
</p>
|
||
</div>
|
||
|
||
<!-- Footer Badge -->
|
||
<div class="flex items-center justify-center pt-4">
|
||
<div class="bg-gradient-to-r from-rose-100 to-pink-100 px-6 py-2 rounded-full">
|
||
<p class="text-xs text-gray-600 font-medium">
|
||
{{ data.template?.nama_template }} •
|
||
<span class="uppercase">{{ data.template?.paket }}</span>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Decorative Bottom Corners -->
|
||
<div class="absolute bottom-4 left-4 w-16 h-16 border-l-4 border-b-4 border-rose-300 rounded-bl-2xl"></div>
|
||
<div class="absolute bottom-4 right-4 w-16 h-16 border-r-4 border-b-4 border-rose-300 rounded-br-2xl"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Floating Hearts Animation -->
|
||
<div class="fixed inset-0 pointer-events-none overflow-hidden -z-10">
|
||
<div class="heart-float" style="left: 10%; animation-delay: 0s;">❤️</div>
|
||
<div class="heart-float" style="left: 30%; animation-delay: 2s;">💕</div>
|
||
<div class="heart-float" style="left: 50%; animation-delay: 4s;">💖</div>
|
||
<div class="heart-float" style="left: 70%; animation-delay: 1s;">💗</div>
|
||
<div class="heart-float" style="left: 90%; animation-delay: 3s;">💝</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed } from 'vue'
|
||
import { useRuntimeConfig } from '#app'
|
||
|
||
const props = defineProps({
|
||
data: {
|
||
type: Object,
|
||
required: true,
|
||
validator: (data) => {
|
||
return data && typeof data === 'object' && 'template' in data
|
||
},
|
||
},
|
||
})
|
||
|
||
const config = useRuntimeConfig()
|
||
const backendUrl = config.public.apiBaseUrl
|
||
|
||
const formData = computed(() => props.data.form || {})
|
||
|
||
const imageUrl = computed(() => {
|
||
const foto = props.data.template?.foto
|
||
return foto
|
||
? `${backendUrl}/storage/${foto}`
|
||
: 'https://images.unsplash.com/photo-1519741497674-611481863552?w=800&h=600&fit=crop'
|
||
})
|
||
|
||
const formatDate = (dateString) => {
|
||
if (!dateString) return null
|
||
try {
|
||
const date = new Date(dateString)
|
||
if (isNaN(date.getTime())) return null
|
||
|
||
return date.toLocaleDateString('id-ID', {
|
||
weekday: 'long',
|
||
year: 'numeric',
|
||
month: 'long',
|
||
day: 'numeric',
|
||
})
|
||
} catch (error) {
|
||
console.error('Error formatting date:', error)
|
||
return null
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
@keyframes float {
|
||
0%, 100% {
|
||
transform: translateY(0px);
|
||
}
|
||
50% {
|
||
transform: translateY(-20px);
|
||
}
|
||
}
|
||
|
||
@keyframes fade-in {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(-10px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
@keyframes heart-float {
|
||
0% {
|
||
transform: translateY(100vh) rotate(0deg);
|
||
opacity: 0;
|
||
}
|
||
10% {
|
||
opacity: 1;
|
||
}
|
||
90% {
|
||
opacity: 1;
|
||
}
|
||
100% {
|
||
transform: translateY(-100vh) rotate(360deg);
|
||
opacity: 0;
|
||
}
|
||
}
|
||
|
||
.animate-float {
|
||
animation: float 6s ease-in-out infinite;
|
||
}
|
||
|
||
.animate-fade-in {
|
||
animation: fade-in 1s ease-out;
|
||
}
|
||
|
||
.heart-float {
|
||
position: absolute;
|
||
font-size: 1.5rem;
|
||
animation: heart-float 15s linear infinite;
|
||
bottom: -50px;
|
||
}
|
||
</style>
|