anycoder-81258471 / index.html
samirerty's picture
Upload folder using huggingface_hub
f00f91a verified
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>پیام رسان مینیمال | MinimalChat</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">
<link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.browser.min.js"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Vazirmatn', 'sans-serif'],
},
spacing: {
'safe-top': 'env(safe-area-inset-top)',
'safe-bottom': 'env(safe-area-inset-bottom)',
}
}
}
}
</script>
<style>
body {
font-family: 'Vazirmatn', sans-serif;
background: linear-gradient(135deg, #1e1b4b 0%, #312e81 50%, #1e1b4b 100%);
background-attachment: fixed;
-webkit-tap-highlight-color: transparent;
}
.glass-panel {
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.input-minimal {
background: transparent;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
transition: all 0.3s;
}
.input-minimal:focus {
border-color: rgba(255, 255, 255, 0.6);
outline: none;
}
.message-bubble-me {
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
border-radius: 16px 16px 4px 16px;
}
.message-bubble-other {
background: rgba(255, 255, 255, 0.12);
border-radius: 16px 16px 16px 4px;
}
.fade-in {
animation: fadeIn 0.3s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.slide-in {
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from {
transform: translateX(100%);
}
to {
transform: translateX(0);
}
}
.slide-out {
animation: slideOut 0.3s ease-out;
}
@keyframes slideOut {
from {
transform: translateX(0);
}
to {
transform: translateX(100%);
}
}
/* Custom Scrollbar */
::-webkit-scrollbar {
width: 4px;
height: 4px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.3);
}
/* Mobile Optimizations */
@media (max-width: 768px) {
.mobile-sidebar {
position: fixed;
top: 0;
right: 0;
height: 100vh;
height: 100dvh;
width: 85%;
max-width: 300px;
z-index: 40;
transform: translateX(100%);
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.mobile-sidebar.open {
transform: translateX(0);
}
.sidebar-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(4px);
z-index: 35;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
}
.sidebar-overlay.active {
opacity: 1;
pointer-events: auto;
}
.chat-container {
position: fixed;
inset: 0;
z-index: 30;
}
.safe-bottom {
padding-bottom: env(safe-area-inset-bottom, 20px);
}
}
/* Touch friendly buttons */
.touch-target {
min-height: 44px;
min-width: 44px;
}
/* Prevent zoom on input focus for iOS */
@media screen and (max-width: 768px) {
input, textarea, select {
font-size: 16px;
}
}
/* Message animations */
.message-enter {
animation: messagePop 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
@keyframes messagePop {
0% {
opacity: 0;
transform: scale(0.8) translateY(20px);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
}
}
/* Loading shimmer */
.shimmer {
background: linear-gradient(90deg, rgba(255,255,255,0.05) 25%, rgba(255,255,255,0.1) 50%, rgba(255,255,255,0.05) 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
</style>
</head>
<body class="text-white h-screen h-[100dvh] overflow-hidden selection:bg-blue-500/30 bg-slate-900">
<!-- Toast Container -->
<div id="toast-container"
class="fixed top-4 left-1/2 transform -translate-x-1/2 z-50 flex flex-col gap-2 w-full max-w-sm px-4 pointer-events-none">
</div>
<!-- Auth View -->
<div id="auth-view" class="h-full w-full flex items-center justify-center p-4 overflow-y-auto">
<div class="glass-panel p-6 md:p-8 rounded-2xl w-full max-w-md fade-in my-auto">
<div class="text-center mb-6 md:mb-8">
<div class="w-14 h-14 md:w-16 md:h-16 bg-white/10 rounded-full mx-auto flex items-center justify-center mb-4">
<i class="fa-solid fa-comments text-xl md:text-2xl"></i>
</div>
<h1 class="text-xl md:text-2xl font-bold">پیام رسان مینیمال</h1>
<p class="text-white/50 text-xs md:text-sm mt-1">بدون سرور، کاملاً محلی</p>
</div>
<!-- Tabs -->
<div class="flex gap-4 mb-6 border-b border-white/10 pb-1">
<button onclick="switchAuthTab('login')" id="tab-login" class="flex-1 pb-2 text-sm font-medium border-b-2 border-white text-white transition-colors touch-target flex items-center justify-center">ورود</button>
<button onclick="switchAuthTab('register')" id="tab-register" class="flex-1 pb-2 text-sm font-medium border-b-2 border-transparent text-white/50 hover:text-white transition-colors touch-target flex items-center justify-center">ثبت نام</button>
</div>
<!-- Login Form -->
<form id="login-form" class="space-y-4 md:space-y-5" onsubmit="handleLogin(event)">
<div>
<label class="block text-xs text-white/60 mb-2">شماره موبایل</label>
<input type="tel" id="login-phone" placeholder="09XXXXXXXXX" inputmode="tel" class="w-full input-minimal py-3 text-white placeholder-white/30 touch-target" required>
</div>
<div>
<label class="block text-xs text-white/60 mb-2">رمز عبور</label>
<input type="password" id="login-password" placeholder="••••••••" class="w-full input-minimal py-3 text-white placeholder-white/30 touch-target" required>
</div>
<button type="submit" class="w-full bg-white text-slate-900 font-bold py-3 rounded-lg hover:bg-white/90 transition-colors mt-4 touch-target active:scale-95 transform transition-transform">
ورود
</button>
</form>
<!-- Register Form -->
<form id="register-form" class="space-y-4 md:space-y-5 hidden" onsubmit="handleRegister(event)">
<div>
<label class="block text-xs text-white/60 mb-2">نام کامل</label>
<input type="text" id="reg-name" placeholder="نام شما" class="w-full input-minimal py-3 text-white placeholder-white/30 touch-target" required>
</div>
<div>
<label class="block text-xs text-white/60 mb-2">شماره موبایل</label>
<input type="tel" id="reg-phone" placeholder="09XXXXXXXXX" inputmode="tel" class="w-full input-minimal py-3 text-white placeholder-white/30 touch-target" required>
</div>
<div>
<label class="block text-xs text-white/60 mb-2">رمز عبور</label>
<input type="password" id="reg-password" placeholder="حداقل ۴ کاراکتر" class="w-full input-minimal py-3 text-white placeholder-white/30 touch-target" required>
</div>
<button type="submit" class="w-full bg-white text-slate-900 font-bold py-3 rounded-lg hover:bg-white/90 transition-colors mt-4 touch-target active:scale-95 transform transition-transform">
ثبت نام
</button>
</form>
<div class="mt-6 text-center">
<p class="text-xs text-white/40">
Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank"
class="hover:text-white underline">anycoder</a>
</p>
</div>
</div>
</div>
<!-- Dashboard View -->
<div id="dashboard-view" class="hidden h-full w-full flex flex-col md:flex-row relative">
<!-- Mobile Sidebar Overlay -->
<div id="sidebar-overlay" class="sidebar-overlay md:hidden" onclick="toggleSidebar()"></div>
<!-- Sidebar -->
<aside id="sidebar" class="mobile-sidebar md:relative md:transform-none md:w-72 md:h-full glass-panel border-l border-white/10 flex flex-col bg-slate-900/95 md:bg-transparent">
<!-- Profile -->
<div class="p-4 md:p-6 border-b border-white/10 flex items-center justify-between">
<div class="flex items-center gap-3 flex-1">
<div class="w-10 h-10 md:w-12 md:h-12 rounded-full bg-blue-500/20 flex items-center justify-center text-blue-300 font-bold text-lg">
<span id="user-avatar-initial">U</span>
</div>
<div class="flex-1 min-w-0">
<h2 id="user-name-display" class="font-bold text-sm truncate">کاربر</h2>
<p id="user-phone-display" class="text-xs text-white/50 font-mono">09--------</p>
</div>
</div>
<button onclick="logout()" class="text-white/40 hover:text-white transition-colors p-2 touch-target mr-2">
<i class="fa-solid fa-arrow-right-from-bracket text-lg"></i>
</button>
</div>
<!-- Create Room -->
<div class="p-4 border-b border-white/10">
<div class="flex justify-between items-center mb-3">
<span class="text-xs font-medium text-white/60">اتاق‌های من</span>
<span id="room-count-badge" class="text-xs bg-white/10 px-2 py-0.5 rounded-full">۰/۳</span>
</div>
<button onclick="openCreateRoomModal()" id="btn-create-room" class="w-full py-3 border border-dashed border-white/20 rounded-lg text-sm text-white/70 hover:border-white/40 hover:text-white transition-colors touch-target">
<i class="fa-solid fa-plus ml-1"></i> اتاق جدید
</button>
<p id="room-limit-msg" class="text-xs text-red-400 mt-2 hidden">حداکثر ۳ اتاق مجاز است</p>
</div>
<!-- Room List -->
<div class="flex-1 overflow-y-auto p-2 space-y-1" id="room-list-container">
<div class="text-center mt-8 text-white/30 text-sm">
<p>اتاقی وجود ندارد</p>
</div>
</div>
<!-- Mobile Safe Area -->
<div class="h-safe-bottom md:hidden"></div>
</aside>
<!-- Main Content -->
<main class="flex-1 flex flex-col h-full relative bg-slate-900/20 w-full">
<!-- Mobile Header -->
<header class="h-14 glass-panel border-b border-white/10 flex items-center justify-between px-4 md:px-6 md:hidden">
<button onclick="toggleSidebar()" class="touch-target flex items-center justify-center w-10 h-10 -mr-2 text-white/80">
<i class="fa-solid fa-bars text-lg"></i>
</button>
<span class="text-sm font-medium text-white/60">پیام رسان مینیمال</span>
<div class="w-10"></div> <!-- Spacer for balance -->
</header>
<!-- Desktop Header -->
<header class="hidden md:flex h-14 glass-panel border-b border-white/10 items-center justify-between px-6">
<span class="text-sm font-medium text-white/60">داشبورد</span>
<div class="flex items-center gap-2 text-xs text-white/40">
<span class="w-2 h-2 bg-green-500 rounded-full animate-pulse"></span>
آنلاین
</div>
</header>
<!-- Welcome Screen -->
<div id="welcome-screen" class="flex-1 flex flex-col items-center justify-center p-8 text-center">
<div class="w-16 h-16 md:w-20 md:h-20 bg-white/5 rounded-full flex items-center justify-center mb-4">
<i class="fa-regular fa-comments text-2xl md:text-3xl text-white/40"></i>
</div>
<h2 class="text-lg md:text-xl font-bold mb-2">به پیام رسان خوش آمدید</h2>
<p class="text-white/50 text-sm max-w-md">اتاق جدید بسازید یا یکی را انتخاب کنید</p>
<button onclick="openCreateRoomModal()" class="mt-6 md:hidden bg-white/10 px-6 py-3 rounded-full text-sm font-medium touch-target">
<i class="fa-solid fa-plus ml-2"></i>ساخت اتاق جدید
</button>
</div>
<!-- Chat Interface -->
<div id="chat-interface" class="hidden absolute inset-0 bg-slate-900 flex flex-col fade-in z-20">
<!-- Chat Header -->
<div class="h-14 glass-panel border-b border-white/10 flex items-center justify-between px-4 safe-top">
<div class="flex items-center gap-3 flex-1 min-w-0">
<button onclick="closeChat()" class="md:hidden text-white/60 hover:text-white touch-target w-10 h-10 flex items-center justify-center -mr-2">
<i class="fa-solid fa-arrow-right text-lg"></i>
</button>
<div class="w-9 h-9 md:w-10 md:h-10 rounded-full bg-indigo-500/20 flex items-center justify-center shrink-0">
<i class="fa-solid fa-hashtag text-sm text-indigo-300"></i>
</div>
<div class="min-w-0 flex-1">
<h3 id="chat-room-name" class="font-bold text-sm truncate">اتاق</h3>
<span id="chat-user-count" class="text-xs text-white/50">۲ عضو</span>
</div>
</div>
<button onclick="copyRoomLink()" class="text-white/40 hover:text-white text-sm touch-target w-10 h-10 flex items-center justify-center">
<i class="fa-solid fa-share-nodes text-lg"></i>
</button>
</div>
<!-- Messages -->
<div id="messages-container" class="flex-1 overflow-y-auto p-4 space-y-3 pb-20 md:pb-4">
<!-- Messages injected here -->
</div>
<!-- Input -->
<div class="absolute bottom-0 left-0 right-0 p-3 md:p-4 glass-panel border-t border-white/10 safe-bottom bg-slate-900/90 backdrop-blur-xl">
<form onsubmit="sendMessage(event)" class="flex gap-2 max-w-4xl mx-auto">
<input type="text" id="message-input" placeholder="پیام خود را بنویسید..."
class="flex-1 bg-white/10 border border-white/10 rounded-full px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-white/30 focus:bg-white/15 transition-all touch-target"
autocomplete="off">
<button type="submit" class="bg-blue-600 hover:bg-blue-500 text-white w-11 h-11 rounded-full flex items-center justify-center transition-colors touch-target active:scale-95 transform shadow-lg shadow-blue-600/30 shrink-0">
<i class="fa-solid fa-paper-plane text-sm"></i>
</button>
</form>
</div>
</div>
</main>
</div>
<!-- Create Room Modal -->
<div id="create-room-modal"
class="fixed inset-0 z-50 hidden flex items-end md:items-center justify-center p-0 md:p-4 bg-black/60 backdrop-blur-sm transition-opacity">
<div class="glass-panel w-full md:max-w-sm rounded-t-2xl md:rounded-2xl p-6 fade-in bg-slate-900 border-t md:border border-white/10">
<div class="flex justify-between items-center mb-4">
<h3 class="font-bold text-lg">اتاق جدید</h3>
<button onclick="closeCreateRoomModal()" class="text-white/40 hover:text-white touch-target w-10 h-10 flex items-center justify-center">
<i class="fa-solid fa-xmark text-xl"></i>
</button>
</div>
<form onsubmit="handleCreateRoom(event)" class="space-y-4">
<div>
<label class="block text-xs text-white/60 mb-2">نام اتاق</label>
<input type="text" id="new-room-name" placeholder="مثلاً: گروه دوستان"
class="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white placeholder-white/30 focus:outline-none focus:border-white/30 touch-target"
required>
</div>
<div class="flex gap-3 pt-2">
<button type="button" onclick="closeCreateRoomModal()" class="flex-1 py-3 rounded-xl border border-white/10 text-sm hover:bg-white/5 transition-colors touch-target">
انصراف
</button>
<button type="submit" class="flex-1 py-3 rounded-xl bg-white text-slate-900 text-sm font-bold hover:bg-white/90 transition-colors touch-target active:scale-95 transform">
ساختن
</button>
</div>
</form>
</div>
</div>
<script>
// Data & State
const DB_KEYS = {
USERS: 'chat_app_users',
ROOMS: 'chat_app_rooms',
MESSAGES: 'chat_app_messages',
SESSION: 'chat_app_session'
};
let currentUser = null;
let currentRoomId = null;
let isSidebarOpen = false;
// Init
document.addEventListener('DOMContentLoaded', () => {
checkSession();
const urlParams = new URLSearchParams(window.location.search);
const inviteRoomId = urlParams.get('room');
if (inviteRoomId && currentUser) {
joinRoomById(inviteRoomId);
} else if (inviteRoomId) {
showToast('ابتدا وارد شوید', 'info');
}
// Handle resize
window.addEventListener('resize', () => {
if (window.innerWidth >= 768) {
document.getElementById('sidebar').classList.remove('open');
document.getElementById('sidebar-overlay').classList.remove('active');
isSidebarOpen = false;
}
});
// Handle keyboard for mobile
const messageInput = document.getElementById('message-input');
if (messageInput) {
messageInput.addEventListener('focus', () => {
setTimeout(scrollToBottom, 300);
});
}
});
function checkSession() {
const session = localStorage.getItem(DB_KEYS.SESSION);
if (session) {
currentUser = JSON.parse(session);
showDashboard();
}
}
// Sidebar Toggle for Mobile
function toggleSidebar() {
const sidebar = document.getElementById('sidebar');
const overlay = document.getElementById('sidebar-overlay');
isSidebarOpen = !isSidebarOpen;
if (isSidebarOpen) {
sidebar.classList.add('open');
overlay.classList.add('active');
} else {
sidebar.classList.remove('open');
overlay.classList.remove('active');
}
}
// Auth
function switchAuthTab(tab) {
const loginForm = document.getElementById('login-form');
const registerForm = document.getElementById('register-form');
const loginTab = document.getElementById('tab-login');
const registerTab = document.getElementById('tab-register');
if (tab === 'login') {
loginForm.classList.remove('hidden');
registerForm.classList.add('hidden');
loginTab.classList.add('border-white', 'text-white');
loginTab.classList.remove('border-transparent', 'text-white/50');
registerTab.classList.remove('border-white', 'text-white');
registerTab.classList.add('border-transparent', 'text-white/50');
} else {
loginForm.classList.add('hidden');
registerForm.classList.remove('hidden');
registerTab.classList.add('border-white', 'text-white');
registerTab.classList.remove('border-transparent', 'text-white/50');
loginTab.classList.remove('border-white', 'text-white');
loginTab.classList.add('border-transparent', 'text-white/50');
}
}
function handleRegister(e) {
e.preventDefault();
const name = document.getElementById('reg-name').value.trim();
const phone = document.getElementById('reg-phone').value.trim();
const password = document.getElementById('reg-password').value;
if (phone.length < 11) {
showToast('شماره موبایل صحیح نیست', 'error');
return;
}
let users = JSON.parse(localStorage.getItem(DB_KEYS.USERS) || '[]');
if (users.find(u => u.phone === phone)) {
showToast('این شماره قبلا ثبت شده', 'error');
return;
}
const newUser = {
id: Date.now().toString(),
name,
phone,
password,
createdAt: new Date().toISOString()
};
users.push(newUser);
localStorage.setItem(DB_KEYS.USERS, JSON.stringify(users));
currentUser = { id: newUser.id, name: newUser.name, phone: newUser.phone };
localStorage.setItem(DB_KEYS.SESSION, JSON.stringify(currentUser));
confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } });
showToast('ثبت نام موفق', 'success');
showDashboard();
}
function handleLogin(e) {
e.preventDefault();
const phone = document.getElementById('login-phone').value.trim();
const password = document.getElementById('login-password').value;
const users = JSON.parse(localStorage.getItem(DB_KEYS.USERS) || '[]');
const user = users.find(u => u.phone === phone && u.password === password);
if (user) {
currentUser = { id: user.id, name: user.name, phone: user.phone };
localStorage.setItem(DB_KEYS.SESSION, JSON.stringify(currentUser));
showToast(`خوش آمدید ${user.name}`, 'success');
showDashboard();
} else {
showToast('اطلاعات اشتباه است', 'error');
}
}
function logout() {
localStorage.removeItem(DB_KEYS.SESSION);
currentUser = null;
currentRoomId = null;
showAuth();
showToast('خروج انجام شد', 'info');
// Close sidebar on mobile
if (isSidebarOpen) toggleSidebar();
}
// Views
function showAuth() {
document.getElementById('auth-view').classList.remove('hidden');
document.getElementById('dashboard-view').classList.add('hidden');
}
function showDashboard() {
document.getElementById('auth-view').classList.add('hidden');
document.getElementById('dashboard-view').classList.remove('hidden');
document.getElementById('user-name-display').innerText = currentUser.name;
document.getElementById('user-phone-display').innerText = currentUser.phone;
document.getElementById('user-avatar-initial').innerText = currentUser.name.charAt(0);
renderRoomList();
}
// Rooms
function renderRoomList() {
const allRooms = JSON.parse(localStorage.getItem(DB_KEYS.ROOMS) || '[]');
const myRooms = allRooms.filter(r => r.creatorId === currentUser.id || (r.members && r.members.includes(currentUser.id)));
const container = document.getElementById('room-list-container');
const createdCount = allRooms.filter(r => r.creatorId === currentUser.id).length;
document.getElementById('room-count-badge').innerText = `${createdCount}/۳`;
const createBtn = document.getElementById('btn-create-room');
const limitMsg = document.getElementById('room-limit-msg');
if (createdCount >= 3) {
createBtn.disabled = true;
createBtn.classList.add('opacity-50', 'cursor-not-allowed');
limitMsg.classList.remove('hidden');
} else {
createBtn.disabled = false;
createBtn.classList.remove('opacity-50', 'cursor-not-allowed');
limitMsg.classList.add('hidden');
}
if (myRooms.length === 0) {
container.innerHTML = `<div class="text-center mt-8 text-white/30 text-sm px-4"><p>اتاقی وجود ندارد</p><p class="text-xs mt-1">اولین اتاق را بسازید</p></div>`;
return;
}
container.innerHTML = myRooms.map(room => `
<div onclick="openRoom('${room.id}')" class="p-3 rounded-xl hover:bg-white/5 cursor-pointer transition-colors flex items-center justify-between group touch-target">
<div class="flex items-center gap-3 min-w-0 flex-1">
<div class="w-10 h-10 rounded-full bg-white/5 flex items-center justify-center text-sm font-bold text-white/60 group-hover:bg-white/10 shrink-0">
${room.name.charAt(0)}
</div>
<div class="min-w-0 flex-1">
<span class="text-sm font-medium block truncate">${room.name}</span>
<span class="text-xs text-white/40">${room.members ? room.members.length : 1} عضو</span>
</div>
</div>
<i class="fa-solid fa-chevron-left text-xs text-white/20 group-hover:text-white/40 mr-2"></i>
</div>
`).join('');
}
function openCreateRoomModal() {
document.getElementById('create-room-modal').classList.remove('hidden');
setTimeout(() => document.getElementById('new-room-name').focus(), 100);
// Close sidebar on mobile when opening modal
if (isSidebarOpen) toggleSidebar();
}
function closeCreateRoomModal() {
document.getElementById('create-room-modal').classList.add('hidden');
document.getElementById('new-room-name').value = '';
}
function handleCreateRoom(e) {
e.preventDefault();
const name = document.getElementById('new-room-name').value.trim();
if (!name) return;
const rooms = JSON.parse(localStorage.getItem(DB_KEYS.ROOMS) || '[]');
const myRoomCount = rooms.filter(r => r.creatorId === currentUser.id).length;
if (myRoomCount >= 3) {
showToast('محودیت ۳ اتاق', 'error');
return;
}
const newRoom = {
id: 'room_' + Date.now(),
name,
creatorId: currentUser.id,
members: [currentUser.id],
createdAt: new Date().toISOString()
};
rooms.push(newRoom);
localStorage.setItem(DB_KEYS.ROOMS, JSON.stringify(rooms));
closeCreateRoomModal();
renderRoomList();
showToast('اتاق ساخته شد', 'success');
openRoom(newRoom.id);
}
function joinRoomById(roomId) {
const rooms = JSON.parse(localStorage.getItem(DB_KEYS.ROOMS) || '[]');
const roomIndex = rooms.findIndex(r => r.id === roomId);
if (roomIndex === -1) {
showToast('اتاق یافت نشد', 'error');
return;
}
if (!rooms[roomIndex].members) rooms[roomIndex].members = [];
if (!rooms[roomIndex].members.includes(currentUser.id)) {
rooms[roomIndex].members.push(currentUser.id);
localStorage.setItem(DB_KEYS.ROOMS, JSON.stringify(rooms));
showToast('به اتاق پیوستید', 'success');
renderRoomList();
}
openRoom(roomId);
}
// Chat
function openRoom(roomId) {
currentRoomId = roomId;
const rooms = JSON.parse(localStorage.getItem(DB_KEYS.ROOMS) || '[]');
const room = rooms.find(r => r.id === roomId);
if (!room) return;
document.getElementById('welcome-screen').classList.add('hidden');
document.getElementById('chat-interface').classList.remove('hidden');
document.getElementById('chat-room-name').innerText = room.name;
document.getElementById('chat-user-count').innerText = `${room.members ? room.members.length : 1} عضو`;
loadMessages();
setTimeout(() => {
const input = document.getElementById('message-input');
if (input && window.innerWidth > 768) input.focus();
}, 100);
// Close sidebar on mobile when opening room
if (isSidebarOpen) toggleSidebar();
}
function closeChat() {
document.getElementById('chat-interface').classList.add('hidden');
document.getElementById('welcome-screen').classList.remove('hidden');
currentRoomId = null;
}
function loadMessages() {
const allMessages = JSON.parse(localStorage.getItem(DB_KEYS.MESSAGES) || '[]');
const roomMessages = allMessages.filter(m => m.roomId === currentRoomId);
const container = document.getElementById('messages-container');
container.innerHTML = '';
if (roomMessages.length === 0) {
container.innerHTML = `<div class="text-center text-white/30 text-sm mt-10 flex flex-col items-center"><i class="fa-regular fa-comments text-3xl mb-2 opacity-50"></i><p>اولین پیام را ارسال کنید</p></div>`;
} else {
roomMessages.forEach(msg => renderMessageBubble(msg));
}
scrollToBottom();
}
function renderMessageBubble(msg) {
const container = document.getElementById('messages-container');
const isMe = msg.userId === currentUser.id;
const div = document.createElement('div');
div.className = `flex w-full ${isMe ? 'justify-start' : 'justify-end'} message-enter mb-3`;
const users = JSON.parse(localStorage.getItem(DB_KEYS.USERS) || '[]');
const sender = users.find(u => u.id === msg.userId);
const senderName = sender ? sender.name : 'Unknown';
const time = new Date(msg.timestamp).toLocaleTimeString('fa-IR', {hour: '2-digit', minute:'2-digit'});
div.innerHTML = `
<div class="max-w-[85%] md:max-w-[70%] flex flex-col ${isMe ? 'items-start' : 'items-end'}">
${!isMe ? `<span class="text-[11px] text-white/50 mb-1 mr-1">${senderName}</span>` : ''}
<div class="${isMe ? 'message-bubble-me' : 'message-bubble-other'} px-4 py-2.5 text-sm shadow-lg">
<p class="leading-relaxed break-words">${escapeHtml(msg.text)}</p>
</div>
<span class="text-[10px] text-white/30 mt-1 mx-1">${time}</span>
</div>
`;
container.appendChild(div);
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function sendMessage(e) {
e.preventDefault();
const input = document.getElementById('message-input');
const text = input.value.trim();
if (!text || !currentRoomId) return;
const newMessage = {
id: Date.now().toString(),
roomId: currentRoomId,
userId: currentUser.id,
text: text,
timestamp: new Date().toISOString()
};
const allMessages = JSON.parse(localStorage.getItem(DB_KEYS.MESSAGES) || '[]');
allMessages.push(newMessage);
localStorage.setItem(DB_KEYS.MESSAGES, JSON.stringify(allMessages));
input.value = '';
const container = document.getElementById('messages-container');
if (container.children.length > 0 && container.children[0].classList.contains('text-center')) {
container.innerHTML = '';
}
renderMessageBubble(newMessage);
scrollToBottom();
}
function scrollToBottom() {
const container = document.getElementById('messages-container');
container.scrollTop = container.scrollHeight;
}
function copyRoomLink() {
if(!currentRoomId) return;
const link = `${window.location.origin}${window.location.pathname}?room=${currentRoomId}`;
navigator.clipboard.writeText(link).then(() => {
showToast('لینک کپی شد', 'success');
}).catch(() => {
// Fallback for older browsers
const textArea = document.createElement("textarea");
textArea.value = link;
document.body.appendChild(textArea);
textArea.select();
document.execCommand("copy");
document.body.removeChild(textArea);
showToast('لینک کپی شد', 'success');
});
}
// Utils
function showToast(message, type = 'info') {
const container = document.getElementById('toast-container');
const toast = document.createElement('div');
let bgClass = 'bg-white/10';
let icon = 'fa-info-circle';
if (type === 'success') { bgClass = 'bg-green-500/20 text-green-200 border border-green-500/30'; icon = 'fa-check-circle'; }
if (type === 'error') { bgClass = 'bg-red-500/20 text-red-200 border border-red-500/30'; icon = 'fa-exclamation-circle'; }
toast.className = `${bgClass} px-4 py-3 rounded-xl flex items-center gap-3 text-sm backdrop-blur-md fade-in shadow-lg`;
toast.innerHTML = `<i class="fa-solid ${icon} text-base"></i><span class="font-medium">${message}</span>`;
container.appendChild(toast);
setTimeout(() => {
toast.style.opacity = '0';
toast.style.transform = 'translateY(-10px)';
setTimeout(() => toast.remove(), 300);
}, 3000);
}
// Close modal on outside click
document.getElementById('create-room-modal').addEventListener('click', function(e) {
if (e.target === this) {
closeCreateRoomModal();
}
});
</script>
</body>
</html>