| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> |
| <meta name="robots" content="noindex, nofollow"> |
| <title>Rox Admin Panel</title> |
| <meta name="description" content="Rox AI Admin Panel - Secure administration interface"> |
| <meta name="theme-color" content="#667eea"> |
| |
| <link rel="icon" type="image/svg+xml" href="/admin/icon-admin-192.svg"> |
| |
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css" crossorigin="anonymous"> |
| <script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js" crossorigin="anonymous"></script> |
| <script> |
| |
| window.katexReady = new Promise((resolve) => { |
| if (typeof katex !== 'undefined') { |
| resolve(true); |
| } else { |
| |
| const checkKatex = setInterval(() => { |
| if (typeof katex !== 'undefined') { |
| clearInterval(checkKatex); |
| resolve(true); |
| } |
| }, 50); |
| |
| setTimeout(() => { |
| clearInterval(checkKatex); |
| resolve(false); |
| }, 5000); |
| } |
| }); |
| </script> |
| <link rel="stylesheet" href="admin.css"> |
| </head> |
| <body> |
| |
| <div class="login-overlay" id="loginOverlay"> |
| <div class="login-box"> |
| <div class="login-logo"> |
| <svg width="64" height="64" viewBox="0 0 64 64"> |
| <defs> |
| <linearGradient id="loginGrad" x1="0%" y1="0%" x2="100%" y2="100%"> |
| <stop offset="0%" stop-color="#667eea"/> |
| <stop offset="100%" stop-color="#764ba2"/> |
| </linearGradient> |
| </defs> |
| <path d="M32 8 L56 20 L56 44 L32 56 L8 44 L8 20 Z" fill="none" stroke="url(#loginGrad)" stroke-width="2"/> |
| <circle cx="32" cy="32" r="8" fill="url(#loginGrad)"/> |
| </svg> |
| </div> |
| <h2>Admin Access</h2> |
| <p>Enter credentials to continue</p> |
| <form id="loginForm"> |
| <div class="input-group"> |
| <input type="password" id="passwordInput" placeholder="Admin Password" required autocomplete="current-password"> |
| </div> |
| <button type="submit" class="btn btn-primary" id="loginBtn"> |
| <span class="btn-text">Login</span> |
| <span class="btn-loading" style="display:none;"> |
| <svg class="spinner" width="16" height="16" viewBox="0 0 24 24"> |
| <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="3" fill="none" stroke-dasharray="31.4 31.4" stroke-linecap="round"/> |
| </svg> |
| </span> |
| </button> |
| </form> |
| <div class="login-error" id="loginError"></div> |
| <div class="login-attempts" id="loginAttempts"></div> |
| </div> |
| </div> |
|
|
| |
| <div class="app" id="app" style="display: none;"> |
| |
| <button class="mobile-menu-btn" id="mobileMenuBtn" aria-label="Open menu"> |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <line x1="3" y1="6" x2="21" y2="6"/> |
| <line x1="3" y1="12" x2="21" y2="12"/> |
| <line x1="3" y1="18" x2="21" y2="18"/> |
| </svg> |
| </button> |
| |
| |
| <div class="sidebar-overlay" id="sidebarOverlay"></div> |
| |
| |
| <aside class="sidebar" id="sidebar"> |
| |
| <button class="panel-close-btn mobile-only" id="sidebarCloseBtn" aria-label="Close sidebar"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <line x1="18" y1="6" x2="6" y2="18"/> |
| <line x1="6" y1="6" x2="18" y2="18"/> |
| </svg> |
| </button> |
| <div class="sidebar-header"> |
| <div class="logo-section"> |
| <svg width="28" height="28" viewBox="0 0 64 64"> |
| <defs> |
| <linearGradient id="sidebarGrad" x1="0%" y1="0%" x2="100%" y2="100%"> |
| <stop offset="0%" stop-color="#667eea"/> |
| <stop offset="100%" stop-color="#764ba2"/> |
| </linearGradient> |
| </defs> |
| <path d="M32 8 L56 20 L56 44 L32 56 L8 44 L8 20 Z" fill="none" stroke="url(#sidebarGrad)" stroke-width="2"/> |
| <circle cx="32" cy="32" r="6" fill="url(#sidebarGrad)"/> |
| </svg> |
| <h1>Rox Admin</h1> |
| </div> |
| <button class="btn-logout" id="btnLogout" title="Logout"> |
| <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/> |
| <polyline points="16 17 21 12 16 7"/> |
| <line x1="21" y1="12" x2="9" y2="12"/> |
| </svg> |
| </button> |
| </div> |
| |
| <div class="stats-row"> |
| <div class="stat-box" title="Total unique users who have interacted with Rox AI"> |
| <div class="stat-val" id="totalUsers">0</div> |
| <div class="stat-lbl">Users</div> |
| <div class="stat-trend" id="usersTrend"></div> |
| </div> |
| <div class="stat-box" title="Total conversation threads created"> |
| <div class="stat-val" id="totalChats">0</div> |
| <div class="stat-lbl">Chats</div> |
| <div class="stat-trend" id="chatsTrend"></div> |
| </div> |
| <div class="stat-box" title="Messages sent today (resets at midnight)"> |
| <div class="stat-val" id="todayQueries">0</div> |
| <div class="stat-lbl">Today</div> |
| <div class="stat-trend" id="todayTrend"></div> |
| </div> |
| </div> |
|
|
| <div class="sidebar-tabs"> |
| <button class="tab-btn active" data-tab="users" title="Users (Ctrl+1)"> |
| Users |
| <kbd class="tab-shortcut">1</kbd> |
| </button> |
| <button class="tab-btn" data-tab="stats" title="Statistics (Ctrl+2)"> |
| Stats |
| <kbd class="tab-shortcut">2</kbd> |
| </button> |
| </div> |
|
|
| <div class="tab-content" id="usersTab"> |
| <div class="search-box"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <circle cx="11" cy="11" r="8"/> |
| <path d="M21 21l-4.35-4.35"/> |
| </svg> |
| <input type="text" id="userSearch" placeholder="Search users... (Ctrl+F)" autocomplete="off"> |
| <div class="search-results-count" id="searchResultsCount" style="display: none;"></div> |
| </div> |
| <div class="users-section"> |
| <div class="section-title"> |
| Active Users |
| <div class="section-actions"> |
| <button class="btn-icon" id="sortUsersBtn" title="Sort users"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <path d="M3 6h18M7 12h10m-7 6h4"/> |
| </svg> |
| </button> |
| </div> |
| </div> |
| <div class="user-list" id="userList"> |
| <div class="loading-skeleton"> |
| <div class="skeleton-item"></div> |
| <div class="skeleton-item"></div> |
| <div class="skeleton-item"></div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="tab-content" id="statsTab" style="display:none;"> |
| <div class="stats-summary"> |
| <div class="summary-title">📊 Quick Overview</div> |
| <div class="summary-grid"> |
| <div class="summary-item"> |
| <span class="summary-value" id="summaryTotalUsers">0</span> |
| <span class="summary-label">Total Users</span> |
| </div> |
| <div class="summary-item"> |
| <span class="summary-value" id="summaryOnline">0</span> |
| <span class="summary-label">Online Now</span> |
| </div> |
| <div class="summary-item"> |
| <span class="summary-value" id="summaryToday">0</span> |
| <span class="summary-label">Today</span> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="analytics-section"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 3v18h18"/><path d="M18 17V9"/><path d="M13 17V5"/><path d="M8 17v-3"/></svg> |
| Analytics Overview |
| </div> |
| <div class="analytics-grid"> |
| <div class="analytics-card"> |
| <div class="analytics-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg> |
| </div> |
| <div class="analytics-content"> |
| <div class="analytics-value" id="yesterdayQueries">0</div> |
| <div class="analytics-label">Yesterday</div> |
| </div> |
| </div> |
| <div class="analytics-card"> |
| <div class="analytics-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/><path d="M8 14h.01M12 14h.01M16 14h.01M8 18h.01M12 18h.01M16 18h.01"/></svg> |
| </div> |
| <div class="analytics-content"> |
| <div class="analytics-value" id="weekQueries">0</div> |
| <div class="analytics-label">This Week</div> |
| </div> |
| </div> |
| <div class="analytics-card"> |
| <div class="analytics-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 20V10"/><path d="M12 20V4"/><path d="M6 20v-6"/></svg> |
| </div> |
| <div class="analytics-content"> |
| <div class="analytics-value" id="monthQueries">0</div> |
| <div class="analytics-label">This Month</div> |
| </div> |
| </div> |
| <div class="analytics-card highlight"> |
| <div class="analytics-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/></svg> |
| </div> |
| <div class="analytics-content"> |
| <div class="analytics-value" id="newUsersToday">0</div> |
| <div class="analytics-label">New Today</div> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="realtime-section"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg> |
| Real-time Metrics |
| </div> |
| <div class="realtime-grid"> |
| <div class="realtime-card"> |
| <div class="realtime-icon pulse"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--success)" stroke-width="2"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="3" fill="var(--success)"/></svg> |
| </div> |
| <div class="realtime-info"> |
| <div class="realtime-value" id="realtimeOnline">0</div> |
| <div class="realtime-label">Online Now</div> |
| </div> |
| </div> |
| <div class="realtime-card"> |
| <div class="realtime-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> |
| </div> |
| <div class="realtime-info"> |
| <div class="realtime-value" id="lastHourQueries">0</div> |
| <div class="realtime-label">Last Hour</div> |
| </div> |
| </div> |
| <div class="realtime-card"> |
| <div class="realtime-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 1l4 4-4 4"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><path d="M7 23l-4-4 4-4"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg> |
| </div> |
| <div class="realtime-info"> |
| <div class="realtime-value" id="returningUsers">0</div> |
| <div class="realtime-label">Returning</div> |
| </div> |
| </div> |
| <div class="realtime-card"> |
| <div class="realtime-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/><polyline points="17 6 23 6 23 12"/></svg> |
| </div> |
| <div class="realtime-info"> |
| <div class="realtime-value" id="returningRate">0%</div> |
| <div class="realtime-label">Return Rate</div> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="engagement-section"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg> |
| Engagement Metrics |
| </div> |
| <div class="engagement-grid"> |
| <div class="engagement-card"> |
| <div class="engagement-header"> |
| <span class="engagement-icon"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg> |
| </span> |
| <span class="engagement-title">Page Views</span> |
| </div> |
| <div class="engagement-value" id="totalPageViews">0</div> |
| <div class="engagement-sub">Avg: <span id="avgPageViews">0</span>/user</div> |
| </div> |
| <div class="engagement-card"> |
| <div class="engagement-header"> |
| <span class="engagement-icon"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> |
| </span> |
| <span class="engagement-title">Avg Session</span> |
| </div> |
| <div class="engagement-value" id="avgSessionDuration">0m</div> |
| <div class="engagement-sub">Total: <span id="totalSessions">0</span> sessions</div> |
| </div> |
| <div class="engagement-card"> |
| <div class="engagement-header"> |
| <span class="engagement-icon"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg> |
| </span> |
| <span class="engagement-title">Bounce Rate</span> |
| </div> |
| <div class="engagement-value" id="bounceRate">0%</div> |
| <div class="engagement-sub">Single page visits</div> |
| </div> |
| <div class="engagement-card"> |
| <div class="engagement-header"> |
| <span class="engagement-icon"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/></svg> |
| </span> |
| <span class="engagement-title">New This Month</span> |
| </div> |
| <div class="engagement-value" id="newUsersMonth">0</div> |
| <div class="engagement-sub">User acquisition</div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="error-section"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg> |
| Error & Performance |
| </div> |
| <div class="error-grid"> |
| <div class="error-card"> |
| <div class="error-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--error)" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg> |
| </div> |
| <div class="error-content"> |
| <div class="error-value" id="totalErrors">0</div> |
| <div class="error-label">Total Errors</div> |
| </div> |
| </div> |
| <div class="error-card"> |
| <div class="error-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 18 13.5 8.5 8.5 13.5 1 6"/><polyline points="17 18 23 18 23 12"/></svg> |
| </div> |
| <div class="error-content"> |
| <div class="error-value" id="errorRate">0%</div> |
| <div class="error-label">Error Rate</div> |
| </div> |
| </div> |
| <div class="error-card"> |
| <div class="error-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--warning)" stroke-width="2"><path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z"/></svg> |
| </div> |
| <div class="error-content"> |
| <div class="error-value" id="recentErrors">0</div> |
| <div class="error-label">Recent Errors</div> |
| </div> |
| </div> |
| <div class="error-card"> |
| <div class="error-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg> |
| </div> |
| <div class="error-content"> |
| <div class="error-value" id="totalTokens">0</div> |
| <div class="error-label">Total Tokens</div> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="top-users-section"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="8" r="7"/><polyline points="8.21 13.89 7 23 12 20 17 23 15.79 13.88"/></svg> |
| Top Users |
| </div> |
| <div id="topUsersChart" class="top-users-chart"></div> |
| </div> |
| |
| |
| <div class="daily-activity"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 3v18h18"/><path d="M18 17V9"/><path d="M13 17V5"/><path d="M8 17v-3"/></svg> |
| 7-Day Activity |
| </div> |
| <div id="dailyActivityChart" class="daily-chart"></div> |
| </div> |
| |
| <div class="stats-detail"> |
| <div class="stat-card"> |
| <div class="stat-card-title">Avg Response Time</div> |
| <div class="stat-card-value" id="avgResponseTime">0ms</div> |
| <div class="stat-sparkline" id="responseTimeSparkline"></div> |
| </div> |
| <div class="stat-card"> |
| <div class="stat-card-title">Total Messages</div> |
| <div class="stat-card-value" id="totalMessages">0</div> |
| <div class="stat-sparkline" id="messagesSparkline"></div> |
| </div> |
| <div class="stat-card"> |
| <div class="stat-card-title">Active Sessions</div> |
| <div class="stat-card-value" id="activeSessions">0</div> |
| <div class="activity-indicator" id="activityIndicator"></div> |
| </div> |
| <div class="stat-card"> |
| <div class="stat-card-title">Peak Usage Hour</div> |
| <div class="stat-card-value" id="peakHour">--</div> |
| <div class="stat-card-subtitle" id="peakHourLabel">Most active time</div> |
| </div> |
| <div class="stat-card"> |
| <div class="stat-card-title">Online Users</div> |
| <div class="stat-card-value" id="onlineUsers">0</div> |
| <div class="stat-card-subtitle">Currently active</div> |
| </div> |
| <div class="stat-card"> |
| <div class="stat-card-title">Avg Chats/User</div> |
| <div class="stat-card-value" id="avgChatsPerUser">0</div> |
| <div class="stat-card-subtitle">Engagement metric</div> |
| </div> |
| <div class="stat-card"> |
| <div class="stat-card-title">Avg Msgs/Chat</div> |
| <div class="stat-card-value" id="avgMessagesPerChat">0</div> |
| <div class="stat-card-subtitle">Conversation depth</div> |
| </div> |
| <div class="stat-card"> |
| <div class="stat-card-title">New This Week</div> |
| <div class="stat-card-value" id="newUsersWeek">0</div> |
| <div class="stat-card-subtitle">User growth</div> |
| </div> |
| </div> |
| |
| |
| <div class="distribution-section"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg> |
| User Distribution |
| </div> |
| <div class="distribution-grid"> |
| <div class="distribution-card"> |
| <div class="distribution-title"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg> |
| Browser Usage |
| </div> |
| <div id="browserDistribution" class="distribution-chart"></div> |
| </div> |
| <div class="distribution-card"> |
| <div class="distribution-title"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg> |
| Operating System |
| </div> |
| <div id="osDistribution" class="distribution-chart"></div> |
| </div> |
| <div class="distribution-card"> |
| <div class="distribution-title"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="5" y="2" width="14" height="20" rx="2" ry="2"/><line x1="12" y1="18" x2="12.01" y2="18"/></svg> |
| Device Type |
| </div> |
| <div id="deviceDistribution" class="distribution-chart"></div> |
| </div> |
| <div class="distribution-card"> |
| <div class="distribution-title"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg> |
| Language |
| </div> |
| <div id="languageDistribution" class="distribution-chart"></div> |
| </div> |
| <div class="distribution-card"> |
| <div class="distribution-title"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg> |
| Traffic Source |
| </div> |
| <div id="refererDistribution" class="distribution-chart"></div> |
| </div> |
| <div class="distribution-card"> |
| <div class="distribution-title"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg> |
| Country |
| </div> |
| <div id="countryDistribution" class="distribution-chart"></div> |
| </div> |
| <div class="distribution-card"> |
| <div class="distribution-title"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="9" y1="21" x2="9" y2="9"/></svg> |
| Screen Resolution |
| </div> |
| <div id="screenDistribution" class="distribution-chart"></div> |
| </div> |
| </div> |
| </div> |
| |
| <div class="hourly-usage"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> |
| Hourly Activity |
| </div> |
| <div id="hourlyUsageChart" class="hourly-chart"></div> |
| </div> |
| <div class="model-usage"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/></svg> |
| Model Usage |
| </div> |
| <div id="modelUsageChart" class="usage-chart"></div> |
| </div> |
| <div class="system-health"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg> |
| System Health |
| </div> |
| <div id="systemHealthChart" class="health-chart"></div> |
| <div class="performance-indicators" id="performanceIndicators"> |
| <div class="perf-indicator"> |
| <div class="perf-dot loading"></div> |
| <span>Loading...</span> |
| </div> |
| </div> |
| </div> |
| <div class="server-info"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="20" height="8" rx="2" ry="2"/><rect x="2" y="14" width="20" height="8" rx="2" ry="2"/><line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/></svg> |
| Server Information |
| </div> |
| <div id="serverInfoChart" class="server-info-chart"></div> |
| </div> |
| |
| |
| <div class="user-insights-section"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg> |
| User Insights |
| </div> |
| <div class="insights-grid"> |
| <div class="insight-card"> |
| <div class="insight-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg> |
| </div> |
| <div class="insight-content"> |
| <div class="insight-value" id="avgEngagement">0%</div> |
| <div class="insight-label">Avg Engagement</div> |
| </div> |
| </div> |
| <div class="insight-card"> |
| <div class="insight-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> |
| </div> |
| <div class="insight-content"> |
| <div class="insight-value" id="avgTimeOnSite">0m</div> |
| <div class="insight-label">Avg Time on Site</div> |
| </div> |
| </div> |
| <div class="insight-card"> |
| <div class="insight-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="5" y="2" width="14" height="20" rx="2" ry="2"/><line x1="12" y1="18" x2="12.01" y2="18"/></svg> |
| </div> |
| <div class="insight-content"> |
| <div class="insight-value" id="mobilePercent">0%</div> |
| <div class="insight-label">Mobile Users</div> |
| </div> |
| </div> |
| <div class="insight-card"> |
| <div class="insight-icon"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 1l4 4-4 4"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><path d="M7 23l-4-4 4-4"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg> |
| </div> |
| <div class="insight-content"> |
| <div class="insight-value" id="avgSessionsPerUser">0</div> |
| <div class="insight-label">Avg Sessions/User</div> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="heatmap-section"> |
| <div class="section-title"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg> |
| Weekly Activity Heatmap |
| </div> |
| <div id="weeklyHeatmap" class="weekly-heatmap"></div> |
| </div> |
| </div> |
| </aside> |
|
|
| |
| <main class="main"> |
| <header class="main-header"> |
| <div class="header-left"> |
| <button class="menu-btn" id="menuBtn"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <path d="M3 12h18M3 6h18M3 18h18"/> |
| </svg> |
| </button> |
| <nav class="breadcrumb" id="breadcrumb"> |
| <span class="breadcrumb-item active">Dashboard</span> |
| </nav> |
| <div class="connection-status" id="connectionStatus" title="Connection status"> |
| <div class="connection-dot"></div> |
| <span>Connected</span> |
| </div> |
| <span class="last-updated" id="lastUpdated">Updated just now</span> |
| <div class="auto-refresh-indicator" id="autoRefreshIndicator" title="Auto-refresh active"> |
| <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <path d="M23 4v6h-6M1 20v-6h6"/> |
| <path d="M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"/> |
| </svg> |
| </div> |
| </div> |
| <div class="header-actions"> |
| <button class="btn btn-secondary" id="refreshBtn" title="Refresh data (Ctrl+R)"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <path d="M23 4v6h-6M1 20v-6h6"/> |
| <path d="M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"/> |
| </svg> |
| <span>Refresh</span> |
| <div class="btn-progress" id="refreshProgress"></div> |
| </button> |
| <button class="btn btn-secondary" id="helpBtn" title="Keyboard shortcuts"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <circle cx="12" cy="12" r="10"/> |
| <path d="M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3"/> |
| <line x1="12" y1="17" x2="12.01" y2="17"/> |
| </svg> |
| <span>Help</span> |
| </button> |
| <div class="dropdown" id="exportDropdown"> |
| <button class="btn btn-secondary dropdown-toggle" id="exportBtn" title="Export options"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/> |
| <polyline points="7 10 12 15 17 10"/> |
| <line x1="12" y1="15" x2="12" y2="3"/> |
| </svg> |
| <span>Export</span> |
| <svg class="dropdown-arrow" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <polyline points="6 9 12 15 18 9"/> |
| </svg> |
| </button> |
| <div class="dropdown-menu" id="exportMenu"> |
| <button class="dropdown-item" id="exportJsonBtn"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/> |
| <polyline points="14 2 14 8 20 8"/> |
| </svg> |
| Export All (JSON) |
| </button> |
| <button class="dropdown-item" id="exportPdfBtn"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/> |
| <polyline points="14 2 14 8 20 8"/> |
| <line x1="16" y1="13" x2="8" y2="13"/> |
| <line x1="16" y1="17" x2="8" y2="17"/> |
| </svg> |
| Export Stats (PDF) |
| </button> |
| <button class="dropdown-item" id="exportUsersPdfBtn"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"/> |
| <circle cx="9" cy="7" r="4"/> |
| <path d="M23 21v-2a4 4 0 00-3-3.87"/> |
| <path d="M16 3.13a4 4 0 010 7.75"/> |
| </svg> |
| Export Users (PDF) |
| </button> |
| </div> |
| </div> |
| <button class="btn btn-danger" id="clearBtn" title="Clear all logs"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <path d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/> |
| </svg> |
| <span>Clear</span> |
| </button> |
| </div> |
| </header> |
|
|
| <div class="content-area"> |
| |
| <div class="user-details-panel" id="userDetailsPanel"> |
| <div class="user-details-header"> |
| <h3>User Details</h3> |
| <button class="btn-close-panel" id="closeUserDetails"> |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> |
| </button> |
| </div> |
| <div class="user-details-content" id="userDetailsContent"> |
| <div class="empty-state"> |
| <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"> |
| <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/> |
| </svg> |
| <p>Select a user to view details</p> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="chats-panel" id="chatsPanel"> |
| |
| <button class="panel-close-btn mobile-only" id="chatsPanelCloseBtn" aria-label="Close chats panel"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <line x1="18" y1="6" x2="6" y2="18"/> |
| <line x1="6" y1="6" x2="18" y2="18"/> |
| </svg> |
| </button> |
| <div class="chats-header"> |
| <span>Chats by </span> |
| <span id="selectedUserName">-</span> |
| <div class="chat-count-badge" id="chatCountBadge" style="display: none;"> |
| <span id="chatCount">0</span> |
| </div> |
| </div> |
| <div class="chats-list" id="chatsList"> |
| <div class="empty-state"> |
| <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"> |
| <path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/> |
| </svg> |
| <p>Select a user to view chats</p> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="chat-view" id="chatView"> |
| <div class="chat-view-header" id="chatHeader" style="display: none;"> |
| <div class="chat-info"> |
| <h3 id="chatTitle">Chat</h3> |
| <p id="chatMeta"></p> |
| </div> |
| <div class="chat-actions"> |
| <button class="btn btn-sm" id="exportChatJsonBtn" title="Export chat as JSON"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/> |
| <polyline points="14 2 14 8 20 8"/> |
| </svg> |
| <span>JSON</span> |
| </button> |
| <button class="btn btn-sm btn-primary" id="exportChatPdfBtn" title="Export chat as PDF"> |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/> |
| <polyline points="14 2 14 8 20 8"/> |
| <line x1="16" y1="13" x2="8" y2="13"/> |
| <line x1="16" y1="17" x2="8" y2="17"/> |
| </svg> |
| <span>PDF</span> |
| </button> |
| </div> |
| </div> |
| <div class="messages-area" id="messagesArea"> |
| <div class="empty-state"> |
| <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"> |
| <path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/> |
| </svg> |
| <p>Select a user, then select a chat to view messages</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| </main> |
| </div> |
| |
| |
| <div class="chats-panel-overlay" id="chatsPanelOverlay"></div> |
|
|
| |
| <div class="toast-container" id="toastContainer"></div> |
|
|
| |
| <div class="dialog-overlay" id="dialogOverlay" style="display:none;"> |
| <div class="dialog-box"> |
| <div class="dialog-icon" id="dialogIcon"></div> |
| <h3 id="dialogTitle">Confirm</h3> |
| <p id="dialogMessage">Are you sure?</p> |
| <div class="dialog-actions"> |
| <button class="btn btn-secondary" id="dialogCancel">Cancel</button> |
| <button class="btn btn-danger" id="dialogConfirm">Confirm</button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="dialog-overlay" id="helpOverlay" style="display:none;"> |
| <div class="dialog-box help-dialog"> |
| <div class="dialog-icon help"> |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| <circle cx="12" cy="12" r="10"/> |
| <path d="M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3"/> |
| <line x1="12" y1="17" x2="12.01" y2="17"/> |
| </svg> |
| </div> |
| <h3>Keyboard Shortcuts</h3> |
| <div class="shortcuts-grid"> |
| <div class="shortcut-item"> |
| <kbd>Ctrl + R</kbd> |
| <span>Refresh data</span> |
| </div> |
| <div class="shortcut-item"> |
| <kbd>Ctrl + F</kbd> |
| <span>Focus search</span> |
| </div> |
| <div class="shortcut-item"> |
| <kbd>Ctrl + 1</kbd> |
| <span>Users tab</span> |
| </div> |
| <div class="shortcut-item"> |
| <kbd>Ctrl + 2</kbd> |
| <span>Stats tab</span> |
| </div> |
| <div class="shortcut-item"> |
| <kbd>Esc</kbd> |
| <span>Close dialogs</span> |
| </div> |
| <div class="shortcut-item"> |
| <kbd>Enter / Space</kbd> |
| <span>Select item</span> |
| </div> |
| </div> |
| <div class="dialog-actions"> |
| <button class="btn btn-primary" id="helpClose">Got it</button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <script src="admin.js" type="module"></script> |
| </body> |
| </html> |
|
|