Spaces:
Running
Running
| <html lang="es"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Mapa Turístico de Isla Mauricio</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" /> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| #map { | |
| height: 600px; | |
| border-radius: 16px; | |
| box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); | |
| } | |
| .custom-popup .leaflet-popup-content-wrapper { | |
| border-radius: 12px; | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(5px); | |
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); | |
| border-left: 5px solid #3b82f6; | |
| } | |
| .custom-popup .leaflet-popup-tip { | |
| background: rgba(255, 255, 255, 0.95); | |
| } | |
| .legend { | |
| background: rgba(255, 255, 255, 0.9); | |
| padding: 10px; | |
| border-radius: 8px; | |
| box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); | |
| max-height: 400px; | |
| overflow-y: auto; | |
| } | |
| .legend i { | |
| width: 18px; | |
| height: 18px; | |
| float: left; | |
| margin-right: 8px; | |
| opacity: 0.9; | |
| border-radius: 50%; | |
| } | |
| .location-card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15); | |
| } | |
| .active-card { | |
| border-left: 4px solid #3b82f6; | |
| background-color: #f8fafc; | |
| } | |
| .search-box { | |
| position: absolute; | |
| top: 10px; | |
| left: 50px; | |
| z-index: 1000; | |
| width: 300px; | |
| } | |
| .weather-card { | |
| background: linear-gradient(135deg, #3b82f6, #6366f1); | |
| color: white; | |
| border-radius: 12px; | |
| } | |
| .tour-guide { | |
| background: linear-gradient(135deg, #10b981, #14b8a6); | |
| color: white; | |
| border-radius: 12px; | |
| } | |
| .language-selector { | |
| position: absolute; | |
| top: 10px; | |
| right: 10px; | |
| z-index: 1000; | |
| } | |
| .scrollable-cards { | |
| max-height: 600px; | |
| overflow-y: auto; | |
| padding-right: 8px; | |
| } | |
| .scrollable-cards::-webkit-scrollbar { | |
| width: 6px; | |
| } | |
| .scrollable-cards::-webkit-scrollbar-track { | |
| background: #f1f1f1; | |
| border-radius: 10px; | |
| } | |
| .scrollable-cards::-webkit-scrollbar-thumb { | |
| background: #cbd5e1; | |
| border-radius: 10px; | |
| } | |
| .scrollable-cards::-webkit-scrollbar-thumb:hover { | |
| background: #94a3b8; | |
| } | |
| /* --- A partir de aquí, reglas para el chat de Relevance AI --- */ | |
| html body .relevanceai-chat-bubble-container, | |
| html body .relevanceai-chat-bubble-container iframe { | |
| position: fixed ; | |
| z-index: 2147483647 ; | |
| bottom: 20px ; | |
| right: 20px ; | |
| pointer-events: auto ; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <header class="text-center mb-12"> | |
| <h1 class="text-4xl font-bold text-blue-800 mb-3">Descubre Isla Mauricio</h1> | |
| <p class="text-xl text-gray-600 max-w-3xl mx-auto"> | |
| Explora los lugares más fascinantes de este paraíso tropical en el Océano Índico | |
| </p> | |
| <div class="mt-6"> | |
| <div class="inline-flex items-center bg-gradient-to-r from-blue-500 to-teal-400 text-white px-6 py-3 rounded-full shadow-lg"> | |
| <i class="fas fa-map-marked-alt mr-2"></i> | |
| <span>Mapa Interactivo</span> | |
| </div> | |
| </div> | |
| </header> | |
| <div class="grid grid-cols-1 lg:grid-cols-4 gap-8 mb-8"> | |
| <div class="lg:col-span-1 bg-white p-6 rounded-xl shadow-md"> | |
| <div class="mb-6"> | |
| <h2 class="text-2xl font-semibold text-gray-800 mb-2 flex items-center"> | |
| <i class="fas fa-list-ul text-blue-500 mr-3"></i> | |
| Lugares destacados | |
| </h2> | |
| <div class="relative"> | |
| <input type="text" id="search-input" placeholder="Buscar lugares..." class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> | |
| <i class="fas fa-search absolute right-3 top-3 text-gray-400"></i> | |
| </div> | |
| </div> | |
| <div class="scrollable-cards" id="location-list"> | |
| <!-- Las tarjetas de ubicación se generarán con JavaScript --> | |
| </div> | |
| </div> | |
| <div class="lg:col-span-3 relative"> | |
| <div id="map" class="w-full"></div> | |
| <div class="mt-4 flex flex-wrap gap-2 justify-center" id="category-filters"> | |
| <!-- Los filtros por categoría se generarán con JavaScript --> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8"> | |
| <div class="weather-card p-6 shadow-md w-full"> | |
| <div class="flex items-center justify-between flex-wrap"> | |
| <div> | |
| <h3 class="text-xl font-semibold mb-1">Clima en Mauricio</h3> | |
| <p class="text-sm opacity-90">Actualizado en tiempo real</p> | |
| </div> | |
| <i class="fas fa-cloud-sun text-4xl opacity-80"></i> | |
| </div> | |
| <div class="mt-4 grid grid-cols-2 gap-4"> | |
| <div> | |
| <p class="text-sm opacity-90">Temperatura</p> | |
| <p id="temp" class="text-2xl font-bold">--</p> | |
| </div> | |
| <div> | |
| <p class="text-sm opacity-90">Humedad</p> | |
| <p id="humedad" class="text-2xl font-bold">--</p> | |
| </div> | |
| <div> | |
| <p class="text-sm opacity-90">Viento</p> | |
| <p id="viento" class="text-2xl font-bold">--</p> | |
| </div> | |
| <div> | |
| <p class="text-sm opacity-90">Condición</p> | |
| <p id="condicion" class="text-2xl font-bold">--</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="tour-guide p-6 shadow-md"> | |
| <div class="flex items-center justify-between"> | |
| <div> | |
| <h3 class="text-xl font-semibold mb-1">Reserva ahora </h3> | |
| <p class="text-sm opacity-90">8 Bonitos hoteles disponibles</p> | |
| </div> | |
| <i class="fas fa-user-tie text-4xl opacity-80"></i> | |
| </div> | |
| <div class="mt-4"> | |
| <p class="mb-3">Donde los preciosos lugares crean excepcionales recuerdos... | |
| Arrecifes de coral, vistas al océano, playas de arena blanca. Cada rincón es inolvidable. | |
| ¿Ya ha hecho una reserva?.</p> | |
| <a href="https://bookings.beachcomber-hotels.com/?hotel_id=&hotel_name=&contryId=195&country_id=195&client_type_id=8&adults=2&infant=0&children=0&check_in=&check_out=&isIndustryPartner=0&isTravelAgent=0&lang=es" target="_blank" rel="noopener noreferrer"> | |
| <button class="w-full bg-white text-teal-600 font-medium py-2 px-4 rounded-lg hover:bg-opacity-90 transition"> | |
| <i class="fas fa-calendar-check mr-2"></i> Reservar ahora | |
| </button> | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-md p-6 mt-8"> | |
| <h2 class="text-2xl font-semibold text-gray-800 mb-4">Sobre Isla Mauricio</h2> | |
| <div class="grid md:grid-cols-3 gap-6"> | |
| <div class="bg-blue-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-blue-800 mb-2 flex items-center"> | |
| <i class="fas fa-globe-africa mr-2"></i> Geografía | |
| </h3> | |
| <p class="text-gray-700"> | |
| Isla Mauricio es un país insular ubicado en el Océano Índico, a unos 2,000 km de la costa sureste de África. Conocida por sus playas, lagunas y arrecifes. | |
| </p> | |
| </div> | |
| <div class="bg-green-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-green-800 mb-2 flex items-center"> | |
| <i class="fas fa-umbrella-beach mr-2"></i> Clima | |
| </h3> | |
| <p class="text-gray-700"> | |
| Clima tropical con veranos cálidos y húmedos (noviembre a abril) e inviernos más frescos y secos (mayo a octubre). Temperaturas promedio entre 20°C y 30°C. | |
| </p> | |
| </div> | |
| <div class="bg-purple-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-purple-800 mb-2 flex items-center"> | |
| <i class="fas fa-landmark mr-2"></i> Cultura | |
| </h3> | |
| <p class="text-gray-700"> | |
| Mezcla única de influencias africanas, indias, europeas y chinas. Idiomas oficiales: inglés y francés, aunque el criollo mauriciano es ampliamente hablado. | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mt-8 bg-white rounded-xl shadow-md p-6"> | |
| <h2 class="text-2xl font-semibold text-gray-800 mb-4">Galería de Fotos</h2> | |
| <div class="grid grid-cols-2 md:grid-cols-4 gap-4"> | |
| <div class="rounded-lg overflow-hidden h-40"> | |
| <img src="https://cdn.beachcomber-hotels.com/v9/sites/default/files/styles/silder_desktop/public/royal-palm/slider-be-royal-palm-d.webp?itok=jHac7dsm?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80" alt="Playa de Mauricio" class="w-full h-full object-cover hover:scale-105 transition duration-300"> | |
| </div> | |
| <div class="rounded-lg overflow-hidden h-40"> | |
| <img src="https://cdn.beachcomber-hotels.com/v9/sites/default/files/styles/silder_desktop/public/dinarobin/slider-be-dinarobin-d.webp?itok=ZobJDW9o?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80" alt="Naturaleza de Mauricio" class="w-full h-full object-cover hover:scale-105 transition duration-300"> | |
| </div> | |
| <div class="rounded-lg overflow-hidden h-40"> | |
| <img src="https://cdn.beachcomber-hotels.com/v9/sites/default/files/styles/silder_desktop/public/paradis/slider-be-paradis-d.webp?itok=c_hwKZii?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80" alt="Ciudad de Mauricio" class="w-full h-full object-cover hover:scale-105 transition duration-300"> | |
| </div> | |
| <div class="rounded-lg overflow-hidden h-40"> | |
| <img src="https://cdn.beachcomber-hotels.com/v9/sites/default/files/styles/silder_desktop/public/trou-aux-biches/slider-be-trou-aux-biches-d.webp?itok=fiR9xNNj?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80" alt="Cultura de Mauricio" class="w-full h-full object-cover hover:scale-105 transition duration-300"> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Datos de los lugares turísticos con imágenes corregidas | |
| const locations = [ | |
| { | |
| id: 1, | |
| name: "Playa de Trou aux Biches", | |
| description: "Una de las playas más hermosas con arena blanca y aguas cristalinas perfectas para snorkeling.", | |
| lat: -20.034686, | |
| lng: 57.543839, | |
| category: "playa", | |
| icon: "umbrella-beach", | |
| color: "blue", | |
| image: "https://huggingface.co/spaces/svilalta/beachcomber-map/resolve/main/Trou%20aux%20biches.jpg?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "Todo el día", | |
| precio: "Gratis", | |
| destacado: "Mejor atardecer", | |
| rating: 4.8 | |
| }, | |
| { | |
| id: 2, | |
| name: "Parque Nacional Black River Gorges", | |
| description: "Reserva natural con senderos para caminatas, cascadas y una gran variedad de flora y fauna endémica.", | |
| lat: -20.4050, | |
| lng: 57.4550, | |
| category: "naturaleza", | |
| icon: "tree", | |
| color: "green", | |
| image: "https://huggingface.co/spaces/svilalta/beachcomber-map/resolve/main/Blackrivergorges.avif?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "8:00 AM - 6:00 PM", | |
| precio: "Entrada gratuita", | |
| destacado: "Vista panorámica", | |
| rating: 4.6 | |
| }, | |
| { | |
| id: 3, | |
| name: "Chamarel - Tierra de los 7 Colores", | |
| description: "Dunas de arena con siete colores distintos debido a la composición mineralógica única del lugar.", | |
| lat: -20.4406, | |
| lng: 57.3911, | |
| category: "naturaleza", | |
| icon: "mountain", | |
| color: "orange", | |
| image: "https://huggingface.co/spaces/svilalta/beachcomber-map/resolve/main/chamarel-colored-earth.jpg?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "8:30 AM - 5:30 PM", | |
| precio: "250 MUR (≈6 USD)", | |
| destacado: "Fenómeno geológico", | |
| rating: 4.7 | |
| }, | |
| { | |
| id: 4, | |
| name: "Port Louis", | |
| description: "La capital de Mauricio, con el famoso mercado central, el hipódromo y el Caudan Waterfront.", | |
| lat: -20.1619, | |
| lng: 57.5012, | |
| category: "ciudad", | |
| icon: "city", | |
| color: "red", | |
| image: "https://huggingface.co/spaces/svilalta/beachcomber-map/resolve/main/Port_Louis_Mauritius.jpeg?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "Mercado: 6:00 AM - 6:00 PM", | |
| precio: "Varía por actividad", | |
| destacado: "Cultura local", | |
| rating: 4.4 | |
| }, | |
| { | |
| id: 5, | |
| name: "Le Morne Brabant", | |
| description: "Montaña icónica declarada Patrimonio de la Humanidad por la UNESCO, con playas espectaculares en su base.", | |
| lat: -20.4525, | |
| lng: 57.3197, | |
| category: "naturaleza", | |
| icon: "mountain", | |
| color: "purple", | |
| image: "https://huggingface.co/spaces/svilalta/beachcomber-map/resolve/main/Le%20morne%20bravant.jpg?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "Todo el día", | |
| precio: "Gratis", | |
| destacado: "Patrimonio UNESCO", | |
| rating: 4.9 | |
| }, | |
| { | |
| id: 6, | |
| name: "Botánico Pamplemousses", | |
| description: "Uno de los jardines botánicos más antiguos del hemisferio sur, famoso por sus nenúfares gigantes.", | |
| lat: -20.1056, | |
| lng: 57.5683, | |
| category: "jardin", | |
| icon: "leaf", | |
| color: "teal", | |
| image: "https://huggingface.co/spaces/svilalta/beachcomber-map/resolve/main/jardin-botanico-pamplemousses.avif?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "8:30 AM - 5:30 PM", | |
| precio: "200 MUR (≈5 USD)", | |
| destacado: "Nenúfares gigantes", | |
| rating: 4.5 | |
| }, | |
| { | |
| id: 7, | |
| name: "Ile aux Cerfs", | |
| description: "Isla paradisíaca con playas de arena blanca y aguas turquesas, ideal para deportes acuáticos.", | |
| lat: -20.3864, | |
| lng: 57.7886, | |
| category: "playa", | |
| icon: "umbrella-beach", | |
| color: "blue", | |
| image: "https://huggingface.co/spaces/svilalta/beachcomber-map/resolve/main/ile-aux-cerfs.jpg?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "9:00 AM - 5:00 PM", | |
| precio: "Transporte en barco desde 500 MUR (≈12 USD)", | |
| destacado: "Deportes acuáticos", | |
| rating: 4.7 | |
| }, | |
| { | |
| id: 8, | |
| name: "Grand Bassin", | |
| description: "Lago sagrado hindú rodeado de templos y estatuas, incluyendo una gran estatua de Shiva.", | |
| lat: -20.4167, | |
| lng: 57.4833, | |
| category: "cultura", | |
| icon: "place-of-worship", | |
| color: "yellow", | |
| image: "https://huggingface.co/spaces/svilalta/beachcomber-map/resolve/main/lac-grand-bassin.webp?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "6:00 AM - 8:00 PM", | |
| precio: "Gratis", | |
| destacado: "Sitio religioso", | |
| rating: 4.3 | |
| }, | |
| // Hoteles Beachcomber con coordenadas corregidas | |
| { | |
| id: 9, | |
| name: "Beachcomber Victoria", | |
| description: "Hotel familiar con amplias instalaciones frente al mar en Pointe aux Piments.", | |
| lat: -20.0644, | |
| lng: 57.5186, | |
| category: "hotel", | |
| icon: "hotel", | |
| color: "pink", | |
| image: "https://cdn.crowdriff.com/in-use/8812e6a3-944c-705a-e1d4-206db01e015d/1080.jpg?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "Check-in: 14:00, Check-out: 12:00", | |
| precio: "Desde 250 USD/noche", | |
| destacado: "Piscinas y spa", | |
| rating: 4.6 | |
| }, | |
| { | |
| id: 10, | |
| name: "Trou aux Biches Beachcomber Golf Resort & Spa", | |
| description: "Ubicado en la costa noroeste de Mauricio, en el pueblo de Trou-aux-Biches, este resort se encuentra frente a una playa de arena blanca y una laguna turquesa, rodeado por un jardín tropical de 35 hectáreas.", | |
| lat: -20.0358, | |
| lng: 57.5448, | |
| category: "hotel", | |
| icon: "hotel", | |
| color: "pink", | |
| image: "https://cdn.crowdriff.com/in-use/7b0eb52d-fe67-a47d-f190-7aae6e67faa6/1080.jpg?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "Check-in: 14:00, Check-out: 12:00", | |
| precio: "Desde 400 USD/noche", | |
| destacado: "Campo de golf", | |
| rating: 4.8 | |
| }, | |
| { | |
| id: 11, | |
| name: "Canonnier Beachcomber Golf Resort & Spa", | |
| description: "Localizado en Pointe aux Canonniers, en la costa norte de Mauricio, este hotel está construido sobre un sitio histórico con vistas al océano y rodeado de jardines tropicales.", | |
| lat: -20.0103, | |
| lng: 57.5459, | |
| category: "hotel", | |
| icon: "hotel", | |
| color: "pink", | |
| image: "https://cdn.crowdriff.com/in-use/2772fa49-c9c9-78c0-c480-e0041416663d/1080.jpg?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "Check-in: 14:00, Check-out: 12:00", | |
| precio: "Desde 200 USD/noche", | |
| destacado: "Fuerte histórico", | |
| rating: 4.5 | |
| }, | |
| { | |
| id: 12, | |
| name: "Beachcomber Dinarobin", | |
| description: "Resort exclusivo a los pies del Morne Brabant con villas de lujo.", | |
| lat: -20.4519, | |
| lng: 57.3169, | |
| category: "hotel", | |
| icon: "hotel", | |
| color: "pink", | |
| image: "https://cdn.crowdriff.com/in-use/be6e3eaa-295e-24af-f2e9-daf12f98619a/1080.jpg?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "Check-in: 14:00, Check-out: 12:00", | |
| precio: "Desde 500 USD/noche", | |
| destacado: "Golf y spa", | |
| rating: 4.9 | |
| }, | |
| { | |
| id: 13, | |
| name: "Paradis Beachcomber Golf Resort & Spa", | |
| description: "Situado en la península de Le Morne, en la costa suroeste de Mauricio, este resort ofrece vistas impresionantes de la montaña Le Morne Brabant y acceso directo a una playa de arena blanca.", | |
| lat: -20.4399, | |
| lng: 57.3202, | |
| category: "hotel", | |
| icon: "hotel", | |
| color: "pink", | |
| image: "https://cdn.crowdriff.com/in-use/d35327de-976f-0e7d-b00c-2d208ec7a405/1080.jpg?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "Check-in: 14:00, Check-out: 12:00", | |
| precio: "Desde 450 USD/noche", | |
| destacado: "Campo de golf", | |
| rating: 4.7 | |
| }, | |
| { | |
| id: 14, | |
| name: "Beachcomber Shandrani", | |
| description: "Resort todo incluido en Blue Bay, cerca del parque marino.", | |
| lat: -20.4283, | |
| lng: 57.7167, | |
| category: "hotel", | |
| icon: "hotel", | |
| color: "pink", | |
| image: "https://cdn.crowdriff.com/in-use/24c33873-5093-d67f-9b36-a58ffb36369e/1080.jpg?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "Check-in: 14:00, Check-out: 12:00", | |
| precio: "Desde 350 USD/noche", | |
| destacado: "Todo incluido", | |
| rating: 4.6 | |
| }, | |
| { | |
| id: 15, | |
| name: "Beachcomber Royal Palm", | |
| description: "Hotel boutique de ultra lujo en Grand Baie, miembro de Leading Hotels of the World.", | |
| lat: -20.0167, | |
| lng: 57.5833, | |
| category: "hotel", | |
| icon: "hotel", | |
| color: "pink", | |
| image: "https://cdn.crowdriff.com/in-use/fca168ba-05e1-5fef-045c-1003a255bf00/1080.jpg?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "Check-in: 14:00, Check-out: 12:00", | |
| precio: "Desde 700 USD/noche", | |
| destacado: "Restaurante gourmet", | |
| rating: 4.9 | |
| }, | |
| { | |
| id: 16, | |
| name: "Beachcomber Mauricia", | |
| description: "Hotel moderno y animado en Grand Baie con ambiente juvenil.", | |
| lat: -20.0167, | |
| lng: 57.5800, | |
| category: "hotel", | |
| icon: "hotel", | |
| color: "pink", | |
| image: "https://images.unsplash.com/photo-1566073771259-6a8506099945?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80", | |
| horario: "Check-in: 14:00, Check-out: 12:00", | |
| precio: "Desde 180 USD/noche", | |
| destacado: "Vida nocturna", | |
| rating: 4.4 | |
| } | |
| ]; | |
| // Categorías únicas para los filtros | |
| const categories = [...new Set(locations.map(loc => loc.category))]; | |
| // Inicializar el mapa | |
| const map = L.map('map').setView([-20.2000, 57.5000], 10); | |
| // Añadir capa de mapa base | |
| L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |
| attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' | |
| }).addTo(map); | |
| // Añadir capa de satélite | |
| const satelliteLayer = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { | |
| attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community' | |
| }); | |
| // Control de capas | |
| const baseLayers = { | |
| "Mapa": L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |
| attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' | |
| }), | |
| "Satélite": satelliteLayer | |
| }; | |
| L.control.layers(baseLayers, null, {position: 'topright'}).addTo(map); | |
| // Iconos personalizados | |
| const iconColors = { | |
| blue: '#3b82f6', | |
| green: '#10b981', | |
| orange: '#f59e0b', | |
| red: '#ef4444', | |
| purple: '#8b5cf6', | |
| teal: '#14b8a6', | |
| yellow: '#eab308', | |
| pink: '#ec4899' | |
| }; | |
| // Crear marcadores para cada ubicación | |
| const markers = {}; | |
| locations.forEach(location => { | |
| const icon = L.divIcon({ | |
| html: `<div class="relative"> | |
| <i class="fas fa-${location.icon} text-white text-lg absolute inset-0 flex items-center justify-center"></i> | |
| <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| <path d="M16 32C24.8366 32 32 24.8366 32 16C32 7.16344 24.8366 0 16 0C7.16344 0 0 7.16344 0 16C0 24.8366 7.16344 32 16 32Z" fill="${iconColors[location.color]}"/> | |
| </svg> | |
| </div>`, | |
| className: '', | |
| iconSize: [32, 32], | |
| iconAnchor: [16, 32], | |
| popupAnchor: [0, -32] | |
| }); | |
| const marker = L.marker([location.lat, location.lng], { | |
| icon: icon, | |
| riseOnHover: true | |
| }).addTo(map); | |
| // Popup personalizado | |
| const popupContent = ` | |
| <div class="custom-popup w-64"> | |
| <div class="flex items-start"> | |
| <div class="flex-shrink-0 min-w-[128px] min-h-[72px] max-w-[128px] max-h-[72px] rounded-md overflow-hidden bg-gray-200"> | |
| <img src="${location.image}" | |
| alt="${location.name}" | |
| class="w-full h-full object-cover" | |
| onload="this.closest('.leaflet-popup-content-wrapper').style.height='auto';" | |
| onerror="this.style.display='none'"> | |
| </div> | |
| <div class="ml-4"> | |
| <h3 class="text-lg font-medium text-gray-900">${location.name}</h3> | |
| <div class="flex items-center mt-1"> | |
| ${renderStars(location.rating)} | |
| <span class="text-xs text-gray-500 ml-1">${location.rating}</span> | |
| </div> | |
| <p class="text-sm text-gray-500 mt-1">${location.description}</p> | |
| </div> | |
| </div> | |
| <div class="mt-2 grid grid-cols-2 gap-2 text-xs"> | |
| <div class="flex items-center"> | |
| <i class="fas fa-clock text-gray-500 mr-1"></i> | |
| <span>${location.horario}</span> | |
| </div> | |
| <div class="flex items-center"> | |
| <i class="fas fa-tag text-gray-500 mr-1"></i> | |
| <span>${location.precio}</span> | |
| </div> | |
| </div> | |
| <div class="mt-3 flex justify-between items-center"> | |
| <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-${location.color}-100 text-${location.color}-800"> | |
| ${location.category.charAt(0).toUpperCase() + location.category.slice(1)} | |
| </span> | |
| <span class="text-xs text-gray-500"> | |
| <i class="fas fa-star text-yellow-400 mr-1"></i> | |
| ${location.destacado} | |
| </span> | |
| </div> | |
| </div> | |
| `; | |
| marker.bindPopup(popupContent, { | |
| className: 'custom-popup', | |
| maxWidth: 300 | |
| }); | |
| markers[location.id] = marker; | |
| // Eventos del marcador | |
| marker.on('click', function() { | |
| highlightLocationCard(location.id); | |
| }); | |
| }); | |
| // Función para renderizar estrellas de rating | |
| function renderStars(rating) { | |
| let stars = ''; | |
| const fullStars = Math.floor(rating); | |
| const hasHalfStar = rating % 1 >= 0.5; | |
| for (let i = 0; i < fullStars; i++) { | |
| stars += '<i class="fas fa-star text-yellow-400 text-xs"></i>'; | |
| } | |
| if (hasHalfStar) { | |
| stars += '<i class="fas fa-star-half-alt text-yellow-400 text-xs"></i>'; | |
| } | |
| const emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0); | |
| for (let i = 0; i < emptyStars; i++) { | |
| stars += '<i class="far fa-star text-yellow-400 text-xs"></i>'; | |
| } | |
| return stars; | |
| } | |
| // Añadir leyenda | |
| const legend = L.control({position: 'bottomright'}); | |
| legend.onAdd = function(map) { | |
| const div = L.DomUtil.create('div', 'legend'); | |
| div.innerHTML = ` | |
| <h4 class="font-medium mb-2">Leyenda</h4> | |
| ${categories.map(cat => { | |
| const loc = locations.find(l => l.category === cat); | |
| return ` | |
| <div class="flex items-center mb-1"> | |
| <i class="fas fa-${loc.icon} text-${loc.color}-500 mr-2"></i> | |
| <span class="text-sm">${cat.charAt(0).toUpperCase() + cat.slice(1)}</span> | |
| </div> | |
| `; | |
| }).join('')} | |
| `; | |
| return div; | |
| }; | |
| legend.addTo(map); | |
| // Generar lista de ubicaciones con información adicional | |
| const locationList = document.getElementById('location-list'); | |
| locations.forEach(location => { | |
| const card = document.createElement('div'); | |
| card.className = `location-card bg-white p-4 rounded-lg shadow-sm cursor-pointer transition-all duration-300 border-l-4 border-transparent mb-3`; | |
| card.dataset.id = location.id; | |
| card.innerHTML = ` | |
| <div class="flex items-start"> | |
| <div class="flex-shrink-0 h-12 w-12 rounded-full bg-${location.color}-100 flex items-center justify-center"> | |
| <i class="fas fa-${location.icon} text-${location.color}-600"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <h3 class="text-sm font-medium text-gray-900">${location.name}</h3> | |
| <div class="flex items-center mt-1"> | |
| ${renderStars(location.rating)} | |
| <span class="text-xs text-gray-500 ml-1">${location.rating}</span> | |
| </div> | |
| <p class="text-xs text-gray-500 mt-1">${location.description.substring(0, 60)}...</p> | |
| <div class="mt-2 grid grid-cols-2 gap-1 text-xs text-gray-600"> | |
| <div class="flex items-center"> | |
| <i class="fas fa-clock mr-1 text-gray-400"></i> | |
| <span>${location.horario}</span> | |
| </div> | |
| <div class="flex items-center"> | |
| <i class="fas fa-tag mr-1 text-gray-400"></i> | |
| <span>${location.precio}</span> | |
| </div> | |
| </div> | |
| <div class="mt-2"> | |
| <span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-${location.color}-50 text-${location.color}-700"> | |
| <i class="fas fa-star text-yellow-400 mr-1"></i> | |
| ${location.destacado} | |
| </span> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| locationList.appendChild(card); | |
| // Evento click para las tarjetas | |
| card.addEventListener('click', function() { | |
| const id = parseInt(this.dataset.id); | |
| const location = locations.find(loc => loc.id === id); | |
| map.setView([location.lat, location.lng], 14); | |
| markers[id].openPopup(); | |
| highlightLocationCard(id); | |
| }); | |
| }); | |
| // Generar filtros por categoría | |
| const categoryFilters = document.getElementById('category-filters'); | |
| categoryFilters.innerHTML = ` | |
| <button class="filter-btn px-4 py-2 rounded-full bg-blue-100 text-blue-800 text-sm font-medium mr-2 mb-2 transition-all hover:bg-blue-200 active" data-category="all"> | |
| <i class="fas fa-globe mr-1"></i> Todos | |
| </button> | |
| ${categories.map(cat => { | |
| const icon = locations.find(loc => loc.category === cat).icon; | |
| const color = locations.find(loc => loc.category === cat).color; | |
| return ` | |
| <button class="filter-btn px-4 py-2 rounded-full bg-${color}-100 text-${color}-800 text-sm font-medium mr-2 mb-2 transition-all hover:bg-${color}-200" data-category="${cat}"> | |
| <i class="fas fa-${icon} mr-1"></i> ${cat.charAt(0).toUpperCase() + cat.slice(1)} | |
| </button> | |
| `; | |
| }).join('')} | |
| `; | |
| // Eventos para los filtros | |
| document.querySelectorAll('.filter-btn').forEach(btn => { | |
| btn.addEventListener('click', function() { | |
| // Actualizar botón activo | |
| document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active')); | |
| this.classList.add('active'); | |
| const category = this.dataset.category; | |
| // Filtrar marcadores | |
| locations.forEach(location => { | |
| if (category === 'all' || location.category === category) { | |
| map.addLayer(markers[location.id]); | |
| document.querySelector(`.location-card[data-id="${location.id}"]`).style.display = 'block'; | |
| } else { | |
| map.removeLayer(markers[location.id]); | |
| document.querySelector(`.location-card[data-id="${location.id}"]`).style.display = 'none'; | |
| } | |
| }); | |
| }); | |
| }); | |
| // Función para resaltar la tarjeta de ubicación | |
| function highlightLocationCard(id) { | |
| document.querySelectorAll('.location-card').forEach(card => { | |
| card.classList.remove('active-card'); | |
| }); | |
| document.querySelector(`.location-card[data-id="${id}"]`).classList.add('active-card'); | |
| // Scroll to the card if it's not visible | |
| const card = document.querySelector(`.location-card[data-id="${id}"]`); | |
| card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); | |
| } | |
| // Función de búsqueda | |
| const searchInput = document.getElementById('search-input'); | |
| searchInput.addEventListener('input', function() { | |
| const searchTerm = this.value.toLowerCase(); | |
| locations.forEach(location => { | |
| const card = document.querySelector(`.location-card[data-id="${location.id}"]`); | |
| const matches = location.name.toLowerCase().includes(searchTerm) || | |
| location.description.toLowerCase().includes(searchTerm) || | |
| location.category.toLowerCase().includes(searchTerm) || | |
| location.destacado.toLowerCase().includes(searchTerm); | |
| if (matches) { | |
| card.style.display = 'block'; | |
| map.addLayer(markers[location.id]); | |
| } else { | |
| card.style.display = 'none'; | |
| map.removeLayer(markers[location.id]); | |
| } | |
| }); | |
| }); | |
| // Mostrar todos los lugares al cargar | |
| document.querySelector('.filter-btn[data-category="all"]').click(); | |
| }); | |
| </script> | |
| <script> | |
| async function cargarClima() { | |
| const apiKey = 'be3a73d969a45ef91488e40c451538fc'; // ← Sustituye esto por tu API key real de OpenWeatherMap | |
| const ciudad = 'Port Louis, MU'; | |
| const url = `https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(ciudad)}&appid=${apiKey}&units=metric&lang=es`; | |
| try { | |
| const res = await fetch(url); | |
| const data = await res.json(); | |
| document.getElementById('temp').textContent = `${Math.round(data.main.temp)}°C`; | |
| document.getElementById('humedad').textContent = `${data.main.humidity}%`; | |
| document.getElementById('viento').textContent = `${data.wind.speed} km/h`; | |
| document.getElementById('condicion').textContent = data.weather[0].description; | |
| } catch (error) { | |
| console.error('Error al obtener el clima:', error); | |
| } | |
| } | |
| // Ejecutar al cargar la página | |
| window.addEventListener('load', cargarClima); | |
| </script> | |
| <script defer data-relevanceai-share-id="d7b62b/da163491735b-4702-9131-164746123dbb/e9f3d66a-015a-42a2-904a-b12726603090" src="https://app.relevanceai.com/embed/chat-bubble.js" data-share-styles="hide_tool_steps=true&hide_file_uploads=true&hide_conversation_list=false&bubble_style=icon&primary_color=%23000&bubble_icon=pd%2Fchat&input_placeholder_text=Ayuda+%7C+Help+%3F&hide_logo=true&hide_description=true" ></script> | |
| </body> | |
| </html> |