Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Social Chat - Anime Recommendation</title> | |
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@300;400;500;700&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script> | |
<style> | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
body { | |
font-family: 'Inter', 'Noto Sans JP', sans-serif; | |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
height: 100vh; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
overflow: hidden; | |
} | |
.chat-container { | |
width: 90%; | |
max-width: 800px; | |
height: 90vh; | |
background: rgba(255, 255, 255, 0.1); | |
backdrop-filter: blur(20px); | |
border-radius: 20px; | |
border: 1px solid rgba(255, 255, 255, 0.2); | |
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); | |
display: flex; | |
flex-direction: column; | |
overflow: hidden; | |
} | |
.chat-header { | |
padding: 20px; | |
border-bottom: 1px solid rgba(255, 255, 255, 0.2); | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
background: rgba(255, 255, 255, 0.05); | |
} | |
.chat-title { | |
color: white; | |
font-size: 24px; | |
font-weight: 600; | |
display: flex; | |
align-items: center; | |
gap: 10px; | |
} | |
.chat-info { | |
color: rgba(255, 255, 255, 0.8); | |
font-size: 14px; | |
display: flex; | |
align-items: center; | |
gap: 15px; | |
} | |
.user-count { | |
background: rgba(255, 255, 255, 0.2); | |
padding: 4px 8px; | |
border-radius: 10px; | |
font-size: 12px; | |
font-weight: 500; | |
} | |
.messages-container { | |
flex: 1; | |
overflow-y: auto; | |
padding: 20px; | |
display: flex; | |
flex-direction: column; | |
gap: 15px; | |
} | |
.message { | |
max-width: 70%; | |
padding: 12px 16px; | |
border-radius: 15px; | |
word-wrap: break-word; | |
animation: fadeIn 0.3s ease; | |
} | |
.message.user { | |
background: rgba(255, 255, 255, 0.2); | |
color: white; | |
align-self: flex-end; | |
border-bottom-right-radius: 5px; | |
} | |
.message.other { | |
background: rgba(255, 255, 255, 0.1); | |
color: white; | |
align-self: flex-start; | |
border-bottom-left-radius: 5px; | |
} | |
.message.system { | |
background: rgba(255, 255, 255, 0.05); | |
color: rgba(255, 255, 255, 0.7); | |
align-self: center; | |
text-align: center; | |
font-size: 12px; | |
font-style: italic; | |
max-width: 90%; | |
} | |
.message-header { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-bottom: 5px; | |
font-size: 12px; | |
gap:5px; | |
} | |
.username { | |
font-weight: 600; | |
color: rgba(255, 255, 255, 0.9); | |
} | |
.timestamp { | |
color: rgba(255, 255, 255, 0.6); | |
font-size: 11px; | |
} | |
.message-content { | |
font-size: 14px; | |
line-height: 1.4; | |
} | |
.chat-input-container { | |
padding: 20px; | |
border-top: 1px solid rgba(255, 255, 255, 0.2); | |
background: rgba(255, 255, 255, 0.05); | |
} | |
.chat-input-wrapper { | |
display: flex; | |
gap: 10px; | |
align-items: center; | |
} | |
.chat-input { | |
flex: 1; | |
padding: 12px 16px; | |
border: 1px solid rgba(255, 255, 255, 0.2); | |
border-radius: 15px; | |
background: rgba(255, 255, 255, 0.1); | |
color: white; | |
font-size: 14px; | |
outline: none; | |
transition: all 0.3s ease; | |
} | |
.chat-input::placeholder { | |
color: rgba(255, 255, 255, 0.6); | |
} | |
.chat-input:focus { | |
border-color: rgba(255, 255, 255, 0.4); | |
background: rgba(255, 255, 255, 0.15); | |
} | |
.send-btn { | |
background: rgba(255, 255, 255, 0.2); | |
border: none; | |
color: white; | |
padding: 12px 16px; | |
border-radius: 15px; | |
cursor: pointer; | |
font-size: 14px; | |
font-weight: 500; | |
transition: all 0.3s ease; | |
min-width: 80px; | |
} | |
.send-btn:hover { | |
background: rgba(255, 255, 255, 0.3); | |
transform: translateY(-1px); | |
} | |
.send-btn:active { | |
transform: translateY(0); | |
} | |
.back-btn { | |
position: absolute; | |
top: 20px; | |
left: 20px; | |
background: rgba(255, 255, 255, 0.1); | |
backdrop-filter: blur(10px); | |
border: 1px solid rgba(255, 255, 255, 0.2); | |
color: white; | |
padding: 10px 16px; | |
border-radius: 15px; | |
text-decoration: none; | |
font-size: 14px; | |
font-weight: 500; | |
transition: all 0.3s ease; | |
z-index: 1000; | |
} | |
.back-btn:hover { | |
background: rgba(255, 255, 255, 0.2); | |
transform: translateY(-2px); | |
} | |
.username-change { | |
display: flex; | |
align-items: center; | |
gap: 10px; | |
margin-bottom: 10px; | |
} | |
.username-input { | |
padding: 8px 12px; | |
border: 1px solid rgba(255, 255, 255, 0.2); | |
border-radius: 10px; | |
background: rgba(255, 255, 255, 0.1); | |
color: white; | |
font-size: 12px; | |
outline: none; | |
width: 150px; | |
} | |
.username-input::placeholder { | |
color: rgba(255, 255, 255, 0.6); | |
} | |
.change-username-btn { | |
background: rgba(255, 255, 255, 0.2); | |
border: none; | |
color: white; | |
padding: 8px 12px; | |
border-radius: 10px; | |
cursor: pointer; | |
font-size: 12px; | |
transition: all 0.3s ease; | |
} | |
.change-username-btn:hover { | |
background: rgba(255, 255, 255, 0.3); | |
} | |
@keyframes fadeIn { | |
from { | |
opacity: 0; | |
transform: translateY(10px); | |
} | |
to { | |
opacity: 1; | |
transform: translateY(0); | |
} | |
} | |
/* Scrollbar styling */ | |
.messages-container::-webkit-scrollbar { | |
width: 6px; | |
} | |
.messages-container::-webkit-scrollbar-track { | |
background: rgba(255, 255, 255, 0.1); | |
border-radius: 10px; | |
} | |
.messages-container::-webkit-scrollbar-thumb { | |
background: rgba(255, 255, 255, 0.3); | |
border-radius: 10px; | |
} | |
.messages-container::-webkit-scrollbar-thumb:hover { | |
background: rgba(255, 255, 255, 0.5); | |
} | |
/* Mobile responsive */ | |
@media (max-width: 768px) { | |
.chat-container { | |
width: 95%; | |
height: 95vh; | |
} | |
.chat-header { | |
padding: 15px; | |
} | |
.chat-title { | |
font-size: 20px; | |
} | |
.messages-container { | |
padding: 15px; | |
} | |
.message { | |
max-width: 85%; | |
padding: 10px 14px; | |
} | |
.chat-input-container { | |
padding: 15px; | |
} | |
.username-change { | |
flex-direction: column; | |
align-items: flex-start; | |
} | |
.username-input { | |
width: 100%; | |
margin-bottom: 5px; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<a href="/" class="back-btn">← Back to Home</a> | |
<div class="chat-container"> | |
<div class="chat-header"> | |
<div class="chat-title"> | |
<span>💬</span> | |
Anime Chat | |
</div> | |
<div class="chat-info"> | |
<span>Online: <span class="user-count" id="userCount">0</span></span> | |
</div> | |
</div> | |
<div class="messages-container" id="messagesContainer"> | |
<!-- Messages will be dynamically added here --> | |
</div> | |
<div class="chat-input-container"> | |
<div class="username-change"> | |
<input type="text" class="username-input" id="usernameInput" placeholder="Change username..."> | |
<button class="change-username-btn" onclick="changeUsername()">Change Name</button> | |
</div> | |
<div class="chat-input-wrapper"> | |
<input type="text" class="chat-input" id="messageInput" placeholder="Type your message..." maxlength="500"> | |
<button class="send-btn" onclick="sendMessage()">Send</button> | |
</div> | |
</div> | |
</div> | |
<script> | |
const socket = io(); | |
let currentUsername = ''; | |
// DOM elements | |
const messagesContainer = document.getElementById('messagesContainer'); | |
const messageInput = document.getElementById('messageInput'); | |
const usernameInput = document.getElementById('usernameInput'); | |
const userCountElement = document.getElementById('userCount'); | |
// Socket event listeners | |
socket.on('connect', function() { | |
console.log('Connected to chat server'); | |
}); | |
socket.on('chat_history', function(messages) { | |
messagesContainer.innerHTML = ''; | |
messages.forEach(message => { | |
addMessageToChat(message); | |
}); | |
scrollToBottom(); | |
}); | |
socket.on('new_message', function(message) { | |
addMessageToChat(message); | |
scrollToBottom(); | |
}); | |
socket.on('user_count', function(count) { | |
userCountElement.textContent = count; | |
}); | |
socket.on('username_changed', function(data) { | |
currentUsername = data.username; | |
usernameInput.value = ''; | |
usernameInput.placeholder = `Current: ${currentUsername}`; | |
}); | |
// Functions | |
function addMessageToChat(message) { | |
const messageElement = document.createElement('div'); | |
if (message.type === 'system') { | |
messageElement.className = 'message system'; | |
messageElement.innerHTML = ` | |
<div class="message-content">${message.message}</div> | |
`; | |
} else { | |
const isOwnMessage = message.username === currentUsername; | |
messageElement.className = `message ${isOwnMessage ? 'user' : 'other'}`; | |
messageElement.innerHTML = ` | |
<div class="message-header"> | |
<span class="username">${message.username}</span> | |
<span class="timestamp">${message.timestamp}</span> | |
</div> | |
<div class="message-content">${message.message}</div> | |
`; | |
} | |
messagesContainer.appendChild(messageElement); | |
} | |
function sendMessage() { | |
const message = messageInput.value.trim(); | |
if (message) { | |
socket.emit('send_message', { message: message }); | |
messageInput.value = ''; | |
} | |
} | |
function changeUsername() { | |
const newUsername = usernameInput.value.trim(); | |
if (newUsername && newUsername.length >= 2) { | |
socket.emit('change_username', { username: newUsername }); | |
} | |
} | |
function scrollToBottom() { | |
messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
} | |
// Event listeners | |
messageInput.addEventListener('keypress', function(e) { | |
if (e.key === 'Enter') { | |
sendMessage(); | |
} | |
}); | |
usernameInput.addEventListener('keypress', function(e) { | |
if (e.key === 'Enter') { | |
changeUsername(); | |
} | |
}); | |
// Auto-scroll to bottom when new messages arrive | |
const observer = new MutationObserver(function() { | |
scrollToBottom(); | |
}); | |
observer.observe(messagesContainer, { | |
childList: true, | |
subtree: true | |
}); | |
</script> | |
</body> | |
</html> |