Spaces:
Running
Running
| <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> |