You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
334 lines
8.5 KiB
334 lines
8.5 KiB
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Mi Mascota Adorable</title>
|
|
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css">
|
|
<style>
|
|
body,
|
|
html {
|
|
margin: 0;
|
|
padding: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
overflow: hidden;
|
|
}
|
|
|
|
body {
|
|
/* Background image will be set dynamically via JavaScript */
|
|
background-size: cover;
|
|
background-position: center;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
#app {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 100%;
|
|
}
|
|
|
|
.pet-overlay {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
/* background-color: rgba(0, 0, 0, 0.7); */
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
opacity: 0;
|
|
animation: fadeIn 0.5s ease-in-out forwards;
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from {
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.pet-text {
|
|
color: white;
|
|
padding-left: 0.25em;
|
|
padding-right: 0.25em;
|
|
font-size: 4rem;
|
|
font-weight: bold;
|
|
text-align: center;
|
|
animation: scaleUp 0.7s ease-in-out 0.3s forwards;
|
|
transform: scale(0);
|
|
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
@keyframes scaleUp {
|
|
from {
|
|
transform: scale(0);
|
|
}
|
|
|
|
to {
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
.pet-images {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
margin-top: 2rem;
|
|
}
|
|
|
|
.pet-image {
|
|
width: 220px;
|
|
height: 220px;
|
|
border-radius: 50%;
|
|
border: 5px solid white;
|
|
background-size: cover;
|
|
background-position: center;
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
|
|
animation: scaleIn 0.8s ease-out 0.8s forwards;
|
|
transform: scale(0);
|
|
opacity: 0;
|
|
}
|
|
|
|
@keyframes scaleIn {
|
|
from {
|
|
transform: scale(0);
|
|
opacity: 0;
|
|
}
|
|
to {
|
|
transform: scale(1);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes slideInLeft {
|
|
from {
|
|
transform: translateX(-200px);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
transform: translateX(0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes slideInRight {
|
|
from {
|
|
transform: translateX(200px);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
transform: translateX(0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.pet-info {
|
|
color: white;
|
|
margin-top: 2rem;
|
|
text-align: center;
|
|
max-width: 600px;
|
|
opacity: 0;
|
|
animation: fadeIn 1s ease-in-out 1.5s forwards;
|
|
}
|
|
|
|
.social-links {
|
|
position: absolute;
|
|
bottom: 20px;
|
|
width: 100%;
|
|
text-align: center;
|
|
}
|
|
|
|
.social-links a {
|
|
color: white;
|
|
margin: 0 15px;
|
|
font-size: 2rem;
|
|
text-decoration: none;
|
|
transition: transform 0.3s ease;
|
|
}
|
|
|
|
.social-links a:hover {
|
|
transform: scale(1.2);
|
|
}
|
|
|
|
.paw-print {
|
|
position: absolute;
|
|
font-size: 2rem;
|
|
color: rgba(255, 255, 255, 0.3);
|
|
animation: float 3s infinite ease-in-out;
|
|
}
|
|
|
|
.heart-print {
|
|
position: absolute;
|
|
color: rgba(255, 105, 180, 0.3);
|
|
animation: pulse 4s infinite ease-in-out;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0% {
|
|
transform: scale(1) rotate(0deg);
|
|
opacity: 0.3;
|
|
}
|
|
50% {
|
|
transform: scale(1.3) rotate(15deg);
|
|
opacity: 0.6;
|
|
}
|
|
100% {
|
|
transform: scale(1) rotate(0deg);
|
|
opacity: 0.3;
|
|
}
|
|
}
|
|
|
|
@keyframes float {
|
|
0% {
|
|
transform: translateY(0) rotate(0deg);
|
|
}
|
|
50% {
|
|
transform: translateY(-20px) rotate(10deg);
|
|
}
|
|
100% {
|
|
transform: translateY(0) rotate(0deg);
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div id="app">
|
|
<div v-if="isLoading" class="pet-overlay">
|
|
<div class="pet-text">Loading...</div>
|
|
</div>
|
|
<div v-else-if="error" class="pet-overlay">
|
|
<div class="pet-text">Error loading configuration</div>
|
|
<div style="color: white; margin-top: 1rem; font-size: 1rem;">{{ error }}</div>
|
|
</div>
|
|
<div v-else-if="showPet" class="pet-overlay">
|
|
<!-- Decorative paw and heart prints -->
|
|
<i v-for="(paw, index) in pawPrints" :key="'paw-'+index" class="fas fa-paw paw-print"
|
|
:style="{ top: paw.top + '%', left: paw.left + '%', animationDelay: paw.delay + 's' }"></i>
|
|
<i v-for="(heart, index) in heartPrints" :key="'heart-'+index" class="fas fa-heart heart-print"
|
|
:style="{ top: heart.top + '%', left: heart.left + '%', animationDelay: heart.delay + 's', fontSize: heart.size + 'rem' }"></i>
|
|
|
|
<div class="pet-text">{{ config.matchText }}</div>
|
|
<div class="pet-images">
|
|
<div ref="centerImage" class="pet-image"></div>
|
|
</div>
|
|
<div class="pet-info">
|
|
<p>{{ config.description }}</p>
|
|
</div>
|
|
</div>
|
|
<div v-if="!isLoading && !error" class="social-links">
|
|
<a v-for="social in visibleSocialLinks" :key="social.name" :href="social.url" target="_blank">
|
|
<i :class="social.icon"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const { createApp, ref, onMounted, computed, nextTick } = Vue;
|
|
|
|
createApp({
|
|
setup() {
|
|
const showPet = ref(false);
|
|
const config = ref({});
|
|
const isLoading = ref(true);
|
|
const error = ref(null);
|
|
|
|
// Template ref for the image element
|
|
const centerImage = ref(null);
|
|
|
|
// Generate random paw prints for decoration
|
|
const pawPrints = Array.from({ length: 6 }, (_, i) => ({
|
|
top: Math.random() * 100,
|
|
left: Math.random() * 100,
|
|
delay: Math.random() * 5
|
|
}));
|
|
|
|
// Generate random heart prints for decoration
|
|
const heartPrints = Array.from({ length: 6 }, (_, i) => ({
|
|
top: Math.random() * 100,
|
|
left: Math.random() * 100,
|
|
delay: Math.random() * 5,
|
|
size: 1 + Math.random() * 2.5 // Random size between 1rem and 2.5rem
|
|
}));
|
|
|
|
// Function to load configuration from data.json
|
|
const loadConfig = async () => {
|
|
try {
|
|
const dataJsonPath = './data.json';
|
|
const response = await fetch(dataJsonPath, { cache: 'no-store', headers: { 'Cache-Control': 'no-cache' } });
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
const data = await response.json();
|
|
config.value = data;
|
|
isLoading.value = false;
|
|
} catch (err) {
|
|
console.error('Error loading configuration:', err);
|
|
error.value = err.message;
|
|
isLoading.value = false;
|
|
}
|
|
};
|
|
|
|
// Function to set the pet image
|
|
const setMatchImages = async () => {
|
|
await nextTick(); // Wait for DOM to be updated
|
|
|
|
if (centerImage.value && config.value.centerImage) {
|
|
centerImage.value.style.backgroundImage = `url('${config.value.centerImage}')`;
|
|
}
|
|
};
|
|
|
|
// Computed property to filter social links that have URLs
|
|
const visibleSocialLinks = computed(() => {
|
|
const socialPlatforms = ['github', 'linkedin', 'twitter', 'instagram', 'facebook'];
|
|
return socialPlatforms
|
|
.map(platform => config.value[platform])
|
|
.filter(social => social && social.url && social.url.trim() !== "");
|
|
});
|
|
|
|
onMounted(async () => {
|
|
// Load configuration from data.json
|
|
await loadConfig();
|
|
|
|
// Set dynamic page title
|
|
document.title = config.value.pageTitle;
|
|
|
|
// Set dynamic background image
|
|
document.body.style.backgroundImage = `url('${config.value.backgroundImageUrl}')`;
|
|
|
|
setTimeout(async () => {
|
|
showPet.value = true;
|
|
// Set pet images after the pet overlay is shown
|
|
await setMatchImages();
|
|
}, 500);
|
|
});
|
|
|
|
return {
|
|
showPet,
|
|
config,
|
|
visibleSocialLinks,
|
|
isLoading,
|
|
error,
|
|
centerImage,
|
|
pawPrints,
|
|
heartPrints
|
|
};
|
|
}
|
|
}).mount('#app');
|
|
</script>
|
|
</body>
|
|
|
|
</html>
|
|
|