Spaces:
Running
Running
| <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"> | |
| <title>داشبورد چت | Chat Dashboard</title> | |
| <!-- فونت فارسی وزیرمتن --> | |
| <link href="https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/Vazirmatn-font-face.css" rel="stylesheet" type="text/css" /> | |
| <!-- آیکونهای Phosphor --> | |
| <script src="https://unpkg.com/@phosphor-icons/web"></script> | |
| <style> | |
| :root { | |
| /* پالت رنگی مدرن */ | |
| --primary: #4f46e5; | |
| --primary-hover: #4338ca; | |
| --bg-body: #f3f4f6; | |
| --bg-surface: #ffffff; | |
| --text-main: #111827; | |
| --text-secondary: #6b7280; | |
| --border: #e5e7eb; | |
| --danger: #ef4444; | |
| --success: #10b981; | |
| --message-bg: #f3f4f6; | |
| --message-self: #4f46e5; | |
| --text-self: #ffffff; | |
| /* ابعاد */ | |
| --sidebar-width: 320px; | |
| --header-height: 64px; | |
| --border-radius: 12px; | |
| --safe-area-bottom: env(safe-area-inset-bottom); | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| -webkit-tap-highlight-color: transparent; | |
| } | |
| body { | |
| font-family: 'Vazirmatn', sans-serif; | |
| background-color: var(--bg-body); | |
| color: var(--text-main); | |
| height: 100vh; | |
| overflow: hidden; | |
| display: flex; | |
| } | |
| /* --- Scrollbar Styling --- */ | |
| ::-webkit-scrollbar { | |
| width: 6px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: transparent; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: #d1d5db; | |
| border-radius: 10px; | |
| } | |
| /* --- Sidebar (Right Side) --- */ | |
| .sidebar { | |
| width: var(--sidebar-width); | |
| background-color: var(--bg-surface); | |
| border-left: 1px solid var(--border); | |
| display: flex; | |
| flex-direction: column; | |
| height: 100%; | |
| z-index: 50; | |
| transition: transform 0.3s ease; | |
| } | |
| .sidebar-header { | |
| padding: 20px; | |
| border-bottom: 1px solid var(--border); | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .avatar { | |
| width: 48px; | |
| height: 48px; | |
| border-radius: 50%; | |
| object-fit: cover; | |
| border: 2px solid var(--primary); | |
| } | |
| .user-info h3 { | |
| font-size: 0.95rem; | |
| font-weight: 700; | |
| } | |
| .user-info p { | |
| font-size: 0.8rem; | |
| color: var(--text-secondary); | |
| } | |
| .sidebar-content { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 16px; | |
| padding-bottom: calc(16px + var(--safe-area-bottom)); | |
| } | |
| .logout-btn { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 8px; | |
| width: 100%; | |
| padding: 10px; | |
| margin-bottom: 24px; | |
| border: 1px solid var(--border); | |
| background: transparent; | |
| color: var(--danger); | |
| border-radius: var(--border-radius); | |
| cursor: pointer; | |
| font-family: inherit; | |
| font-weight: 500; | |
| transition: all 0.2s; | |
| } | |
| .logout-btn:hover { | |
| background-color: #fef2f2; | |
| } | |
| .rooms-section-title { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 12px; | |
| padding: 0 4px; | |
| } | |
| .rooms-section-title h4 { | |
| font-size: 0.9rem; | |
| color: var(--text-secondary); | |
| font-weight: 600; | |
| } | |
| .badge { | |
| background-color: var(--primary); | |
| color: white; | |
| font-size: 0.75rem; | |
| padding: 2px 8px; | |
| border-radius: 10px; | |
| font-weight: bold; | |
| } | |
| .new-room-btn { | |
| width: 100%; | |
| padding: 12px; | |
| background-color: var(--text-main); | |
| color: white; | |
| border: none; | |
| border-radius: var(--border-radius); | |
| font-family: inherit; | |
| font-weight: 600; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 8px; | |
| margin-bottom: 16px; | |
| transition: opacity 0.2s; | |
| } | |
| .new-room-btn:disabled { | |
| background-color: #d1d5db; | |
| cursor: not-allowed; | |
| opacity: 0.7; | |
| } | |
| .room-list { | |
| list-style: none; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| .room-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| padding: 12px; | |
| border-radius: var(--border-radius); | |
| cursor: pointer; | |
| transition: background-color 0.2s; | |
| border: 1px solid transparent; | |
| } | |
| .room-item:hover { | |
| background-color: #f9fafb; | |
| border-color: var(--border); | |
| } | |
| .room-item.active { | |
| background-color: #eef2ff; | |
| border-color: var(--primary); | |
| } | |
| .room-icon { | |
| width: 40px; | |
| height: 40px; | |
| background-color: #e0e7ff; | |
| color: var(--primary); | |
| border-radius: 10px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 1.2rem; | |
| } | |
| .room-details { | |
| flex: 1; | |
| } | |
| .room-name { | |
| font-weight: 600; | |
| font-size: 0.9rem; | |
| display: block; | |
| } | |
| .room-role { | |
| font-size: 0.75rem; | |
| color: var(--text-secondary); | |
| } | |
| /* --- Main Content --- */ | |
| .main-content { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| background-color: var(--bg-body); | |
| position: relative; | |
| height: 100%; | |
| overflow: hidden; | |
| } | |
| /* Header */ | |
| .top-header { | |
| height: var(--header-height); | |
| background-color: var(--bg-surface); | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 0 20px; | |
| border-bottom: 1px solid var(--border); | |
| flex-shrink: 0; | |
| } | |
| .header-right { | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| } | |
| .header-title { | |
| font-size: 1.1rem; | |
| font-weight: 700; | |
| } | |
| .status-indicator { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| font-size: 0.85rem; | |
| color: var(--success); | |
| background: #ecfdf5; | |
| padding: 4px 10px; | |
| border-radius: 20px; | |
| } | |
| .status-dot { | |
| width: 8px; | |
| height: 8px; | |
| background-color: var(--success); | |
| border-radius: 50%; | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4); } | |
| 70% { box-shadow: 0 0 0 6px rgba(16, 185, 129, 0); } | |
| 100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); } | |
| } | |
| .menu-btn { | |
| background: none; | |
| border: none; | |
| font-size: 1.5rem; | |
| cursor: pointer; | |
| color: var(--text-main); | |
| display: none; /* Hidden on desktop */ | |
| } | |
| .anycoder-link { | |
| font-size: 0.8rem; | |
| color: var(--text-secondary); | |
| text-decoration: none; | |
| transition: color 0.2s; | |
| } | |
| .anycoder-link:hover { color: var(--primary); } | |
| /* Views Container */ | |
| .views-container { | |
| flex: 1; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .view { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| display: flex; | |
| flex-direction: column; | |
| transition: transform 0.3s ease, opacity 0.3s ease; | |
| } | |
| .view.hidden { | |
| transform: translateX(-20px); | |
| opacity: 0; | |
| pointer-events: none; | |
| z-index: -1; | |
| } | |
| .view.active { | |
| transform: translateX(0); | |
| opacity: 1; | |
| pointer-events: auto; | |
| z-index: 10; | |
| } | |
| /* Welcome Screen */ | |
| #welcome-view { | |
| align-items: center; | |
| justify-content: center; | |
| text-align: center; | |
| padding: 20px; | |
| } | |
| .welcome-icon { | |
| font-size: 5rem; | |
| color: var(--primary); | |
| margin-bottom: 20px; | |
| opacity: 0.8; | |
| } | |
| .welcome-title { | |
| font-size: 1.5rem; | |
| margin-bottom: 10px; | |
| color: var(--text-main); | |
| } | |
| .welcome-subtitle { | |
| color: var(--text-secondary); | |
| margin-bottom: 30px; | |
| max-width: 300px; | |
| } | |
| .mobile-create-btn { | |
| display: none; /* Only visible on mobile */ | |
| padding: 12px 24px; | |
| background-color: var(--primary); | |
| color: white; | |
| border: none; | |
| border-radius: var(--border-radius); | |
| font-family: inherit; | |
| font-weight: 600; | |
| font-size: 1rem; | |
| cursor: pointer; | |
| box-shadow: 0 4px 6px -1px rgba(79, 70, 229, 0.2); | |
| } | |
| /* Chat Interface */ | |
| #chat-view { | |
| background-color: #fff; | |
| } | |
| .chat-header { | |
| height: 60px; | |
| border-bottom: 1px solid var(--border); | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 0 20px; | |
| background-color: var(--bg-surface); | |
| } | |
| .chat-info h2 { | |
| font-size: 1rem; | |
| } | |
| .chat-info span { | |
| font-size: 0.8rem; | |
| color: var(--text-secondary); | |
| } | |
| .share-btn { | |
| background: #f3f4f6; | |
| border: none; | |
| width: 36px; | |
| height: 36px; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: var(--text-main); | |
| cursor: pointer; | |
| transition: background 0.2s; | |
| } | |
| .share-btn:hover { background: #e5e7eb; } | |
| .messages-container { | |
| flex: 1; | |
| padding: 20px; | |
| overflow-y: auto; | |
| background-color: #f9fafb; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 16px; | |
| } | |
| .message { | |
| max-width: 70%; | |
| padding: 12px 16px; | |
| border-radius: 16px; | |
| font-size: 0.9rem; | |
| line-height: 1.5; | |
| position: relative; | |
| animation: fadeIn 0.3s ease; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .message.received { | |
| background-color: var(--bg-surface); | |
| color: var(--text-main); | |
| align-self: flex-start; | |
| border-bottom-right-radius: 4px; | |
| box-shadow: 0 1px 2px rgba(0,0,0,0.05); | |
| } | |
| .message.sent { | |
| background-color: var(--message-self); | |
| color: var(--text-self); | |
| align-self: flex-end; | |
| border-bottom-left-radius: 4px; | |
| box-shadow: 0 2px 4px rgba(79, 70, 229, 0.3); | |
| } | |
| .input-area { | |
| padding: 16px; | |
| background-color: var(--bg-surface); | |
| border-top: 1px solid var(--border); | |
| display: flex; | |
| gap: 12px; | |
| align-items: center; | |
| padding-bottom: calc(16px + var(--safe-area-bottom)); | |
| } | |
| .input-wrapper { | |
| flex: 1; | |
| position: relative; | |
| } | |
| .message-input { | |
| width: 100%; | |
| padding: 12px 16px; | |
| border-radius: 24px; | |
| border: 1px solid var(--border); | |
| background-color: #f9fafb; | |
| font-family: inherit; | |
| outline: none; | |
| transition: border-color 0.2s; | |
| } | |
| .message-input:focus { | |
| border-color: var(--primary); | |
| background-color: #fff; | |
| } | |
| .send-btn { | |
| width: 48px; | |
| height: 48px; | |
| border-radius: 50%; | |
| background-color: var(--primary); | |
| color: white; | |
| border: none; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 1.2rem; | |
| cursor: pointer; | |
| transition: transform 0.1s, background-color 0.2s; | |
| flex-shrink: 0; | |
| } | |
| .send-btn:active { | |
| transform: scale(0.95); | |
| } | |
| .send-btn:hover { | |
| background-color: var(--primary-hover); | |
| } | |
| /* --- Responsive Queries --- */ | |
| @media (max-width: 768px) { | |
| .sidebar { | |
| position: fixed; | |
| right: 0; | |
| top: 0; | |
| bottom: 0; | |
| transform: translateX(100%); | |
| box-shadow: -4px 0 15px rgba(0,0,0,0.1); | |
| } | |
| .sidebar.open { | |
| transform: translateX(0); | |
| } | |
| .menu-btn { | |
| display: block; | |
| } | |
| .mobile-create-btn { | |
| display: block; | |
| } | |
| .status-indicator { | |
| display: none; /* Hide status on mobile header to save space */ | |
| } | |
| /* Overlay for sidebar */ | |
| .overlay { | |
| position: fixed; | |
| top: 0; left: 0; right: 0; bottom: 0; | |
| background: rgba(0,0,0,0.5); | |
| z-index: 40; | |
| opacity: 0; | |
| pointer-events: none; | |
| transition: opacity 0.3s; | |
| } | |
| .overlay.active { | |
| opacity: 1; | |
| pointer-events: auto; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Overlay for Mobile Sidebar --> | |
| <div class="overlay" id="overlay"></div> | |
| <!-- Sidebar (Right) --> | |
| <aside class="sidebar" id="sidebar"> | |
| <!-- User Profile --> | |
| <div class="sidebar-header"> | |
| <img src="https://picsum.photos/seed/user123/100/100" alt="Avatar" class="avatar"> | |
| <div class="user-info"> | |
| <h3>علی محمدی</h3> | |
| <p>09123456789</p> | |
| </div> | |
| </div> | |
| <div class="sidebar-content"> | |
| <!-- Logout --> | |
| <button class="logout-btn" onclick="handleLogout()"> | |
| <i class="ph ph-sign-out"></i> | |
| خروج از حساب | |
| </button> | |
| <!-- My Rooms Section --> | |
| <div class="rooms-section-title"> | |
| <h4>اتاقهای من</h4> | |
| <span class="badge" id="room-count-badge">0</span> | |
| </div> | |
| <!-- New Room Button --> | |
| <button class="new-room-btn" id="new-room-btn" onclick="createNewRoom()"> | |
| <i class="ph ph-plus-circle"></i> | |
| اتاق جدید | |
| </button> | |
| <!-- Room List --> | |
| <ul class="room-list" id="room-list"> | |
| <!-- Rooms will be injected here via JS --> | |
| </ul> | |
| </div> | |
| </aside> | |
| <!-- Main Content --> | |
| <main class="main-content"> | |
| <!-- Header --> | |
| <header class="top-header"> | |
| <div class="header-right"> | |
| <button class="menu-btn" onclick="toggleSidebar()"> | |
| <i class="ph ph-list"></i> | |
| </button> | |
| <div class="header-title">داشبورد کاربر</div> | |
| </div> | |
| <div class="header-left" style="display: flex; align-items: center; gap: 12px;"> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link"> | |
| Built with anycoder | |
| </a> | |
| <div class="status-indicator" id="desktop-status"> | |
| <span class="status-dot"></span> | |
| آنلاین | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Views Container --> | |
| <div class="views-container"> | |
| <!-- 1. Welcome Screen --> | |
| <div id="welcome-view" class="view active"> | |
| <div class="welcome-icon"> | |
| <i class="ph ph-chat-circle-dots"></i> | |
| </div> | |
| <h1 class="welcome-title">به داشبورد خوش آمدید</h1> | |
| <p class="welcome-subtitle">برای شروع گفتگو، یک اتاق انتخاب کنید یا اتاق جدیدی بسازید.</p> | |
| <button class="mobile-create-btn" onclick="createNewRoomMobile()">ایجاد اتاق</button> | |
| </div> | |
| <!-- 2. Chat Interface --> | |
| <div id="chat-view" class="view hidden"> | |
| <!-- Chat Header --> | |
| <div class="chat-header"> | |
| <div class="chat-info"> | |
| <h2 id="active-room-name">نام اتاق</h2> | |
| <span id="active-room-members">0 عضو</span> | |
| </div> | |
| <button class="share-btn" title="اشتراک گذاری"> | |
| <i class="ph ph-share-network"></i> | |
| </button> | |
| </div> | |
| <!-- Messages Container --> | |
| <div class="messages-container" id="messages-container"> | |
| <!-- Messages will be injected here --> | |
| <div class="message received"> | |
| سلام! به اتاق خوش آمدید. | |
| </div> | |
| </div> | |
| <!-- Input Area --> | |
| <div class="input-area"> | |
| <div class="input-wrapper"> | |
| <input type="text" class="message-input" id="message-input" placeholder="پیام خود را بنویسید..." onkeypress="handleEnter(event)"> | |
| </div> | |
| <button class="send-btn" onclick="sendMessage()"> | |
| <i class="ph ph-paper-plane-right"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <script> | |
| // --- State Management --- | |
| const state = { | |
| rooms: [ | |
| { id: 1, name: "گروه برنامه نویسی", role: "Created", members: 12 }, | |
| { id: 2, name: "پروژه طراحی", role: "Member", members: 5 } | |
| ], | |
| activeRoomId: null, | |
| maxRooms: 3 | |
| }; | |
| // --- DOM Elements --- | |
| const roomListEl = document.getElementById('room-list'); | |
| const roomCountBadge = document.getElementById('room-count-badge'); | |
| const newRoomBtn = document.getElementById('new-room-btn'); | |
| const sidebar = document.getElementById('sidebar'); | |
| const overlay = document.getElementById('overlay'); | |
| const welcomeView = document.getElementById('welcome-view'); | |
| const chatView = document.getElementById('chat-view'); | |
| const activeRoomName = document.getElementById('active-room-name'); | |
| const activeRoomMembers = document.getElementById('active-room-members'); | |
| const messagesContainer = document.getElementById('messages-container'); | |
| const messageInput = document.getElementById('message-input'); | |
| // --- Initialization --- | |
| function init() { | |
| renderRooms(); | |
| updateRoomButtonState(); | |
| } | |
| // --- Sidebar Logic --- | |
| function toggleSidebar() { | |
| sidebar.classList.toggle('open'); | |
| overlay.classList.toggle('active'); | |
| } | |
| // Close sidebar when clicking overlay | |
| overlay.addEventListener('click', () => { | |
| sidebar.classList.remove('open'); | |
| overlay.classList.remove('active'); | |
| }); | |
| function handleLogout() { | |
| if(confirm("آیا مطمئن هستید که میخواهید خارج شوید؟")) { | |
| alert("خروج با موفقیت انجام شد."); | |
| // In a real app: window.location.href = '/login'; | |
| } | |
| } | |
| // --- Room Logic --- | |
| function renderRooms() { | |
| roomListEl.innerHTML = ''; | |
| roomCountBadge.textContent = state.rooms.length; | |
| state.rooms.forEach(room => { | |
| const li = document.createElement('li'); | |
| li.className = `room-item ${state.activeRoomId === room.id ? 'active' : ''}`; | |
| li.onclick = () => selectRoom(room.id); | |
| const roleColor = room.role === 'Created' ? 'var(--primary)' : 'var(--text-secondary)'; | |
| li.innerHTML = ` | |
| <div class="room-icon"> | |
| <i class="ph ph-users-three"></i> | |
| </div> | |
| <div class="room-details"> | |
| <span class="room-name">${room.name}</span> | |
| <span class="room-role" style="color: ${roleColor}">${room.role}</span> | |
| </div> | |
| <i class="ph ph-caret-left" style="color: #d1d5db;"></i> | |
| `; | |
| roomListEl.appendChild(li); | |
| }); | |
| } | |
| function updateRoomButtonState() { | |
| if (state.rooms.length >= state.maxRooms) { | |
| newRoomBtn.disabled = true; | |
| newRoomBtn.innerHTML = `<i class="ph ph-prohibit"></i> محدودیت اتاق (۳)`; | |
| } else { | |
| newRoomBtn.disabled = false; | |
| newRoomBtn.innerHTML = `<i class="ph ph-plus-circle"></i> اتاق جدید`; | |
| } | |
| } | |
| function createNewRoom() { | |
| if (state.rooms.length >= state.maxRooms) return; | |
| const newId = state.rooms.length + 1; | |
| const newRoom = { | |
| id: newId, | |
| name: `اتاق جدید شماره ${newId}`, | |
| role: "Created", | |
| members: 1 | |
| }; | |
| state.rooms.push(newRoom); | |
| renderRooms(); | |
| updateRoomButtonState(); | |
| // Automatically select the new room | |
| selectRoom(newId); | |
| } | |
| function createNewRoomMobile() { | |
| createNewRoom(); | |
| // Close sidebar on mobile after creation | |
| sidebar.classList.remove('open'); | |
| overlay.classList.remove('active'); | |
| } | |
| function selectRoom(roomId) { | |
| state.activeRoomId = roomId; | |
| const room = state.rooms.find(r => r.id === roomId); | |
| // Update UI | |
| renderRooms(); // To update active class | |
| // Switch View | |
| if (window.innerWidth <= 768) { | |
| sidebar.classList.remove('open'); | |
| overlay.classList.remove('active'); | |
| } | |
| welcomeView.classList.remove('active'); | |
| welcomeView.classList.add('hidden'); | |
| chatView.classList.remove('hidden'); | |
| chatView.classList.add('active'); | |
| // Update Chat Header | |
| activeRoomName.textContent = room.name; | |
| activeRoomMembers.textContent = `${room.members} عضو`; | |
| // Clear messages (simulation) | |
| messagesContainer.innerHTML = ` | |
| <div style="text-align: center; color: var(--text-secondary); font-size: 0.8rem; margin: 20px 0;"> | |
| -- شروع مکالمه در ${room.name} -- | |
| </div> | |
| <div class="message received"> | |
| سلام! به ${room.name} خوش آمدید. | |
| </div> | |
| `; | |
| } | |
| // --- Chat Logic --- | |
| function handleEnter(e) { | |
| if (e.key === 'Enter') { | |
| sendMessage(); | |
| } | |
| } | |
| function sendMessage() { | |
| const text = messageInput.value.trim(); | |
| if (!text) return; | |
| // Add Sent Message | |
| const sentMsg = document.createElement('div'); | |
| sentMsg.className = 'message sent'; | |
| sentMsg.textContent = text; | |
| messagesContainer.appendChild(sentMsg); | |
| // Clear Input | |
| messageInput.value = ''; | |
| // Scroll to bottom | |
| messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
| // Simulate Reply (Optional interaction) | |
| setTimeout(() => { | |
| const replyMsg = document.createElement('div'); | |
| replyMsg.className = 'message received'; | |
| replyMsg.textContent = "پیام شما دریافت شد."; | |
| messagesContainer.appendChild(replyMsg); | |
| messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
| }, 1000); | |
| } | |
| // Run Init | |
| init(); | |
| </script> | |
| </body> | |
| </html> |