Repository: midudev/lolalolitaland.com
Branch: main
Commit: ea0cc3c2c2aa
Files: 44
Total size: 136.1 KB
Directory structure:
gitextract_oiw4y92l/
├── .editorconfig
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .vscode/
│ ├── css_custom_tailwind.json
│ ├── extensions.json
│ ├── launch.json
│ └── settings.json
├── CONTRIBUTING.md
├── README.md
├── astro.config.mjs
├── package.json
├── public/
│ ├── events/
│ │ └── event-lolalolita.ics
│ └── googlee0d1fc8a4713db25.html
├── pull_request_template.md
├── src/
│ ├── components/
│ │ ├── BackToTop.astro
│ │ ├── BubbleBackground.astro
│ │ ├── DotBackground.astro
│ │ ├── Header.astro
│ │ ├── HeaderLink.astro
│ │ ├── LeafletMap.astro
│ │ ├── Marquee.astro
│ │ ├── Sponsor.astro
│ │ ├── SponsorsBar.astro
│ │ ├── StarryBackground.astro
│ │ └── WaveSeparator.astro
│ ├── consts/
│ │ ├── galleryImages.ts
│ │ ├── geoJSONData.ts
│ │ └── map-styles.js
│ ├── layouts/
│ │ └── Layout.astro
│ ├── pages/
│ │ ├── 404.astro
│ │ └── index.astro
│ ├── sections/
│ │ ├── ComoLlegar.astro
│ │ ├── FAQ.astro
│ │ ├── Footer.astro
│ │ ├── Gallery.astro
│ │ ├── Hero.astro
│ │ ├── Info.astro
│ │ ├── Map.astro
│ │ ├── Rides.astro
│ │ └── Tickets.astro
│ └── styles/
│ └── global.css
├── tailwind.config.js
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
================================================
FILE: .gitignore
================================================
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store
# jetbrains setting folder
.idea/
package-lock.json
bun.lock
bun.lockb
yarn.lock
================================================
FILE: .prettierignore
================================================
# build output
dist/
.output/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store
# Astro generated files
.astro/
# Lock files
package-lock.json
yarn.lock
pnpm-lock.yaml
================================================
FILE: .prettierrc
================================================
{
"printWidth": 100,
"semi": false,
"singleQuote": false,
"tabWidth": 2,
"trailingComma": "es5",
"useTabs": false,
"plugins": ["prettier-plugin-astro", "prettier-plugin-tailwindcss"],
"overrides": [
{
"files": "*.astro",
"options": {
"parser": "astro"
}
}
]
}
================================================
FILE: .vscode/css_custom_tailwind.json
================================================
{
"version": 4.0,
"atDirectives": [
{
"name": "@theme",
"description": "Use the `@theme` directive to define your project's custom design tokens, like fonts, colors, and breakpoints",
"references": [
{
"name": "Tailwind Documentation — Functions and directives",
"url": "https://tailwindcss.com/docs/functions-and-directives#theme-directive"
}
]
},
{
"name": "@source",
"description": "Use the `@source` directive to explicitly specify source files that aren't picked up by Tailwind's automatic content detection",
"references": [
{
"name": "Tailwind Documentation — Functions and directives",
"url": "https://tailwindcss.com/docs/functions-and-directives#source-directive"
}
]
},
{
"name": "@utility",
"description": "Use the `@utility` directive to add custom utilities to your project that work with variants like `hover`, `focus` and `lg`",
"references": [
{
"name": "Tailwind Documentation — Functions and directives",
"url": "https://tailwindcss.com/docs/functions-and-directives#utility-directive"
}
]
},
{
"name": "@variant",
"description": "Use the `@variant` directive to apply a Tailwind variant to styles in your CSS",
"references": [
{
"name": "Tailwind Documentation — Functions and directives",
"url": "https://tailwindcss.com/docs/functions-and-directives#variant-directive"
}
]
},
{
"name": "@custom-variant",
"description": "Use the `@custom-variant` directive to add a custom variant in your project",
"references": [
{
"name": "Tailwind Documentation — Functions and directives",
"url": "https://tailwindcss.com/docs/functions-and-directives#custom-variant-directive"
}
]
},
{
"name": "@apply",
"description": "Use the `@apply` directive to inline any existing utility classes into your own custom CSS",
"references": [
{
"name": "Tailwind Documentation — Functions and directives",
"url": "https://tailwindcss.com/docs/functions-and-directives#apply-directive"
}
]
},
{
"name": "@reference",
"description": "If you want to use `@apply` or `@variant` in the `<style>` block of a Vue or Svelte component, or within CSS modules, you will need to import your theme variables, custom utilities, and custom variants to make those values available in that context",
"references": [
{
"name": "Tailwind Documentation — Functions and directives",
"url": "https://tailwindcss.com/docs/functions-and-directives#reference-directive"
}
]
},
{
"name": "@config",
"description": "Use the `@config` directive to load a legacy JavaScript-based configuration file",
"references": [
{
"name": "Tailwind Documentation — Functions and directives",
"url": "https://tailwindcss.com/docs/functions-and-directives#config-directive"
}
]
},
{
"name": "@plugin",
"description": "Use the `@plugin` directive to load a legacy JavaScript-based plugin",
"references": [
{
"name": "Tailwind Documentation — Functions and directives",
"url": "https://tailwindcss.com/docs/functions-and-directives#plugin-directive"
}
]
}
]
}
================================================
FILE: .vscode/extensions.json
================================================
{
"recommendations": [
"astro-build.astro-vscode",
"bradlc.vscode-tailwindcss",
"esbenp.prettier-vscode",
"editorconfig.editorconfig"
]
}
================================================
FILE: .vscode/launch.json
================================================
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}
================================================
FILE: .vscode/settings.json
================================================
{
"css.customData": [".vscode/css_custom_tailwind.json"],
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[astro]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"prettier.documentSelectors": ["**/*.astro"],
"editor.tabSize": 2,
"editor.insertSpaces": true
}
================================================
FILE: CONTRIBUTING.md
================================================
## 🤝 Cómo Contribuir
Las contribuciones son lo que hacen que la comunidad de código abierto sea un lugar increíble para aprender, inspirar y crear. ¡Cualquier contribución que hagas es **muy apreciada**!
Si tienes alguna sugerencia que podría mejorar el proyecto, por favor haz un [_fork_](https://github.com/midudev/lolalolitaland.com/fork) del repositorio y crea una [_pull request_](https://github.com/midudev/lolalolitaland.com/pulls). También puedes simplemente abrir un [_issue_](https://github.com/midudev/lolalolitaland.com/issues) con la etiqueta "enhancement".
Aquí tienes una guía rápida:
1. Haz un [_fork_](https://github.com/midudev/lolalolitaland.com/fork) del Proyecto
2. Clona tu fork (`git clone https://github.com/<USERNAME>/lolalolitaland.com`)
3. Añade el repositorio original como remoto (`git remote add upstream https://github.com/midudev/lolalolitaland.com.git`)
4. Crea tu Rama de Funcionalidad (`git switch -c feature/CaracteristicaIncreible`)
5. Realiza tus Cambios (`git commit -m 'Add: alguna CaracterísticaIncreible'`)
6. Haz Push a la Rama (`git push origin feature/CaracteristicaIncreible`)
7. Abre una [_pull request_](https://github.com/midudev/lolalolitaland.com/pulls)
Por favor, consulta nuestra [guía de contribución aquí](https://github.com/midudev/lolalolitaland.com/blob/master/CONTRIBUTING.md) para saber cómo puedes empezar de la mejor manera y siguiendo [buenas prácticas](https://github.com/midudev/lolalolitaland.com/blob/main/CONTRIBUTING.md#buenas-prácticas-).
### Contribuir desde Stackblitz
Si quieres contribuir de una manera más sencilla, puedes iniciar este proyecto desde _Stackblitz_ usando tu cuenta de GitHub:
[](https://stackblitz.com/github/midudev/lolalolitaland.com)
> [!NOTE]
>
> Nota: antes de codificar una nueva funcionalidad ve a la
> sección de issues y PRs del repositorio y verifica que ya no se
> esté discutiendo sobre ese tema, o que ya otra persona no lo
> haya realizado.
### 📋 Estándares de Código
#### Commits
Si es posible describe tus proyectos para que los mantenedores los puedan analizar de una forma más rápida y eficiente.
- `feat:` - Nuevas características
- `fix:` - Correcciones de bugs
- `docs:` - Cambios en documentación
- `style:` - Cambios que no afectan el código (espacios, formato, etc)
- `refactor:` - Refactorización del código
- `test:` - Añadir o modificar tests
- `chore:` - Cambios en el proceso de build o herramientas auxiliares
Ejemplo: `feat: add newsletter subscription component`
#### Código
- Utiliza en lo posible el estilo de codificación configurado
- Nombra las variables y funciones en camelCase
- Utiliza nombres descriptivos en variables y funciones
- Los componentes de Astro deben ir en PascalCase
- Comenta tu código cuando solo sea necesario
- Sigue las reglas de ESLint configuradas en el proyecto
#### CSS/TailwindCSS
- Utiliza las clases de Tailwind siempre que sea posible
- Evita CSS personalizado a menos que sea absolutamente necesario
#### Pull Requests
- Describe claramente los cambios realizados
- Incluye capturas de pantalla si hay cambios visuales
- Asegúrate de que los tests pasen
- Referencia los issues relacionados si los hay
- Mantén los PR pequeños y enfocados en una sola característica
### For de contribuir
- Todos los aportes son importantes
- Codificación
- Pruebas manuales o automatizadas
- Traducciones, correcciones ortográficas
### 🚫 Qué evitar
- No hagas commit directamente a `main`
- No uses `!important` en CSS
- No dejes console.logs en el código
- No añadas dependencias sin discutirlo primero
- No modifiques la configuración del proyecto sin consenso
- Evita ser grosero o imponerte en las discusiones
### 👥 Proceso de Review
1. Los PR necesitan al menos una aprobación
2. Atiende los comentarios del review
3. Asegúrate de que el CI/CD pase
## Estructura del Proyecto
```
└── 📁lolalolitaland.com
└── 📁public <-- images, fonts, Svgs
└── 📁src
└── 📁components
└── 📁consts
└── 📁layouts
└── 📁pages
└── 📁sections
└── 📁styles
```
<p align="right"><a href="#readme-top">volver arriba ⬆️</a></p>
================================================
FILE: README.md
================================================
# 🌸 LOLA LOLITA LAND 🌸 - Sitio Web Oficial 2025
Este proyecto es una iniciativa de la influencer [@lolalolita](https://www.instagram.com/lolalolita) se realiza el 15 y 16 de Junio del 2025 en Aquopolis, Madrid. Sitio web desarrollado por [midudev](https://twitch.tv/midudev), gracias a la colaboración de [@infojobs](https://www.infojobs.net/).

🖼️ Diseño en Figma (Pendiente...)
### 📝 Licencia del Proyecto
Ten en cuenta que este proyecto es de código abierto y abierto a contribuciones de la comunidad pero **su licencia no permite trabajos derivados, ni gratuitos ni comerciales**. <!-- Revisa el archivo [LICENSE.md](LICENSE.md) para más información. -->
### 🛠️ Tecnologías
- [Astro 5](https://astro.build)
- [TailwindCSS 4.0](https://tailwindcss.com)
## 🔧 Instalación
Instala las dependencias
```sh
pnpm install
```
Inicia el proyecto en modo desarrollo
```sh
pnpm run dev
```
## 🤝 Cómo Contribuir
Las contribuciones hacen que la comunidad de código abierto sea un lugar increíble para aprender, inspirarse y crear. ¡Cualquier contribución que hagas será muy apreciada! [guia de contribución✨](https://github.com/midudev/lolalolitaland.com/blob/master/CONTRIBUTING.md)
¡Happy Code! 🎉
## Colaboradores
**¡Gracias a todos los colaboradores que han hecho posible este proyecto!**
[](https://github.com/midudev/lolalolitaland.com/graphs/contributors)
================================================
FILE: astro.config.mjs
================================================
// @ts-check
import { defineConfig } from "astro/config"
import tailwindcss from "@tailwindcss/vite"
// https://astro.build/config
export default defineConfig({
vite: {
plugins: [tailwindcss()],
},
build: {
inlineStylesheets: "always",
},
})
================================================
FILE: package.json
================================================
{
"name": "lolalolitaland-com-v2",
"type": "module",
"version": "0.0.3",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@fontsource/poppins": "5.2.6",
"@midudev/tailwind-animations": "0.2.0",
"@tailwindcss/vite": "4.1.10",
"astro": "5.9.4",
"geojson": "0.5.0",
"leaflet": "1.9.4",
"sharp": "0.34.2",
"tailwindcss": "4.1.10"
},
"devDependencies": {
"@types/geojson": "7946.0.16",
"@types/leaflet": "1.9.18",
"prettier": "3.5.3",
"prettier-plugin-astro": "0.14.1",
"prettier-plugin-tailwindcss": "0.6.12"
}
}
================================================
FILE: public/events/event-lolalolita.ics
================================================
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//NONSGML iCal//EN
BEGIN:VEVENT
SUMMARY:Lola Lolita Land 🌸
DTSTART;VALUE=DATE:20250614
DTEND;VALUE=DATE:20250616
DESCRIPTION:La experiencia más refrescante.
LOCATION:Aquópolis Villanueva de la Cañada
UID:20250614T000000Z-1234567890@yourdomain.com
STATUS:CONFIRMED
TRANSP:OPAQUE
BEGIN:VALARM
TRIGGER:-PT15M
DESCRIPTION:Recordatorio: Lola Lolita Land 🌸
ACTION:DISPLAY
END:VALARM
END:VEVENT
END:VCALENDAR
================================================
FILE: public/googlee0d1fc8a4713db25.html
================================================
google-site-verification: googlee0d1fc8a4713db25.html
================================================
FILE: pull_request_template.md
================================================
## ¿Qué se ha hecho en esta PR?
Se ha añadido una plantilla mejorada para las Pull Requests (PR) del proyecto, con el objetivo de estandarizar y facilitar la descripción de los cambios realizados.
Esta nueva plantilla proporciona una estructura clara y consistente para los desarrolladores al documentar sus PRs, mejorando la comunicación dentro del equipo. En esta parte se describirá lo que se ha hecho.
**Arregla:** *(Indica aquí si arregla algún issue, ya sea en JIRA, GitHub u otra herramienta)*
---
## Tipo de cambio
Marca las opciones relevantes para esta PR:
- [ ] Corrección de errores (cambio no disruptivo que soluciona un problema)
- [ ] Nueva funcionalidad (cambio no disruptivo que añade una nueva funcionalidad)
- [ ] Cambio disruptivo (corrección o funcionalidad que causa que una funcionalidad existente no funcione como se espera)
- [ ] Mejora de documentación
---
## ¿Se han realizado tests automáticos?
- [ ] Sí
- [ ] No
---
## ¿Cuál es el comportamiento esperado tras el cambio?
Por ejemplo:
No afecta al comportamiento del producto final.
El objetivo es proporcionar una herramienta útil para los desarrolladores del equipo, mejorando la calidad de las descripciones de PR.
---
## ¿Cómo se pueden testear las características introducidas en esta PR?
Por ejemplo:
No es necesario realizar pruebas, ya que el cambio únicamente afecta al archivo de plantilla de PR y no a funcionalidades del producto.
---
## Capturas de pantalla
<!-- Si es necesario, añade capturas de pantalla u otros elementos visuales que ayuden a entender los cambios realizados -->
No se requieren capturas de pantalla.
---
## Enlaces adicionales
Poner enlaces necesarios aquí, si no hay poner:
No hay enlaces adicionales.
================================================
FILE: src/components/BackToTop.astro
================================================
<!-- Div para observar el scroll y mostrar/ocultar el botón -->
<div
id="scroll-observer"
class="pointer-events-none absolute top-[300px] left-0 h-[1px] w-[1px]"
aria-hidden="true"
>
</div>
<a
class="via-theme-blue hover:to-theme-blue fixed right-8 bottom-8 z-40 flex h-12 w-12 flex-col items-center justify-center overflow-hidden rounded-full bg-gradient-to-r from-blue-500 to-blue-400 opacity-0 shadow-lg"
id="back-to-top"
href="#top"
aria-label="Volver arriba"
>
<svg viewBox="0 0 384 512" class="absolute h-5 w-4">
<path
fill="#fff"
d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"
></path>
</svg>
</a>
<style>
a {
border: none;
border-radius: 50%;
transition: 500ms;
animation: shimmer 3s linear infinite;
}
a svg {
fill: white;
position: absolute;
}
a::after {
content: "Volver Arriba";
position: fixed;
transform: translateY(35px);
font-size: 14px;
transition: 500ms;
color: transparent;
user-select: none;
}
a:hover::after {
color: white;
mix-blend-mode: difference;
}
a:hover svg {
animation: bounce 2s infinite linear;
}
a::before {
content: "";
z-index: 10;
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.3), transparent);
transform: rotate(30deg);
animation: shine 3s linear infinite;
}
@keyframes bounce {
0% {
transform: translateY(4%);
}
25% {
transform: translateY(-8%);
}
50% {
transform: translateY(4%);
}
75% {
transform: translateY(-8%);
}
100% {
transform: translateY(4%);
}
}
button:focus {
outline: none;
}
@keyframes shimmer {
0% {
background-position: 0% 0;
}
100% {
background-position: 200% 0;
}
}
@keyframes shine {
0% {
transform: translateX(-100%) rotate(30deg);
}
100% {
transform: translateX(100%) rotate(30deg);
}
}
</style>
<script>
if (typeof document !== "undefined") {
const manageBackToTopButton = () => {
const button = document.getElementById("back-to-top")
const observerTarget = document.getElementById("scroll-observer")
if (!button || !observerTarget) return
const updateButtonVisibility = (shouldShow: boolean) => {
requestAnimationFrame(() => {
if (shouldShow) {
button.classList.remove("opacity-0")
button.classList.add("opacity-100")
button.classList.add("cursor-pointer")
button.classList.remove("cursor-default")
} else {
button.classList.remove("opacity-100")
button.classList.add("opacity-0")
button.classList.remove("cursor-pointer")
button.classList.add("cursor-default")
}
})
}
const observer = new IntersectionObserver(
(entries) => {
const isScrolledDown = !entries[0].isIntersecting
updateButtonVisibility(isScrolledDown)
},
{ threshold: 0 }
)
observer.observe(observerTarget)
return () => {
observer.disconnect()
}
}
const initialize = () => {
manageBackToTopButton()
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initialize)
} else {
initialize()
}
}
</script>
================================================
FILE: src/components/BubbleBackground.astro
================================================
---
const bubbles = Array.from({ length: 30 }, (_, i) => ({
id: i + 1,
size: `${Math.random() * 30 + 10}px`,
left: `${Math.random() * 95}%`,
top: `${Math.random() * 95}%`,
delay: `${Math.random() * 3}s`, // Minimal delay for faster start
duration: `${Math.random() * 3 + 2}s`, // Super fast animations (2-5s)
}))
const instanceId = Math.random().toString(36).substring(2, 9)
---
<style>
.bubble {
@apply absolute rounded-full bg-radial-[at_50%_75%] from-[transparent] via-[#bedbff6f] to-[transparent] to-90%;
bottom: -10px; /* Start slightly below the container */
will-change: transform, opacity;
opacity: 0; /* Start transparent */
border: 1px solid #e4e4e4;
box-shadow: 0 0 8px rgba(255, 255, 255, 0.3); /* Enhanced glow */
contain: strict;
}
.tickets-button {
background-size: 200% 100%;
position: relative;
overflow: hidden;
}
.tickets-button::before {
content: "";
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.3), transparent);
transform: rotate(30deg);
animation: shine 3s linear infinite;
}
@keyframes shimmer {
100% {
background-position: 200% 0;
}
}
@keyframes shine {
0% {
transform: translateX(-100%) rotate(30deg);
}
100% {
transform: translateX(100%) rotate(50deg);
}
}
@keyframes bubbles {
0% {
transform: translateY(0);
opacity: 0;
background-position: 0% 0;
}
3% {
/* Even faster fade in */
transform: translateY(-10%);
}
30% {
/* Faster midpoint */
transform: translateY(-100%);
opacity: 0.7;
}
70% {
transform: translateY(-200%);
opacity: 0.5;
}
100% {
transform: translateY(-300%); /* Much longer travel distance */
opacity: 0;
background-position: 200% 0;
}
}
</style>
<div class="ocean pointer-events-none absolute inset-0 h-full overflow-hidden" data-id={instanceId}>
{
bubbles.map(({ size, left, duration, delay }) => (
<div
class="bubble tickets-button"
style={`
width: ${size};
height: ${size};
left: ${left};
animation:
bubbles ${duration} linear infinite ${delay},
shimmer 3s linear infinite;
`}
/>
))
}
</div>
================================================
FILE: src/components/DotBackground.astro
================================================
<div class="dot-background-container">
<canvas id="dotCanvas" class="dot-canvas"></canvas>
</div>
<style>
.dot-background-container {
position: fixed; /* Cambiado a fixed para seguir la ventana */
top: 0;
left: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
z-index: -10; /* Valor negativo para asegurar que esté detrás de todo */
pointer-events: none;
}
.dot-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none; /* Cambiado a none para que no interfiera con otros elementos */
}
</style>
<script>
class DotBackground {
canvas: HTMLCanvasElement
ctx: CanvasRenderingContext2D
dots: Array<{
x: number
y: number
color: string
targetColor: string
alpha: number
targetAlpha?: number
size: number
}>
mouse: { x: number; y: number }
radius: number
pinkColor: string
grayColor: string
dotSize: number
dotSpacing: number
animationFrameId: number | null
constructor() {
this.canvas = document.getElementById("dotCanvas") as HTMLCanvasElement
this.ctx = this.canvas.getContext("2d") as CanvasRenderingContext2D
this.dots = []
this.mouse = { x: 0, y: 0 }
this.radius = 100 // Radio de influencia del ratón reducido
this.pinkColor = "#fff"
this.grayColor = "#fff"
this.dotSize = 1.0 // Puntos ligeramente más pequeños
this.dotSpacing = 30 // Puntos más juntos
this.animationFrameId = null
// Inicializar todo
this.init()
}
init() {
this.setupCanvas()
this.createDots()
this.setupEventListeners()
this.animate()
}
setupCanvas() {
// Configurar el canvas para que ocupe toda la ventana visible
const dpr = window.devicePixelRatio || 1
this.canvas.width = window.innerWidth * dpr
this.canvas.height = window.innerHeight * dpr
this.ctx.scale(dpr, dpr)
this.canvas.style.width = `${window.innerWidth}px`
this.canvas.style.height = `${window.innerHeight}px`
}
createDots() {
// Crear una cuadrícula de puntos que cubra la ventana visible
const cols = Math.floor(window.innerWidth / this.dotSpacing)
const rows = Math.floor(window.innerHeight / this.dotSpacing)
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
const x = i * this.dotSpacing + this.dotSpacing / 2
const y = j * this.dotSpacing + this.dotSpacing / 2
this.dots.push({
x: x,
y: y,
color: this.grayColor,
targetColor: this.grayColor,
alpha: 0.2,
size: this.dotSize,
})
}
}
}
setupEventListeners() {
// Manejar eventos de ventana y mouse
window.addEventListener("resize", this.handleResize.bind(this))
document.addEventListener("mousemove", this.handleMouseMove.bind(this))
document.addEventListener("touchmove", this.handleTouchMove.bind(this), { passive: true })
}
handleResize() {
// Actualizar el canvas y los puntos cuando cambia el tamaño de la ventana
if (this.animationFrameId !== null) {
cancelAnimationFrame(this.animationFrameId)
}
this.dots = []
this.setupCanvas()
this.createDots()
this.animate()
}
handleMouseMove(e: MouseEvent) {
// Actualizar posición del ratón relativa al canvas
this.mouse.x = e.clientX
this.mouse.y = e.clientY
}
handleTouchMove(e: TouchEvent) {
if (e.touches.length > 0) {
// Actualizar posición del toque relativa al canvas
this.mouse.x = e.touches[0].clientX
this.mouse.y = e.touches[0].clientY
}
}
animate() {
// Limpiar el canvas
this.ctx.clearRect(
0,
0,
this.canvas.width / (window.devicePixelRatio || 1),
this.canvas.height / (window.devicePixelRatio || 1)
)
// Actualizar y dibujar puntos
this.updateDots()
this.drawDots()
// Continuar la animación
this.animationFrameId = requestAnimationFrame(this.animate.bind(this))
}
updateDots() {
this.dots.forEach((dot) => {
const dx = this.mouse.x - dot.x
const dy = this.mouse.y - dot.y
const distance = Math.sqrt(dx * dx + dy * dy)
// Actualizar color objetivo basado en la distancia al ratón
if (distance < this.radius) {
// Aplicar una curva de intensidad no lineal para acentuar el centro
const normalizedDistance = distance / this.radius
// Usar una función exponencial para que la intensidad caiga más rápidamente al alejarse del centro
const intensity = Math.pow(1 - normalizedDistance, 2.5)
dot.targetColor = this.pinkColor
// Los puntos más cercanos mantienen alta intensidad, los lejanos son más sutiles
if (normalizedDistance < 0.3) {
// Puntos centrales (30% del radio) mantienen alta intensidad
dot.targetAlpha = 0.5 + intensity * 0.3
} else {
// Puntos exteriores tienen intensidad reducida
dot.targetAlpha = 0.3 + intensity * 0.2
}
} else {
dot.targetColor = this.grayColor
dot.targetAlpha = dot.alpha
}
// Transición suave de color
if (dot.color !== dot.targetColor) {
// Interpolación de color para transición suave
const currentColor = this.hexToRgb(dot.color)
const targetColor = this.hexToRgb(dot.targetColor)
// Velocidad de transición
const transitionSpeed = dot.targetColor === this.pinkColor ? 0.15 : 0.05
// Actualizar componentes RGB
currentColor.r += (targetColor.r - currentColor.r) * transitionSpeed
currentColor.g += (targetColor.g - currentColor.g) * transitionSpeed
currentColor.b += (targetColor.b - currentColor.b) * transitionSpeed
// Convertir de nuevo a hex
dot.color = this.rgbToHex(
Math.round(currentColor.r),
Math.round(currentColor.g),
Math.round(currentColor.b)
)
}
})
}
drawDots() {
this.dots.forEach((dot) => {
this.ctx.beginPath()
this.ctx.arc(dot.x, dot.y, dot.size, 0, Math.PI * 2)
this.ctx.fillStyle = dot.color
this.ctx.globalAlpha = dot.targetAlpha || dot.alpha
this.ctx.fill()
})
}
hexToRgb(hex: string) {
// Expandir formato abreviado (por ejemplo, "#03F") a formato completo (por ejemplo, "#0033FF")
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i
hex = hex.replace(
shorthandRegex,
(m: string, r: string, g: string, b: string) => r + r + g + g + b + b
)
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
return result
? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16),
}
: { r: 0, g: 0, b: 0 }
}
rgbToHex(r: number, g: number, b: number) {
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`
}
}
// Inicializar cuando el DOM esté completamente cargado
// Iniciar el efecto cuando el DOM esté completamente cargado
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => {
new DotBackground()
})
} else {
// Si el documento ya está cargado, iniciar inmediatamente
new DotBackground()
}
</script>
================================================
FILE: src/components/Header.astro
================================================
---
import HeaderLink, { Device, Target } from "@/components/HeaderLink.astro"
---
<header class="animate-blur-header fixed top-0 z-60 w-screen">
<nav
class="mx-auto flex max-w-6xl items-center justify-between px-4 py-6 pb-0 uppercase lg:px-8"
aria-label="Global"
>
<div class="flex">
<div class="hidden lg:flex lg:gap-x-12">
<HeaderLink text="Info" href="/#info" device={Device.DESKTOP} />
<HeaderLink text="Preguntas" href="/#faq" device={Device.DESKTOP} />
<HeaderLink
text="Aut. Menores"
href="/hoja-de-responsabilidad.pdf"
device={Device.DESKTOP}
target={Target.BLANK}
/>
</div>
<div class="flex lg:hidden">
<button
type="button"
id="open-menu-button"
class="-m-2.5 inline-flex cursor-pointer items-center justify-center rounded-md p-2.5 text-white transition-all duration-300 will-change-transform hover:scale-150"
>
<span class="sr-only">Abrir Menú Principal</span>
<svg
class="size-6"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
aria-hidden="true"
data-slot="icon"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"></path>
</svg>
</button>
</div>
</div>
<div class="flex flex-1 justify-end">
<div class="relative flex flex-col items-end">
<span
id="tickets-button"
class="tickets-button relative cursor-not-allowed rounded-full bg-gray-300 px-5 py-2 text-sm/6 font-bold text-gray-500 opacity-70 shadow-lg"
aria-disabled="true">¡Gracias por asistir!</span
>
</div>
</div>
</nav>
<dialog
class="bg-primary z-50 max-h-[80vh] w-full max-w-full translate-x-0 transition-discrete duration-300 lg:hidden starting:-translate-x-full [&:not([open])]:-translate-x-full"
id="mobile-menu"
role="dialog"
aria-modal="true"
>
<div class="z-10 overflow-y-auto px-6 py-6">
<div class="flex items-center justify-between">
<div class="flex flex-1">
<button
type="button"
id="close-menu-button"
class="-m-2.5 cursor-pointer p-2.5 text-white transition-all duration-300 ease-in will-change-transform hover:scale-150"
>
<span class="sr-only">Cerrar Menú</span>
<svg
class="size-6"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
aria-hidden="true"
data-slot="icon"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path>
</svg>
</button>
</div>
</div>
<div class="mt-6 space-y-2">
<HeaderLink text="Info" href="/#info" device={Device.MOBILE} />
<HeaderLink text="Preguntas" href="/#faq" device={Device.MOBILE} />
<HeaderLink
text="Aut. Menores"
href="/hoja-de-responsabilidad.pdf"
device={Device.MOBILE}
target={Target.BLANK}
/>
<span
class="block w-full cursor-not-allowed rounded-full bg-gray-300 px-5 py-2 text-center font-bold text-gray-500 opacity-70"
aria-disabled="true">¡Gracias por asistir!</span
>
</div>
</div>
</dialog>
</header>
<div id="backdrop"></div>
<div data-target class="absolute top-[150px]"></div>
<script>
// Get the menu elements
const mobileMenu = document.getElementById("mobile-menu") as HTMLDialogElement
const openMenuButton = document.getElementById("open-menu-button")
const closeMenuButton = document.getElementById("close-menu-button")
const mobileItems = mobileMenu.querySelectorAll("a")
const backdrop = document.getElementById("backdrop")
const toggleMenu = () => {
mobileMenu.open ? mobileMenu.close() : mobileMenu.showModal()
if (mobileMenu.open) {
backdrop?.classList.add("visible")
} else {
backdrop?.classList.remove("visible")
}
}
// Add event listener to open menu button
openMenuButton?.addEventListener("click", toggleMenu)
// Add event listener to close menu button
closeMenuButton?.addEventListener("click", toggleMenu)
document.addEventListener("click", (event) => {
const isClickInsideMenu = mobileMenu.contains(event.target as Node)
const isClickInsideButton = openMenuButton?.contains(event.target as Node)
if (isClickInsideMenu && !isClickInsideButton) {
mobileMenu.close()
backdrop?.classList.remove("visible")
}
})
mobileItems?.forEach((item) => item.addEventListener("click", toggleMenu))
const target = document.querySelector("[data-target]")
const header = document.querySelector("header")
const ticketsButton = document.getElementById("tickets-button")
const handleIntersection = ([entry]: IntersectionObserverEntry[]) => {
if (entry.isIntersecting) {
ticketsButton?.classList.add(
"from-[#ff0695]",
"via-[#ff99d1]",
"to-[#ff0695]",
"shadow-[#ff0695]/30",
"hover:shadow-[#ff0695]/40"
)
ticketsButton?.classList.remove(
"from-[#383acf]",
"via-[#8688ff]",
"to-[#383acf]",
"shadow-[#383acf]/30",
"hover:shadow-[#383acf]/40"
)
header?.classList.remove("end-state")
} else {
ticketsButton?.classList.remove(
"from-[#ff0695]",
"via-[#ff99d1]",
"to-[#ff0695]",
"shadow-[#ff0695]/30",
"hover:shadow-[#ff0695]/40"
)
ticketsButton?.classList.add(
"from-[#383acf]",
"via-[#8688ff]",
"to-[#383acf]",
"shadow-[#383acf]/30",
"hover:shadow-[#383acf]/40"
)
header?.classList.add("end-state")
}
}
const createObserver = (target: Element, callback: IntersectionObserverCallback) => {
const observer = new IntersectionObserver(callback, { threshold: 0.5 })
observer.observe(target)
}
if (target) {
createObserver(target, handleIntersection)
}
</script>
<style>
@reference "../styles/global.css";
header {
@apply border-b border-b-transparent;
transition:
background 0.3s,
padding-bottom 0.2s,
border-bottom-color 0.1s;
}
.end-state {
@apply bg-primary/60 border-b-[#b50066] pb-6 backdrop-blur-md;
}
#backdrop {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease-in-out;
z-index: 100;
}
.tickets-button {
background-size: 200% 100%;
animation: shimmer 3s linear infinite;
position: relative;
overflow: hidden;
}
.tickets-button::before {
content: "";
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.3), transparent);
transform: rotate(30deg);
animation: shine 3s linear infinite;
}
@keyframes shimmer {
0% {
background-position: 0% 0;
}
100% {
background-position: 200% 0;
}
}
@keyframes shine {
0% {
transform: translateX(-100%) rotate(30deg);
}
100% {
transform: translateX(100%) rotate(30deg);
}
}
#backdrop.visible {
opacity: 1;
}
dialog::backdrop {
display: none;
}
</style>
================================================
FILE: src/components/HeaderLink.astro
================================================
---
export enum Device {
MOBILE = "MOBILE",
DESKTOP = "DESKTOP",
}
export enum Target {
BLANK = "_blank",
SELF = "_self",
PARENT = "_parent",
TOP = "_top",
}
export type Props = {
href: string
text: string
device: Device
target?: Target
extraClasses?: string
}
const { href, text, device, target, extraClasses } = Astro.props
const desktopClasses =
"relative text-sm/6 font-semibold text-white after:absolute after:bottom-[-2px] after:left-0 after:h-0.5 after:w-0 after:bg-white after:transition-all after:duration-300 hover:after:w-full"
const mobileClasses =
"hover:text-primary-light border-primary-light -mx-3 block rounded-lg px-3 py-2 text-base/7 font-semibold text-white hover:bg-white"
---
<a
href={href}
class:list={[device === Device.DESKTOP ? desktopClasses : mobileClasses, extraClasses]}
target={target}>{text}</a
>
================================================
FILE: src/components/LeafletMap.astro
================================================
---
// Leaflet CSS and dependencies will be loaded dynamically
import type { FeatureCollection, Geometry, GeoJsonProperties } from "geojson"
export interface Props {
latitude: number
longitude: number
zoom: number
/** URL del tileLayer, ver: https://leafletjs.com/reference.html#tilelayer */
tileLayer: string
/** Atribución requerida por la mayoría de tile servers */
attribution: string
geoJSON?: { data: FeatureCollection<Geometry, GeoJsonProperties>; color: string }[]
}
const { latitude, longitude, zoom, tileLayer, attribution, geoJSON } = Astro.props
---
<leaflet-map
class="block h-full"
data-latitude={latitude}
data-longitude={longitude}
data-zoom={zoom}
data-tiles={tileLayer}
data-attribution={attribution}
data-geojson={JSON.stringify(geoJSON)}
>
</leaflet-map>
<script>
class LeafletMap extends HTMLElement {
private observer: IntersectionObserver | null = null
private initialized = false
connectedCallback() {
// Create an intersection observer to detect when the map is about to be visible
this.observer = new IntersectionObserver(this.handleIntersection.bind(this), {
rootMargin: "200px", // Load when map is within 200px of viewport
threshold: 0,
})
this.observer.observe(this)
}
disconnectedCallback() {
// Clean up the observer when the element is removed from the DOM
if (this.observer) {
this.observer.disconnect()
this.observer = null
}
}
async handleIntersection(entries: IntersectionObserverEntry[]) {
const isIntersecting = entries[0]?.isIntersecting
if (isIntersecting && !this.initialized) {
this.initialized = true
// Stop observing once we've initialized
if (this.observer) {
this.observer.disconnect()
this.observer = null
}
// Dynamically load Leaflet CSS
await this.loadLeafletCSS()
// Dynamically import Leaflet
const leafletModule = await import("leaflet")
const L = leafletModule.default
// Initialize the map
await this.initializeMap(L)
}
}
async loadLeafletCSS() {
return new Promise<void>((resolve) => {
const link = document.createElement("link")
link.rel = "stylesheet"
link.href = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
link.integrity = "sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
link.crossOrigin = ""
link.onload = () => {
// Add custom CSS for the pink color theme after Leaflet CSS is loaded
this.addCustomStyles()
resolve()
}
document.head.appendChild(link)
})
}
addCustomStyles() {
// Add the custom CSS for the pink color theme
const style = document.createElement("style")
style.textContent = `
.leaflet-tile {
filter: hue-rotate(220deg);
}
.leaflet-pane {
z-index: 10;
}
.leaflet-top {
z-index: 11;
}
.leaflet-control-zoom.leaflet-bar.leaflet-control {
border-radius: 24px;
overflow: hidden;
margin: 14px;
border-color: var(--color-primary);
}
a.leaflet-control-zoom-in,
a.leaflet-control-zoom-out {
background-color: var(--color-primary-light);
color: var(--color-primary);
border-color: var(--color-primary);
}
a.leaflet-control-zoom-in:hover,
a.leaflet-control-zoom-out:hover {
background-color: var(--color-primary);
color: white;
border-color: var(--color-primary-light);
}
`
document.head.appendChild(style)
}
async initializeMap(L: any) {
const { latitude, longitude, zoom, tiles, attribution, geojson } = this.dataset
const latlng = [Number(latitude), Number(longitude)]
const map = L.map(this, {
scrollWheelZoom: false,
dragging: false,
attributionControl: true,
}).setView(latlng, Number(zoom))
// Habilitar interactividad al hacer clic
map.once("click", () => {
map.scrollWheelZoom.enable()
map.dragging.enable()
})
L.tileLayer(tiles as string, { attribution }).addTo(map)
// Definir icono personalizado
const myIcon = L.icon({
iconUrl: "images/icons/marker.webp",
iconSize: [25, 36],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41],
})
L.marker(latlng, { icon: myIcon }).addTo(map).bindPopup("Aquopolis Villanueva de la Cañada")
if (!geojson) return
const geoJSONData = JSON.parse(geojson as string)
geoJSONData.forEach(({ data, color }: { data: any; color: string }) => {
L.geoJSON(data, {
style: { color, weight: 5, opacity: 0.65 },
}).addTo(map)
})
}
}
window.customElements.define("leaflet-map", LeafletMap)
</script>
<!-- Styles are now added dynamically in JavaScript -->
================================================
FILE: src/components/Marquee.astro
================================================
---
export type Props = {
content: Array<string>
}
const { content } = Astro.props
---
<div class="flex mt-10 gap-x-4 overflow-hidden py-4 md:py-6 lg:py-8">
{
content.map((item, index) => (
<div class="marquee-content animate-marquee flex flex-none justify-around gap-x-4 [&>*]:leading-none [&>*]:font-black [&>*]:uppercase">
<div class="text-[5vh] text-[#6c4bbc] md:text-[6vh] lg:text-[4vw]">{item}</div>
{index !== content.length - 1 && (
<div class="text-[5vh] text-[#6c4bbc] md:text-[6vh] lg:text-[4vw]"> · </div>
)}
</div>
))
}
</div>
================================================
FILE: src/components/Sponsor.astro
================================================
---
const { href } = Astro.props
---
<a
href={href}
target="_blank"
rel="noopener noreferrer"
class="group relative flex max-h-12 grow-0 items-center justify-center bg-transparent object-contain p-1 lg:col-span-1"
>
<slot />
<div
class="animate-shiny pointer-events-none absolute inset-0 h-full w-full bg-[linear-gradient(110deg,transparent_0%,transparent_43%,rgba(255,255,255,0.3)_50%,transparent_57%,transparent_100%)] bg-[length:200%_100%]"
>
</div>
</a>
================================================
FILE: src/components/SponsorsBar.astro
================================================
---
import Sponsor from "@/components/Sponsor.astro"
import Cerave from "@/assets/cerave.svg"
import Dkny from "@/assets/dkny.webp"
import Donettes from "@/assets/donettes.svg"
import InfoJobs from "@/assets/infojobs.svg"
import Trolli from "@/assets/trolli.svg"
import Grefusa from "@/assets/grefusa.webp"
import Snacking from "@/assets/snacking.svg"
import Novotel from "@/assets/novotel.webp"
import Flamingueo from "@/assets/flamingueo.webp"
import LOreal from "@/assets/loreal.webp"
import Uber from "@/assets/uber.webp"
import { Image } from "astro:assets"
---
<!-- Floating sponsor logos section -->
<div
class="to-primary relative -mt-16 w-full overflow-hidden bg-gradient-to-b from-[#ff0695] py-4 text-center"
>
<div class="container mx-auto px-4">
<!-- Sponsors container with floating animation -->
<div class="animate-float-1 relative z-10 mx-auto flex justify-center">
<div
class="inline-flex flex-wrap items-center justify-center gap-x-4 gap-y-4 whitespace-nowrap"
>
<!-- Official Sponsors -->
<div class="flex flex-col items-center rounded-[2rem] bg-white px-5 py-3 shadow-lg">
<h3 class="text-primary-dark mb-2 text-xs font-semibold">Patrocinadores oficiales</h3>
<div class="flex flex-wrap items-center justify-center gap-2">
<Sponsor href="https://www.infojobs.net/" isOfficial>
<InfoJobs
title="InfoJobs"
width="90"
height="27"
class="inline-block transition-transform group-hover:scale-110"
/>
</Sponsor>
<Sponsor href="https://www.cerave.es/" isOfficial>
<Cerave
title="Cerave"
width="90"
height="27"
class="inline-block transition-transform group-hover:scale-110"
/>
</Sponsor>
<Sponsor href="https://www.dkny.com/" isOfficial>
<Image
src={Dkny}
alt="DKNY"
title="DKNY"
width="500"
height="122"
class="inline-block w-22 transition-transform group-hover:scale-110"
/>
</Sponsor>
<Sponsor href="https://www.campofrio.es/marcas/snackin">
<Image
src={Snacking}
title="Snacking"
alt="Snacking"
class="inline-block h-auto w-20 rounded bg-[#6a3f6e] px-2 transition-transform group-hover:scale-110"
/>
</Sponsor>
<Sponsor href="https://grefusa.com/" isOfficial>
<Image
src={Grefusa}
alt="Grefusa"
title="Grefusa"
width="90"
height="27"
class="inline-block w-14 transition-transform group-hover:scale-110"
/>
</Sponsor>
</div>
</div>
<!-- Collaborators -->
<div class="flex flex-col items-center rounded-[2rem] bg-white px-5 py-3 shadow-lg">
<h3 class="text-primary-dark mb-2 text-xs font-semibold">Colaboradores</h3>
<div class="flex items-center gap-6">
<Sponsor href="https://www.loreal.com/es-es/espana/">
<Image
src={LOreal}
title="Loreal"
alt="Loreal"
class="inline-block w-24 transition-transform group-hover:scale-110"
/>
</Sponsor>
<Sponsor href="https://www.donettes.com/">
<Image
src={Donettes}
title="Donettes"
alt="Donettes"
width="90"
height="27"
class="inline-block transition-transform group-hover:scale-110"
/>
</Sponsor>
<Sponsor href="https://trolli.es/">
<Image
src={Trolli}
title="Trolli"
alt="Trolli"
width="90"
height="27"
class="inline-block w-16 transition-transform group-hover:scale-110"
/>
</Sponsor>
<Sponsor href="https://flamingueo.com/">
<Image
src={Flamingueo}
title="Flamingueo"
alt="Flamingueo"
class="inline-block w-16 invert transition-transform group-hover:scale-110"
/>
</Sponsor>
<Sponsor
href="https://all.accor.com/lien_externe.svlt?goto=rech_resa&destination=9298&sourceid=CONCBW&dayIn=13&monthIn=06&yearIn=2025&nightNb=3&preferredCode=CONCBW&merchantid=par-accorFR"
>
<Image
src={Novotel}
title="Novotel"
alt="Novotel"
class="inline-block h-auto w-20 rounded transition-transform group-hover:scale-110"
/>
</Sponsor>
<Sponsor href="https://www.uber.com/es/es-es/ride/?utm_source=LolaLolitaLand">
<Image
src={Uber}
title="Uber"
alt="Uber"
class="-mt-2 inline-block w-20 transition-transform group-hover:scale-110"
/>
</Sponsor>
</div>
</div>
</div>
</div>
<!-- Decorative bubbles -->
<div class="bubble bubble-1"></div>
<div class="bubble bubble-2"></div>
<div class="bubble bubble-3"></div>
<div class="bubble bubble-4"></div>
<div class="bubble bubble-5"></div>
</div>
</div>
<style>
/* Floating animations for sponsor logos */
@keyframes float-1 {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
@keyframes float-2 {
0% {
transform: translateY(-5px);
}
50% {
transform: translateY(5px);
}
100% {
transform: translateY(-5px);
}
}
.animate-float-1 {
animation: float-1 6s ease-in-out infinite;
}
.animate-float-2 {
animation: float-2 7s ease-in-out infinite;
}
/* Bubble animations */
.bubble {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
animation: bubble-rise linear infinite;
}
.bubble-1 {
width: 40px;
height: 40px;
left: 10%;
bottom: -20px;
animation-duration: 8s;
}
.bubble-2 {
width: 20px;
height: 20px;
left: 20%;
bottom: -10px;
animation-duration: 5s;
animation-delay: 1s;
}
.bubble-3 {
width: 30px;
height: 30px;
left: 60%;
bottom: -15px;
animation-duration: 7s;
animation-delay: 2s;
}
.bubble-4 {
width: 15px;
height: 15px;
left: 80%;
bottom: -8px;
animation-duration: 6s;
animation-delay: 3s;
}
.bubble-5 {
width: 25px;
height: 25px;
left: 40%;
bottom: -12px;
animation-duration: 9s;
animation-delay: 4s;
}
@keyframes bubble-rise {
0% {
transform: translateY(0) scale(1);
opacity: 0;
}
20% {
opacity: 0.8;
}
100% {
transform: translateY(-100vh) scale(1.5);
opacity: 0;
}
}
</style>
================================================
FILE: src/components/StarryBackground.astro
================================================
---
const starCount = 120
const minDistance = 5
// Función para calcular la distancia entre dos puntos
const getDistance = (x1: number, y1: number, x2: number, y2: number) => {
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
}
const stars: any[] = []
while (stars.length < starCount) {
const newStar = {
top: Math.random() * 95,
left: Math.random() * 100,
size: Math.random() * 6 + 10, // Tamaño entre 10 y 16 px
opacity: Math.random() * 0.2 + 0.5, // Opacidad entre 0.5 y 1
rotation: Math.random() * 360, // Rotación entre 0 y 360 grados
}
// Verificar que la nueva estrella no esté demasiado cerca de otra
if (
stars.every(
(star) => getDistance(star.left, star.top, newStar.left, newStar.top) >= minDistance
)
) {
stars.push(newStar)
}
}
---
<div class="pointer-events-none absolute inset-0 overflow-hidden">
{
stars.map((star, index) => (
<div
class="bg-primary-light absolute animate-pulse shadow-[0_0_6px_rgba(255,182,193,0.8)]"
style={`top: ${star.top}%; left: ${star.left}%; width: ${star.size}px; height: ${star.size}px; opacity: ${star.opacity}; transform: rotate(${star.rotation}deg); clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);`}
/>
))
}
</div>
================================================
FILE: src/components/WaveSeparator.astro
================================================
---
const { bottomColor = "#ff0695", hasBubbles = false } = Astro.props
---
<div
class={`wave-container ${hasBubbles ? "wave-bubbles" : ""}`}
style={`--bottom-color: ${bottomColor};`}
>
<style>
.wave-container {
position: relative;
}
.wave-container::before {
content: "";
width: 100%;
height: 15px;
position: absolute;
bottom: -0.3%;
left: 0;
background-color: var(--bottom-color);
mask-image: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1200 134' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M0 98L50 92C100 86 200 74 300 50C400 26 500 -10 600 2C700 14 800 74 900 98C1000 122 1100 110 1150 104L1200 98V134H1150C1100 134 1000 134 900 134C800 134 700 134 600 134C500 134 400 134 300 134C200 134 100 134 50 134H0V98Z' fill='black'/></svg>");
animation: wave 17s linear infinite;
box-shadow: 10px 10px 10px 10px rgba(0, 0, 0, 0.1);
}
.wave-container.wave-bubbles::before {
z-index: 1;
bottom: -15px;
mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 -0.0830269 1200 112.4'><path d='M 0 98 L 50 92 C 100 86 200 74 300 50 S 512 -9 600 2 S 800 74 900 98 S 1100 110 1150 104 L 1200 98 V 0 H 1154 H 0 V 98 Z' fill='black'/></svg>");
}
@keyframes wave {
0% {
mask-position: 100% 0;
}
100% {
mask-position: 0% 0;
}
}
@media (max-width: 850px) {
.wave-container::before {
height: 7.5px;
}
.wave-container.wave-bubbles::before {
bottom: -7.5px;
}
}
</style>
</div>
================================================
FILE: src/consts/galleryImages.ts
================================================
import GalleryImg1 from "@/assets/images/gallery/gallery_01.webp"
import GalleryImg2 from "@/assets/images/gallery/gallery_02.webp"
import GalleryImg3 from "@/assets/images/gallery/gallery_03.webp"
import GalleryImg5 from "@/assets/images/gallery/gallery_05.webp"
import GalleryImg6 from "@/assets/images/gallery/gallery_06.webp"
import GalleryImg7 from "@/assets/images/gallery/gallery_07.webp"
import GalleryImg8 from "@/assets/images/gallery/gallery_08.webp"
import GalleryImg9 from "@/assets/images/gallery/gallery_09.webp"
import GalleryImg10 from "@/assets/images/gallery/gallery_10.webp"
import GalleryImg11 from "@/assets/images/gallery/gallery_11.webp"
import GalleryImg12 from "@/assets/images/gallery/gallery_12.webp"
import GalleryImg13 from "@/assets/images/gallery/gallery_13.webp"
import GalleryImg14 from "@/assets/images/gallery/gallery_14.webp"
import GalleryImg15 from "@/assets/images/gallery/gallery_15.webp"
import GalleryImg16 from "@/assets/images/gallery/gallery_16.webp"
import GalleryImg17 from "@/assets/images/gallery/gallery_17.webp"
import GalleryImg18 from "@/assets/images/gallery/gallery_18.webp"
import GalleryImg19 from "@/assets/images/gallery/gallery_19.webp"
import GalleryImg20 from "@/assets/images/gallery/gallery_20.webp"
import GalleryImg21 from "@/assets/images/gallery/gallery_21.webp"
import GalleryImg22 from "@/assets/images/gallery/gallery_22.webp"
import GalleryImg23 from "@/assets/images/gallery/gallery_23.webp"
import GalleryImg24 from "@/assets/images/gallery/gallery_24.webp"
import GalleryImg25 from "@/assets/images/gallery/gallery_25.webp"
import GalleryImg26 from "@/assets/images/gallery/gallery_26.webp"
import GalleryImg27 from "@/assets/images/gallery/gallery_27.webp"
import GalleryImg28 from "@/assets/images/gallery/gallery_28.webp"
import GalleryImg29 from "@/assets/images/gallery/gallery_29.webp"
import GalleryImg30 from "@/assets/images/gallery/gallery_30.webp"
import GalleryImg31 from "@/assets/images/gallery/gallery_31.webp"
import GalleryImg32 from "@/assets/images/gallery/gallery_32.webp"
import GalleryImg33 from "@/assets/images/gallery/gallery_33.webp"
import GalleryImg34 from "@/assets/images/gallery/gallery_34.webp"
import GalleryImg35 from "@/assets/images/gallery/gallery_35.webp"
import GalleryImg36 from "@/assets/images/gallery/gallery_36.webp"
import GalleryImg37 from "@/assets/images/gallery/gallery_37.webp"
export const galleryImages = [
{
image: GalleryImg1,
alt: "Lola Lolita en un escenario con Carlos Baute.",
thumb: "thumb1",
},
{
image: GalleryImg2,
alt: "Lola Lolita Land, festival de música.",
thumb: "thumb2",
},
{
image: GalleryImg3,
alt: "Lola Índigo en un escenario en el festival de Lola Lolita Land.",
thumb: "thumb3",
},
{
image: GalleryImg5,
alt: "Lola Lolita junto a un grupo de bailarines.",
thumb: "thumb4",
},
{
image: GalleryImg6,
alt: "Lola Lolita junto a un grupo de bailarines.",
thumb: "thumb5",
},
{
image: GalleryImg7,
alt: "Lola Lolita junto a un grupo de bailarines.",
thumb: "thumb6",
},
{
image: GalleryImg8,
alt: "Lola Lolita junto a un grupo de bailarines.",
thumb: "thumb7",
},
{
image: GalleryImg9,
alt: "Lola Lolita junto a un grupo de bailarines.",
thumb: "thumb8",
},
{
image: GalleryImg10,
alt: "Lola Lolita junto a un grupo de bailarines.",
thumb: "thumb9",
},
{
image: GalleryImg11,
alt: "Marina Reche en el evento de Lola Lolita Land.",
thumb: "thumb10",
},
{
image: GalleryImg12,
alt: "Marina Reche en el evento de Lola Lolita Land.",
thumb: "thumb11",
},
{
image: GalleryImg13,
alt: "DJ en el evento de Lola Lolita Land.",
thumb: "thumb12",
},
{
image: GalleryImg14,
alt: "DJ en el evento de Lola Lolita Land.",
thumb: "thumb13",
},
{
image: GalleryImg15,
alt: "Grupo de personas con tambores sobre un escenario.",
thumb: "thumb14",
},
{
image: GalleryImg16,
alt: "Grupo de personas con tambores sobre un escenario.",
thumb: "thumb15",
},
{
image: GalleryImg17,
alt: "Gente mirando hacia el escenario.",
thumb: "thumb16",
},
{
image: GalleryImg18,
alt: "Gente mirando hacia el escenario.",
thumb: "thumb17",
},
{
image: GalleryImg19,
alt: "Lola Lolita en un escenario cantando.",
thumb: "thumb18",
},
{
image: GalleryImg20,
alt: "Lola Lolita en un escenario bailando.",
thumb: "thumb19",
},
{
image: GalleryImg21,
alt: "Lola Lolita en un escenario bailando junto a Abraham Mateo cantando.",
thumb: "thumb20",
},
{
image: GalleryImg22,
alt: "Dos personas lanzando regalos al público.",
thumb: "thumb21",
},
{
image: GalleryImg23,
alt: "Lola Lolita dándose un abrazo con sus fans.",
thumb: "thumb22",
},
{ image: GalleryImg24, alt: "DJ en el evento.", thumb: "thumb23" },
{
image: GalleryImg25,
alt: "Gente de fiesta en el evento de Lola Lolita.",
thumb: "thumb24",
},
{
image: GalleryImg26,
alt: "Lola Lolita saliendo de una caja sorpresa.",
thumb: "thumb25",
},
{
image: GalleryImg27,
alt: "Gente sobre el escenario bailando y rapeando.",
thumb: "thumb26",
},
{
image: GalleryImg28,
alt: "Lola Lolita cantando y bailando junto a otras personas.",
thumb: "thumb27",
},
{ image: GalleryImg29, alt: "Lola Lolita Land.", thumb: "thumb28" },
{
image: GalleryImg30,
alt: "Lola Lolita cantando sobre un escenario con un traje azul.",
thumb: "thumb29",
},
{
image: GalleryImg31,
alt: "Lola Lolita celebrando junto a Carlos Baute.",
thumb: "thumb30",
},
{
image: GalleryImg32,
alt: "Lola Lolita tomándose una foto con un grupo de personas.",
thumb: "thumb31",
},
{
image: GalleryImg33,
alt: "Lola Índigo y otras dos chicas cantando y bailando sobre el escenario.",
thumb: "thumb32",
},
{
image: GalleryImg34,
alt: "Lola Índigo y otras dos chicas cantando y bailando sobre el escenario.",
thumb: "thumb33",
},
{
image: GalleryImg35,
alt: "Lola Índigo y otras dos chicas cantando y bailando sobre el escenario.",
thumb: "thumb34",
},
{
image: GalleryImg36,
alt: "El público mirando la coreografía de Lola Lolita junto a su grupo.",
thumb: "thumb35",
},
{ image: GalleryImg37, alt: "Imagen de la galería 37.", thumb: "thumb36" },
]
================================================
FILE: src/consts/geoJSONData.ts
================================================
import type { FeatureCollection, Geometry, GeoJsonProperties } from "geojson"
export const lolalolitalandGeoJSON: FeatureCollection<Geometry, GeoJsonProperties> = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {
name: "Aquopolis Villanueva de la Cañada",
amenity: "Parque Acuático",
popupContent: "Lolalolitaland",
},
geometry: {
coordinates: [
[
[-3.99076369718523, 40.45536289516917],
[-3.9903189790816214, 40.45554486964127],
[-3.990155158873449, 40.455574594431596],
[-3.9900581269040174, 40.4555765121593],
[-3.989746213601734, 40.45562017324792],
[-3.9891993962796732, 40.45577514093404],
[-3.9877151778341897, 40.4565245001821],
[-3.986617827976488, 40.45688371127795],
[-3.986762901959281, 40.45739742873948],
[-3.986874497331769, 40.458015158171435],
[-3.9871395363399245, 40.45832295937666],
[-3.9872399721744216, 40.45822531225053],
[-3.98763892562863, 40.458221066720256],
[-3.987895594983911, 40.458333573185996],
[-3.9883615793518743, 40.458009647005866],
[-3.9889269617388265, 40.458145917956614],
[-3.9890551384914943, 40.4581485899335],
[-3.989316473572501, 40.4581222396026],
[-3.9896014481069244, 40.458347573973214],
[-3.989959063207891, 40.458262542223935],
[-3.9901490462303855, 40.45801169793688],
[-3.9904675471792928, 40.45781187215661],
[-3.9911771896460095, 40.457905407701986],
[-3.9914006990829876, 40.45762054904381],
[-3.991830954751606, 40.45762054904381],
[-3.9919594726791843, 40.45739946387951],
[-3.9912386547409824, 40.45630253057408],
[-3.9908475132244234, 40.4562089927972],
[-3.990981618887105, 40.4558518473593],
[-3.990875451903719, 40.455826336897786],
[-3.990836337751716, 40.45589861651237],
[-3.9906072405783277, 40.45586460258619],
[-3.990646354730387, 40.45577531594671],
[-3.9908810396400725, 40.45557123175476],
[-3.99076369718523, 40.45536289516917],
],
],
type: "Polygon",
},
},
],
}
/**
* @type {GeoJSON.GeoJsonObject}
*/
export const potaBlavaGeoJSON: FeatureCollection<Geometry, GeoJsonProperties> = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {
name: "El Prat de Llobregat",
amenity: "Ciudad",
popupContent: "El Prat de Llobregat",
},
geometry: {
coordinates: [
[
[2.0945220342870527, 41.33458690034561],
[2.0847138915145536, 41.331468102419336],
[2.081260991679869, 41.32943896819731],
[2.0750558690643004, 41.32203576302666],
[2.0755562372234806, 41.32015665316527],
[2.080310170662699, 41.315308274548414],
[2.082662102693604, 41.31365447275482],
[2.0846137177570654, 41.31320342453546],
[2.092320172776084, 41.31218856656821],
[2.093220903020807, 41.3163606571309],
[2.0942717976104177, 41.31876607610627],
[2.0952225897980554, 41.319179499686044],
[2.0972242755620982, 41.319367415682706],
[2.0983251971485117, 41.31820231507206],
[2.09647364733749, 41.317300286831085],
[2.0974744877031526, 41.315721709910974],
[2.0983108585439822, 41.315862318781285],
[2.1006538515882767, 41.316724486417],
[2.104239102690798, 41.317362246919686],
[2.102879225001061, 41.31952810403456],
[2.1024426319370946, 41.32019650904729],
[2.1020899990773216, 41.32131890959104],
[2.1039539156197975, 41.3221007951754],
[2.1049950221570555, 41.322794395502854],
[2.105364447058065, 41.32256739984433],
[2.1080175895234277, 41.32522824370241],
[2.110737900153538, 41.326552319827016],
[2.11006621851638, 41.32806551673701],
[2.1088890598913395, 41.32946273622369],
[2.1069583312912243, 41.33144228403759],
[2.1048605204076125, 41.333491470875686],
[2.102502803751662, 41.33471816412478],
[2.0959865947252183, 41.33322661361933],
[2.0945220342870527, 41.33458690034561],
],
],
type: "Polygon",
},
},
],
}
================================================
FILE: src/consts/map-styles.js
================================================
export const MAP_STYLES =
[
{
"featureType": "all",
"elementType": "geometry.stroke",
"stylers": [
{
"visibility": "simplified"
}
]
},
{
"featureType": "administrative",
"elementType": "all",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "administrative",
"elementType": "labels",
"stylers": [
{
"visibility": "simplified"
},
{
"color": "#a31645"
}
]
},
{
"featureType": "landscape",
"elementType": "all",
"stylers": [
{
"weight": "3.79"
},
{
"visibility": "on"
},
{
"color": "#ffecf0"
}
]
},
{
"featureType": "landscape",
"elementType": "geometry",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "landscape",
"elementType": "geometry.stroke",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "poi",
"elementType": "all",
"stylers": [
{
"visibility": "simplified"
},
{
"color": "#a31645"
}
]
},
{
"featureType": "poi",
"elementType": "geometry",
"stylers": [
{
"saturation": "0"
},
{
"lightness": "0"
},
{
"visibility": "off"
}
]
},
{
"featureType": "poi",
"elementType": "geometry.stroke",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "poi.business",
"elementType": "all",
"stylers": [
{
"visibility": "simplified"
},
{
"color": "#d89ca8"
}
]
},
{
"featureType": "poi.business",
"elementType": "geometry",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "poi.business",
"elementType": "geometry.fill",
"stylers": [
{
"visibility": "on"
},
{
"saturation": "0"
}
]
},
{
"featureType": "poi.business",
"elementType": "labels",
"stylers": [
{
"color": "#a31645"
}
]
},
{
"featureType": "poi.business",
"elementType": "labels.icon",
"stylers": [
{
"visibility": "simplified"
},
{
"lightness": "84"
}
]
},
{
"featureType": "road",
"elementType": "all",
"stylers": [
{
"saturation": -100
},
{
"lightness": 45
}
]
},
{
"featureType": "road.highway",
"elementType": "all",
"stylers": [
{
"visibility": "simplified"
}
]
},
{
"featureType": "road.arterial",
"elementType": "labels.icon",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "transit",
"elementType": "all",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "water",
"elementType": "all",
"stylers": [
{
"color": "#d89ca8"
},
{
"visibility": "on"
}
]
},
{
"featureType": "water",
"elementType": "geometry.fill",
"stylers": [
{
"visibility": "on"
},
{
"color": "#fedce3"
}
]
},
{
"featureType": "water",
"elementType": "labels",
"stylers": [
{
"visibility": "off"
}
]
}
]
================================================
FILE: src/layouts/Layout.astro
================================================
---
import "@fontsource/poppins/400.css"
import "@fontsource/poppins/500.css"
import "@fontsource/poppins/600.css"
import "@fontsource/poppins/700.css"
import "@fontsource/poppins/900.css"
import Header from "@/components/Header.astro"
import BackToTop from "@/components/BackToTop.astro"
import "@/styles/global.css"
interface Props {
title?: string
}
const { title = "Lola Lolita Land · 14 y 15 de Junio en Aquopolis, Madrid" } = Astro.props
const preloadImg = "/images/hero.webp"
---
<!doctype html>
<html lang="es" class="scroll-smooth">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preload" as="image" href={preloadImg} />
<title>{title}</title>
<meta
name="description"
content="Evento organizado por Lola Lolita. Atracciones, música y muchísimos otros influencers presentes en uno de los mayores eventos organizados en España por una estrella de las redes sociales."
/>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta property="og:title" content="Lola Lolita Land" />
<meta
property="og:description"
content="Lola Lolita Land te espera el 14 y 15 de junio en Aquópolis Madrid. Vive dos días de diversión con un parque acuático lleno de sorpresas, toboganes y piscinas. Celebra el inicio del verano con una experiencia única, la segunda edición de este evento lleno de invitados especiales y momentos inolvidables. Un día para disfrutar con amigos y familiares, y crear recuerdos juntos."
/>
<meta property="og:image" content="/images/hero.webp" />
<meta property="og:url" content="https://www.lolalolitaland.com/" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Lola Lolita Land" />
<meta name="twitter:card" content="photo" />
<meta name="twitter:title" content="Lola Lolita Land" />
<meta
name="twitter:description"
content="Lola Lolita Land te espera el 14 y 15 de junio en Aquópolis Madrid. Vive dos días de diversión con un parque acuático lleno de sorpresas, toboganes y piscinas. Celebra el inicio del verano con una experiencia única, la segunda edición de este evento lleno de invitados especiales y momentos inolvidables. Un día para disfrutar con amigos y familiares, y crear recuerdos juntos."
/>
<meta name="twitter:image" content="/images/hero.webp" />
<meta name="twitter:url" content="https://www.lolalolitaland.com/" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Event",
"name": "Lola Lolita Land",
"description": "Lola Lolita Land te espera el 14 y 15 de junio en Aquópolis Madrid. Vive dos días de diversión con un parque acuático lleno de sorpresas, toboganes y piscinas. Celebra el inicio del verano con una experiencia única, la segunda edición de este evento lleno de invitados especiales y momentos inolvidables.",
"image": "https://www.lolalolitaland.com/images/hero.webp",
"startDate": "2025-06-14T10:00:00+02:00",
"endDate": "2025-06-15T20:00:00+02:00",
"eventStatus": "https://schema.org/EventScheduled",
"eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode",
"location": {
"@type": "Place",
"name": "Aquópolis Madrid",
"address": {
"@type": "PostalAddress",
"addressLocality": "Madrid",
"addressRegion": "Madrid",
"addressCountry": "ES"
}
},
"performer": {
"@type": "Person",
"name": "Lola Lolita"
},
"organizer": {
"@type": "Organization",
"name": "Lola Lolita",
"url": "https://www.lolalolitaland.com"
},
"offers": {
"@type": "Offer",
"url": "https://www.lolalolitaland.com",
"availability": "https://schema.org/InStock",
"priceCurrency": "EUR"
}
}
</script>
</head>
<body class="bg-primary w-screen overflow-x-hidden">
<Header />
<slot />
<BackToTop />
</body>
</html>
================================================
FILE: src/pages/404.astro
================================================
---
import Layout from "../layouts/Layout.astro"
import BubbleBackground from "../components/BubbleBackground.astro"
---
<Layout title="Página no encontrada - Lola Lolita Land">
<BubbleBackground />
<main class="bg-theme-blue flex min-h-screen items-center justify-center">
<div
class="container mx-auto flex flex-col items-center px-4 md:flex-row md:items-start md:justify-center md:space-x-12"
>
<div class="max-w-lg text-center">
<h1
class="mb-4 bg-gradient-to-r from-[#ff0695] to-[#ff99d1] bg-clip-text text-6xl font-bold text-transparent md:text-7xl lg:text-8xl"
>
404
</h1>
<h2 class="mb-4 text-3xl font-bold text-white uppercase md:text-4xl">
Página no encontrada
</h2>
<p class="mx-8 mb-8 text-lg text-balance text-white opacity-85">
¡Hola! Lo sentimos, pero no pudimos encontrar lo que buscabas. Verifica que la dirección
URL sea correcta.
</p>
<a
href="/"
class="bg-primary hover:bg-primary/80 inline-block rounded-full px-8 py-3 font-bold text-white transition-colors hover:scale-105"
>
IR AL INICIO
</a>
</div>
</div>
</main>
</Layout>
================================================
FILE: src/pages/index.astro
================================================
---
import Layout from "@/layouts/Layout.astro"
import Hero from "@/sections/Hero.astro"
import Tickets from "@/sections/Tickets.astro"
import Map from "@/sections/Map.astro"
import Rides from "@/sections/Rides.astro"
import Gallery from "@/sections/Gallery.astro"
import FAQ from "@/sections/FAQ.astro"
import Footer from "@/sections/Footer.astro"
import Info from "@/sections/Info.astro"
import ComoLlegar from "@/sections/ComoLlegar.astro"
export const prerender = true
---
<Layout>
<Hero />
<Tickets />
<Info />
<ComoLlegar />
<Map />
<Rides />
<FAQ />
<Gallery />
<Footer />
</Layout>
================================================
FILE: src/sections/ComoLlegar.astro
================================================
================================================
FILE: src/sections/FAQ.astro
================================================
---
// import FaqImage from "@/assets/images/faq.webp"
import FaqImage from "@/assets/images/gallery/gallery_04.webp"
import WaveSeparator from "@/components/WaveSeparator.astro"
import { Image } from "astro:assets"
---
<WaveSeparator bottomColor="var(--color-primary)" />
<section id="faq">
<div class="mx-auto max-w-7xl px-6 py-24 pt-12 lg:px-8">
<div class="lg:grid lg:grid-cols-12 lg:gap-8">
<div
class="flex flex-col items-center justify-center sm:gap-y-4 lg:col-span-5 lg:items-start"
>
<h2
class="text-center text-3xl font-semibold tracking-tight text-pretty text-white sm:text-4xl lg:text-left"
>
Preguntas
<span class="magic relative inline-block">
<span class="magic-star">
<svg viewBox="0 0 512 512">
<path
d="M512 255.1c0 11.34-7.406 20.86-18.44 23.64l-171.3 42.78l-42.78 171.1C276.7 504.6 267.2 512 255.9 512s-20.84-7.406-23.62-18.44l-42.66-171.2L18.47 279.6C7.406 276.8 0 267.3 0 255.1c0-11.34 7.406-20.83 18.44-23.61l171.2-42.78l42.78-171.1C235.2 7.406 244.7 0 256 0s20.84 7.406 23.62 18.44l42.78 171.2l171.2 42.78C504.6 235.2 512 244.6 512 255.1z"
></path>
</svg>
</span>
<span class="magic-star">
<svg viewBox="0 0 512 512">
<path
d="M512 255.1c0 11.34-7.406 20.86-18.44 23.64l-171.3 42.78l-42.78 171.1C276.7 504.6 267.2 512 255.9 512s-20.84-7.406-23.62-18.44l-42.66-171.2L18.47 279.6C7.406 276.8 0 267.3 0 255.1c0-11.34 7.406-20.83 18.44-23.61l171.2-42.78l42.78-171.1C235.2 7.406 244.7 0 256 0s20.84 7.406 23.62 18.44l42.78 171.2l171.2 42.78C504.6 235.2 512 244.6 512 255.1z"
></path>
</svg>
</span>
<span class="magic-star">
<svg viewBox="0 0 512 512">
<path
d="M512 255.1c0 11.34-7.406 20.86-18.44 23.64l-171.3 42.78l-42.78 171.1C276.7 504.6 267.2 512 255.9 512s-20.84-7.406-23.62-18.44l-42.66-171.2L18.47 279.6C7.406 276.8 0 267.3 0 255.1c0-11.34 7.406-20.83 18.44-23.61l171.2-42.78l42.78-171.1C235.2 7.406 244.7 0 256 0s20.84 7.406 23.62 18.44l42.78 171.2l171.2 42.78C504.6 235.2 512 244.6 512 255.1z"
></path>
</svg>
</span>
<span class="magic-text">frecuentes</span>
</span>
</h2>
<div
class="card group relative bg-cover bg-center outline-0 transition-transform duration-100"
data-color="have"
>
<Image
src={FaqImage}
width={384}
height={576}
alt="Lola Lolita firmando autógrafos en un escenario."
class="card-front-image card-image h-auto w-full max-w-sm rounded-[2rem]"
/>
<div class="card-faders">
<Image
width={384}
height={576}
alt={"Lola Lolita firmmando autografos1"}
class="card-fader card-image rounded-[2rem]"
src={FaqImage}
/>
<Image
width={384}
height={576}
alt={"Lola Lolita firmmando autografos2"}
class="card-fader card-image rounded-[2rem]"
src={FaqImage}
/>
<Image
width={384}
height={576}
alt={"Lola Lolita firmmando autografos3"}
class="card-fader card-image rounded-[2rem]"
src={FaqImage}
/>
<Image
width={384}
height={576}
alt={"Lola Lolita firmmando autografos4"}
class="card-fader card-image rounded-[2rem]"
src={FaqImage}
/>
<Image
width={384}
height={576}
alt={"Lola Lolita firmmando autografos5"}
class="card-fader card-image rounded-[2rem]"
src={FaqImage}
/>
<Image
width={384}
height={576}
alt={"Lola Lolita firmmando autografos6"}
class="card-fader card-image rounded-[2rem]"
src={FaqImage}
/>
<Image
width={384}
height={576}
alt={"Lola Lolita firmmando autografos7"}
class="card-fader card-image rounded-[2rem]"
src={FaqImage}
/>
<Image
width={384}
height={576}
alt={"Lola Lolita firmmando autografos8"}
class="card-fader card-image rounded-[2rem]"
src={FaqImage}
/>
</div>
</div>
</div>
<div class="pt-[68px] lg:col-span-7 lg:mt-0">
<div class="space-y-10">
<div class="bg-theme-blue relative rounded-xl md:rounded-t-xl" data-card-faq>
<dl>
<dt class="px-4 pt-4 font-semibold text-white">
¿Pueden ir menores de edad al evento?
</dt>
<div class="text-primary mx-4 my-2 border-t border-current" aria-hidden="true"></div>
<dd class="mt-1 max-w-2xl px-4 pb-6 text-sm text-pretty text-pink-100">
Se prohíbe el acceso a los menores de 14 años que no vayan acompañados por un adulto
que se haga responsable de la custodia y comportamiento de los mismos.
</dd>
</dl>
<div
class="hidden opacity-100 transition-all duration-500 ease-in-out sm:block"
data-wave-saparator-primary
>
<WaveSeparator bottomColor="var(--color-primary)" />
</div>
</div>
<div class="flex flex-col items-start justify-between gap-10 lg:flex-row">
<div
class="bg-theme-blue relative w-full rounded-xl md:w-auto md:rounded-t-xl"
data-card-faq
>
<dl>
<dt class="px-4 pt-4 font-semibold text-white">¿Cuántos días va a durar?</dt>
<div class="text-primary mx-4 my-2 border-t border-current" aria-hidden="true">
</div>
<dd class="mt-1 max-w-2xl px-4 pb-6 text-sm text-pretty text-pink-100">
Son dos días, el 14 y 15 de junio de 2025.
</dd>
</dl>
<div
class="hidden opacity-100 transition-all duration-500 ease-in-out sm:block"
data-wave-saparator-primary
>
<WaveSeparator bottomColor="var(--color-primary)" />
</div>
</div>
<div class="bg-theme-blue relative rounded-xl md:rounded-t-xl" data-card-faq>
<dl>
<dt class="px-4 pt-4 font-semibold text-white">¿Dónde se celebra?</dt>
<div class="text-primary mx-4 my-2 border-t border-current" aria-hidden="true">
</div>
<dd class="mt-1 max-w-2xl px-4 pb-6 text-sm text-pretty text-pink-100">
En el parque Aquopolis de Madrid, en Villanueva de la Cañada.
</dd>
</dl>
<div
class="hidden opacity-100 transition-all duration-500 ease-in-out sm:block"
data-wave-saparator-primary
>
<WaveSeparator bottomColor="var(--color-primary)" />
</div>
</div>
</div>
<div class="flex flex-col items-start justify-between gap-10 lg:flex-row">
<div class="bg-theme-blue relative rounded-xl md:rounded-t-xl" data-card-faq>
<dl>
<dt class="px-4 pt-4 font-semibold text-white">¿Asistirá Lola Lolita?</dt>
<div class="text-primary mx-4 my-2 border-t border-current" aria-hidden="true">
</div>
<dd class="mt-1 max-w-2xl px-4 pb-6 text-sm text-pretty text-pink-100">
Sí, Lola Lolita estará allí con unas cuantas sorpresas.
</dd>
</dl>
<div
class="hidden opacity-100 transition-all duration-500 ease-in-out sm:block"
data-wave-saparator-primary
>
<WaveSeparator bottomColor="var(--color-primary)" />
</div>
</div>
<div class="bg-theme-blue relative rounded-xl md:rounded-t-xl" data-card-faq>
<dl>
<dt class="px-4 pt-4 font-semibold text-white">
¿Hay comida para celíacos, veganos y vegetarianos?
</dt>
<div class="text-primary mx-4 my-2 border-t border-current" aria-hidden="true">
</div>
<dd class="mt-1 max-w-2xl px-4 pb-6 text-sm text-pretty text-pink-100">
¡Por supuesto que sí! Hay opciones para todos los gustos y necesidades. ¡Nadie se
quedará sin disfrutar de este día!
</dd>
</dl>
<div
class="hidden opacity-100 transition-all duration-500 ease-in-out sm:block"
data-wave-saparator-primary
>
<WaveSeparator bottomColor="var(--color-primary)" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<style>
.card {
background-size: cover;
background-position: center;
position: relative;
outline: none;
}
.card .card-front-image {
position: relative;
z-index: 2;
}
.card .card-image {
width: clamp(300px, 20vw, 500px);
aspect-ratio: 2 / 3;
border-radius: clamp(0.5rem, 0.75vw, 2rem);
}
.card-faders {
height: 100%;
width: 100%;
position: absolute;
left: 0px;
top: 0px;
z-index: 1;
opacity: 0;
transition: opacity 1500ms;
pointer-events: none;
}
.card:hover .card-faders {
opacity: 1;
}
.card-fader {
position: absolute;
left: 0px;
top: 0px;
}
.card-fader:nth-child(odd) {
animation: fade-left 3s linear infinite;
}
.card-fader:nth-child(even) {
animation: fade-right 3s linear infinite;
}
.card-fader:is(:nth-child(3), :nth-child(4)) {
animation-delay: 750ms;
}
.card-fader:is(:nth-child(5), :nth-child(6)) {
animation-delay: 1500ms;
}
.card-fader:is(:nth-child(7), :nth-child(8)) {
animation-delay: 2250ms;
}
@media (max-width: 1200px) {
.card .card-image {
width: 400px;
}
}
@media (max-width: 600px) {
.card {
width: 80%;
}
.card .card-image {
width: 100%;
}
}
@keyframes fade-left {
from {
scale: 1;
translate: 0%;
opacity: 1;
}
to {
scale: 0.8;
translate: -30%;
opacity: 0;
}
}
@keyframes fade-right {
from {
scale: 1;
translate: 0%;
opacity: 1;
}
to {
scale: 0.8;
translate: 30%;
opacity: 0;
}
}
.magic-star {
--size: clamp(20px, 1.5vw, 30px);
animation: scale 700ms ease forwards;
display: block;
height: var(--size);
left: var(--star-left);
position: absolute;
top: var(--star-top);
width: var(--size);
}
.magic > .magic-star > svg {
animation: rotate 1000ms linear infinite;
display: block;
opacity: 0.7;
}
.magic > .magic-star > svg > path {
fill: #dfdf18;
}
.magic > .magic-text {
animation: background-pan 3s linear infinite;
background: linear-gradient(to right, #383acf, #61e2e5, #383acf, #383acf);
background-size: 200%;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
white-space: nowrap;
}
</style>
<script>
let index = 0
let interval = 1000
const rand = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1)) + min
const animate = (star: HTMLElement) => {
star.style.setProperty("--star-left", `${rand(-10, 100)}%`)
star.style.setProperty("--star-top", `${rand(-40, 80)}%`)
star.style.animation = "none"
star.offsetHeight
star.style.animation = ""
}
for (const star of document.getElementsByClassName(
"magic-star"
) as HTMLCollectionOf<HTMLElement>) {
setTimeout(
() => {
animate(star)
setInterval(() => animate(star), 1000)
},
index++ * (interval / 3)
)
}
</script>
================================================
FILE: src/sections/Footer.astro
================================================
---
import Sponsor from "@/components/Sponsor.astro"
import Instagram from "../../public/icons/instagram.svg"
import TikTok from "../../public/icons/tiktok.svg"
import InfoJobs from "../assets/infojobs.svg"
---
<footer
class="footer footer-horizontal footer-center text-primary-content flex flex-col items-center justify-center p-10 text-center"
>
<aside class="flex flex-col items-center">
<div
class="logo lazy_background_image_maskImage lazy_background_image relative size-28 lg:size-32"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="4.71132 2 10.58 15"
role="img"
aria-labelledby="logoTitle"
>
<title id="logoTitle">Lola Lolita Land</title>
<path
d="M 5 2 L 15 2 C 16 3 14 4 15 5 C 16 6 14 7 15 8 C 16 9 14 10 15 11 C 16 12 14 13 15 14 C 16 15 14 16 15 17 L 5 17 C 4 16 6 15 5 14 C 4 13 6 12 5 11 C 4 10 6 9 5 8 C 4 7 6 6 5 5 C 4 4 6 3 5 2"
fill="#383acf"></path>
</svg>
</div>
<nav class="mt-6">
<div class="grid grid-flow-col gap-4">
<a
class="transition hover:scale-110"
href="https://www.instagram.com/lolalolita/"
target="_blank"
rel="noopener noreferrer"
aria-label="Visitar perfil de Instagram de Lola Lolita"
>
<span class="sr-only">Instagram de Lola Lolita</span>
<Instagram name="instagram" class="size-6 fill-white md:size-8" aria-hidden="true" />
</a>
<a
class="transition hover:scale-110"
href="https://www.tiktok.com/@lolalolita"
target="_blank"
rel="noopener noreferrer"
aria-label="Visitar perfil de TikTok de Lola Lolita"
>
<span class="sr-only">TikTok de Lola Lolita</span>
<TikTok name="tiktok" class="size-6 fill-white md:size-8" aria-hidden="true" />
</a>
</div>
</nav>
<div class="mt-8 flex flex-wrap justify-center gap-4">
<a
class="text-xs text-white/80 transition hover:text-white hover:underline"
href="https://villanueva.aquopolis.es/condiciones-de-contratacion"
target="_blank"
rel="noopener noreferrer"
>
Condiciones de contratación
</a>
<a
class="text-xs text-white/80 transition hover:text-white hover:underline"
href="https://villanueva.aquopolis.es/normas-de-funcionamiento"
target="_blank"
rel="noopener noreferrer"
>
Normas de funcionamiento
</a>
</div>
<div
class="mt-8 mb-8 flex items-center justify-center gap-2 rounded bg-white px-4 text-xs text-black"
>
Web patrocinada por:
<Sponsor href="https://www.infojobs.net/" isOfficial>
<InfoJobs
title="InfoJobs"
width="90"
height="27"
class="inline-block transition-transform group-hover:scale-110"
/>
</Sponsor>
</div>
<p class="90 mt-2 text-xs text-pretty text-white">
Copyright © {new Date().getFullYear()} - Todos los derechos reservados
</p>
</aside>
</footer>
<style>
.logo {
-webkit-mask-image: url("/favicon.svg");
mask-image: url("/favicon.svg");
-webkit-mask-size: cover;
mask-size: cover;
background-color: rgb(243, 243, 243);
position: relative;
overflow: hidden;
}
.lazy_background_image_maskImage {
-webkit-mask-size: cover;
mask-size: cover;
-webkit-mask-image: url("/favicon.svg");
mask-image: url("/favicon.svg");
}
.lazy_background_image {
transition: 1s cubic-bezier(0.6, 0.6, 0, 1) opacity;
}
.logo svg {
width: 200px;
height: 300px;
position: absolute;
top: 10px;
left: 0;
animation: 8s linear infinite;
transform: translate(-300px, -70px) rotate(20deg);
animation-name: logo_animation !important;
}
@keyframes logo_animation {
0% {
transform: translate(-300px, -70px) rotate(20deg);
}
100% {
transform: translate(600px, -70px) rotate(20deg);
}
}
</style>
================================================
FILE: src/sections/Gallery.astro
================================================
---
import { galleryImages } from "@/consts/galleryImages"
import { Image } from "astro:assets"
import BubbleBackground from "@/components/BubbleBackground.astro"
import WaveSeparator from "@/components/WaveSeparator.astro"
---
<WaveSeparator bottomColor="var(--color-primary)" hasBubbles />
<section class="bg-theme-blue relative py-16 md:px-6 lg:px-8">
<BubbleBackground />
<div class="mx-auto max-w-6xl" id="gallery">
<div class="relative mb-12 flex items-center justify-center">
<h2
class="title mb-2 block p-4 text-center text-[1.65rem] font-bold text-white sm:text-sm lg:text-4xl xl:text-5xl"
>
¡Así fue el año pasado!
</h2>
<h2
class="title2 mb-2 block p-4 text-center text-[1.65rem] font-bold text-white sm:text-sm lg:text-4xl xl:text-5xl"
>
¡Así fue el año pasado!
</h2>
</div>
<h3
class="block pb-20 text-center text-lg font-bold text-white opacity-80 max-md:px-6 max-md:pb-5"
>
Aquí tienes algunos recuerdos de la primera edición de Lola Lolita Land
</h3>
<ul
id="slider-mobile"
class="flex snap-x snap-mandatory overflow-x-auto p-10 md:hidden [&>*:nth-child(even)]:rotate-2 [&>*:nth-child(odd)]:rotate-[-2deg]"
>
{
galleryImages.map(({ image, alt, thumb }, index) => (
<li
class="-m-1 aspect-9/10 w-72 shrink-0 cursor-pointer snap-center rounded-md shadow-sm transition-transform duration-300 will-change-transform"
id={thumb + "slider"}
data-index={index}
>
<Image
src={image}
alt={alt}
width={950}
height={900}
data-thumbID={thumb + "slider"}
class="border-theme-blue-light h-full w-full rounded-md border border-dashed object-cover"
loading="lazy"
/>
</li>
))
}
</ul>
<ul
class="hidden grid-cols-1 gap-8 sm:grid-cols-2 md:grid md:grid-cols-3 lg:grid-cols-4 [&>*:nth-child(even)]:rotate-2 [&>*:nth-child(n)]:hover:scale-105 [&>*:nth-child(n)]:hover:rotate-0 [&>*:nth-child(n)]:hover:shadow-xl [&>*:nth-child(odd)]:rotate-[-2deg]"
>
{
galleryImages.map(({ image, alt, thumb }, index) => (
<li
id={thumb}
class="aspect-9/10 cursor-pointer rounded-md shadow-sm transition-transform duration-300 will-change-transform"
data-index={index}
>
<Image
src={image}
alt={alt}
width={950}
height={900}
data-thumbID={thumb}
class="border-theme-blue-light h-full w-full rounded-md border border-dashed object-cover"
loading="lazy"
/>
</li>
))
}
</ul>
</div>
<div
class="pointer-events-none fixed inset-0 flex cursor-pointer items-center justify-center p-4 opacity-0 transition-opacity duration-300 ease-in-out"
role="dialog"
aria-modal="true"
aria-labelledby="lightbox-title"
id="lightbox"
>
<h2 id="lightbox-title" class="sr-only">Galería de imágenes de Lola Lolita Land</h2>
<div class="relative w-full max-w-5xl p-4">
<button
type="button"
id="close-lightbox"
class="hover:text-primary absolute top-1 -right-16 z-[999999] cursor-pointer rounded-full bg-white p-2.5 text-gray-700 transition-all duration-300 ease-in will-change-transform hover:scale-125 sm:top-6 sm:right-6 md:top-8 md:right-8"
>
<span class="sr-only">Cerrar Galería</span>
<svg
class="size-6"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
aria-hidden="true"
data-slot="icon"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path>
</svg>
</button>
<button
id="prev-image"
class="hover:text-primary absolute -bottom-16 left-8 z-50 flex h-12 w-12 transform cursor-pointer items-center justify-center rounded-full bg-white p-2.5 text-2xl text-gray-700 transition-all duration-300 ease-in-out hover:scale-125 md:top-1/2 md:-translate-y-1/2 lg:-left-16"
>
<
</button>
<button
id="next-image"
class="hover:text-primary absolute right-8 -bottom-16 z-50 flex h-12 w-12 transform cursor-pointer items-center justify-center rounded-full bg-white p-2.5 text-2xl text-gray-700 transition-all duration-300 ease-in-out hover:scale-125 md:top-1/2 md:-translate-y-1/2 lg:-right-16"
>
>
</button>
<figure id="light-box-content"></figure>
</div>
</div>
</section>
<WaveSeparator bottomColor="var(--color-primary)" />
<script>
const galleryItems = Array.from(
document.querySelectorAll("#gallery li img")
) as HTMLImageElement[]
const lightBox = document.getElementById("lightbox") as HTMLDivElement
const lightBoxImgContainer = document.getElementById("light-box-content") as HTMLDivElement
const btnCloseLightBox = document.getElementById("close-lightbox") as HTMLButtonElement
const btnPrev = document.getElementById("prev-image") as HTMLButtonElement
const btnNext = document.getElementById("next-image") as HTMLButtonElement
let currentIndex = 0
const openLightBox = (index: number) => {
if (index < 0 || index >= galleryItems.length) return
currentIndex = index
const image = galleryItems[index] as HTMLImageElement
const previousImage = lightBoxImgContainer.querySelector("img") as HTMLImageElement
if (previousImage) {
const galleryParentID = previousImage.getAttribute("data-thumbID")
const galleryParent = document.getElementById(`${galleryParentID}`) as HTMLLIElement
galleryParent.appendChild(previousImage)
}
// Evitamos el error de dupliacado de viewTransitionName
galleryItems.forEach((img) => (img.style.viewTransitionName = "none"))
image.style.viewTransitionName = "selected-img"
lightBoxImgContainer.appendChild(image)
lightBox.classList.remove("opacity-0", "pointer-events-none")
lightBox.classList.add(
"bg-[#ff0693a4]",
"z-[9999]",
"opacity-100",
"pointer-events-auto",
"backdrop-blur-[10px]"
)
document.body.style.overflow = "hidden"
updateNavigationButtons()
}
const closeLightBox = (image: HTMLImageElement) => {
lightBox.classList.add("opacity-0", "pointer-events-none")
lightBox.classList.remove(
"bg-[#ff0693a4]",
"z-[9999]",
"opacity-100",
"pointer-events-auto",
"backdrop-blur-[10px]"
)
const galleryParentID = image.getAttribute("data-thumbID")
const galleryParent = document.getElementById(`${galleryParentID}`) as HTMLLIElement
galleryParent.appendChild(image)
document.body.style.overflow = "" // Restaurar scroll
}
const navigateLightBox = (direction: number) => {
let newIndex = currentIndex + direction
if (newIndex < 0 || newIndex >= galleryItems.length) return
if (!document.startViewTransition) {
openLightBox(newIndex)
return
}
document.startViewTransition(() => {
openLightBox(newIndex)
})
}
const updateNavigationButtons = () => {
if (btnPrev && btnNext) {
btnPrev.style.display = currentIndex > 0 ? "flex" : "none"
btnNext.style.display = currentIndex < galleryItems.length - 1 ? "flex" : "none"
}
}
galleryItems.forEach((image, index) => {
image.addEventListener("click", () => {
if (!document.startViewTransition) {
openLightBox(index)
return
}
galleryItems.forEach((img) => {
img.style.viewTransitionName = ""
})
image.style.viewTransitionName = "selected-img"
document.startViewTransition(() => {
openLightBox(index)
})
})
})
const handleClose = async () => {
const image = lightBoxImgContainer.querySelector("img") as HTMLImageElement
if (!image) return
if (!document.startViewTransition) {
closeLightBox(image)
return
}
const animation = document.startViewTransition(() => {
closeLightBox(image)
})
await animation.finished
image.style.viewTransitionName = "none"
}
lightBox.addEventListener("click", handleClose)
btnCloseLightBox.addEventListener("click", (event) => {
event.stopPropagation()
handleClose()
})
if (btnPrev && btnNext) {
btnPrev.addEventListener("click", (event) => {
event.stopPropagation()
navigateLightBox(-1)
})
btnNext.addEventListener("click", (event) => {
event.stopPropagation()
navigateLightBox(1)
})
}
document.addEventListener("keydown", async (event) => {
const isLightboxOpen = !lightBox.classList.contains("opacity-0")
if (event.key === "Escape") {
await handleClose()
} else if ((event.key === "ArrowRight" || event.key === "d") && isLightboxOpen) {
event.preventDefault()
navigateLightBox(1)
} else if ((event.key === "ArrowLeft" || event.key === "a") && isLightboxOpen) {
event.preventDefault()
navigateLightBox(-1)
}
})
const slider = document.getElementById("slider-mobile") as HTMLDivElement
const sliderItems = Array.from(slider.children) as HTMLElement[]
if (slider) {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
;(entry.target as HTMLElement).style.transform = "scale(1)"
} else {
;(entry.target as HTMLElement).style.transform = "scale(0.8)"
}
})
},
{
root: slider,
threshold: 0.9,
}
)
sliderItems.forEach((item) => {
observer.observe(item)
})
}
</script>
<style>
.title {
position: absolute;
color: transparent;
-webkit-text-stroke: 2px white;
}
.title2 {
position: absolute;
color: #ff0695;
animation: water 3s ease-in-out infinite;
}
@keyframes water {
0%,
100% {
clip-path: polygon(
0% 65%,
10% 50%,
25% 35%,
40% 50%,
55% 65%,
70% 50%,
85% 35%,
100% 50%,
100% 100%,
0% 100%
);
}
50% {
clip-path: polygon(
0% 35%,
15% 50%,
30% 65%,
45% 50%,
60% 35%,
75% 50%,
90% 65%,
100% 50%,
100% 100%,
0% 100%
);
}
}
#slider-mobile {
scrollbar-width: none;
}
#slider-mobile::-webkit-scrollbar {
display: none;
}
</style>
================================================
FILE: src/sections/Hero.astro
================================================
---
import DotBackground from "../components/DotBackground.astro"
---
<section class="relative pb-12">
<DotBackground />
<div
class="bg-theme-blue-light relative mx-auto mb-16 h-screen w-full md:aspect-video md:h-full md:object-cover"
>
<div
title="Logo de Lola Lolita Land"
class="absolute top-20 right-0 left-0 z-50 mx-auto flex justify-center md:top-0 lg:top-14"
>
<div
class="logo lazy_background_image_maskImage lazy_background_image relative size-56 md:size-44 lg:size-56"
>
<svg viewBox="4.71132 2 12.58 15">
<path
d="M 5 2 L 17 2 C 18 3 16 4 17 5 C 18 6 16 7 17 8 C 18 9 16 10 17 11 C 18 12 16 13 17 14 C 18 15 16 16 17 17 L 5 17 C 4 16 6 15 5 14 C 4 13 6 12 5 11 C 4 10 6 9 5 8 C 4 7 6 6 5 5 C 4 4 6 3 5 2"
fill="#ff0695"></path>
</svg>
</div>
</div>
<div
class="image relative"
title="Fotografía de una joven recostada, que es Lola Lolita, sobre la arena con una cola de sirena azul, frente a una piscina con toboganes rosas en un entorno tropical, con el texto ‘Lola Lolita Land’ en la parte superior."
>
<!-- Date and location temporarily hidden
<div class="date-location-container">
<div class="date">14-15 DE JUNIO</div>
<div class="location">Aquopolis de Madrid</div>
</div>
-->
<div class="water"></div>
<svg>
<defs>
<filter id="turbulence" x="0" y="0" width="100%" height="100%">
<feTurbulence
id="sea-filter"
type="fractalNoise"
numOctaves="3"
seed="2"
baseFrequency="0.01 0.04"></feTurbulence>
<feDisplacementMap scale="10" in="SourceGraphic"></feDisplacementMap>
<animate
xlink:href="#sea-filter"
attributeName="baseFrequency"
dur="60s"
keyTimes="0;0.5;1"
values="0.02 0.03;0.04 0.06;0.02 0.06"
repeatCount="indefinite"></animate>
</filter>
</defs>
</svg>
</div>
<div class="absolute inset-0 bg-gradient-to-b from-transparent from-85% to-[#ff0695]"></div>
<div class="absolute z-20 w-full" id="header-waves">
<svg
class="waves"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 24 150 28 "
preserveAspectRatio="none"
>
<defs>
<path
id="wave-path"
d="M-160 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z"
>
</path>
</defs>
<g class="wave4">
<use xlink:href="#wave-path" x="50" y="0" class="fill-[#383acf] opacity-30"></use>
</g>
<g class="wave1">
<use xlink:href="#wave-path" x="50" y="3" class="fill-[#ff0695] opacity-50"></use>
</g>
<g class="wave2">
<use xlink:href="#wave-path" x="50" y="6" class="fill-[#ff0695] opacity-70"></use>
</g>
<g class="wave3">
<use xlink:href="#wave-path" x="50" y="9" class="fill-[#ff0695] opacity-50"></use>
</g>
</svg>
</div>
</div>
<style>
.date-location-container {
position: absolute;
bottom: 12%;
left: 0;
right: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 10;
text-align: center;
}
.date {
font-family: "Montserrat", sans-serif;
font-weight: 900;
font-size: clamp(1.4rem, 4vw, 3rem);
color: #ff0695;
text-shadow:
2px 2px 0 rgba(0, 0, 0, 0.3),
0 0 8px rgba(0, 0, 0, 0.2);
letter-spacing: 1px;
margin-bottom: 0.1rem;
line-height: 1;
}
.location {
font-family: "Montserrat", sans-serif;
font-weight: 700;
font-size: clamp(0.8rem, 2vw, 1.5rem);
color: #ff6bc5;
text-shadow:
1px 1px 0 rgba(0, 0, 0, 0.3),
0 0 6px rgba(0, 0, 0, 0.2);
letter-spacing: 0.5px;
}
.image {
background-image: url("/images/hero.webp");
height: 100%;
width: 100%;
background-size: cover;
z-index: 20;
}
.water {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url("/images/mask_hero.webp");
background-size: cover;
filter: url("#turbulence");
}
@media (max-width: 640px) and (orientation: portrait) {
.image {
background-image: url("/images/hero_sm_portrait.webp");
}
.water {
background-image: url("/images/mask_hero_sm_portrait.webp");
}
}
.logo {
-webkit-mask-image: url("/favicon.svg");
mask-image: url("/favicon.svg");
-webkit-mask-size: cover;
mask-size: cover;
background-color: rgb(243, 243, 243);
position: relative;
overflow: hidden;
}
.lazy_background_image_maskImage {
-webkit-mask-size: cover;
mask-size: cover;
-webkit-mask-image: url("/favicon.svg");
mask-image: url("/favicon.svg");
}
.lazy_background_image {
transition: 1s cubic-bezier(0.6, 0.6, 0, 1) opacity;
}
.logo svg {
width: 250px;
height: 300px;
position: absolute;
top: 30px;
left: 0;
animation: 8s linear infinite;
transform: translate(-300px, -70px) rotate(20deg);
animation-name: logo_animation !important;
}
@keyframes logo_animation {
0% {
transform: translate(-300px, -70px) rotate(20deg);
}
100% {
transform: translate(600px, -70px) rotate(20deg);
}
}
/* wave animation start */
.waves {
height: 80px;
width: 100%;
margin-top: -70px;
}
.wave1 use {
animation: move-forever1 10s linear infinite;
animation-delay: -2s;
}
.wave2 use {
animation: move-forever2 8s linear infinite;
animation-delay: -2s;
}
.wave3 use {
animation: move-forever3 6s linear infinite;
animation-delay: -2s;
}
.wave4 use {
animation: move-forever3 4s linear infinite;
animation-delay: -2s;
}
@-webkit-keyframes move-forever1 {
0% {
transform: translate(85px, 0%);
}
100% {
transform: translate(-90px, 0%);
}
}
@keyframes move-forever1 {
0% {
transform: translate(85px, 0%);
}
100% {
transform: translate(-90px, 0%);
}
}
@-webkit-keyframes move-forever2 {
0% {
transform: translate(-90px, 0%);
}
100% {
transform: translate(85px, 0%);
}
}
@keyframes move-forever2 {
0% {
transform: translate(-90px, 0%);
}
100% {
transform: translate(85px, 0%);
}
}
@-webkit-keyframes move-forever3 {
0% {
transform: translate(-90px, 0%);
}
100% {
transform: translate(85px, 0%);
}
}
@keyframes move-forever3 {
0% {
transform: translate(-90px, 0%);
}
100% {
transform: translate(85px, 0%);
}
}
@-webkit-keyframes move-forever4 {
0% {
transform: translate(-90px, 0%);
}
100% {
transform: translate(85px, 0%);
}
}
@keyframes move-forever4 {
0% {
transform: translate(-90px, 0%);
}
100% {
transform: translate(85px, 0%);
}
}
.waves > use {
animation: wave 25s cubic-bezier(0.5, 0.5, 0.45, 0.5) infinite;
}
@keyframes wave {
0% {
transform: translate3d(-90px, 0, 0);
}
100% {
transform: translate3d(85px, 0, 0);
}
}
@keyframes background-pan {
from {
background-position: 0% center;
}
to {
background-position: -200% center;
}
}
@keyframes scale {
from,
to {
transform: scale(0);
}
50% {
transform: scale(1);
}
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(180deg);
}
}
</style>
</section>
================================================
FILE: src/sections/Info.astro
================================================
---
import { Image } from "astro:assets"
import CalendarImage from "@/assets/images/calendario.webp"
---
<div class="mx-auto max-w-2xl p-4 pb-32 lg:max-w-6xl">
<div
class="mx-auto flex flex-row items-center justify-center gap-x-4 text-lg font-semibold tracking-tight text-balance text-gray-950 md:gap-x-8 md:text-2xl lg:text-3xl xl:text-4xl"
>
<div class="shrink-0">
<Image
class="mx-auto inline-block size-20 rounded-full md:size-28"
src="/avatar.webp"
alt="Lola Lolita"
width={112}
height={112}
/>
</div>
<span class="inline-block py-4 text-left text-white md:py-6 lg:py-8">
¿Estáis preparados para
<br />
pasar
<span class="magic relative inline-block">
<span class="magic-star">
<svg viewBox="0 0 512 512">
<path
d="M512 255.1c0 11.34-7.406 20.86-18.44 23.64l-171.3 42.78l-42.78 171.1C276.7 504.6 267.2 512 255.9 512s-20.84-7.406-23.62-18.44l-42.66-171.2L18.47 279.6C7.406 276.8 0 267.3 0 255.1c0-11.34 7.406-20.83 18.44-23.61l171.2-42.78l42.78-171.1C235.2 7.406 244.7 0 256 0s20.84 7.406 23.62 18.44l42.78 171.2l171.2 42.78C504.6 235.2 512 244.6 512 255.1z"
></path>
</svg>
</span>
<span class="magic-star">
<svg viewBox="0 0 512 512">
<path
d="M512 255.1c0 11.34-7.406 20.86-18.44 23.64l-171.3 42.78l-42.78 171.1C276.7 504.6 267.2 512 255.9 512s-20.84-7.406-23.62-18.44l-42.66-171.2L18.47 279.6C7.406 276.8 0 267.3 0 255.1c0-11.34 7.406-20.83 18.44-23.61l171.2-42.78l42.78-171.1C235.2 7.406 244.7 0 256 0s20.84 7.406 23.62 18.44l42.78 171.2l171.2 42.78C504.6 235.2 512 244.6 512 255.1z"
></path>
</svg>
</span>
<span class="magic-star">
<svg viewBox="0 0 512 512">
<path
d="M512 255.1c0 11.34-7.406 20.86-18.44 23.64l-171.3 42.78l-42.78 171.1C276.7 504.6 267.2 512 255.9 512s-20.84-7.406-23.62-18.44l-42.66-171.2L18.47 279.6C7.406 276.8 0 267.3 0 255.1c0-11.34 7.406-20.83 18.44-23.61l171.2-42.78l42.78-171.1C235.2 7.406 244.7 0 256 0s20.84 7.406 23.62 18.44l42.78 171.2l171.2 42.78C504.6 235.2 512 244.6 512 255.1z"
></path>
</svg>
</span>
<span class="magic-text">dos días inolvidables</span>?
</span>
</span>
</div>
<div
class="view-animate-[--subjectReveal] animate-zoom-in animate-range-[entry_0%_cover_20%] grid scroll-mt-[31rem] grid-cols-1 gap-4 pt-10 sm:mt-4 md:scroll-mt-[34rem] lg:scroll-mt-[26rem] lg:grid-cols-6"
id="info"
>
<div class="relative lg:col-span-3">
<div
class="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] bg-white max-lg:rounded-t-[calc(2rem+1px)] lg:rounded-tl-[calc(2rem+1px)] lg:rounded-bl-[calc(2rem+1px)]"
>
<div class="relative h-80 w-full overflow-hidden">
<Image
class="relative h-full w-full object-cover object-[85%_center] [mask-image:linear-gradient(to_bottom,black_80%,transparent_100%)] sm:object-center"
src={CalendarImage}
width={672}
height={320}
alt="Calendario con la fecha del evento Lola Lolita Land 14 y 15 de junio de 2025"
/>
</div>
<div class="p-4 pt-4 sm:p-6 md:p-8 lg:p-10">
<h3 class="text-primary text-center text-sm/4 font-semibold lg:text-left">
14 y 15 de junio
</h3>
<p
class="mx-auto mt-2 max-w-[50ch] text-center text-xs/5 text-balance text-gray-600 sm:text-sm/6 lg:mx-0 lg:text-left"
>
Apunta en tu calendario, porque LolaLolita Land abre sus puertas el 14 y 15 de junio
para darle la bienvenida al verano.
</p>
<div class="mt-4 flex flex-col justify-start gap-2 lg:flex-row lg:gap-4">
<a
class="group inline-flex min-h-[38px] w-full items-center justify-center space-x-1 rounded-lg bg-gradient-to-br from-[#ff0695]/90 to-[#ff0695] p-1 px-3 text-center text-xs/4 break-words text-white shadow-[inset_0px_0px_8px_rgba(255,255,255,0.2)] transition-all duration-300 ease-out hover:scale-105 hover:from-[#ff0695] hover:to-[#ff0695]/90 hover:shadow-[inset_0px_0px_12px_rgba(255,255,255,0.3)] active:scale-100 lg:w-auto"
href="https://calendar.google.com/calendar/render?action=TEMPLATE&text=Lola+Lolita+Land+🌸&dates=20250614/20250616&details=La+experiencia+más+refrescante.&location=Aquopolis+Villanueva+de+la+Cañada"
target="_blank"
rel="noopener noreferrer"
>
<svg
class="transition-opacity"
x="0px"
y="0px"
width="30"
height="30"
viewBox="0 0 48 48"
>
<rect width="22" height="22" x="13" y="13" fill="#fff"></rect>
<polygon
fill="#1e88e5"
points="25.68,20.92 26.688,22.36 28.272,21.208 28.272,29.56 30,29.56 30,18.616 28.56,18.616"
></polygon>
<path
fill="#1e88e5"
d="M22.943,23.745c0.625-0.574,1.013-1.37,1.013-2.249c0-1.747-1.533-3.168-3.417-3.168 c-1.602,0-2.972,1.009-3.33,2.453l1.657,0.421c0.165-0.664,0.868-1.146,1.673-1.146c0.942,0,1.709,0.646,1.709,1.44 c0,0.794-0.767,1.44-1.709,1.44h-0.997v1.728h0.997c1.081,0,1.993,0.751,1.993,1.64c0,0.904-0.866,1.64-1.931,1.64 c-0.962,0-1.784-0.61-1.914-1.418L17,26.802c0.262,1.636,1.81,2.87,3.6,2.87c2.007,0,3.64-1.511,3.64-3.368 C24.24,25.281,23.736,24.363,22.943,23.745z"
></path>
<polygon fill="#fbc02d" points="34,42 14,42 13,38 14,34 34,34 35,38"></polygon>
<polygon fill="#4caf50" points="38,35 42,34 42,14 38,13 34,14 34,34"></polygon>
<path fill="#1e88e5" d="M34,14l1-4l-1-4H9C7.343,6,6,7.343,6,9v25l4,1l4-1V14H34z"
></path>
<polygon fill="#e53935" points="34,34 34,42 42,34"></polygon>
<path fill="#1565c0" d="M39,6h-5v8h8V9C42,7.343,40.657,6,39,6z"></path>
<path fill="#1565c0" d="M9,42h5v-8H6v5C6,40.657,7.343,42,9,42z"></path>
</svg>
<span>Añadir a Google Calendar</span>
</a>
<a
class="group inline-flex min-h-[38px] w-full items-center justify-center space-x-1 rounded-lg bg-gradient-to-br from-[#ff0695]/90 to-[#ff0695] p-1 px-3 text-center text-xs/4 break-words text-white shadow-[inset_0px_0px_8px_rgba(255,255,255,0.2)] transition-all duration-300 ease-out hover:scale-105 hover:from-[#ff0695] hover:to-[#ff0695]/90 hover:shadow-[inset_0px_0px_12px_rgba(255,255,255,0.3)] active:scale-100 lg:w-auto"
href="/events/event-lolalolita.ics"
download="Lola Lolita Land · 14 y 15 de Junio"
target="_blank"
rel="noopener noreferrer"
>
<svg x="0px" y="0px" width="30" height="30" viewBox="0 0 48 48">
<path
fill="#eceff1"
d="M15.556,43h16.889C38.274,43,43,38.274,43,32.444V15.556C43,9.726,38.274,5,32.444,5H15.556 C9.726,5,5,9.726,5,15.556v16.889C5,38.274,9.726,43,15.556,43z"
></path><path
fill="#ff3d00"
d="M20.868,13.77L21.437,10h1.199l-1.067,6h-1.215l-0.7-3.536L18.96,16h-1.22l-1.071-6h1.207 l0.565,3.766L19.145,10h1.018L20.868,13.77z"
></path><path
fill="#ff3d00"
d="M26.39,13.404h-1.887v1.591h2.234V16h-3.446v-6h3.437v1.009h-2.225v1.418h1.887V13.404z"
></path><path
fill="#ff3d00"
d="M27.433,16v-6h1.587c0.7,0,1.259,0.223,1.675,0.667c0.416,0.445,0.628,1.055,0.636,1.83v0.973 c0,0.788-0.208,1.407-0.625,1.857C30.291,15.775,29.717,16,28.986,16H27.433z M28.645,11.009v3.985h0.363 c0.404,0,0.688-0.106,0.853-0.319c0.165-0.213,0.252-0.58,0.26-1.102V12.53c0-0.56-0.079-0.951-0.235-1.173 c-0.157-0.221-0.423-0.337-0.8-0.348H28.645z"
></path><path
fill="#424242"
d="M23.211,36.004h-9.884V33.7l4.539-5.771c0.576-0.799,1-1.5,1.273-2.103 c0.273-0.603,0.409-1.181,0.409-1.734c0-0.745-0.128-1.329-0.386-1.751c-0.257-0.422-0.628-0.633-1.112-0.633 c-0.53,0-0.95,0.246-1.261,0.737c-0.311,0.492-0.467,1.183-0.467,2.074H13.05c0-1.029,0.213-1.97,0.639-2.823 c0.426-0.853,1.025-1.515,1.797-1.987C16.258,19.236,17.132,19,18.107,19c1.498,0,2.659,0.413,3.485,1.239 c0.826,0.826,1.239,1.999,1.239,3.52c0,0.944-0.229,1.903-0.685,2.874c-0.457,0.972-1.285,2.168-2.483,3.588l-2.154,3.076h5.702 V36.004z"
></path><path
fill="#424242"
d="M34.662,23.689c0,0.814-0.173,1.536-0.519,2.166c-0.346,0.63-0.822,1.133-1.428,1.509 c0.691,0.392,1.237,0.931,1.636,1.619c0.399,0.687,0.599,1.496,0.599,2.425c0,1.49-0.43,2.667-1.29,3.531 c-0.86,0.864-2.032,1.296-3.514,1.296s-2.661-0.432-3.537-1.296c-0.875-0.864-1.313-2.041-1.313-3.531 c0-0.929,0.199-1.739,0.599-2.43c0.399-0.691,0.949-1.229,1.648-1.613c-0.615-0.376-1.094-0.879-1.44-1.509 c-0.346-0.63-0.519-1.351-0.519-2.166c0-1.467,0.411-2.615,1.233-3.445C27.638,19.415,28.741,19,30.123,19 c1.398,0,2.504,0.419,3.318,1.256C34.255,21.093,34.662,22.237,34.662,23.689z M30.146,33.527c0.491,0,0.87-0.21,1.135-0.628 c0.265-0.418,0.397-1,0.397-1.745s-0.138-1.328-0.415-1.751s-0.657-0.634-1.14-0.634c-0.484,0-0.866,0.211-1.146,0.634 s-0.421,1.006-0.421,1.751s0.14,1.327,0.421,1.745C29.257,33.318,29.647,33.527,30.146,33.527z M31.413,23.861 c0-0.653-0.106-1.175-0.317-1.566c-0.211-0.392-0.535-0.588-0.973-0.588c-0.415,0-0.73,0.19-0.944,0.57 c-0.215,0.38-0.323,0.908-0.323,1.584c0,0.661,0.108,1.192,0.323,1.596c0.215,0.403,0.537,0.605,0.967,0.605 c0.43,0,0.749-0.202,0.956-0.605C31.309,25.054,31.413,24.522,31.413,23.861z"
></path>
</svg>
<span>Añadir a Apple Calendar</span>
</a>
</div>
</div>
</div>
<div
class="pointer-events-none absolute inset-px rounded-lg shadow-sm ring-1 ring-black/5 max-lg:rounded-t-[2rem] lg:rounded-tl-[2rem] lg:rounded-bl-[2rem]"
>
</div>
</div>
<div class="relative lg:col-span-3">
<div
class="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] bg-white lg:rounded-tr-[calc(2rem+1px)] lg:rounded-br-[calc(2rem+1px)]"
>
<div class="relative h-80 w-full overflow-hidden">
<Image
class="relative h-full w-full object-cover object-center [mask-image:linear-gradient(to_bottom,black_80%,transparent_100%)]"
src="/images/aquopolis.webp"
alt="Imagen de los toboganes en Aquopolis"
width={1000}
height={513}
/>
</div>
<div class="p-4 pt-4 sm:p-6 md:p-8 lg:p-10">
<h3 class="text-primary text-center text-sm/4 font-semibold lg:text-left">
La experiencia más refrescante
</h3>
<p
class="mx-auto mt-2 max-w-[50ch] text-center text-xs/5 text-balance text-gray-600 sm:text-sm/6 lg:mx-0 lg:text-left"
>
Este año Lola Lolita Land se celebra en Aquopolis, Madrid, un parque acuático lleno de
toboganes y piscinas.
</p>
<div class="mt-4 flex flex-col items-stretch gap-2 lg:flex-row lg:items-center lg:gap-4">
<a
class="group inline-flex min-h-[38px] w-full items-center justify-center space-x-1 rounded-lg bg-gradient-to-br from-[#ff0695]/90 to-[#ff0695] p-1 px-3 text-center text-xs/4 break-words text-white shadow-[inset_0px_0px_8px_rgba(255,255,255,0.2)] transition-all duration-300 ease-out hover:scale-105 hover:from-[#ff0695] hover:to-[#ff0695]/90 hover:shadow-[inset_0px_0px_12px_rgba(255,255,255,0.3)] active:scale-100 lg:flex-1"
href="https://villanueva.aquopolis.es/condiciones-de-contratacion"
target="_blank"
rel="noopener noreferrer"
>
<svg
class="text-white transition-all"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
<path d="M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7l5 5v11a2 2 0 0 1-2 2z"></path>
<path d="M9 9h1"></path>
<path d="M9 13h6"></path>
<path d="M9 17h6"></path>
</svg>
<span>Condiciones de contratación</span>
</a>
<a
class="group inline-flex min-h-[38px] w-full items-center justify-center space-x-1 rounded-lg bg-gradient-to-br from-[#ff0695]/90 to-[#ff0695] p-1 px-3 text-center text-xs/4 break-words text-white shadow-[inset_0px_0px_8px_rgba(255,255,255,0.2)] transition-all duration-300 ease-out hover:scale-105 hover:from-[#ff0695] hover:to-[#ff0695]/90 hover:shadow-[inset_0px_0px_12px_rgba(255,255,255,0.3)] active:scale-100 lg:flex-1"
href="https://villanueva.aquopolis.es/normas-de-funcionamiento"
target="_blank"
rel="noopener noreferrer"
>
<svg
class="text-white transition-all"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 16v-4"></path>
<path d="M12 8h.01"></path>
</svg>
<span>Normas de funcionamiento</span>
</a>
</div>
</div>
</div>
<div
class="pointer-events-none absolute inset-px rounded-lg shadow-sm ring-1 ring-black/5 lg:rounded-tr-[2rem] lg:rounded-br-[2rem]"
>
</div>
</div>
</div>
</div>
<script>
let index = 0
let interval = 1000
const rand = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1)) + min
const animate = (star: HTMLElement) => {
star.style.setProperty("--star-left", `${rand(-10, 100)}%`)
star.style.setProperty("--star-top", `${rand(-40, 80)}%`)
star.style.animation = "none"
}
for (const star of document.getElementsByClassName(
"magic-star"
) as HTMLCollectionOf<HTMLElement>) {
setTimeout(
() => {
animate(star)
setInterval(() => animate(star), interval)
},
index++ * (interval / 3)
)
}
</script>
<style>
/* letter animation START */
.magic-star {
--size: clamp(20px, 1.5vw, 30px);
animation: scale 700ms ease forwards;
display: block;
height: var(--size);
left: var(--star-left);
position: absolute;
top: var(--star-top);
width: var(--size);
}
.magic > .magic-star > svg {
animation: rotate 1000ms linear infinite;
display: block;
opacity: 0.7;
}
.magic > .magic-star > svg > path {
fill: #dfdf18;
}
.magic > .magic-text {
animation: background-pan 3s linear infinite;
background: linear-gradient(to right, #383acf, #61e2e5, #383acf, #383acf);
background-size: 200%;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
white-space: nowrap;
}
</style>
================================================
FILE: src/sections/Map.astro
================================================
---
import Uber from "@/assets/uber.webp"
import LeafletMap from "@/components/LeafletMap.astro"
import BubbleBackground from "@/components/BubbleBackground.astro"
import WaveSeparator from "@/components/WaveSeparator.astro"
import { lolalolitalandGeoJSON, potaBlavaGeoJSON } from "@/consts/geoJSONData.ts"
import { Image } from "astro:assets"
---
<WaveSeparator bottomColor="var(--color-primary)" hasBubbles />
<section id="mapa" class="bg-theme-blue relative py-12 pb-24">
<BubbleBackground />
<h2
class="mx-auto flex flex-row items-center justify-center gap-x-4 py-4 text-left text-lg font-semibold tracking-tight text-balance text-white md:gap-x-8 md:py-6 md:text-2xl lg:py-8 lg:pb-4 lg:text-3xl xl:text-4xl"
>
¡Nos vemos aquí!
</h2>
<h3 class="flex flex-col items-center justify-center gap-1.5 text-white md:flex-row">
Lola Lolita Land se celebra en <a
href="https://maps.app.goo.gl/QEWvh6e1cAZoqhCS7"
target="_blank"
rel="noopener"
class="hover:text-primary animate-ease-in-out inline-block max-w-full rounded-lg bg-pink-200 px-2 py-1 text-center break-words text-pink-950 transition hover:bg-white"
>Aquopolis Villanueva de la Cañada</a
>
</h3>
<div class="m-auto mt-4 flex max-w-[1315px] flex-row flex-wrap gap-8 p-4">
<div class="relative h-[630px] min-w-[300px] flex-1 overflow-hidden rounded-[2rem] bg-black">
<LeafletMap
latitude={40.45673263671421}
longitude={-3.990346247363024}
zoom={16}
tileLayer="https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png"
attribution=`<a class="mr-5" href="http://www.openstreetmap.org/">OpenStreetMap</a>`
geoJSON={[
{ data: lolalolitalandGeoJSON, color: "var(--color-primary)" },
{ data: potaBlavaGeoJSON, color: "green" },
]}
/>
</div>
<div
class="flex w-full flex-shrink-0 flex-col gap-y-8 overflow-hidden md:w-[375px] lg:w-[550px]"
>
<div class="flex flex-col gap-2 px-4">
<h3
class="mb-2 flex w-fit flex-0 items-center gap-x-1 rounded-[2rem] bg-white px-4 py-2 text-base font-bold text-black"
>
Cómo llegar con <a
target="_blank"
rel="noopener"
href="https://www.uber.com/es/es-es/ride/?utm_source=LolaLolitaLand"
>
<Image
src={Uber}
title="Uber"
alt="Uber"
class="-mt-1 inline-block w-14 transition-transform group-hover:scale-110"
/>
</a>
</h3>
<p class="text-white">
¿Primera vez con UBER Teens? ¡Tienes un 50% de descuento pillando tu viaje a Lola Lolita
land!<br />
<span class="font-semibold"
>Código: <span class="text-primary-light">UBER_X_LOLALOLITA</span></span
>
</p>
<p class="text-xs text-white/90">
Te recogen en la entrada del Aquopolis. Más fácil, ¡ni hecho por nosotras!
</p>
</div>
{/* TRANSPORTE PÚBLICO */}
<div class="flex flex-col gap-2 px-4">
<h3
class="mb-2 flex w-fit flex-0 items-center gap-x-1 rounded-[2rem] bg-white px-4 py-2 text-base font-bold text-black"
>
Llegar en transporte público
</h3>
<p class="text-white">
Coge el bus 627 desde Moncloa (nivel -1, isla 1) y en nada estás en el parque.
</p>
<h4 class="font-semibold text-white">¿Vienes de fuera de Madrid?</h4>
<p class="text-white">
Desde Atocha puedes pillar el bus 001 (<span class="italic">¡gratis!</span>) hasta
Moncloa, o bajarte en metro directo al intercambiador.
</p>
</div>
{/* COCHE PROPIO */}
<div class="flex flex-col gap-2 px-4">
<h3
class="mb-2 flex w-fit flex-0 items-center gap-x-1 rounded-[2rem] bg-white px-4 py-2 text-base font-bold text-black"
>
Cómo llegar en coche
</h3>
<ul class="list-disc pl-6 text-left text-white">
<li><b>M-600:</b> conecta El Escorial con Brunete</li>
<li><b>M-501:</b> une la M-40 / M-50 con la M-600</li>
<li><b>M-503:</b> va desde Villanueva de la Cañada hasta la M-50 / Majadahonda</li>
</ul>
<p class="text-white">Y tranqui, ¡Aquopolis tiene parking!</p>
<p class="mt-2 text-xs text-white">
Pon buena música, activa el GPS y... ¡nos vemos en Lola Lolita land!
</p>
</div>
</div>
</div>
</section>
================================================
FILE: src/sections/Rides.astro
================================================
================================================
FILE: src/sections/Tickets.astro
================================================
---
import Marquee from "@/components/Marquee.astro"
import SponsorsBar from "@/components/SponsorsBar.astro"
import Ticket from "public/icons/ticket.svg"
import Clock from "public/icons/clock.svg"
---
<SponsorsBar />
<section class="relative w-full overflow-hidden" id="tickets">
<div class="bg-primary-light mx-auto my-[3%] -ml-2 w-[120%] -rotate-3 text-white">
<Marquee content={Array(8).fill("Entradas")} />
</div>
<div class="relative container mx-auto px-4 py-12">
<p
class="absolute inset-0 z-10 m-auto flex h-full w-full max-w-xl items-center justify-center text-center text-2xl font-semibold text-balance text-amber-200 text-shadow-[0_0_10px_#000]"
>
¡Gracias por asistir al evento! ¡Hasta el año que viene!
</p>
<div class="pointer-events-none mx-auto grid max-w-4xl grid-cols-1 gap-8 blur md:grid-cols-2">
<!-- Día 1: 14 de junio -->
<div
class="ticket-card group relative overflow-hidden rounded-[calc(var(--radius-lg)+1px)] rounded-t-[calc(2rem+1px)] border-0 bg-gradient-to-br from-white to-[#fff8fb] backdrop-blur-sm transition-all duration-300 hover:translate-y-[-5px] md:rounded-t-[calc(var(--radius-lg)+1px)] md:rounded-tl-[calc(2rem+1px)] md:rounded-bl-[calc(2rem+1px)]"
>
<div class="absolute inset-0 bg-gradient-to-br from-[#ff0695]/5 to-[#ff99d1]/10 opacity-50">
</div>
<div
class="absolute -top-20 -right-20 h-40 w-40 rounded-full bg-[#ff0695]/10 blur-3xl transition-all duration-500 group-hover:bg-[#ff0695]/20"
>
</div>
<div
class="absolute -bottom-24 -left-24 h-40 w-40 rounded-full bg-[#ff99d1]/10 blur-3xl transition-all duration-500 group-hover:bg-[#ff99d1]/20"
>
</div>
<div class="relative p-8">
<div class="flex items-start justify-between">
<div>
<div class="inline-block rounded-full bg-[#ff0695]/10 px-3 py-1">
<p class="text-primary text-xs font-semibold tracking-wide uppercase">Día 1</p>
</div>
<div class="mt-4 flex items-center gap-3">
<h3
class="bg-gradient-to-r from-[#ff0695] to-[#ff99d1] bg-clip-text text-5xl font-bold text-transparent"
>
14
</h3>
<div>
<p class="text-lg font-medium text-gray-800">de junio</p>
<p class="text-base text-gray-600">Sábado</p>
</div>
</div>
</div>
<div class="rounded-full bg-white/80 p-3 shadow-md">
<Ticket title="ticket" class="h-6 w-6 -rotate-12 fill-[#ff0695]" />
</div>
</div>
<div class="mt-8">
<a
href="https://lolalolitaland.deporticket.com/web-evento/11028-lola-lolita-land-14"
class="tickets-button relative flex w-full items-center justify-center gap-3 rounded-full bg-gradient-to-r from-[#ff0695] via-[#ff99d1] to-[#ff0695] px-4 py-3 font-bold text-white shadow-lg shadow-[#ff0695]/30 transition-all hover:scale-105 hover:shadow-xl hover:shadow-[#ff0695]/40"
tabindex="0"
aria-label="Comprar entrada para Lola Lolita Land para el 14 de junio (enlace externo, se abre en una pestaña nueva)"
target="_blank"
rel="noopener noreferrer"
>
<Ticket
aria-hidden="true"
focusable="false"
class="hidden h-5 w-5 -rotate-12 animate-bounce fill-white sm:inline-block"
/>
<span class="text-sm sm:text-base">Comprar entrada</span>
</a>
</div>
</div>
</div>
<!-- Día 2: 15 de junio -->
<div
class="ticket-card group pointer-events-none relative overflow-hidden rounded-[calc(var(--radius-lg)+1px)] rounded-b-[calc(2rem+1px)] border-0 bg-gradient-to-br from-white to-[#fff8fb] backdrop-blur-sm transition-all duration-300 hover:translate-y-[-5px] md:rounded-tr-[calc(2rem+1px)] md:rounded-b-[calc(var(--radius-lg)+1px)] md:rounded-br-[calc(2rem+1px)]"
>
<div class="absolute inset-0 bg-gradient-to-br from-[#ff0695]/5 to-[#ff99d1]/10 opacity-50">
</div>
<div
class="absolute -top-20 -right-20 h-40 w-40 rounded-full bg-[#ff0695]/10 blur-3xl transition-all duration-500 group-hover:bg-[#ff0695]/20"
>
</div>
<div
class="absolute -bottom-24 -left-24 h-40 w-40 rounded-full bg-[#ff99d1]/10 blur-3xl transition-all duration-500 group-hover:bg-[#ff99d1]/20"
>
</div>
<div class="relative p-8">
<div class="flex items-start justify-between">
<div>
<div class="inline-block rounded-full bg-[#ff0695]/10 px-3 py-1">
<p class="text-primary text-xs font-semibold tracking-wide uppercase">Día 2</p>
</div>
<div class="mt-4 flex items-center gap-3">
<h3
class="bg-gradient-to-r from-[#ff0695] to-[#ff99d1] bg-clip-text text-5xl font-bold text-transparent"
>
15
</h3>
<div>
<p class="text-lg font-medium text-gray-800">de junio</p>
<p class="text-base text-gray-600">Domingo</p>
</div>
</div>
</div>
<div class="rounded-full bg-white/80 p-3 shadow-md">
<Ticket title="ticket" class="h-6 w-6 -rotate-12 fill-[#ff0695]" />
</div>
</div>
<div class="mt-8">
<a
href="https://lolalolitaland.deporticket.com/web-evento/11215-lola-lolita-land-15"
class="tickets-button relative flex w-full items-center justify-center gap-3 rounded-full bg-gradient-to-r from-[#ff0695] via-[#ff99d1] to-[#ff0695] px-4 py-3 font-bold text-white shadow-lg shadow-[#ff0695]/30 transition-all hover:scale-105 hover:shadow-xl hover:shadow-[#ff0695]/40"
tabindex="0"
aria-label="Comprar entrada para Lola Lolita Land para el 15 de junio (enlace externo, se abre en una pestaña nueva)"
target="_blank"
rel="noopener noreferrer"
>
<Ticket
aria-hidden="true"
focusable="false"
class="hidden h-5 w-5 -rotate-12 animate-bounce fill-white sm:inline-block"
/>
<span class="text-sm sm:text-base">Comprar entrada</span>
</a>
</div>
</div>
</div>
</div>
</div>
<style>
.tickets-button {
background-size: 200% 100%;
/* animation: shimmer 3s linear infinite; */
position: relative;
overflow: hidden;
}
/* .tickets-button::before {
content: "";
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.3), transparent);
transform: rotate(30deg);
animation: shine 3s linear infinite;
} */
@keyframes shimmer {
0% {
background-position: 0% 0;
}
100% {
background-position: 200% 0;
}
}
@keyframes shine {
0% {
transform: translateX(-100%) rotate(30deg);
}
100% {
transform: translateX(100%) rotate(30deg);
}
}
</style>
</section>
================================================
FILE: src/styles/global.css
================================================
@import "tailwindcss";
@plugin "@midudev/tailwind-animations";
@theme {
--color-primary-light: #ff99d1;
--color-primary: #ff0695;
--color-primary-dark: #a80060;
--color-theme-blue: #383acf;
--color-theme-blue-light: #66dfff;
--color-theme-cyan: #61e2e5;
--color-theme-green: #2b8364;
--color-theme-green-light: #98d354;
--font-special: "Amertha", sans-serif;
/* animations */
--animate-marquee: slide-left 10s linear infinite;
--animate-shiny: shiny 5s linear forwards infinite;
@keyframes slide-left {
0% {
transform: translateX(0);
}
100% {
transform: translateX(calc(-100% - 1rem));
}
}
@keyframes shiny {
from {
background-position: 0 0;
}
to {
background-position: -200% 0;
}
}
}
@layer {
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background-color: var(--color-primary-light);
border: 1px solid #fff;
border-radius: 3px;
}
::-webkit-scrollbar-thumb {
background-color: #ff0593a8;
border: 1px solid #fff;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background-color: var(--color-primary);
}
}
@font-face {
font-family: "Amertha";
src: url("/fonts/amertha.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
body {
font-family: "Poppins", sans-serif;
transition: background-color 1000ms;
}
.text-stroke {
-webkit-text-stroke: 0.1rem white;
}
================================================
FILE: tailwind.config.js
================================================
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
theme: {
extend: {
keyframes: {
shimmer: {
'0%': { backgroundPosition: '0% 0' },
'100%': { backgroundPosition: '200% 0' }
},
shine: {
'0%': { transform: 'translateX(-100%) rotate(30deg)' },
'100%': { transform: 'translateX(100%) rotate(30deg)' }
}
},
animation: {
shimmer: 'shimmer 3s linear infinite',
shine: 'shine 3s linear infinite'
},
rotate: {
'30': '30deg'
}
},
},
plugins: [],
}
================================================
FILE: tsconfig.json
================================================
{
"extends": "astro/tsconfigs/strict",
"include": [
".astro/types.d.ts",
"**/*"
],
"exclude": [
"dist"
],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
}
}
gitextract_oiw4y92l/ ├── .editorconfig ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .vscode/ │ ├── css_custom_tailwind.json │ ├── extensions.json │ ├── launch.json │ └── settings.json ├── CONTRIBUTING.md ├── README.md ├── astro.config.mjs ├── package.json ├── public/ │ ├── events/ │ │ └── event-lolalolita.ics │ └── googlee0d1fc8a4713db25.html ├── pull_request_template.md ├── src/ │ ├── components/ │ │ ├── BackToTop.astro │ │ ├── BubbleBackground.astro │ │ ├── DotBackground.astro │ │ ├── Header.astro │ │ ├── HeaderLink.astro │ │ ├── LeafletMap.astro │ │ ├── Marquee.astro │ │ ├── Sponsor.astro │ │ ├── SponsorsBar.astro │ │ ├── StarryBackground.astro │ │ └── WaveSeparator.astro │ ├── consts/ │ │ ├── galleryImages.ts │ │ ├── geoJSONData.ts │ │ └── map-styles.js │ ├── layouts/ │ │ └── Layout.astro │ ├── pages/ │ │ ├── 404.astro │ │ └── index.astro │ ├── sections/ │ │ ├── ComoLlegar.astro │ │ ├── FAQ.astro │ │ ├── Footer.astro │ │ ├── Gallery.astro │ │ ├── Hero.astro │ │ ├── Info.astro │ │ ├── Map.astro │ │ ├── Rides.astro │ │ └── Tickets.astro │ └── styles/ │ └── global.css ├── tailwind.config.js └── tsconfig.json
SYMBOL INDEX (1 symbols across 1 files) FILE: src/consts/map-styles.js constant MAP_STYLES (line 1) | const MAP_STYLES =
Condensed preview — 44 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (149K chars).
[
{
"path": ".editorconfig",
"chars": 147,
"preview": "root = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ni"
},
{
"path": ".gitignore",
"chars": 311,
"preview": "# build output\ndist/\n\n# generated types\n.astro/\n\n# dependencies\nnode_modules/\n\n# logs\nnpm-debug.log*\nyarn-debug.log*\nyar"
},
{
"path": ".prettierignore",
"chars": 301,
"preview": "# build output\ndist/\n.output/\n\n# dependencies\nnode_modules/\n\n# logs\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-"
},
{
"path": ".prettierrc",
"chars": 312,
"preview": "{\n \"printWidth\": 100,\n \"semi\": false,\n \"singleQuote\": false,\n \"tabWidth\": 2,\n \"trailingComma\": \"es5\",\n \"useTabs\": "
},
{
"path": ".vscode/css_custom_tailwind.json",
"chars": 3531,
"preview": "{\n \"version\": 4.0,\n \"atDirectives\": [\n {\n \"name\": \"@theme\",\n \"description\": \"Use the `@theme` directive t"
},
{
"path": ".vscode/extensions.json",
"chars": 158,
"preview": "{\n \"recommendations\": [\n \"astro-build.astro-vscode\",\n \"bradlc.vscode-tailwindcss\",\n \"esbenp.prettier-vscode\",\n"
},
{
"path": ".vscode/launch.json",
"chars": 207,
"preview": "{\n \"version\": \"0.2.0\",\n \"configurations\": [\n {\n \"command\": \"./node_modules/.bin/astro dev\",\n \"name\": \"Dev"
},
{
"path": ".vscode/settings.json",
"chars": 636,
"preview": "{\n \"css.customData\": [\".vscode/css_custom_tailwind.json\"],\n \"editor.formatOnSave\": true,\n \"editor.defaultFormatter\": "
},
{
"path": "CONTRIBUTING.md",
"chars": 4213,
"preview": "## 🤝 Cómo Contribuir\n\nLas contribuciones son lo que hacen que la comunidad de código abierto sea un lugar increíble para"
},
{
"path": "README.md",
"chars": 1503,
"preview": "# 🌸 LOLA LOLITA LAND 🌸 - Sitio Web Oficial 2025\n\nEste proyecto es una iniciativa de la influencer [@lolalolita](https://"
},
{
"path": "astro.config.mjs",
"chars": 260,
"preview": "// @ts-check\nimport { defineConfig } from \"astro/config\"\n\nimport tailwindcss from \"@tailwindcss/vite\"\n\n// https://astro."
},
{
"path": "package.json",
"chars": 670,
"preview": "{\n \"name\": \"lolalolitaland-com-v2\",\n \"type\": \"module\",\n \"version\": \"0.0.3\",\n \"scripts\": {\n \"dev\": \"astro dev\",\n "
},
{
"path": "public/events/event-lolalolita.ics",
"chars": 450,
"preview": "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//Apple Inc.//NONSGML iCal//EN\nBEGIN:VEVENT\nSUMMARY:Lola Lolita Land 🌸\nDTSTART;VALUE"
},
{
"path": "public/googlee0d1fc8a4713db25.html",
"chars": 53,
"preview": "google-site-verification: googlee0d1fc8a4713db25.html"
},
{
"path": "pull_request_template.md",
"chars": 1737,
"preview": "## ¿Qué se ha hecho en esta PR?\n\nSe ha añadido una plantilla mejorada para las Pull Requests (PR) del proyecto, con el o"
},
{
"path": "src/components/BackToTop.astro",
"chars": 3667,
"preview": "<!-- Div para observar el scroll y mostrar/ocultar el botón -->\n<div\n id=\"scroll-observer\"\n class=\"pointer-events-none"
},
{
"path": "src/components/BubbleBackground.astro",
"chars": 2419,
"preview": "---\nconst bubbles = Array.from({ length: 30 }, (_, i) => ({\n id: i + 1,\n size: `${Math.random() * 30 + 10}px`,\n left:"
},
{
"path": "src/components/DotBackground.astro",
"chars": 7670,
"preview": "<div class=\"dot-background-container\">\n <canvas id=\"dotCanvas\" class=\"dot-canvas\"></canvas>\n</div>\n\n<style>\n .dot-back"
},
{
"path": "src/components/Header.astro",
"chars": 7671,
"preview": "---\nimport HeaderLink, { Device, Target } from \"@/components/HeaderLink.astro\"\n---\n\n<header class=\"animate-blur-header f"
},
{
"path": "src/components/HeaderLink.astro",
"chars": 866,
"preview": "---\nexport enum Device {\n MOBILE = \"MOBILE\",\n DESKTOP = \"DESKTOP\",\n}\n\nexport enum Target {\n BLANK = \"_blank\",\n SELF "
},
{
"path": "src/components/LeafletMap.astro",
"chars": 5085,
"preview": "---\n// Leaflet CSS and dependencies will be loaded dynamically\nimport type { FeatureCollection, Geometry, GeoJsonPropert"
},
{
"path": "src/components/Marquee.astro",
"chars": 602,
"preview": "---\nexport type Props = {\n content: Array<string>\n}\n\nconst { content } = Astro.props\n---\n\n<div class=\"flex mt-10 gap-x-"
},
{
"path": "src/components/Sponsor.astro",
"chars": 479,
"preview": "---\nconst { href } = Astro.props\n---\n\n<a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"group rela"
},
{
"path": "src/components/SponsorsBar.astro",
"chars": 7252,
"preview": "---\nimport Sponsor from \"@/components/Sponsor.astro\"\nimport Cerave from \"@/assets/cerave.svg\"\nimport Dkny from \"@/assets"
},
{
"path": "src/components/StarryBackground.astro",
"chars": 1320,
"preview": "---\nconst starCount = 120\nconst minDistance = 5\n\n// Función para calcular la distancia entre dos puntos\nconst getDistanc"
},
{
"path": "src/components/WaveSeparator.astro",
"chars": 1627,
"preview": "---\nconst { bottomColor = \"#ff0695\", hasBubbles = false } = Astro.props\n---\n\n<div\n class={`wave-container ${hasBubbles "
},
{
"path": "src/consts/galleryImages.ts",
"chars": 6496,
"preview": "import GalleryImg1 from \"@/assets/images/gallery/gallery_01.webp\"\nimport GalleryImg2 from \"@/assets/images/gallery/galle"
},
{
"path": "src/consts/geoJSONData.ts",
"chars": 4651,
"preview": "import type { FeatureCollection, Geometry, GeoJsonProperties } from \"geojson\"\n\nexport const lolalolitalandGeoJSON: Featu"
},
{
"path": "src/consts/map-styles.js",
"chars": 3480,
"preview": "export const MAP_STYLES = \n[\n {\n \"featureType\": \"all\",\n \"elementType\": \"geometry.stroke\",\n \"stylers\": [\n "
},
{
"path": "src/layouts/Layout.astro",
"chars": 4172,
"preview": "---\nimport \"@fontsource/poppins/400.css\"\nimport \"@fontsource/poppins/500.css\"\nimport \"@fontsource/poppins/600.css\"\nimpor"
},
{
"path": "src/pages/404.astro",
"chars": 1245,
"preview": "---\nimport Layout from \"../layouts/Layout.astro\"\nimport BubbleBackground from \"../components/BubbleBackground.astro\"\n---"
},
{
"path": "src/pages/index.astro",
"chars": 611,
"preview": "---\nimport Layout from \"@/layouts/Layout.astro\"\n\nimport Hero from \"@/sections/Hero.astro\"\nimport Tickets from \"@/section"
},
{
"path": "src/sections/ComoLlegar.astro",
"chars": 0,
"preview": ""
},
{
"path": "src/sections/FAQ.astro",
"chars": 12471,
"preview": "---\n// import FaqImage from \"@/assets/images/faq.webp\"\nimport FaqImage from \"@/assets/images/gallery/gallery_04.webp\"\nim"
},
{
"path": "src/sections/Footer.astro",
"chars": 4053,
"preview": "---\nimport Sponsor from \"@/components/Sponsor.astro\"\nimport Instagram from \"../../public/icons/instagram.svg\"\nimport Tik"
},
{
"path": "src/sections/Gallery.astro",
"chars": 10704,
"preview": "---\nimport { galleryImages } from \"@/consts/galleryImages\"\n\nimport { Image } from \"astro:assets\"\nimport BubbleBackground"
},
{
"path": "src/sections/Hero.astro",
"chars": 8246,
"preview": "---\nimport DotBackground from \"../components/DotBackground.astro\"\n---\n\n<section class=\"relative pb-12\">\n <DotBackground"
},
{
"path": "src/sections/Info.astro",
"chars": 15675,
"preview": "---\nimport { Image } from \"astro:assets\"\nimport CalendarImage from \"@/assets/images/calendario.webp\"\n---\n\n<div class=\"mx"
},
{
"path": "src/sections/Map.astro",
"chars": 4550,
"preview": "---\nimport Uber from \"@/assets/uber.webp\"\n\nimport LeafletMap from \"@/components/LeafletMap.astro\"\nimport BubbleBackgroun"
},
{
"path": "src/sections/Rides.astro",
"chars": 0,
"preview": ""
},
{
"path": "src/sections/Tickets.astro",
"chars": 7517,
"preview": "---\nimport Marquee from \"@/components/Marquee.astro\"\nimport SponsorsBar from \"@/components/SponsorsBar.astro\"\n\nimport Ti"
},
{
"path": "src/styles/global.css",
"chars": 1480,
"preview": "@import \"tailwindcss\";\n@plugin \"@midudev/tailwind-animations\";\n\n@theme {\n --color-primary-light: #ff99d1;\n --color-pri"
},
{
"path": "tailwind.config.js",
"chars": 668,
"preview": "/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n content: [\"./src/**/*.{astro,html,js,jsx,md,mdx,svelte,"
},
{
"path": "tsconfig.json",
"chars": 238,
"preview": "{\n \"extends\": \"astro/tsconfigs/strict\",\n \"include\": [\n \".astro/types.d.ts\",\n \"**/*\"\n ],\n \"exclude\": [\n \"dis"
}
]
About this extraction
This page contains the full source code of the midudev/lolalolitaland.com GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 44 files (136.1 KB), approximately 41.3k tokens, and a symbol index with 1 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.