coffee-list / index.html
digpas's picture
нужно добавить Поиск кофе по базе + возможность добавлять фото в отзывах и расширить Тип кофе (есть еще Дрипы) - Initial Deployment
25fcba8 verified
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>КофеОтзывы - система отзывов о кофе</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.coffee-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
.star-rating input {
display: none;
}
.star-rating label {
font-size: 24px;
color: #ccc;
cursor: pointer;
transition: color 0.2s;
}
.star-rating input:checked ~ label,
.star-rating label:hover,
.star-rating label:hover ~ label {
color: #f8d64e;
}
.star-rating input:checked + label {
color: #f8d64e;
}
.coffee-type-btn.active {
background-color: #6f4e37;
color: white;
}
.rating-filter-btn.active {
background-color: #4a5568;
color: white;
}
.animated-bg {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { background-color: #f5f5f5; }
50% { background-color: #e2e8f0; }
100% { background-color: #f5f5f5; }
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<!-- Header -->
<header class="bg-amber-900 text-white shadow-lg">
<div class="container mx-auto px-4 py-6">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="flex items-center mb-4 md:mb-0">
<i class="fas fa-coffee text-3xl mr-3"></i>
<h1 class="text-2xl md:text-3xl font-bold">КофеОтзывы</h1>
</div>
<p class="text-amber-200 text-center md:text-right">Делитесь мнением о любимом кофе и находите новые вкусы</p>
</div>
</div>
</header>
<!-- Main Content -->
<main class="container mx-auto px-4 py-8">
<!-- Filters Section -->
<div class="bg-white rounded-lg shadow-md p-6 mb-8">
<h2 class="text-xl font-semibold mb-4 text-gray-800">Фильтры отзывов</h2>
<div class="mb-6">
<h3 class="text-lg font-medium mb-3 text-gray-700">Тип кофе</h3>
<div class="flex flex-wrap gap-2">
<button class="coffee-type-btn px-4 py-2 rounded-full border border-gray-300 hover:bg-amber-100 transition" data-type="all">
Все типы
</button>
<button class="coffee-type-btn px-4 py-2 rounded-full border border-gray-300 hover:bg-amber-100 transition" data-type="зерновой">
Зерновой <i class="fas fa-coffee-beans ml-1"></i>
</button>
<button class="coffee-type-btn px-4 py-2 rounded-full border border-gray-300 hover:bg-amber-100 transition" data-type="молотый">
Молотый <i class="fas fa-mortar-pestle ml-1"></i>
</button>
<button class="coffee-type-btn px-4 py-2 rounded-full border border-gray-300 hover:bg-amber-100 transition" data-type="растворимый">
Растворимый <i class="fas fa-glass-water ml-1"></i>
</button>
<button class="coffee-type-btn px-4 py-2 rounded-full border border-gray-300 hover:bg-amber-100 transition" data-type="капсульный">
Капсульный <i class="fas fa-capsules ml-1"></i>
</button>
<button class="coffee-type-btn px-4 py-2 rounded-full border border-gray-300 hover:bg-amber-100 transition" data-type="дрипы">
Дрипы <i class="fas fa-filter ml-1"></i>
</button>
</div>
</div>
<div>
<h3 class="text-lg font-medium mb-3 text-gray-700">Рейтинг</h3>
<div class="flex flex-wrap gap-2">
<button class="rating-filter-btn px-4 py-2 rounded-full border border-gray-300 hover:bg-gray-100 transition" data-rating="all">
Все оценки
</button>
<button class="rating-filter-btn px-4 py-2 rounded-full border border-gray-300 hover:bg-gray-100 transition" data-rating="5">
<i class="fas fa-star text-yellow-400"></i> 5
</button>
<button class="rating-filter-btn px-4 py-2 rounded-full border border-gray-300 hover:bg-gray-100 transition" data-rating="4">
<i class="fas fa-star text-yellow-400"></i> 4+
</button>
<button class="rating-filter-btn px-4 py-2 rounded-full border border-gray-300 hover:bg-gray-100 transition" data-rating="3">
<i class="fas fa-star text-yellow-400"></i> 3+
</button>
</div>
</div>
</div>
<!-- Search Section -->
<div class="bg-white rounded-lg shadow-md p-6 mb-8">
<h2 class="text-xl font-semibold mb-4 text-gray-800">Поиск кофе</h2>
<div class="relative">
<input type="text" id="coffeeSearch" placeholder="Введите название или бренд кофе..."
class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-amber-500 focus:border-amber-500">
<button id="searchButton" class="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 hover:text-amber-700">
<i class="fas fa-search"></i>
</button>
</div>
</div>
<!-- Add Review Form -->
<div class="bg-white rounded-lg shadow-md p-6 mb-8">
<h2 class="text-xl font-semibold mb-4 text-gray-800">Добавить отзыв</h2>
<form id="reviewForm" class="space-y-4" enctype="multipart/form-data">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="coffeeName" class="block text-sm font-medium text-gray-700 mb-1">Название кофе</label>
<input type="text" id="coffeeName" required class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-amber-500 focus:border-amber-500">
</div>
<div>
<label for="coffeeBrand" class="block text-sm font-medium text-gray-700 mb-1">Бренд</label>
<input type="text" id="coffeeBrand" required class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-amber-500 focus:border-amber-500">
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="coffeeType" class="block text-sm font-medium text-gray-700 mb-1">Тип кофе</label>
<select id="coffeeType" required class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-amber-500 focus:border-amber-500">
<option value="">Выберите тип</option>
<option value="зерновой">Зерновой</option>
<option value="молотый">Молотый</option>
<option value="растворимый">Растворимый</option>
<option value="капсульный">Капсульный</option>
<option value="дрипы">Дрипы</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Ваша оценка</label>
<div class="star-rating flex justify-center md:justify-start">
<input type="radio" id="star5" name="rating" value="5" required>
<label for="star5"><i class="fas fa-star"></i></label>
<input type="radio" id="star4" name="rating" value="4">
<label for="star4"><i class="fas fa-star"></i></label>
<input type="radio" id="star3" name="rating" value="3">
<label for="star3"><i class="fas fa-star"></i></label>
<input type="radio" id="star2" name="rating" value="2">
<label for="star2"><i class="fas fa-star"></i></label>
<input type="radio" id="star1" name="rating" value="1">
<label for="star1"><i class="fas fa-star"></i></label>
</div>
</div>
</div>
<div>
<label for="reviewText" class="block text-sm font-medium text-gray-700 mb-1">Отзыв</label>
<textarea id="reviewText" rows="4" required class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-amber-500 focus:border-amber-500"></textarea>
</div>
<div>
<label for="reviewPhoto" class="block text-sm font-medium text-gray-700 mb-1">Фото кофе (необязательно)</label>
<input type="file" id="reviewPhoto" accept="image/*" class="w-full text-sm text-gray-500
file:mr-4 file:py-2 file:px-4
file:rounded-md file:border-0
file:text-sm file:font-semibold
file:bg-amber-50 file:text-amber-700
hover:file:bg-amber-100">
</div>
<div class="flex justify-end">
<button type="submit" class="px-6 py-2 bg-amber-700 text-white rounded-md hover:bg-amber-800 transition flex items-center">
<i class="fas fa-paper-plane mr-2"></i> Опубликовать
</button>
</div>
</form>
</div>
<!-- Reviews Section -->
<div class="mb-8">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-bold text-gray-800">Отзывы о кофе</h2>
<div class="text-gray-600">
<span id="reviewsCount">0</span> отзывов
</div>
</div>
<div id="reviewsContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- Reviews will be loaded here -->
</div>
<div id="noReviewsMessage" class="hidden text-center py-12 bg-white rounded-lg shadow">
<i class="fas fa-coffee text-4xl text-gray-400 mb-4"></i>
<h3 class="text-xl font-medium text-gray-600">Отзывов не найдено</h3>
<p class="text-gray-500 mt-2">Попробуйте изменить параметры фильтрации</p>
</div>
</div>
</main>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-8">
<div class="container mx-auto px-4">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="mb-4 md:mb-0">
<div class="flex items-center">
<i class="fas fa-coffee text-2xl mr-2 text-amber-400"></i>
<span class="text-xl font-bold">КофеОтзывы</span>
</div>
<p class="text-gray-400 mt-2">Лучшие отзывы о кофе с 2023 года</p>
</div>
<div class="flex space-x-4">
<a href="#" class="text-gray-400 hover:text-white transition">
<i class="fab fa-vk text-2xl"></i>
</a>
<a href="#" class="text-gray-400 hover:text-white transition">
<i class="fab fa-telegram text-2xl"></i>
</a>
<a href="#" class="text-gray-400 hover:text-white transition">
<i class="fab fa-instagram text-2xl"></i>
</a>
</div>
</div>
<div class="border-t border-gray-700 mt-6 pt-6 text-center text-gray-400 text-sm">
<p>© 2023 КофеОтзывы. Все права защищены.</p>
</div>
</div>
</footer>
<script>
// Sample data for reviews
const reviews = [
{
id: 1,
name: "Jacobs Monarch",
brand: "Jacobs",
type: "зерновой",
rating: 5,
review: "Отличный кофе с насыщенным вкусом и приятным ароматом. Идеально подходит для эспрессо.",
date: "2023-05-15",
author: "Алексей"
},
{
id: 2,
name: "Nescafe Gold",
brand: "Nescafe",
type: "растворимый",
rating: 4,
review: "Хороший растворимый кофе для быстрого приготовления. Вкус мягкий, без горечи.",
date: "2023-06-22",
author: "Мария"
},
{
id: 3,
name: "Lavazza Qualità Oro",
brand: "Lavazza",
type: "молотый",
rating: 5,
review: "Прекрасный итальянский кофе с бархатистым вкусом. Рекомендую всем ценителям.",
date: "2023-04-10",
author: "Дмитрий"
},
{
id: 4,
name: "Paulig Presidentti",
brand: "Paulig",
type: "зерновой",
rating: 4,
review: "Хороший финский кофе с легкой кислинкой. Подходит для разных способов заваривания.",
date: "2023-07-05",
author: "Елена"
},
{
id: 5,
name: "Dallmayr Prodomo",
brand: "Dallmayr",
type: "капсульный",
rating: 3,
review: "Неплохой кофе в капсулах, но ожидал более насыщенного вкуса за такую цену.",
date: "2023-08-12",
author: "Иван"
},
{
id: 6,
name: "Jardin Crema",
brand: "Jardin",
type: "молотый",
rating: 4,
review: "Приятный кофе с нотками шоколада. Хорошо сочетается с молоком.",
date: "2023-09-18",
author: "Ольга"
}
];
// DOM Elements
const reviewsContainer = document.getElementById('reviewsContainer');
const noReviewsMessage = document.getElementById('noReviewsMessage');
const reviewsCount = document.getElementById('reviewsCount');
const reviewForm = document.getElementById('reviewForm');
const coffeeTypeBtns = document.querySelectorAll('.coffee-type-btn');
const ratingFilterBtns = document.querySelectorAll('.rating-filter-btn');
// Current filters
let currentCoffeeType = 'all';
let currentRatingFilter = 'all';
// Initialize the app
document.addEventListener('DOMContentLoaded', () => {
renderReviews(filterReviews());
setupEventListeners();
});
// Filter reviews based on current filters
function filterReviews() {
return reviews.filter(review => {
const typeMatch = currentCoffeeType === 'all' || review.type === currentCoffeeType;
const ratingMatch = currentRatingFilter === 'all' ||
(currentRatingFilter === '5' && review.rating === 5) ||
(currentRatingFilter === '4' && review.rating >= 4) ||
(currentRatingFilter === '3' && review.rating >= 3);
return typeMatch && ratingMatch;
});
}
// Render reviews to the DOM
function renderReviews(reviewsToRender) {
reviewsContainer.innerHTML = '';
if (reviewsToRender.length === 0) {
noReviewsMessage.classList.remove('hidden');
} else {
noReviewsMessage.classList.add('hidden');
reviewsToRender.forEach(review => {
const reviewElement = createReviewElement(review);
reviewsContainer.appendChild(reviewElement);
});
}
reviewsCount.textContent = reviewsToRender.length;
}
// Create a review card element
function createReviewElement(review) {
const reviewElement = document.createElement('div');
reviewElement.className = 'coffee-card bg-white rounded-lg shadow-md overflow-hidden transition duration-300';
// Generate star rating HTML
const starsHtml = Array(5).fill('').map((_, i) =>
`<i class="fas fa-star ${i < review.rating ? 'text-yellow-400' : 'text-gray-300'}"></i>`
).join('');
// Generate coffee type icon
const typeIcons = {
'зерновой': 'fa-coffee-beans',
'молотый': 'fa-mortar-pestle',
'растворимый': 'fa-glass-water',
'капсульный': 'fa-capsules',
'дрипы': 'fa-filter'
};
reviewElement.innerHTML = `
<div class="p-6">
${review.photo ? `
<div class="mb-4 rounded-lg overflow-hidden">
<img src="${review.photo}" alt="${review.name}" class="w-full h-48 object-cover">
</div>
` : ''}
<div class="flex justify-between items-start mb-2">
<h3 class="text-xl font-bold text-gray-800">${review.name}</h3>
<span class="px-3 py-1 bg-amber-100 text-amber-800 rounded-full text-sm font-medium">
${review.brand}
</span>
</div>
<div class="flex items-center mb-3">
<div class="mr-2">
${starsHtml}
</div>
<span class="text-gray-600 text-sm">${review.rating}.0</span>
</div>
<div class="flex items-center text-sm text-gray-500 mb-4">
<i class="fas ${typeIcons[review.type]} mr-1"></i>
<span class="mr-3 capitalize">${review.type}</span>
<i class="fas fa-calendar-alt mr-1"></i>
<span>${review.date}</span>
</div>
<p class="text-gray-700 mb-4">${review.review}</p>
<div class="flex justify-between items-center text-sm">
<span class="text-gray-500">Автор: ${review.author}</span>
<button class="text-amber-700 hover:text-amber-900 transition">
<i class="fas fa-share-alt mr-1"></i> Поделиться
</button>
</div>
</div>
`;
return reviewElement;
}
// Search functionality
function searchCoffee(query) {
return reviews.filter(review => {
const searchStr = query.toLowerCase();
return review.name.toLowerCase().includes(searchStr) ||
review.brand.toLowerCase().includes(searchStr);
});
}
// Set up event listeners
function setupEventListeners() {
// Search input
document.getElementById('searchButton').addEventListener('click', () => {
const query = document.getElementById('coffeeSearch').value;
if (query) {
renderReviews(searchCoffee(query));
}
});
document.getElementById('coffeeSearch').addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
const query = document.getElementById('coffeeSearch').value;
if (query) {
renderReviews(searchCoffee(query));
}
}
});
// Coffee type filter buttons
coffeeTypeBtns.forEach(btn => {
btn.addEventListener('click', () => {
coffeeTypeBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentCoffeeType = btn.dataset.type;
renderReviews(filterReviews());
});
});
// Rating filter buttons
ratingFilterBtns.forEach(btn => {
btn.addEventListener('click', () => {
ratingFilterBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentRatingFilter = btn.dataset.rating;
renderReviews(filterReviews());
});
});
// Form submission
reviewForm.addEventListener('submit', (e) => {
e.preventDefault();
const newReview = {
id: reviews.length + 1,
name: document.getElementById('coffeeName').value,
brand: document.getElementById('coffeeBrand').value,
type: document.getElementById('coffeeType').value,
rating: parseInt(document.querySelector('input[name="rating"]:checked').value),
review: document.getElementById('reviewText').value,
date: new Date().toISOString().split('T')[0],
author: "Вы",
photo: null
};
// Handle photo upload
const photoInput = document.getElementById('reviewPhoto');
if (photoInput.files.length > 0) {
const file = photoInput.files[0];
const reader = new FileReader();
reader.onload = function(e) {
newReview.photo = e.target.result;
};
reader.readAsDataURL(file);
}
reviews.unshift(newReview);
renderReviews(filterReviews());
reviewForm.reset();
// Show success message
const successAlert = document.createElement('div');
successAlert.className = 'fixed bottom-4 right-4 bg-green-500 text-white px-4 py-2 rounded-md shadow-lg flex items-center';
successAlert.innerHTML = `
<i class="fas fa-check-circle mr-2"></i>
<span>Ваш отзыв успешно добавлен!</span>
`;
document.body.appendChild(successAlert);
setTimeout(() => {
successAlert.remove();
}, 3000);
});
}
</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-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=digpas/coffee-list" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>