feat(ui): add persian rtl chat interface
This commit is contained in:
168
app/static/app.js
Normal file
168
app/static/app.js
Normal file
@@ -0,0 +1,168 @@
|
||||
const usernameInput = document.querySelector('#username');
|
||||
const roomInput = document.querySelector('#room');
|
||||
const connectBtn = document.querySelector('#connectBtn');
|
||||
const disconnectBtn = document.querySelector('#disconnectBtn');
|
||||
const clearBtn = document.querySelector('#clearBtn');
|
||||
const messageForm = document.querySelector('#messageForm');
|
||||
const messageInput = document.querySelector('#messageInput');
|
||||
const sendBtn = document.querySelector('#sendBtn');
|
||||
const messages = document.querySelector('#messages');
|
||||
const statusPill = document.querySelector('#connectionStatus');
|
||||
const usersList = document.querySelector('#usersList');
|
||||
const roomTitle = document.querySelector('#roomTitle');
|
||||
const roomSubtitle = document.querySelector('#roomSubtitle');
|
||||
|
||||
let socket = null;
|
||||
let currentUser = '';
|
||||
let currentRoom = '';
|
||||
|
||||
usernameInput.value = localStorage.getItem('chat_username') || '';
|
||||
roomInput.value = localStorage.getItem('chat_room') || 'عمومی';
|
||||
|
||||
function setConnectedState(isConnected) {
|
||||
connectBtn.disabled = isConnected;
|
||||
disconnectBtn.disabled = !isConnected;
|
||||
messageInput.disabled = !isConnected;
|
||||
sendBtn.disabled = !isConnected;
|
||||
usernameInput.disabled = isConnected;
|
||||
roomInput.disabled = isConnected;
|
||||
|
||||
statusPill.textContent = isConnected ? 'متصل' : 'قطع';
|
||||
statusPill.classList.toggle('connected', isConnected);
|
||||
}
|
||||
|
||||
function showEmptyState() {
|
||||
messages.innerHTML = '<div class="empty-state">هنوز پیامی وجود ندارد.<br />وارد یک اتاق شوید و پیام بفرستید.</div>';
|
||||
}
|
||||
|
||||
function clearEmptyState() {
|
||||
const emptyState = messages.querySelector('.empty-state');
|
||||
if (emptyState) emptyState.remove();
|
||||
}
|
||||
|
||||
function safeName(value, fallback) {
|
||||
return value.trim() || fallback;
|
||||
}
|
||||
|
||||
function formatTime(timestamp) {
|
||||
if (!timestamp) return '';
|
||||
const date = new Date(timestamp);
|
||||
if (Number.isNaN(date.getTime())) return '';
|
||||
return date.toLocaleTimeString('fa-IR', { hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
|
||||
function addMessage(payload) {
|
||||
clearEmptyState();
|
||||
|
||||
const card = document.createElement('article');
|
||||
card.className = 'message';
|
||||
|
||||
if (payload.type === 'system') card.classList.add('system');
|
||||
if (payload.client_id === currentUser && payload.type === 'message') card.classList.add('mine');
|
||||
|
||||
const meta = document.createElement('div');
|
||||
meta.className = 'message-meta';
|
||||
|
||||
const sender = document.createElement('span');
|
||||
sender.textContent = payload.client_id || 'ناشناس';
|
||||
|
||||
const time = document.createElement('span');
|
||||
time.textContent = formatTime(payload.timestamp);
|
||||
|
||||
meta.append(sender, time);
|
||||
|
||||
const content = document.createElement('div');
|
||||
content.className = 'message-content';
|
||||
content.textContent = payload.content || '';
|
||||
|
||||
card.append(meta, content);
|
||||
messages.appendChild(card);
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
}
|
||||
|
||||
function updateUsers(users = []) {
|
||||
usersList.innerHTML = '';
|
||||
|
||||
if (!users.length) {
|
||||
const li = document.createElement('li');
|
||||
li.className = 'muted';
|
||||
li.textContent = 'کاربری آنلاین نیست';
|
||||
usersList.appendChild(li);
|
||||
return;
|
||||
}
|
||||
|
||||
users.forEach((user) => {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = user;
|
||||
usersList.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
function connect() {
|
||||
currentUser = safeName(usernameInput.value, 'ناشناس');
|
||||
currentRoom = safeName(roomInput.value, 'عمومی');
|
||||
|
||||
localStorage.setItem('chat_username', currentUser);
|
||||
localStorage.setItem('chat_room', currentRoom);
|
||||
|
||||
const wsProtocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
const wsUrl = `${wsProtocol}://${window.location.host}/ws/${encodeURIComponent(currentRoom)}/${encodeURIComponent(currentUser)}`;
|
||||
|
||||
socket = new WebSocket(wsUrl);
|
||||
|
||||
socket.addEventListener('open', () => {
|
||||
setConnectedState(true);
|
||||
roomTitle.textContent = `اتاق: ${currentRoom}`;
|
||||
roomSubtitle.textContent = `شما با نام ${currentUser} گفتگو میکنید.`;
|
||||
messageInput.focus();
|
||||
});
|
||||
|
||||
socket.addEventListener('message', (event) => {
|
||||
const payload = JSON.parse(event.data);
|
||||
|
||||
if (payload.type === 'presence') {
|
||||
updateUsers(payload.users || []);
|
||||
return;
|
||||
}
|
||||
|
||||
addMessage(payload);
|
||||
});
|
||||
|
||||
socket.addEventListener('close', () => {
|
||||
setConnectedState(false);
|
||||
updateUsers([]);
|
||||
roomSubtitle.textContent = 'ارتباط بسته شد.';
|
||||
socket = null;
|
||||
});
|
||||
|
||||
socket.addEventListener('error', () => {
|
||||
addMessage({
|
||||
type: 'system',
|
||||
client_id: 'سیستم',
|
||||
content: 'خطا در اتصال. مطمئن شوید سرور برنامه در حال اجرا است.',
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
if (socket) socket.close();
|
||||
}
|
||||
|
||||
connectBtn.addEventListener('click', connect);
|
||||
disconnectBtn.addEventListener('click', disconnect);
|
||||
clearBtn.addEventListener('click', showEmptyState);
|
||||
|
||||
messageForm.addEventListener('submit', (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const content = messageInput.value.trim();
|
||||
if (!content || !socket || socket.readyState !== WebSocket.OPEN) return;
|
||||
|
||||
socket.send(JSON.stringify({ content }));
|
||||
messageInput.value = '';
|
||||
messageInput.focus();
|
||||
});
|
||||
|
||||
showEmptyState();
|
||||
setConnectedState(false);
|
||||
Reference in New Issue
Block a user