Spaces:
Running
Running
| <html lang="vi"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Bình luận - ANIDBREMAX</title> | |
| <link rel="stylesheet" href="style.css"> | |
| <style> | |
| .comment-form { | |
| max-width: 600px; | |
| margin: 30px auto; | |
| background: #1f1f1f; | |
| padding: 25px; | |
| border-radius: 8px; | |
| } | |
| .comment-form label { | |
| display: block; | |
| margin-top: 15px; | |
| font-weight: bold; | |
| } | |
| .comment-form select, | |
| .comment-form input, | |
| .comment-form textarea { | |
| width: 100%; | |
| padding: 10px; | |
| margin-top: 5px; | |
| border: 1px solid #333; | |
| border-radius: 5px; | |
| background: #2a2a2a; | |
| color: #eee; | |
| font-size: 14px; | |
| box-sizing: border-box; | |
| } | |
| .comment-form textarea { | |
| resize: vertical; | |
| min-height: 80px; | |
| } | |
| .comment-form button { | |
| margin-top: 15px; | |
| padding: 10px 20px; | |
| background: #e74c3c; | |
| color: #fff; | |
| border: none; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-size: 15px; | |
| width: 100%; | |
| } | |
| .comment-form button:hover { | |
| background: #c0392b; | |
| } | |
| .comment-list { | |
| max-width: 600px; | |
| margin: 20px auto; | |
| } | |
| .comment-item { | |
| background: #1f1f1f; | |
| padding: 15px; | |
| border-radius: 8px; | |
| margin-bottom: 10px; | |
| } | |
| .comment-item .meta { | |
| display: flex; | |
| justify-content: space-between; | |
| font-size: 13px; | |
| color: #888; | |
| margin-bottom: 5px; | |
| } | |
| .comment-item .name { | |
| color: #e74c3c; | |
| font-weight: bold; | |
| } | |
| .comment-item .message { | |
| font-size: 14px; | |
| line-height: 1.5; | |
| } | |
| .filter-bar { | |
| max-width: 600px; | |
| margin: 20px auto; | |
| display: flex; | |
| gap: 10px; | |
| align-items: center; | |
| } | |
| .filter-bar select { | |
| flex: 1; | |
| padding: 10px; | |
| border: 1px solid #333; | |
| border-radius: 5px; | |
| background: #2a2a2a; | |
| color: #eee; | |
| font-size: 14px; | |
| } | |
| #statusMsg { | |
| text-align: center; | |
| margin-top: 10px; | |
| font-size: 14px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header>ANIDBREMAX - Bình luận</header> | |
| <nav> | |
| <a href="index.html">Trang chủ</a> | |
| <a href="comment.html">Bình luận</a> | |
| </nav> | |
| <div class="container"> | |
| <div class="filter-bar"> | |
| <select id="animeSelect" onchange="loadComments()"> | |
| <option value="">-- Chọn anime --</option> | |
| </select> | |
| </div> | |
| <div class="comment-form" id="commentForm"> | |
| <h3 style="margin-top:0">Gửi bình luận</h3> | |
| <label for="cmtName">Tên của bạn</label> | |
| <input type="text" id="cmtName" placeholder="Nhập tên..." maxlength="50"> | |
| <label for="cmtMessage">Nội dung</label> | |
| <textarea id="cmtMessage" placeholder="Nhập bình luận..." maxlength="1000"></textarea> | |
| <button onclick="submitComment()">Gửi bình luận</button> | |
| <div id="statusMsg"></div> | |
| </div> | |
| <div class="comment-list" id="commentList"></div> | |
| </div> | |
| <footer style="text-align:center;padding:20px;color:#666;font-size:13px"> | |
| © 2026 ANIDBREMAX | |
| </footer> | |
| <script> | |
| const animeList = [ | |
| { key: 'eminence1', name: 'The Eminence in Shadow (P1)' }, | |
| { key: 'eminence2', name: 'The Eminence in Shadow (P2)' }, | |
| { key: 'naruto', name: 'Naruto' }, | |
| { key: 'doraemon1', name: 'Doraemon: Nobita Thám Hiểm Vùng Đất Mới' }, | |
| { key: 'doraemon2', name: 'Doraemon: Nobita và Viện Bảo Tàng Bảo Bối' }, | |
| { key: 'doraemon3', name: 'Doraemon: Nobita và Những Hiệp Sĩ Không Gian' }, | |
| { key: 'conan21', name: 'Detective Conan Movie 21: The Crimson Love Letter' }, | |
| { key: 'conan26', name: 'Detective Conan Movie 26: Black Iron Submarine' }, | |
| { key: 'conan27', name: 'Detective Conan Movie 27: The Million Dollar Pentagram' } | |
| ]; | |
| const API = window.location.origin; | |
| function populateAnimeSelect(selectId) { | |
| const sel = document.getElementById(selectId); | |
| animeList.forEach(a => { | |
| const opt = document.createElement('option'); | |
| opt.value = a.key; | |
| opt.textContent = a.name; | |
| sel.appendChild(opt); | |
| }); | |
| } | |
| populateAnimeSelect('animeSelect'); | |
| async function loadComments() { | |
| const anime = document.getElementById('animeSelect').value; | |
| const list = document.getElementById('commentList'); | |
| const form = document.getElementById('commentForm'); | |
| if (!anime) { | |
| list.innerHTML = '<p style="text-align:center;color:#666">Vui lòng chọn anime để xem bình luận</p>'; | |
| form.style.display = 'none'; | |
| return; | |
| } | |
| form.style.display = 'block'; | |
| list.innerHTML = '<p style="text-align:center;color:#666">Đang tải...</p>'; | |
| try { | |
| const res = await fetch(`${API}/api/comments?anime=${encodeURIComponent(anime)}`); | |
| const data = await res.json(); | |
| if (data.length === 0) { | |
| list.innerHTML = '<p style="text-align:center;color:#666">Chưa có bình luận nào</p>'; | |
| return; | |
| } | |
| list.innerHTML = data.map(c => { | |
| const time = new Date(c.created_at).toLocaleString('vi-VN'); | |
| return `<div class="comment-item"> | |
| <div class="meta"> | |
| <span class="name">${escapeHtml(c.name)}</span> | |
| <span>${time}</span> | |
| </div> | |
| <div class="message">${escapeHtml(c.message)}</div> | |
| </div>`; | |
| }).join(''); | |
| } catch (e) { | |
| list.innerHTML = '<p style="text-align:center;color:#e74c3c">Lỗi tải bình luận. Server chưa chạy?</p>'; | |
| } | |
| } | |
| function escapeHtml(text) { | |
| const d = document.createElement('div'); | |
| d.textContent = text; | |
| return d.innerHTML; | |
| } | |
| async function submitComment() { | |
| const anime = document.getElementById('animeSelect').value; | |
| const name = document.getElementById('cmtName').value.trim(); | |
| const message = document.getElementById('cmtMessage').value.trim(); | |
| const status = document.getElementById('statusMsg'); | |
| if (!anime) { status.textContent = 'Vui lòng chọn anime'; return; } | |
| if (!name) { status.textContent = 'Vui lòng nhập tên'; return; } | |
| if (!message) { status.textContent = 'Vui lòng nhập nội dung'; return; } | |
| status.textContent = 'Đang gửi...'; | |
| try { | |
| const res = await fetch(`${API}/api/comments`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ anime, name, message }) | |
| }); | |
| const data = await res.json(); | |
| if (data.success) { | |
| status.textContent = 'Đã gửi bình luận!'; | |
| status.style.color = '#2ecc71'; | |
| document.getElementById('cmtMessage').value = ''; | |
| loadComments(); | |
| } else { | |
| status.textContent = 'Lỗi: ' + (data.error || 'Không xác định'); | |
| status.style.color = '#e74c3c'; | |
| } | |
| } catch (e) { | |
| status.textContent = 'Lỗi kết nối server. Vui lòng chạy: node server.js'; | |
| status.style.color = '#e74c3c'; | |
| } | |
| } | |
| </script> | |
| </body> | |
| </html> | |