<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Miski - Peruvian Restaurant Locator</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyANub9Nz6gkBlEuQfKGYycF3bjTzBBHNCY&libraries=places" async defer></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
body {
background-color: #f5f5f5;
color: #333;
}
header {
background: linear-gradient(135deg, #D73B3E, #A70D10);
color: white;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.logo {
display: flex;
align-items: center;
gap: 15px;
}
.logo img {
width: 200px;
height: auto;
}
.logo h1 {
font-size: 3.6rem;
font-weight: 700;
line-height: 1;
display: flex;
flex-direction: column;
align-items: center;
}
.logo h1 span {
font-size: 3.2rem;
font-weight: 400;
margin-top: 1cm;
}
nav ul {
list-style: none;
display: flex;
gap: 2rem;
}
nav a {
color: white;
text-decoration: none;
font-weight: 500;
font-size: 1.1rem;
transition: color 0.3s ease;
}
nav a:hover {
color: #FFD700;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.results-container {
margin-top: 20px;
}
.restaurant-list {
background-color: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
max-width: 1200px;
margin: 0 auto;
}
.map-container {
width: 100%;
height: 400px;
margin: 20px 0;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
#map {
width: 100%;
height: 100%;
}
.search-container {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
.search-box {
display: flex;
gap: 10px;
margin-bottom: 15px;
}
.search-box input {
flex: 1;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
}
.search-box button {
background-color: #D73B3E;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-weight: 500;
transition: background-color 0.3s ease;
}
.search-box button:hover {
background-color: #A70D10;
}
.filters {
display: flex;
gap: 15px;
align-items: center;
}
.filters select {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 0.9rem;
}
.filters label {
display: flex;
align-items: center;
gap: 5px;
font-size: 0.9rem;
color: #666;
}
.restaurant-card {
background-color: white;
border-radius: 12px;
padding: 25px;
margin-bottom: 30px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
.restaurant-image-gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
margin-bottom: 20px;
border-radius: 8px;
overflow: hidden;
}
.restaurant-image {
position: relative;
height: 200px;
border-radius: 8px;
overflow: hidden;
}
.restaurant-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.restaurant-image img:hover {
transform: scale(1.05);
}
.restaurant-info {
flex: 1;
}
.restaurant-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.restaurant-header h3 {
color: #D73B3E;
font-size: 1.8rem;
margin: 0;
}
.business-status {
padding: 5px 10px;
border-radius: 4px;
font-size: 0.9rem;
font-weight: 500;
}
.business-status.operational {
background-color: #e8f5e9;
color: #2e7d32;
}
.restaurant-description {
font-size: 1.1rem;
line-height: 1.6;
color: #666;
margin: 15px 0;
font-style: italic;
}
.restaurant-details {
background-color: #f8f9fa;
padding: 15px;
border-radius: 8px;
margin: 15px 0;
}
.restaurant-details p {
margin: 8px 0;
color: #666;
}
.restaurant-details a {
color: #D73B3E;
text-decoration: none;
transition: color 0.3s ease;
}
.restaurant-details a:hover {
color: #A70D10;
}
.rating {
display: flex;
align-items: center;
gap: 10px;
margin: 10px 0;
}
.stars {
color: #FFD700;
font-size: 1.2rem;
}
.reviews-section {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid #eee;
}
.reviews-section h4 {
color: #333;
margin-bottom: 15px;
}
.review {
background-color: #f8f9fa;
padding: 15px;
border-radius: 8px;
margin-bottom: 15px;
}
.review-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
}
.reviewer-photo {
width: 40px;
height: 40px;
border-radius: 50%;
}
.reviewer-name {
font-weight: 500;
color: #333;
}
.review-rating {
color: #FFD700;
}
.review-text {
color: #666;
line-height: 1.5;
margin: 10px 0;
}
.review-date {
color: #999;
font-size: 0.9rem;
}
.opening-hours {
margin-top: 20px;
padding: 15px;
background-color: #f8f9fa;
border-radius: 8px;
}
.opening-hours h4 {
color: #333;
margin-bottom: 10px;
}
.hours-list p {
margin: 5px 0;
color: #666;
}
.info-window {
max-width: 400px;
font-family: 'Poppins', sans-serif;
}
.info-window-image {
width: 100%;
height: 200px;
border-radius: 8px;
overflow: hidden;
margin-bottom: 15px;
}
.info-window-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.info-window-content {
padding: 10px;
}
.info-window-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 10px;
}
.info-window-header h3 {
color: #D73B3E;
margin: 0;
font-size: 1.4rem;
}
.info-window-description {
font-size: 0.9rem;
line-height: 1.5;
color: #666;
margin: 10px 0;
font-style: italic;
}
.info-window-details {
background-color: #f8f9fa;
padding: 10px;
border-radius: 6px;
margin-top: 10px;
}
.info-window-details p {
margin: 5px 0;
font-size: 0.9rem;
color: #666;
}
.info-window .open-now {
color: #2e7d32;
font-weight: 500;
}
.info-window .closed-now {
color: #d32f2f;
font-weight: 500;
}
.loading-message, .error-message {
padding: 20px;
text-align: center;
background-color: #f8f9fa;
border-radius: 8px;
margin: 20px 0;
}
@media (max-width: 1024px) {
.restaurant-image-gallery {
grid-template-columns: repeat(2, 1fr);
}
.restaurant-header {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
}
@media (max-width: 768px) {
.logo {
width: 120px;
}
.nav-links {
display: none;
}
.search-box {
flex-direction: column;
}
.filters {
flex-wrap: wrap;
justify-content: space-between;
}
.restaurant-image-gallery {
grid-template-columns: 1fr;
}
.restaurant-card {
padding: 15px;
}
.restaurant-header h3 {
font-size: 1.5rem;
}
.reviews-section {
margin-top: 15px;
padding-top: 15px;
}
.review {
padding: 10px;
}
.info-window {
max-width: 300px;
}
.info-window-image {
height: 150px;
}
.info-window-header h3 {
font-size: 1.2rem;
}
}
</style>
</head>
<body>
<header>
<div class="logo">
<img src="images/PrintMiski.svg" alt="Miski Logo">
<h1>MISKI<br><span style="font-size: 0.8rem; font-weight: 400;">Busca con Gusto !</span></h1>
</div>
<nav>
<ul>
<li><a href="index.html">Home</a></li>
<li><a href="about.html">About</a></li>
<li><a href="products.html">Peruvian Products</a></li>
<li><a href="recipes.html">Peruvian Recipes</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
</nav>
</header>
<div class="container">
<div class="search-container">
<div class="search-box">
<input type="text" id="location-search" placeholder="Enter your location...">
<button onclick="searchRestaurants()"><i class="fas fa-search"></i> Find Peruvian Restaurants</button>
</div>
<div class="filters">
<select id="rating-filter">
<option value="">All Ratings</option>
<option value="4">4+ Stars</option>
<option value="3">3+ Stars</option>
</select>
<select id="price-filter">
<option value="">All Prices</option>
<option value="1">$</option>
<option value="2">$$</option>
<option value="3">$$$</option>
<option value="4">$$$$</option>
</select>
<label>
<input type="checkbox" id="open-now"> Open Now
</label>
</div>
</div>
<div class="map-container">
<div id="map"></div>
</div>
<div class="results-container">
<div class="restaurant-list">
<h2>Peruvian Restaurants Near You</h2>
<div id="loading-restaurants" class="loading-message">
<p>Enter a location to find Peruvian restaurants...</p>
</div>
</div>
</div>
</div>
<script>
let map;
let service;
let infoWindow;
let markers = [];
function initMap() {
const defaultLocation = { lat: -12.0464, lng: -77.0428 }; // Lima, Peru
map = new google.maps.Map(document.getElementById('map'), {
center: defaultLocation,
zoom: 12
});
infoWindow = new google.maps.InfoWindow();
service = new google.maps.places.PlacesService(map);
// Try HTML5 geolocation
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
map.setCenter(pos);
},
() => {
console.log('Error: The Geolocation service failed.');
}
);
}
}
function searchRestaurants() {
const location = document.getElementById('location-search').value;
const geocoder = new google.maps.Geocoder();
geocoder.geocode({ address: location }, (results, status) => {
if (status === 'OK') {
const searchLocation = results[0].geometry.location;
map.setCenter(searchLocation);
map.setZoom(12);
const request = {
query: 'peruvian restaurant near ' + location,
fields: ['name', 'geometry', 'place_id']
};
clearMarkers();
document.querySelector('.restaurant-list').innerHTML = '<h2>Peruvian Restaurants Worldwide</h2><div id="loading-restaurants" class="loading-message"><p>Searching for restaurants...</p></div>';
service.textSearch(request, (results, status) => {
if (status === google.maps.places.PlacesServiceStatus.OK) {
const filteredResults = filterResults(results);
displayResults(filteredResults);
} else {
document.querySelector('.restaurant-list').innerHTML = '<h2>Peruvian Restaurants Worldwide</h2><div class="error-message"><p>No restaurants found. Please try a different location.</p></div>';
}
});
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
function filterResults(results) {
const ratingFilter = document.getElementById('rating-filter').value;
const priceFilter = document.getElementById('price-filter').value;
const openNowFilter = document.getElementById('open-now').checked;
return results.filter(place => {
const meetsRating = !ratingFilter || (place.rating >= parseFloat(ratingFilter));
const meetsPrice = !priceFilter || (place.price_level === parseInt(priceFilter));
const meetsOpenNow = !openNowFilter || place.opening_hours?.isOpen();
return meetsRating && meetsPrice && meetsOpenNow;
});
}
function displayResults(places) {
const restaurantList = document.querySelector('.restaurant-list');
restaurantList.innerHTML = '<h2>Peruvian Restaurants Near You</h2>';
if (places.length === 0) {
restaurantList.innerHTML += '<div class="error-message"><p>No restaurants match your filters. Try adjusting your search criteria.</p></div>';
return;
}
places.forEach(place => {
createMarker(place);
getPlaceDetails(place);
});
}
function createMarker(place) {
const marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
title: place.name,
animation: google.maps.Animation.DROP
});
markers.push(marker);
marker.addListener('click', () => {
getPlaceDetails(place, marker);
});
}
function clearMarkers() {
markers.forEach(marker => marker.setMap(null));
markers = [];
}
function getPlaceDetails(place, marker = null) {
const request = {
placeId: place.place_id,
fields: ['name', 'rating', 'formatted_phone_number', 'formatted_address', 'website', 'photos', 'reviews', 'opening_hours', 'price_level', 'user_ratings_total', 'editorial_summary', 'business_status', 'url']
};
service.getDetails(request, (placeDetails, status) => {
if (status === google.maps.places.PlacesServiceStatus.OK) {
if (marker) {
showInfoWindow(placeDetails, marker);
}
createRestaurantCard(placeDetails);
}
});
}
function showInfoWindow(place, marker) {
const content = createInfoWindowContent(place);
infoWindow.setContent(content);
infoWindow.open(map, marker);
}
function createInfoWindowContent(place) {
const mainPhoto = place.photos ?
`<div class="info-window-image">
<img src="${place.photos[0].getUrl({maxWidth: 300, maxHeight: 200})}" alt="${place.name}">
</div>` : '';
const rating = place.rating ?
`<div class="rating">
<div class="stars">${'★'.repeat(Math.round(place.rating))}</div>
<span>${place.rating} (${place.user_ratings_total} reviews)</span>
</div>` : '';
const status = place.business_status ?
`<p class="business-status ${place.business_status.toLowerCase()}">
<i class="fas fa-info-circle"></i> ${place.business_status}
</p>` : '';
const description = place.editorial_summary ?
`<p class="info-window-description">${place.editorial_summary.overview}</p>` : '';
const phone = place.formatted_phone_number ?
`<p><i class="fas fa-phone"></i> ${place.formatted_phone_number}</p>` : '';
const website = place.website ?
`<p><i class="fas fa-globe"></i> <a href="${place.website}" target="_blank">Visit Website</a></p>` : '';
const mapsLink = place.url ?
`<p><i class="fas fa-map"></i> <a href="${place.url}" target="_blank">View on Google Maps</a></p>` : '';
const price = place.price_level ?
`<p><i class="fas fa-dollar-sign"></i> ${'$'.repeat(place.price_level)}</p>` : '';
const openNow = place.opening_hours?.isOpen() ?
`<p class="open-now"><i class="fas fa-clock"></i> Open Now</p>` :
`<p class="closed-now"><i class="fas fa-clock"></i> Closed</p>`;
return `
<div class="info-window">
${mainPhoto}
<div class="info-window-content">
<div class="info-window-header">
<h3>${place.name}</h3>
${status}
</div>
${rating}
${description}
<div class="info-window-details">
<p><i class="fas fa-map-marker-alt"></i> ${place.formatted_address}</p>
${openNow}
${phone}
${website}
${mapsLink}
${price}
</div>
</div>
</div>
`;
}
function createRestaurantCard(place) {
const restaurantList = document.querySelector('.restaurant-list');
const loadingMessage = document.getElementById('loading-restaurants');
if (loadingMessage) {
loadingMessage.remove();
}
const photoGallery = place.photos ?
`<div class="restaurant-image-gallery">
${Array.from(place.photos.slice(0, 3)).map(photo =>
`<div class="restaurant-image">
<img src="${photo.getUrl({maxWidth: 300, maxHeight: 200})}" alt="${place.name}">
</div>`
).join('')}
</div>` : '';
const rating = place.rating ?
`<div class="rating">
<div class="stars">${'★'.repeat(Math.round(place.rating))}</div>
<span>${place.rating} (${place.user_ratings_total} reviews)</span>
</div>` : '';
const status = place.business_status ?
`<p class="business-status ${place.business_status.toLowerCase()}">
<i class="fas fa-info-circle"></i> ${place.business_status}
</p>` : '';
const phone = place.formatted_phone_number ?
`<p><i class="fas fa-phone"></i> ${place.formatted_phone_number}</p>` : '';
const website = place.website ?
`<p><i class="fas fa-globe"></i> <a href="${place.website}" target="_blank">Visit Website</a></p>` : '';
const mapsLink = place.url ?
`<p><i class="fas fa-map"></i> <a href="${place.url}" target="_blank">View on Google Maps</a></p>` : '';
const price = place.price_level ?
`<p><i class="fas fa-dollar-sign"></i> ${'$'.repeat(place.price_level)}</p>` : '';
const description = place.editorial_summary ?
`<p class="restaurant-description">${place.editorial_summary.overview}</p>` : '';
const reviews = place.reviews ?
`<div class="reviews-section">
<h4>Recent Reviews</h4>
${place.reviews.slice(0, 2).map(review =>
`<div class="review">
<div class="review-header">
<img src="${review.profile_photo_url}" alt="${review.author_name}" class="reviewer-photo">
<span class="reviewer-name">${review.author_name}</span>
<div class="review-rating">${'★'.repeat(review.rating)}</div>
</div>
<p class="review-text">${review.text}</p>
<span class="review-date">${review.relative_time_description}</span>
</div>`
).join('')}
</div>` : '';
const openingHours = place.opening_hours ?
`<div class="opening-hours">
<h4>Opening Hours</h4>
<div class="hours-list">
${place.opening_hours.weekday_text.map(day =>
`<p>${day}</p>`
).join('')}
</div>
</div>` : '';
const card = document.createElement('div');
card.className = 'restaurant-card';
card.innerHTML = `
${photoGallery}
<div class="restaurant-info">
<div class="restaurant-header">
<h3>${place.name}</h3>
${status}
</div>
${rating}
${description}
<div class="restaurant-details">
<p><i class="fas fa-map-marker-alt"></i> ${place.formatted_address}</p>
${phone}
${website}
${mapsLink}
${price}
</div>
${openingHours}
${reviews}
</div>
`;
restaurantList.appendChild(card);
}
window.onload = initMap;
</script>
</body>
</html>