beachcomber-map / index.html
svilalta's picture
Update index.html
2813126 verified
Raw
History Blame Contribute Delete
40.5 kB
<!DOCTYPE html>
<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 !important;
z-index: 2147483647 !important;
bottom: 20px !important;
right: 20px !important;
pointer-events: auto !important;
}
</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: '&copy; <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 &copy; Esri &mdash; 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: '&copy; <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>