Spaces:
Running
Running
| <html lang="vi"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <title>🛸 Aliess Chat Realtime</title> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> | |
| <script src="https://www.gstatic.com/firebasejs/10.12.2/firebase-app-compat.js"></script> | |
| <script src="https://www.gstatic.com/firebasejs/10.12.2/firebase-database-compat.js"></script> | |
| <style> | |
| body { padding: 20px; background: #f9f9f9; } | |
| #chat-box { border: 1px solid #ccc; padding: 10px; max-height: 400px; overflow-y: auto; background: #fff; } | |
| .message { padding: 10px 14px; margin: 10px; border-radius: 12px; max-width: 70%; clear: both; position: relative; } | |
| .left { background-color: #e2e3e5; float: left; } | |
| .right { background-color: #d1e7dd; float: right; text-align: right; } | |
| .owner { background: linear-gradient(to right, #ffe082, #ffd54f); font-weight: bold; float: right; border: 2px solid #ffca28; box-shadow: 0 0 8px rgba(255, 193, 7, 0.5); } | |
| .system { background-color: #f8f9fa; text-align: center; font-style: italic; color: #555; clear: both; border-left: 5px solid #999; } | |
| .sender { font-weight: bold; margin-bottom: 4px; display: block; } | |
| .timestamp { font-size: 12px; color: gray; margin-top: 4px; display: block; } | |
| img { max-width: 100%; border-radius: 8px; margin-top: 6px; } | |
| </style> | |
| </head> | |
| <body class="container"> | |
| <h2 class="mb-4">🛸 Aliess Chat Realtime</h2> | |
| <div class="mb-2"> | |
| <input type="text" id="displayname" class="form-control mb-2" placeholder="Tên hiển thị (VD: Ngọc)"> | |
| <input type="text" id="content" class="form-control mb-2" placeholder="Nhập tin nhắn"> | |
| <input type="file" id="imageInput" class="form-control mb-2"> | |
| <button class="btn btn-success me-2" onclick="sendimg()">Gửi ảnh</button> | |
| <button class="btn btn-primary" onclick="sendMessage()">Gửi tin nhắn</button> | |
| </div> | |
| <h4 class="mt-4">📨 Lịch sử tin nhắn</h4> | |
| <div id="chat-box" class="rounded shadow-sm"></div> | |
| <div class="mt-4"> | |
| <button class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#ownerModal">🔐 Xác thực quyền Owner</button> | |
| </div> | |
| <div class="modal fade" id="ownerModal" tabindex="-1"> | |
| <div class="modal-dialog"> | |
| <div class="modal-content"> | |
| <div class="modal-header"> | |
| <h5 class="modal-title">Xác nhận Admin</h5> | |
| <button type="button" class="btn-close" data-bs-dismiss="modal"></button> | |
| </div> | |
| <div class="modal-body"> | |
| <input type="password" id="owner-code" class="form-control" placeholder="Nhập mã Owner"> | |
| </div> | |
| <div class="modal-footer"> | |
| <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Đóng</button> | |
| <button type="button" class="btn btn-primary" onclick="verifyOwner()">Xác thực</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="notification" class="alert alert-success mt-3 d-none"></div> | |
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> | |
| <script> | |
| let isOwner = false; | |
| let clientId = localStorage.getItem("clientId"); | |
| if (!clientId) { | |
| clientId = "client_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9); | |
| localStorage.setItem("clientId", clientId); | |
| } | |
| const firebaseConfig = { | |
| apiKey: "AIzaSyBBmadZNQryJ2de0fje_C6ON2j9o7fUODc", | |
| authDomain: "webcn-261bd.firebaseapp.com", | |
| databaseURL: "https://webcn-261bd-default-rtdb.firebaseio.com", | |
| projectId: "webcn-261bd", | |
| storageBucket: "webcn-261bd.appspot.com", | |
| messagingSenderId: "721987442092", | |
| appId: "1:721987442092:web:5a034ba60bdc0398d2d609", | |
| measurementId: "G-BQVTLB9LJZ" | |
| }; | |
| firebase.initializeApp(firebaseConfig); | |
| const db = firebase.database(); | |
| function sendMessage() { | |
| let name = document.getElementById("displayname").value.trim(); | |
| const msg = document.getElementById("content").value.trim(); | |
| if (!msg) return; | |
| const forbiddenNames = ["owner", "system", "admin"]; | |
| if (!isOwner && forbiddenNames.includes(name.toLowerCase())) { | |
| alert("🚫 Không được sử dụng tên 'Owner', 'System' hoặc 'Admin'."); | |
| return; | |
| } | |
| if (!name) name = "Guest"; | |
| if (isOwner) { | |
| name = "Owner"; | |
| if (msg === "/c clear") { | |
| db.ref("messages").remove().then(() => { | |
| db.ref("messages/" + (Date.now() + "_sys")).set({ | |
| displayname: "System", | |
| content: "Deleted_content_success", | |
| sender: "system", | |
| timestamp: new Date().toLocaleString("vi-VN") | |
| }); | |
| }); | |
| document.getElementById("content").value = ""; | |
| return; | |
| } | |
| } | |
| const id = Date.now(); | |
| db.ref("messages/" + id).set({ | |
| displayname: name, | |
| content: msg, | |
| sender: clientId, | |
| type: "text", | |
| imgURL: "", | |
| timestamp: new Date().toLocaleString("vi-VN") | |
| }); | |
| document.getElementById("content").value = ""; | |
| } | |
| function sendimg() { | |
| const imageInput = document.getElementById("imageInput"); | |
| const files = imageInput.files[0]; | |
| if (!files) { | |
| alert("Vui lòng chọn hình ảnh để gửi."); | |
| return; | |
| } | |
| const formData = new FormData(); | |
| formData.append("image", files); | |
| fetch("https://api.imgbb.com/1/upload?key=eb64cc8f94a115e3a412694f2a0f10b3", { | |
| method: "POST", | |
| body: formData | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| const imgURL = data.data.url; | |
| let name = document.getElementById("displayname").value.trim(); | |
| if (!name) name = "Guest"; | |
| const id = Date.now(); | |
| db.ref("messages/" + id).set({ | |
| displayname: isOwner ? "Owner" : name, | |
| content: "", | |
| sender: clientId, | |
| type: "image", | |
| imgURL: imgURL, | |
| timestamp: new Date().toLocaleString("vi-VN") | |
| }); | |
| document.getElementById("imageInput").value = ""; | |
| showNotification("✅ Hình ảnh đã được gửi!"); | |
| } else { | |
| alert("Lỗi khi tải ảnh lên. Vui lòng thử lại."); | |
| } | |
| }); | |
| } | |
| const chatBox = document.getElementById("chat-box"); | |
| db.ref("messages").on("value", (snapshot) => { | |
| const data = snapshot.val(); | |
| chatBox.innerHTML = ""; | |
| for (let id in data) { | |
| const msg = data[id]; | |
| let div = document.createElement("div"); | |
| let timeHTML = `<span class="timestamp">🕒 ${msg.timestamp || "Không rõ thời gian"}</span>`; | |
| if (msg.displayname === "System") { | |
| div.className = "message system"; | |
| div.innerHTML = `⚠️ <strong>System:</strong> ${msg.content}<br>${timeHTML}`; | |
| } else if (msg.displayname === "Owner") { | |
| div.className = "message owner"; | |
| if (msg.type === "image") { | |
| div.innerHTML = `<span class="sender">👑 ${msg.displayname}</span><img src="${msg.imgURL}"/>${timeHTML}`; | |
| } else { | |
| div.innerHTML = `<span class="sender">👑 ${msg.displayname}</span><span>${msg.content}</span>${timeHTML}`; | |
| } | |
| } else { | |
| const align = (msg.sender === clientId) ? "right" : "left"; | |
| div.className = `message ${align}`; | |
| if (msg.type === "image") { | |
| div.innerHTML = `<span class="sender">${msg.displayname}</span><img src="${msg.imgURL}"/>${timeHTML}`; | |
| } else { | |
| div.innerHTML = `<span class="sender">${msg.displayname}</span><span>${msg.content}</span>${timeHTML}`; | |
| } | |
| } | |
| chatBox.appendChild(div); | |
| } | |
| chatBox.scrollTop = chatBox.scrollHeight; | |
| }); | |
| function verifyOwner() { | |
| const code = document.getElementById("owner-code").value.trim(); | |
| if (code === "201946") { | |
| isOwner = true; | |
| document.getElementById("displayname").value = "Owner"; | |
| showNotification("✅ Xác thực Owner thành công!"); | |
| const modal = bootstrap.Modal.getInstance(document.getElementById('ownerModal')); | |
| modal.hide(); | |
| } else { | |
| alert("Sai mã Owner."); | |
| } | |
| } | |
| function showNotification(msg) { | |
| const box = document.getElementById("notification"); | |
| box.textContent = msg; | |
| box.classList.remove("d-none"); | |
| setTimeout(() => box.classList.add("d-none"), 3000); | |
| } | |
| document.getElementById("content").addEventListener("keydown", function(event) { | |
| if (event.key === "Enter") { | |
| event.preventDefault(); | |
| sendMessage(); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> | |