condor / index.html
condorhacker's picture
Add 3 files
721f497 verified
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Navigatore Italia</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
<script src="https://unpkg.com/@babylonjs/core@latest"></script>
<script src="https://unpkg.com/@babylonjs/loaders@latest"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" rel="stylesheet"/>
<style>
#map-2d {
height: 100vh;
width: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
#map-3d {
height: 100vh;
width: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 0;
visibility: hidden;
}
.search-suggestion {
@apply p-2 hover:bg-gray-100 cursor-pointer text-sm border-b border-gray-200 last:border-b-0;
}
.voice-bubble {
@apply bg-blue-600 text-white px-3 py-1 rounded-full text-xs animate-pulse;
}
.route-step {
@apply p-2 border-b border-gray-100 text-sm;
}
.route-step:last-child {
@apply border-b-0;
}
</style>
</head>
<body class="font-sans bg-gray-50 relative overflow-hidden">
<!-- 3D Map Container (Babylon.js) -->
<div id="map-3d"></div>
<!-- 2D Map Container (Leaflet) -->
<div id="map-2d"></div>
<!-- Top Navigation Bar -->
<div class="absolute top-0 left-0 w-full z-50 p-4 flex justify-between items-center bg-gradient-to-b from-black/70 to-transparent text-white">
<div class="flex items-center space-x-2">
<div class="bg-blue-500 p-2 rounded-full">
<i class="fas fa-map-marked-alt text-white"></i>
</div>
<h1 class="text-lg font-bold">Navigatore Italia</h1>
</div>
<button id="view-toggle" class="bg-white/20 backdrop-blur-sm p-2 rounded-full">
<i class="fas fa-cube text-white"></i>
</button>
</div>
<!-- Search Bar -->
<div class="absolute top-20 left-1/2 transform -translate-x-1/2 w-11/12 z-50 bg-white rounded-full shadow-lg overflow-hidden">
<div class="flex items-center p-2">
<i class="fas fa-search text-gray-400 ml-3"></i>
<input
type="text"
id="search-input"
placeholder="Cerca città, indirizzo..."
class="flex-grow p-2 outline-none text-sm"
/>
</div>
<!-- Search Suggestions -->
<div id="search-suggestions" class="hidden bg-white rounded-b-full shadow-lg max-h-60 overflow-y-auto">
<!-- Dynamically populated -->
</div>
</div>
<!-- Bottom Panel -->
<div id="bottom-panel" class="absolute bottom-0 left-0 w-full bg-white rounded-t-2xl shadow-lg p-4 transform translate-y-full transition-transform duration-300 z-50">
<div class="w-12 h-1 bg-gray-300 rounded-full mx-auto mb-4"></div>
<!-- Current Location -->
<div class="flex items-center mb-4">
<div class="bg-green-500 p-2 rounded-full mr-3">
<i class="fas fa-location-arrow text-white transform rotate-45"></i>
</div>
<div>
<p class="text-xs text-gray-500">Posizione attuale</p>
<p id="current-location" class="font-medium">Rilevamento posizione...</p>
</div>
</div>
<!-- Route Instructions -->
<div id="route-instructions" class="hidden">
<h3 class="font-bold mb-2">Istruzioni</h3>
<div id="route-steps" class="space-y-1">
<!-- Dynamically added -->
</div>
</div>
<!-- Start Navigation Button -->
<button id="start-navigation" class="hidden mt-4 bg-blue-600 text-white w-full py-3 rounded-xl font-bold shadow-lg hover:bg-blue-700 transition">
<i class="fas fa-car mr-2"></i> Inizia Navigazione
</button>
</div>
<!-- Voice Guidance Bubble -->
<div class="absolute top-32 right-5 z-50 hidden" id="voice-bubble">
<div class="voice-bubble px-4 py-2 rounded-full max-w-xs">
<i class="fas fa-volume-up mr-1"></i> <span id="voice-text">Preparati a girare</span>
</div>
</div>
<!-- Compass & Speed -->
<div class="absolute top-16 left-5 z-50 bg-white/90 backdrop-blur-sm p-2 rounded-full shadow hidden" id="compass-speed">
<div class="text-center">
<div class="text-xs font-bold" id="speed-value">0</div>
<div class="text-xs text-gray-600">km/h</div>
</div>
</div>
<script>
// Simulated Italian locations for search
const italianLocations = [
"Roma, Italia",
"Milano, Italia",
"Napoli, Italia",
"Torino, Italia",
"Palermo, Italia",
"Genova, Italia",
"Bologna, Italia",
"Firenze, Italia",
"Bari, Italia",
"Catania, Italia",
"Venezia, Italia",
"Verona, Italia",
"Messina, Italia",
"Padova, Italia",
"Trieste, Italia",
"Brescia, Italia",
"Taranto, Italia",
"Prato, Italia",
"Reggio Calabria, Italia",
"Modena, Italia",
"Via Garibaldi, Roma",
"Piazza del Duomo, Milano",
"Costiera Amalfitana, Salerno",
"Lago di Garda, Lombardia",
"Cinque Terre, La Spezia",
"Valle d'Aosta",
"Dolomiti, Trentino",
"Sicilia, Catania",
"Sardegna, Cagliari",
"Toscana, Siena"
];
// Initialize Leaflet Map (2D)
const map2d = L.map('map-2d').setView([41.9028, 12.4964], 6); // Center on Italy
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map2d);
// Initialize Babylon.js (3D)
const canvas = document.getElementById("map-3d");
const engine = new BABYLON.Engine(canvas, true);
const createScene = function () {
const scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color3(0.8, 0.9, 1);
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 20, new BABYLON.Vector3(0, 0, 0), scene);
camera.useAutoRotationBehavior = true;
camera.autoRotationBehavior.idleRotationSpeed = 0.01;
camera.autoRotationBehavior.zoomStopsAnimation = false;
camera.panningSensibility = 0;
camera.lowerRadiusLimit = 5;
camera.upperRadiusLimit = 50;
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 0.7;
// Create Italy-like 3D terrain
const ground = BABYLON.MeshBuilder.CreateGroundFromHeightMap(
"gdHM",
"https://www.babylonjs-playground.com/textures/heightMap.png",
{width: 20, height: 20, subdivisions: 100, minHeight: 0, maxHeight: 10, onReady: function(mesh) {
mesh.position.y = -5;
const material = new BABYLON.StandardMaterial("mat", scene);
material.diffuseTexture = new BABYLON.Texture("https://www.babylonjs-playground.com/textures/italy-map.jpg", scene);
mesh.material = material;
}},
scene
);
// Create some random 3D buildings to represent cities
const colors = [new BABYLON.Color3(0.8, 0.4, 0.4), new BABYLON.Color3(0.6, 0.6, 0.8), new BABYLON.Color3(0.9, 0.7, 0.5)];
const cities = [
{ name: "Roma", x: 0, z: 0, height: 2 },
{ name: "Milano", x: 3, z: -2, height: 1.8 },
{ name: "Napoli", x: -2, z: 3, height: 1.6 },
{ name: "Torino", x: 4, z: -4, height: 1.4 },
{ name: "Palermo", x: -6, z: 6, height: 1.2 }
];
cities.forEach(city => {
const box = BABYLON.MeshBuilder.CreateBox("city", {width: 0.5, depth: 0.5, height: city.height}, scene);
box.position = new BABYLON.Vector3(city.x, city.height/2, city.z);
const mat = new BABYLON.StandardMaterial("mat", scene);
mat.diffuseColor = colors[Math.floor(Math.random() * colors.length)];
box.material = mat;
});
return scene;
};
const scene = createScene();
engine.runRenderLoop(function () {
scene.render();
});
window.addEventListener("resize", function () {
engine.resize();
});
// UI Interactions
const searchInput = document.getElementById('search-input');
const searchSuggestions = document.getElementById('search-suggestions');
const bottomPanel = document.getElementById('bottom-panel');
const startNavigationBtn = document.getElementById('start-navigation');
const routeInstructions = document.getElementById('route-instructions');
const routeSteps = document.getElementById('route-steps');
const currentLocation = document.getElementById('current-location');
const viewToggle = document.getElementById('view-toggle');
const map3d = document.getElementById('map-3d');
const voiceBubble = document.getElementById('voice-bubble');
const voiceText = document.getElementById('voice-text');
const compassSpeed = document.getElementById('compass-speed');
const speedValue = document.getElementById('speed-value');
// Toggle between 2D and 3D views
viewToggle.addEventListener('click', () => {
if (map3d.style.visibility === 'visible') {
map3d.style.visibility = 'hidden';
document.getElementById('map-2d').style.zIndex = '1';
viewToggle.innerHTML = '<i class="fas fa-cube text-white"></i>';
} else {
map3d.style.visibility = 'visible';
document.getElementById('map-2d').style.zIndex = '0';
viewToggle.innerHTML = '<i class="fas fa-map text-white"></i>';
}
});
// Search input handling
searchInput.addEventListener('input', () => {
const query = searchInput.value.toLowerCase();
if (query.length > 2) {
const matches = italianLocations.filter(loc => loc.toLowerCase().includes(query));
if (matches.length > 0) {
searchSuggestions.innerHTML = '';
matches.forEach(match => {
const div = document.createElement('div');
div.className = 'search-suggestion';
div.textContent = match;
div.addEventListener('click', () => {
searchInput.value = match;
searchSuggestions.classList.add('hidden');
// Simulate setting destination
setDestination(match);
});
searchSuggestions.appendChild(div);
});
searchSuggestions.classList.remove('hidden');
} else {
searchSuggestions.classList.add('hidden');
}
} else {
searchSuggestions.classList.add('hidden');
}
});
// Close suggestions when clicking outside
document.addEventListener('click', (e) => {
if (!e.target.closest('.search-suggestion') && e.target !== searchInput) {
searchSuggestions.classList.add('hidden');
}
});
// Set destination and show route
function setDestination(destination) {
// Animate up the bottom panel
bottomPanel.classList.remove('translate-y-full');
// Simulate current position
currentLocation.textContent = "Roma, Via Nazionale";
// Show start navigation button and simulate route
startNavigationBtn.classList.remove('hidden');
// Simulate some route steps
const steps = [
"Parti da Via Nazionale verso ovest",
"Svolta a sinistra su Via Cavour",
"Continua su Via Nazionale per 500m",
"Svolta a destra su Via XX Settembre",
"Continua dritto per 1.2 km",
"Destinazione raggiunta"
];
routeSteps.innerHTML = '';
steps.forEach(step => {
const stepDiv = document.createElement('div');
stepDiv.className = 'route-step';
stepDiv.textContent = step;
routeSteps.appendChild(stepDiv);
});
routeInstructions.classList.remove('hidden');
}
// Start navigation simulation
startNavigationBtn.addEventListener('click', () => {
routeInstructions.classList.add('hidden');
startNavigationBtn.classList.add('hidden');
// Show voice bubble and speed
voiceBubble.classList.remove('hidden');
compassSpeed.classList.remove('hidden');
// Simulate voice guidance
const voiceMessages = [
"Preparati a girare a sinistra su Via Cavour",
"Continua dritto per 500 metri",
"Tra 300 metri, svolta a destra",
"Destinazione sulla destra",
"Hai raggiunto la destinazione"
];
let messageIndex = 0;
const voiceInterval = setInterval(() => {
if (messageIndex < voiceMessages.length) {
voiceText.textContent = voiceMessages[messageIndex];
messageIndex++;
} else {
clearInterval(voiceInterval);
setTimeout(() => {
alert("Hai raggiunto la destinazione!");
// Reset
voiceBubble.classList.add('hidden');
compassSpeed.classList.add('hidden');
bottomPanel.classList.add('translate-y-full');
searchInput.value = '';
}, 2000);
}
}, 8000);
// Simulate speed changes
let currentSpeed = 0;
const speedInterval = setInterval(() => {
if (messageIndex < 4) {
currentSpeed = Math.floor(Math.random() * 60) + 30; // 30-90 km/h
} else {
currentSpeed = Math.max(0, currentSpeed - 10);
}
speedValue.textContent = currentSpeed;
}, 1000);
// Stop speed simulation when done
setTimeout(() => {
clearInterval(speedInterval);
}, 30000);
});
// Simulate location updates
let userMarker;
let userPosition = [41.9028, 12.4964]; // Start in Rome
function updateLocation() {
// Simulate small movements
userPosition[0] += (Math.random() - 0.5) * 0.001;
userPosition[1] += (Math.random() - 0.5) * 0.001;
if (userMarker) {
userMarker.setLatLng(userPosition);
} else {
userMarker = L.marker(userPosition, {
icon: L.divIcon({
className: 'user-location',
html: '<div style="background-color: #4285F4; width: 12px; height: 12px; border-radius: 50%; border: 2px solid white; box-shadow: 0 0 5px rgba(0,0,0,0.5);"></div>',
iconSize: [16, 16],
iconAnchor: [8, 8]
})
}).addTo(map2d);
}
// Pan map to user if navigation is active
if (!startNavigationBtn.classList.contains('hidden') && !startNavigationBtn.classList.contains('hidden')) {
map2d.panTo(userPosition);
}
}
// Update location every 3 seconds
setInterval(updateLocation, 3000);
updateLocation(); // Initial location
// Try to get real user location
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position => {
userPosition = [position.coords.latitude, position.coords.longitude];
updateLocation();
currentLocation.textContent = `Lat: ${position.coords.latitude.toFixed(4)}, Lng: ${position.coords.longitude.toFixed(4)}`;
}, error => {
console.log("Unable to get location: ", error);
}, { enableHighAccuracy: true });
}
// Double-tap to expand bottom panel
let lastTap = 0;
bottomPanel.addEventListener('touchend', (e) => {
const currentTime = new Date().getTime();
const tapLength = currentTime - lastTap;
if (tapLength < 300 && tapLength > 0) {
// Double tap detected
if (bottomPanel.classList.contains('translate-y-full')) {
bottomPanel.classList.remove('translate-y-full');
} else {
bottomPanel.classList.add('translate-y-full');
}
}
lastTap = currentTime;
});
// Initial voice guidance
setTimeout(() => {
if (voiceBubble.classList.contains('hidden')) {
voiceBubble.classList.remove('hidden');
voiceText.textContent = "Benvenuto nel navigatore Italia";
}
}, 2000);
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-qwensite.hf.space/logo.svg" alt="qwensite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-qwensite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >QwenSite</a> - 🧬 <a href="https://enzostvs-qwensite.hf.space?remix=condorhacker/condor" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>