undefined / index.html
darkbreakerk's picture
Use Leaflet.js + OpenStreetMap
20691a0 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>StoreSpotter - Find Our Locations</title>
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<style>
.map-container {
height: 70vh;
border-radius: 1rem;
overflow: hidden;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.leaflet-popup-content-wrapper {
border-radius: 0.5rem !important;
padding: 0.5rem !important;
}
.leaflet-popup-content {
margin: 0.5rem !important;
}
.leaflet-control {
margin-right: 0 !important;
margin-bottom: 0 !important;
}
.custom-marker {
background-color: #3B82F6;
width: 20px;
height: 20px;
border-radius: 50%;
border: 3px solid white;
}
.user-marker {
background-color: #10B981;
width: 20px;
height: 20px;
border-radius: 50%;
border: 3px solid white;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7);
}
70% {
transform: scale(1);
box-shadow: 0 0 0 10px rgba(16, 185, 129, 0);
}
100% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba(16, 185, 129, 0);
}
}
</style>
</head>
<body class="bg-gray-50">
<!-- Navigation -->
<nav class="bg-white shadow-sm">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex items-center">
<i data-feather="map-pin" class="text-blue-500"></i>
<span class="ml-2 text-xl font-bold text-gray-800">StoreSpotter</span>
</div>
<div class="flex items-center space-x-4">
<a href="#" class="text-gray-700 hover:text-blue-600">Home</a>
<a href="#" class="text-gray-700 hover:text-blue-600">Stores</a>
<a href="#" class="text-gray-700 hover:text-blue-600">About</a>
<button class="bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600 transition">Contact</button>
</div>
</div>
</div>
</nav>
<!-- Hero Section -->
<div class="relative bg-gradient-to-r from-blue-500 to-blue-600 text-white py-16">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center">
<h1 class="text-4xl font-bold mb-4">Find Our Stores Near You</h1>
<p class="text-xl mb-8">Discover the closest StoreSpotter locations with real-time distance calculation</p>
<div class="max-w-md mx-auto relative">
<input type="text" placeholder="Enter your location" class="w-full px-4 py-3 rounded-lg text-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-300">
<button class="absolute right-2 top-2 bg-blue-600 text-white p-2 rounded-lg hover:bg-blue-700 transition">
<i data-feather="search"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Main Content -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Store List -->
<div class="bg-white rounded-xl shadow-md overflow-hidden lg:col-span-1">
<div class="p-6">
<h2 class="text-2xl font-bold text-gray-800 mb-6">Our Stores</h2>
<div class="space-y-4 max-h-[500px] overflow-y-auto pr-2">
<!-- Store Item 1 -->
<div class="border-b pb-4">
<div class="flex items-start">
<div class="bg-blue-100 p-3 rounded-lg mr-4">
<i data-feather="shopping-bag" class="text-blue-600"></i>
</div>
<div>
<h3 class="font-bold text-gray-800">Main Headquarters</h3>
<p class="text-gray-600">123 Business St, District 1</p>
<p class="text-sm text-gray-500">Open: 8AM - 10PM</p>
<p class="text-blue-500 font-medium mt-1">0.8 km away</p>
</div>
</div>
</div>
<!-- Store Item 2 -->
<div class="border-b pb-4">
<div class="flex items-start">
<div class="bg-blue-100 p-3 rounded-lg mr-4">
<i data-feather="shopping-bag" class="text-blue-600"></i>
</div>
<div>
<h3 class="font-bold text-gray-800">Westside Branch</h3>
<p class="text-gray-600">456 Shopping Ave, District 2</p>
<p class="text-sm text-gray-500">Open: 9AM - 9PM</p>
<p class="text-blue-500 font-medium mt-1">2.3 km away</p>
</div>
</div>
</div>
<!-- Store Item 3 -->
<div class="border-b pb-4">
<div class="flex items-start">
<div class="bg-blue-100 p-3 rounded-lg mr-4">
<i data-feather="shopping-bag" class="text-blue-600"></i>
</div>
<div>
<h3 class="font-bold text-gray-800">Downtown Store</h3>
<p class="text-gray-600">789 Central Blvd, District 3</p>
<p class="text-sm text-gray-500">Open: 7AM - 11PM</p>
<p class="text-blue-500 font-medium mt-1">1.5 km away</p>
</div>
</div>
</div>
<!-- Store Item 4 -->
<div class="border-b pb-4">
<div class="flex items-start">
<div class="bg-blue-100 p-3 rounded-lg mr-4">
<i data-feather="shopping-bag" class="text-blue-600"></i>
</div>
<div>
<h3 class="font-bold text-gray-800">Northside Plaza</h3>
<p class="text-gray-600">321 Market St, District 4</p>
<p class="text-sm text-gray-500">Open: 8AM - 10PM</p>
<p class="text-blue-500 font-medium mt-1">3.2 km away</p>
</div>
</div>
</div>
<!-- Store Item 5 -->
<div class="pb-4">
<div class="flex items-start">
<div class="bg-blue-100 p-3 rounded-lg mr-4">
<i data-feather="shopping-bag" class="text-blue-600"></i>
</div>
<div>
<h3 class="font-bold text-gray-800">Riverside Outlet</h3>
<p class="text-gray-600">654 Waterfront Rd, District 5</p>
<p class="text-sm text-gray-500">Open: 10AM - 8PM</p>
<p class="text-blue-500 font-medium mt-1">5.7 km away</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Map Container -->
<div class="lg:col-span-2">
<div class="map-container" id="map"></div>
<div class="mt-4 flex flex-wrap gap-2">
<button class="bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600 transition flex items-center">
<i data-feather="navigation" class="mr-2"></i> Get Directions
</button>
<button class="bg-gray-100 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-200 transition flex items-center">
<i data-feather="list" class="mr-2"></i> View All Stores
</button>
<button class="bg-gray-100 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-200 transition flex items-center">
<i data-feather="filter" class="mr-2"></i> Filter
</button>
<button id="locate-me" class="bg-green-500 text-white px-4 py-2 rounded-lg hover:bg-green-600 transition flex items-center ml-auto">
<i data-feather="target" class="mr-2"></i> Locate Me
</button>
</div>
</div>
</div>
</div>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-12">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
<div>
<h3 class="text-xl font-bold mb-4">StoreSpotter</h3>
<p class="text-gray-400">Finding your way to our stores since 2023</p>
</div>
<div>
<h4 class="font-bold mb-4">Quick Links</h4>
<ul class="space-y-2">
<li><a href="#" class="text-gray-400 hover:text-white transition">Home</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">Stores</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">About Us</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">Contact</a></li>
</ul>
</div>
<div>
<h4 class="font-bold mb-4">Contact</h4>
<ul class="space-y-2">
<li class="flex items-center text-gray-400"><i data-feather="mail" class="mr-2"></i> hello@storespotter.com</li>
<li class="flex items-center text-gray-400"><i data-feather="phone" class="mr-2"></i> +123 456 7890</li>
<li class="flex items-center text-gray-400"><i data-feather="map-pin" class="mr-2"></i> 123 Business St, City</li>
</ul>
</div>
<div>
<h4 class="font-bold mb-4">Follow Us</h4>
<div class="flex space-x-4">
<a href="#" class="text-gray-400 hover:text-white transition"><i data-feather="facebook"></i></a>
<a href="#" class="text-gray-400 hover:text-white transition"><i data-feather="twitter"></i></a>
<a href="#" class="text-gray-400 hover:text-white transition"><i data-feather="instagram"></i></a>
<a href="#" class="text-gray-400 hover:text-white transition"><i data-feather="linkedin"></i></a>
</div>
</div>
</div>
<div class="border-t border-gray-700 mt-8 pt-8 text-center text-gray-400">
<p>&copy; 2023 StoreSpotter. All rights reserved.</p>
</div>
</div>
</footer>
<script>
// Initialize Leaflet map
const map = L.map('map').setView([10.776888, 106.699992], 12);
// Add OpenStreetMap tiles
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);
// Add store markers
const stores = [
{
name: "Main Headquarters",
address: "123 Business St, District 1",
hours: "8AM - 10PM",
coordinates: [10.778110, 106.704980]
},
{
name: "Westside Branch",
address: "456 Shopping Ave, District 2",
hours: "9AM - 9PM",
coordinates: [10.787870, 106.732470]
},
{
name: "Downtown Store",
address: "789 Central Blvd, District 3",
hours: "7AM - 11PM",
coordinates: [10.782790, 106.691240]
},
{
name: "Northside Plaza",
address: "321 Market St, District 4",
hours: "8AM - 10PM",
coordinates: [10.763380, 106.706990]
},
{
name: "Riverside Outlet",
address: "654 Waterfront Rd, District 5",
hours: "10AM - 8PM",
coordinates: [10.755430, 106.680520]
}
];
const storeIcon = L.divIcon({
className: 'custom-marker',
iconSize: [20, 20]
});
stores.forEach(store => {
const marker = L.marker(store.coordinates, { icon: storeIcon })
.addTo(map)
.bindPopup(`
<div class="font-bold">${store.name}</div>
<div class="text-gray-600">${store.address}</div>
<div class="text-sm text-gray-500">Hours: ${store.hours}</div>
<button class="mt-2 text-sm text-blue-500 hover:underline">Get Directions</button>
`);
});
// Locate me button functionality
document.getElementById('locate-me').addEventListener('click', () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
position => {
const userLocation = [position.coords.latitude, position.coords.longitude];
// Remove existing user marker if any
if (window.userMarker) {
map.removeLayer(window.userMarker);
}
// Create user marker
const userIcon = L.divIcon({
className: 'user-marker',
iconSize: [20, 20]
});
// Add user marker to map
window.userMarker = L.marker(userLocation, { icon: userIcon })
.addTo(map)
.bindPopup(`
<div class="font-bold">Your Location</div>
<div class="text-sm text-gray-600">Accuracy: ${position.coords.accuracy.toFixed(0)} meters</div>
`)
.openPopup();
// Center map on user location
map.flyTo(userLocation, 14);
},
error => {
alert('Unable to retrieve your location: ' + error.message);
},
{
enableHighAccuracy: true
}
);
} else {
alert('Geolocation is not supported by your browser');
}
});
// Initialize feather icons
feather.replace();
</script>
</body>
</html>