commit
beef8fb0da
4 changed files with 351 additions and 0 deletions
|
After Width: | Height: | Size: 194 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
@ -0,0 +1,17 @@ |
|||||
|
{ |
||||
|
"pageTitle": "Pagina de mi mascota", |
||||
|
"backgroundImageUrl": "assets/pet_bg.png", |
||||
|
"matchText": "¡Mi Perro!", |
||||
|
"centerImage": "assets/perro.jpg", |
||||
|
"description": "Conoce a mi mascota. Un compañero fiel y lleno de amor que alegra cada día con su presencia.", |
||||
|
"instagram": { |
||||
|
"url": "https://www.instagram.com/explore/tags/pets/", |
||||
|
"icon": "fab fa-instagram", |
||||
|
"name": "Instagram" |
||||
|
}, |
||||
|
"facebook": { |
||||
|
"url": "", |
||||
|
"icon": "fab fa-facebook", |
||||
|
"name": "Facebook" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,334 @@ |
|||||
|
<!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> |
||||
Loading…
Reference in new issue