Spaces:
Paused
Paused
j49_c
Add advanced features: cleanup old data, subscription plans, firewall protection, enhanced UI
7d1d67d Download index.html from mohammed978/hostbot: direct link, hf CLI and curl.
- Browser
- Download file 81.2 kB
-
https://huggingface.co/spaces/mohammed978/hostbot/resolve/main/index.html
- Command line
-
hf download hf://spaces/mohammed978/hostbot/index.html
-
curl -L -o index.html https://huggingface.co/spaces/mohammed978/hostbot/resolve/main/index.html
81.2 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width,initial-scale=1" /> | |
| <title>الذئب الابيض · OPERATIVE DASHBOARD</title> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap'); | |
| :root { | |
| --bg: #000000; | |
| --card: rgba(15, 15, 20, 0.7); | |
| --border: rgba(255, 255, 255, 0.08); | |
| --primary: #0A84FF; | |
| --primary-glow: rgba(10, 132, 255, 0.2); | |
| --accent: #5E5CE6; | |
| --text: #F5F5F7; | |
| --text-dim: #8E8E93; | |
| --success: #32D74B; | |
| --warning: #FF9F0A; | |
| --error: #FF453A; | |
| --radius-lg: 24px; | |
| --radius-md: 16px; | |
| --radius-sm: 12px; | |
| --mono: 'JetBrains Mono', monospace; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| font-family: 'Plus Jakarta Sans', sans-serif; | |
| } | |
| body { | |
| background-color: var(--bg); | |
| color: var(--text); | |
| min-height: 100vh; | |
| background-image: | |
| radial-gradient(circle at 10% 10%, var(--primary-glow), transparent 40%), | |
| radial-gradient(circle at 90% 90%, rgba(94, 92, 230, 0.1), transparent 40%); | |
| background-attachment: fixed; | |
| } | |
| /* Scrollbar */ | |
| ::-webkit-scrollbar { | |
| width: 6px; | |
| height: 6px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: transparent; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: var(--border); | |
| border-radius: 10px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: var(--text-dim); | |
| } | |
| .topbar { | |
| position: sticky; | |
| top: 0; | |
| z-index: 100; | |
| background: rgba(0, 0, 0, 0.8); | |
| backdrop-filter: blur(20px); | |
| -webkit-backdrop-filter: blur(20px); | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .topbar-content { | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| padding: 16px 24px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| } | |
| .brand { | |
| display: flex; | |
| align-items: center; | |
| gap: 14px; | |
| cursor: pointer; | |
| } | |
| .brand-logo { | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 12px; | |
| object-fit: cover; | |
| border: 1px solid var(--border); | |
| } | |
| .brand-info { | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .brand-name { | |
| font-size: 16px; | |
| font-weight: 800; | |
| letter-spacing: -0.02em; | |
| } | |
| .brand-status { | |
| font-size: 11px; | |
| font-family: var(--mono); | |
| color: var(--text-dim); | |
| text-transform: uppercase; | |
| letter-spacing: 0.05em; | |
| } | |
| .nav-actions { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .btn { | |
| padding: 10px 18px; | |
| border-radius: var(--radius-sm); | |
| font-size: 13px; | |
| font-weight: 700; | |
| cursor: pointer; | |
| transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); | |
| border: 1px solid var(--border); | |
| background: var(--card); | |
| color: var(--text); | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .btn:hover { | |
| background: rgba(255, 255, 255, 0.05); | |
| transform: translateY(-1px); | |
| border-color: rgba(255, 255, 255, 0.2); | |
| } | |
| .btn-primary { | |
| background: var(--primary); | |
| border: none; | |
| color: white; | |
| } | |
| .btn-primary:hover { | |
| background: #0071E3; | |
| box-shadow: 0 4px 15px rgba(10, 132, 255, 0.4); | |
| } | |
| .btn-danger { | |
| color: var(--error); | |
| background: rgba(255, 69, 58, 0.1); | |
| border: 1px solid rgba(255, 69, 58, 0.2); | |
| } | |
| .btn-danger:hover { | |
| background: var(--error); | |
| color: white; | |
| } | |
| @media (max-width: 768px) { | |
| .topbar-content { | |
| padding: 12px 16px; | |
| flex-direction: column; | |
| gap: 12px; | |
| } | |
| .nav-actions { | |
| width: 100%; | |
| overflow-x: auto; | |
| padding-bottom: 4px; | |
| justify-content: flex-start; | |
| } | |
| .btn { | |
| flex-shrink: 0; | |
| padding: 8px 12px; | |
| font-size: 11px; | |
| } | |
| .brand-logo { | |
| width: 32px; | |
| height: 32px; | |
| } | |
| .brand-name { | |
| font-size: 14px; | |
| } | |
| .container { | |
| margin: 16px auto; | |
| padding: 0 16px; | |
| } | |
| } | |
| /* Notification System */ | |
| .notification-container { | |
| position: fixed; | |
| top: 80px; | |
| right: 24px; | |
| z-index: 9999; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 12px; | |
| max-width: 380px; | |
| } | |
| .notification { | |
| background: var(--card); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-md); | |
| padding: 16px 20px; | |
| backdrop-filter: blur(20px); | |
| -webkit-backdrop-filter: blur(20px); | |
| animation: slideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1); | |
| box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 12px; | |
| } | |
| @keyframes slideIn { | |
| from { | |
| opacity: 0; | |
| transform: translateX(100px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateX(0); | |
| } | |
| } | |
| @keyframes slideOut { | |
| from { | |
| opacity: 1; | |
| transform: translateX(0); | |
| } | |
| to { | |
| opacity: 0; | |
| transform: translateX(100px); | |
| } | |
| } | |
| .notification-icon { | |
| width: 32px; | |
| height: 32px; | |
| border-radius: 8px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 16px; | |
| flex-shrink: 0; | |
| } | |
| .notification.success .notification-icon { | |
| background: rgba(50, 215, 75, 0.2); | |
| color: var(--success); | |
| } | |
| .notification.error .notification-icon { | |
| background: rgba(255, 69, 58, 0.2); | |
| color: var(--error); | |
| } | |
| .notification.warning .notification-icon { | |
| background: rgba(255, 159, 10, 0.2); | |
| color: var(--warning); | |
| } | |
| .notification.info .notification-icon { | |
| background: rgba(10, 132, 255, 0.2); | |
| color: var(--primary); | |
| } | |
| .notification-content { | |
| flex: 1; | |
| } | |
| .notification-title { | |
| font-weight: 600; | |
| font-size: 14px; | |
| margin-bottom: 4px; | |
| } | |
| .notification-message { | |
| font-size: 13px; | |
| color: var(--text-dim); | |
| line-height: 1.4; | |
| } | |
| .notification-close { | |
| cursor: pointer; | |
| color: var(--text-dim); | |
| font-size: 18px; | |
| line-height: 1; | |
| padding: 4px; | |
| transition: color 0.2s; | |
| } | |
| .notification-close:hover { | |
| color: var(--text); | |
| } | |
| .notification-progress { | |
| position: absolute; | |
| bottom: 0; | |
| left: 0; | |
| height: 3px; | |
| background: linear-gradient(90deg, var(--primary), var(--accent)); | |
| border-radius: 0 0 var(--radius-md) var(--radius-md); | |
| animation: progress 3s linear forwards; | |
| } | |
| @keyframes progress { | |
| from { width: 100%; } | |
| to { width: 0%; } | |
| } | |
| /* Stats Dashboard */ | |
| .stats-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); | |
| gap: 16px; | |
| margin-bottom: 24px; | |
| } | |
| .stat-card { | |
| background: var(--card); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-md); | |
| padding: 20px; | |
| position: relative; | |
| overflow: hidden; | |
| transition: all 0.3s; | |
| } | |
| .stat-card:hover { | |
| transform: translateY(-2px); | |
| border-color: var(--primary); | |
| } | |
| .stat-card::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 3px; | |
| background: linear-gradient(90deg, var(--primary), var(--accent)); | |
| } | |
| .stat-icon { | |
| width: 48px; | |
| height: 48px; | |
| border-radius: 12px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 24px; | |
| margin-bottom: 12px; | |
| background: rgba(10, 132, 255, 0.1); | |
| } | |
| .stat-value { | |
| font-size: 32px; | |
| font-weight: 800; | |
| margin-bottom: 4px; | |
| background: linear-gradient(135deg, var(--text), var(--text-dim)); | |
| -webkit-background-clip: text; | |
| background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| } | |
| .stat-label { | |
| font-size: 13px; | |
| color: var(--text-dim); | |
| font-weight: 500; | |
| text-transform: uppercase; | |
| letter-spacing: 0.05em; | |
| } | |
| .stat-change { | |
| position: absolute; | |
| top: 16px; | |
| right: 16px; | |
| font-size: 12px; | |
| font-weight: 600; | |
| padding: 4px 8px; | |
| border-radius: 6px; | |
| } | |
| .stat-change.positive { | |
| background: rgba(50, 215, 75, 0.2); | |
| color: var(--success); | |
| } | |
| .stat-change.negative { | |
| background: rgba(255, 69, 58, 0.2); | |
| color: var(--error); | |
| } | |
| /* Activity Chart */ | |
| .chart-container { | |
| background: var(--card); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-md); | |
| padding: 24px; | |
| margin-bottom: 24px; | |
| } | |
| .chart-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 20px; | |
| } | |
| .chart-title { | |
| font-size: 16px; | |
| font-weight: 700; | |
| } | |
| .chart-legend { | |
| display: flex; | |
| gap: 16px; | |
| font-size: 12px; | |
| color: var(--text-dim); | |
| } | |
| .legend-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| .legend-dot { | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| } | |
| .activity-chart { | |
| height: 200px; | |
| display: flex; | |
| align-items: flex-end; | |
| gap: 8px; | |
| padding-top: 20px; | |
| } | |
| .chart-bar { | |
| flex: 1; | |
| background: linear-gradient(180deg, var(--primary), rgba(10, 132, 255, 0.3)); | |
| border-radius: 6px 6px 0 0; | |
| position: relative; | |
| transition: all 0.3s; | |
| cursor: pointer; | |
| } | |
| .chart-bar:hover { | |
| background: linear-gradient(180deg, var(--accent), rgba(94, 92, 230, 0.3)); | |
| transform: scaleY(1.05); | |
| } | |
| .chart-bar::after { | |
| content: attr(data-value); | |
| position: absolute; | |
| top: -24px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| font-size: 11px; | |
| font-weight: 600; | |
| color: var(--text); | |
| opacity: 0; | |
| transition: opacity 0.2s; | |
| white-space: nowrap; | |
| } | |
| .chart-bar:hover::after { | |
| opacity: 1; | |
| } | |
| .chart-labels { | |
| display: flex; | |
| justify-content: space-between; | |
| margin-top: 12px; | |
| font-size: 11px; | |
| color: var(--text-dim); | |
| } | |
| /* Advanced Code Editor */ | |
| .editor-container { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.95); | |
| backdrop-filter: blur(20px); | |
| z-index: 10000; | |
| display: none; | |
| flex-direction: column; | |
| } | |
| .editor-container.active { | |
| display: flex; | |
| } | |
| .editor-header { | |
| padding: 16px 24px; | |
| background: rgba(255, 255, 255, 0.05); | |
| border-bottom: 1px solid var(--border); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .editor-title { | |
| font-family: var(--mono); | |
| font-size: 14px; | |
| font-weight: 600; | |
| color: var(--primary); | |
| } | |
| .editor-toolbar { | |
| display: flex; | |
| gap: 8px; | |
| } | |
| .editor-body { | |
| flex: 1; | |
| display: flex; | |
| overflow: hidden; | |
| } | |
| .editor-sidebar { | |
| width: 200px; | |
| background: rgba(255, 255, 255, 0.02); | |
| border-right: 1px solid var(--border); | |
| padding: 16px; | |
| overflow-y: auto; | |
| } | |
| .file-tree-item { | |
| padding: 8px 12px; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-size: 13px; | |
| color: var(--text-dim); | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .file-tree-item:hover { | |
| background: rgba(255, 255, 255, 0.05); | |
| color: var(--text); | |
| } | |
| .file-tree-item.active { | |
| background: rgba(10, 132, 255, 0.1); | |
| color: var(--primary); | |
| } | |
| .editor-main { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .code-editor-wrapper { | |
| flex: 1; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .code-editor { | |
| width: 100%; | |
| height: 100%; | |
| background: transparent; | |
| border: none; | |
| outline: none; | |
| resize: none; | |
| font-family: 'JetBrains Mono', monospace; | |
| font-size: 14px; | |
| line-height: 1.6; | |
| padding: 20px; | |
| color: var(--text); | |
| tab-size: 4; | |
| } | |
| .code-editor:focus { | |
| outline: none; | |
| } | |
| .editor-statusbar { | |
| padding: 8px 24px; | |
| background: rgba(255, 255, 255, 0.03); | |
| border-top: 1px solid var(--border); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| font-size: 12px; | |
| color: var(--text-dim); | |
| font-family: var(--mono); | |
| } | |
| .editor-status-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| } | |
| /* Syntax Highlighting Colors */ | |
| .syntax-keyword { color: #FF79C6; } | |
| .syntax-string { color: #F1FA8C; } | |
| .syntax-number { color: #BD93F9; } | |
| .syntax-comment { color: #6272A4; font-style: italic; } | |
| .syntax-function { color: #50FA7B; } | |
| .syntax-class { color: #8BE9FD; } | |
| /* Advanced File Manager */ | |
| .fm-dropzone { | |
| border: 2px dashed var(--border); | |
| border-radius: var(--radius-md); | |
| padding: 40px; | |
| text-align: center; | |
| color: var(--text-dim); | |
| transition: all 0.3s; | |
| cursor: pointer; | |
| margin-bottom: 20px; | |
| } | |
| .fm-dropzone.dragover { | |
| border-color: var(--primary); | |
| background: rgba(10, 132, 255, 0.1); | |
| color: var(--primary); | |
| } | |
| .fm-dropzone-icon { | |
| font-size: 48px; | |
| margin-bottom: 16px; | |
| } | |
| .fm-preview-modal { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.9); | |
| backdrop-filter: blur(20px); | |
| z-index: 10000; | |
| display: none; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .fm-preview-modal.active { | |
| display: flex; | |
| } | |
| .fm-preview-content { | |
| max-width: 90%; | |
| max-height: 90%; | |
| background: var(--card); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-md); | |
| padding: 24px; | |
| overflow: auto; | |
| } | |
| .fm-preview-image { | |
| max-width: 100%; | |
| max-height: 80vh; | |
| border-radius: var(--radius-sm); | |
| } | |
| .fm-preview-code { | |
| font-family: var(--mono); | |
| font-size: 14px; | |
| line-height: 1.6; | |
| white-space: pre-wrap; | |
| word-break: break-all; | |
| max-height: 70vh; | |
| overflow: auto; | |
| } | |
| .fm-toolbar { | |
| display: flex; | |
| gap: 8px; | |
| margin-bottom: 16px; | |
| flex-wrap: wrap; | |
| } | |
| .fm-search { | |
| flex: 1; | |
| min-width: 200px; | |
| background: rgba(0, 0, 0, 0.3); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| padding: 8px 12px; | |
| color: var(--text); | |
| outline: none; | |
| } | |
| .fm-search:focus { | |
| border-color: var(--primary); | |
| } | |
| .fm-view-toggle { | |
| display: flex; | |
| gap: 4px; | |
| } | |
| .fm-view-btn { | |
| padding: 8px 12px; | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| color: var(--text); | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .fm-view-btn.active { | |
| background: var(--primary); | |
| border-color: var(--primary); | |
| } | |
| .fm-grid-view { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); | |
| gap: 16px; | |
| } | |
| .fm-grid-item { | |
| background: rgba(255, 255, 255, 0.03); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| padding: 16px; | |
| text-align: center; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .fm-grid-item:hover { | |
| border-color: var(--primary); | |
| background: rgba(10, 132, 255, 0.1); | |
| } | |
| .fm-grid-icon { | |
| font-size: 32px; | |
| margin-bottom: 8px; | |
| } | |
| .fm-grid-name { | |
| font-size: 12px; | |
| color: var(--text); | |
| word-break: break-all; | |
| } | |
| /* Settings Panel */ | |
| .settings-panel { | |
| background: var(--card); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-md); | |
| padding: 32px; | |
| max-width: 600px; | |
| margin: 0 auto; | |
| } | |
| .settings-header { | |
| margin-bottom: 32px; | |
| text-align: center; | |
| } | |
| .settings-header h2 { | |
| font-size: 24px; | |
| font-weight: 700; | |
| margin-bottom: 8px; | |
| } | |
| .settings-header p { | |
| color: var(--text-dim); | |
| font-size: 14px; | |
| } | |
| .settings-section { | |
| margin-bottom: 32px; | |
| padding-bottom: 32px; | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .settings-section:last-child { | |
| border-bottom: none; | |
| margin-bottom: 0; | |
| padding-bottom: 0; | |
| } | |
| .settings-section-title { | |
| font-size: 16px; | |
| font-weight: 700; | |
| margin-bottom: 16px; | |
| color: var(--primary); | |
| } | |
| .settings-item { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 12px 0; | |
| } | |
| .settings-item-label { | |
| flex: 1; | |
| } | |
| .settings-item-label h4 { | |
| font-size: 14px; | |
| font-weight: 600; | |
| margin-bottom: 4px; | |
| } | |
| .settings-item-label p { | |
| font-size: 12px; | |
| color: var(--text-dim); | |
| } | |
| .toggle-switch { | |
| position: relative; | |
| width: 50px; | |
| height: 26px; | |
| background: rgba(255, 255, 255, 0.1); | |
| border-radius: 13px; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| } | |
| .toggle-switch.active { | |
| background: var(--primary); | |
| } | |
| .toggle-switch::after { | |
| content: ''; | |
| position: absolute; | |
| top: 3px; | |
| left: 3px; | |
| width: 20px; | |
| height: 20px; | |
| background: white; | |
| border-radius: 50%; | |
| transition: all 0.3s; | |
| } | |
| .toggle-switch.active::after { | |
| left: 27px; | |
| } | |
| .settings-input { | |
| width: 100%; | |
| background: rgba(0, 0, 0, 0.3); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| padding: 12px 16px; | |
| color: var(--text); | |
| font-size: 14px; | |
| margin-bottom: 16px; | |
| outline: none; | |
| transition: border-color 0.2s; | |
| } | |
| .settings-input:focus { | |
| border-color: var(--primary); | |
| } | |
| .settings-select { | |
| width: 100%; | |
| background: rgba(0, 0, 0, 0.3); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| padding: 12px 16px; | |
| color: var(--text); | |
| font-size: 14px; | |
| margin-bottom: 16px; | |
| outline: none; | |
| cursor: pointer; | |
| } | |
| .settings-select:focus { | |
| border-color: var(--primary); | |
| } | |
| /* Activity Log */ | |
| .activity-log { | |
| background: rgba(0, 0, 0, 0.3); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| padding: 16px; | |
| max-height: 300px; | |
| overflow-y: auto; | |
| } | |
| .activity-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| padding: 12px; | |
| border-bottom: 1px solid var(--border); | |
| transition: background 0.2s; | |
| } | |
| .activity-item:last-child { | |
| border-bottom: none; | |
| } | |
| .activity-item:hover { | |
| background: rgba(255, 255, 255, 0.02); | |
| } | |
| .activity-icon { | |
| width: 36px; | |
| height: 36px; | |
| border-radius: 8px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 16px; | |
| background: rgba(10, 132, 255, 0.1); | |
| color: var(--primary); | |
| } | |
| .activity-content { | |
| flex: 1; | |
| } | |
| .activity-title { | |
| font-size: 13px; | |
| font-weight: 600; | |
| margin-bottom: 2px; | |
| } | |
| .activity-time { | |
| font-size: 11px; | |
| color: var(--text-dim); | |
| } | |
| .activity-status { | |
| font-size: 11px; | |
| font-weight: 600; | |
| padding: 4px 8px; | |
| border-radius: 6px; | |
| } | |
| .activity-status.success { | |
| background: rgba(50, 215, 75, 0.15); | |
| color: var(--success); | |
| } | |
| .activity-status.error { | |
| background: rgba(255, 69, 58, 0.15); | |
| color: var(--error); | |
| } | |
| .activity-status.info { | |
| background: rgba(10, 132, 255, 0.15); | |
| color: var(--primary); | |
| } | |
| /* AI Chat Styling */ | |
| .ai-chat-container { | |
| background: var(--card); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-md); | |
| display: flex; | |
| flex-direction: column; | |
| height: 600px; | |
| overflow: hidden; | |
| } | |
| .ai-chat-header { | |
| padding: 16px 20px; | |
| border-bottom: 1px solid var(--border); | |
| background: rgba(255, 255, 255, 0.03); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .ai-chat-messages { | |
| flex: 1; | |
| padding: 20px; | |
| overflow-y: auto; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 16px; | |
| } | |
| .ai-message { | |
| max-width: 85%; | |
| padding: 12px 16px; | |
| border-radius: 16px; | |
| font-size: 14px; | |
| line-height: 1.5; | |
| } | |
| .ai-message.user { | |
| align-self: flex-end; | |
| background: var(--primary); | |
| color: white; | |
| border-bottom-right-radius: 4px; | |
| } | |
| .ai-message.bot { | |
| align-self: flex-start; | |
| background: rgba(255, 255, 255, 0.08); | |
| border: 1px solid var(--border); | |
| border-bottom-left-radius: 4px; | |
| } | |
| .ai-chat-input-area { | |
| padding: 16px; | |
| border-top: 1px solid var(--border); | |
| display: flex; | |
| gap: 10px; | |
| } | |
| .ai-chat-input { | |
| flex: 1; | |
| background: rgba(0, 0, 0, 0.3); | |
| border: 1px solid var(--border); | |
| border-radius: 12px; | |
| padding: 12px 16px; | |
| color: white; | |
| outline: none; | |
| } | |
| .ai-chat-input:focus { | |
| border-color: var(--primary); | |
| } | |
| .container { | |
| max-width: 1400px; | |
| margin: 32px auto; | |
| padding: 0 24px; | |
| } | |
| .grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); | |
| gap: 20px; | |
| animation: fadeIn 0.5s ease; | |
| } | |
| @keyframes fadeIn { | |
| from { | |
| opacity: 0; | |
| transform: translateY(10px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .card { | |
| background: var(--card); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-md); | |
| padding: 24px; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: space-between; | |
| min-height: 160px; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .card::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 4px; | |
| background: var(--primary); | |
| opacity: 0; | |
| transition: opacity 0.3s; | |
| } | |
| .card:hover { | |
| transform: translateY(-4px); | |
| border-color: var(--primary); | |
| background: rgba(25, 25, 30, 0.8); | |
| } | |
| .card:hover::before { | |
| opacity: 1; | |
| } | |
| .srv-name { | |
| font-size: 18px; | |
| font-weight: 700; | |
| margin-bottom: 4px; | |
| letter-spacing: -0.02em; | |
| } | |
| .srv-meta { | |
| font-size: 13px; | |
| color: var(--text-dim); | |
| font-weight: 500; | |
| } | |
| .status-pill { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 8px; | |
| padding: 6px 14px; | |
| border-radius: 99px; | |
| background: rgba(0, 0, 0, 0.3); | |
| border: 1px solid var(--border); | |
| font-size: 10px; | |
| font-weight: 800; | |
| font-family: var(--mono); | |
| text-transform: uppercase; | |
| letter-spacing: 0.05em; | |
| margin-top: 20px; | |
| } | |
| .dot { | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| background: var(--text-dim); | |
| } | |
| .status-pill.running { | |
| border-color: var(--success); | |
| color: var(--success); | |
| } | |
| .status-pill.running .dot { | |
| background: var(--success); | |
| box-shadow: 0 0 8px var(--success); | |
| } | |
| .status-pill.installing { | |
| border-color: var(--warning); | |
| color: var(--warning); | |
| } | |
| .status-pill.installing .dot { | |
| background: var(--warning); | |
| animation: blink 1s infinite; | |
| } | |
| .status-pill.error { | |
| border-color: var(--error); | |
| color: var(--error); | |
| } | |
| .status-pill.error .dot { | |
| background: var(--error); | |
| } | |
| @keyframes blink { | |
| 0%, | |
| 100% { | |
| opacity: 0.3; | |
| } | |
| 50% { | |
| opacity: 1; | |
| } | |
| } | |
| /* Server Manager View */ | |
| #serverView { | |
| display: none; | |
| } | |
| .view-header { | |
| display: flex; | |
| align-items: flex-end; | |
| justify-content: space-between; | |
| margin-bottom: 24px; | |
| gap: 16px; | |
| flex-wrap: wrap; | |
| } | |
| .view-title h1 { | |
| font-size: 32px; | |
| font-weight: 800; | |
| letter-spacing: -0.04em; | |
| } | |
| .tab-group { | |
| display: flex; | |
| background: var(--card); | |
| padding: 6px; | |
| border-radius: var(--radius-sm); | |
| border: 1px solid var(--border); | |
| } | |
| .tab { | |
| padding: 8px 18px; | |
| border-radius: calc(var(--radius-sm) - 4px); | |
| font-size: 13px; | |
| font-weight: 700; | |
| color: var(--text-dim); | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .tab:hover { | |
| color: var(--text); | |
| } | |
| .tab.active { | |
| background: rgba(255, 255, 255, 0.1); | |
| color: var(--text); | |
| } | |
| .manager-layout { | |
| display: grid; | |
| grid-template-columns: 1fr 320px; | |
| gap: 20px; | |
| } | |
| @media (max-width: 1000px) { | |
| .manager-layout { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| .console-box { | |
| background: #000; | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-md); | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4); | |
| } | |
| .console-nav { | |
| background: #111; | |
| padding: 10px 16px; | |
| border-bottom: 1px solid var(--border); | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| font-size: 11px; | |
| font-family: var(--mono); | |
| color: var(--text-dim); | |
| } | |
| .dots { | |
| display: flex; | |
| gap: 6px; | |
| } | |
| .dots span { | |
| width: 10px; | |
| height: 10px; | |
| border-radius: 50%; | |
| } | |
| .red { | |
| background: #ff5f56; | |
| } | |
| .yellow { | |
| background: #ffbd2e; | |
| } | |
| .green { | |
| background: #27c93f; | |
| } | |
| .console-out { | |
| padding: 20px; | |
| height: 560px; | |
| overflow-y: auto; | |
| font-family: var(--mono); | |
| font-size: 13px; | |
| line-height: 1.6; | |
| color: #e0e0e0; | |
| white-space: pre-wrap; | |
| position: relative; | |
| } | |
| .console-out::before { | |
| content: ''; | |
| position: absolute; | |
| inset: 0; | |
| background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.2) 50%), | |
| linear-gradient(90deg, rgba(255, 0, 0, 0.05), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.05)); | |
| background-size: 100% 4px, 3px 100%; | |
| pointer-events: none; | |
| z-index: 10; | |
| opacity: 0.3; | |
| } | |
| .side-panel { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 16px; | |
| } | |
| .side-card { | |
| background: var(--card); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-md); | |
| padding: 20px; | |
| } | |
| .stat-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 14px; | |
| margin-bottom: 12px; | |
| } | |
| .stat-row:last-child { | |
| margin-bottom: 0; | |
| } | |
| .ico-box { | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 12px; | |
| background: rgba(255, 255, 255, 0.05); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: var(--primary); | |
| } | |
| .stat-val { | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .stat-label { | |
| font-size: 10px; | |
| font-weight: 800; | |
| color: var(--text-dim); | |
| text-transform: uppercase; | |
| letter-spacing: 0.05em; | |
| } | |
| .stat-num { | |
| font-size: 14px; | |
| font-weight: 600; | |
| font-family: var(--mono); | |
| } | |
| /* File Manager */ | |
| .file-manager { | |
| background: var(--card); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-md); | |
| overflow: hidden; | |
| } | |
| .fm-header { | |
| padding: 16px 24px; | |
| border-bottom: 1px solid var(--border); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .fm-path { | |
| font-family: var(--mono); | |
| font-size: 13px; | |
| color: var(--text-dim); | |
| } | |
| .fm-path a { | |
| color: var(--primary); | |
| text-decoration: none; | |
| border-bottom: 1px dotted transparent; | |
| } | |
| .fm-path a:hover { | |
| border-bottom-color: var(--primary); | |
| } | |
| .fm-table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| } | |
| .fm-table th, | |
| .fm-table td { | |
| text-align: left; | |
| padding: 14px 24px; | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .fm-table th { | |
| font-size: 11px; | |
| font-weight: 800; | |
| color: var(--text-dim); | |
| text-transform: uppercase; | |
| letter-spacing: 0.05em; | |
| background: rgba(0, 0, 0, 0.2); | |
| } | |
| .fm-table tr:hover td { | |
| background: rgba(255, 255, 255, 0.02); | |
| } | |
| .fm-name { | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| font-weight: 600; | |
| font-size: 14px; | |
| } | |
| .fm-name:hover { | |
| color: var(--primary); | |
| } | |
| /* Modal Styling */ | |
| .modal-overlay { | |
| position: fixed; | |
| inset: 0; | |
| background: rgba(0, 0, 0, 0.8); | |
| backdrop-filter: blur(8px); | |
| z-index: 1000; | |
| display: none; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 20px; | |
| } | |
| .modal-box { | |
| background: #111; | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-lg); | |
| width: 100%; | |
| max-width: 440px; | |
| padding: 32px; | |
| box-shadow: 0 30px 60px rgba(0, 0, 0, 0.5); | |
| } | |
| .modal-box h3 { | |
| font-size: 20px; | |
| font-weight: 800; | |
| margin-bottom: 16px; | |
| letter-spacing: -0.02em; | |
| } | |
| .modal-box input { | |
| width: 100%; | |
| background: #000; | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| padding: 14px 16px; | |
| color: white; | |
| margin-bottom: 24px; | |
| outline: none; | |
| } | |
| .modal-box input:focus { | |
| border-color: var(--primary); | |
| } | |
| /* Editor */ | |
| #editor-view { | |
| position: fixed; | |
| inset: 0; | |
| background: var(--bg); | |
| z-index: 2000; | |
| display: none; | |
| flex-direction: column; | |
| } | |
| .editor-top { | |
| padding: 16px 24px; | |
| border-bottom: 1px solid var(--border); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| background: #0a0a0a; | |
| } | |
| .editor-area { | |
| flex: 1; | |
| background: #000; | |
| color: #d4d4d4; | |
| font-family: var(--mono); | |
| font-size: 14px; | |
| padding: 30px; | |
| border: none; | |
| outline: none; | |
| resize: none; | |
| line-height: 1.6; | |
| } | |
| .toast-container { | |
| position: fixed; | |
| top: 80px; | |
| right: 24px; | |
| z-index: 9999; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 10px; | |
| } | |
| .toast { | |
| background: rgba(20, 20, 25, 0.95); | |
| backdrop-filter: blur(20px); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| padding: 14px 20px; | |
| font-size: 13px; | |
| font-weight: 600; | |
| color: var(--text); | |
| animation: toastIn 0.3s ease, toastOut 0.3s ease 2.7s; | |
| max-width: 360px; | |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); | |
| } | |
| .toast.success { | |
| border-left: 3px solid var(--success); | |
| } | |
| .toast.error { | |
| border-left: 3px solid var(--error); | |
| } | |
| .toast.info { | |
| border-left: 3px solid var(--primary); | |
| } | |
| @keyframes toastIn { | |
| from { | |
| opacity: 0; | |
| transform: translateX(30px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateX(0); | |
| } | |
| } | |
| @keyframes toastOut { | |
| from { | |
| opacity: 1; | |
| } | |
| to { | |
| opacity: 0; | |
| transform: translateY(-10px); | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="notification-container" id="notificationContainer"></div> | |
| <div class="toast-container" id="toastBox" style="display:none"></div> | |
| <div class="topbar"> | |
| <div class="topbar-content"> | |
| <div class="brand" onclick="goHome()"> | |
| <img src="https://f.top4top.io/p_37210bgwm1.jpg" alt="Logo" class="brand-logo"> | |
| <div class="brand-info"> | |
| <span class="brand-name">الذئب الابيض</span> | |
| <span class="brand-status">v0.1 · SECURE</span> | |
| </div> | |
| </div> | |
| <div class="nav-actions"> | |
| <button class="btn" onclick="showHelp()">❓ HELP / مساعدة</button> | |
| <button class="btn" onclick="switchView('settings')">⚙️ SETTINGS / إعدادات</button> | |
| <button id="adminBtn" class="btn" style="display:none" onclick="location.href='/admin'">OPERATIONS HQ / | |
| الإدارة</button> | |
| <button id="homeBtn" class="btn" style="display:none" onclick="goHome()">DASHBOARD / لوحة التحكم</button> | |
| <button id="newBtn" class="btn btn-primary">+ NEW ENGINE / سيرفر جديد</button> | |
| <button id="delBtn" class="btn btn-danger" style="display:none" onclick="deleteServer()">PURGE / حذف</button> | |
| <button class="btn btn-danger" onclick="location.href='/logout'">TERMINATE / خروج</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="container" id="homeView"> | |
| <div class="stats-grid" id="statsGrid" style="display:none"> | |
| <div class="stat-card"> | |
| <div class="stat-icon">🚀</div> | |
| <div class="stat-value" id="statServers">0</div> | |
| <div class="stat-label">Active Servers</div> | |
| <div class="stat-change positive">+0%</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-icon">⚡</div> | |
| <div class="stat-value" id="statRunning">0</div> | |
| <div class="stat-label">Running</div> | |
| <div class="stat-change positive">+0%</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-icon">💾</div> | |
| <div class="stat-value" id="statMemory">0 MB</div> | |
| <div class="stat-label">Memory Used</div> | |
| <div class="stat-change positive">+0%</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-icon">📊</div> | |
| <div class="stat-value" id="statUptime">0h</div> | |
| <div class="stat-label">Uptime</div> | |
| <div class="stat-change positive">+0%</div> | |
| </div> | |
| </div> | |
| <div class="chart-container" id="chartContainer" style="display:none"> | |
| <div class="chart-header"> | |
| <div class="chart-title">📈 Server Activity</div> | |
| <div class="chart-legend"> | |
| <div class="legend-item"> | |
| <div class="legend-dot" style="background: var(--primary)"></div> | |
| <span>Requests</span> | |
| </div> | |
| <div class="legend-item"> | |
| <div class="legend-dot" style="background: var(--accent)"></div> | |
| <span>Errors</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="activity-chart" id="activityChart"></div> | |
| <div class="chart-labels"> | |
| <span>Mon</span><span>Tue</span><span>Wed</span><span>Thu</span><span>Fri</span><span>Sat</span><span>Sun</span> | |
| </div> | |
| </div> | |
| <div class="billing-panel" id="billingPanel" | |
| style="display:none; padding: 24px; border-radius: 20px; border: 1px solid var(--border); background: var(--card); margin-bottom: 24px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px;"> | |
| <div> | |
| <h3 style="margin-bottom: 8px;">مرحباً <span id="pName" style="color:var(--text)"></span></h3> | |
| <p style="color:var(--text-muted); font-size:14px; font-family: var(--mono);"> | |
| PLAN: <strong id="pPlan"></strong> | | |
| LIMIT: <span id="pBots"></span> BOTS / <span id="pMem"></span> RAM<br> | |
| <span id="aiUsageTxt" style="font-size:11px; color:var(--primary)">AI REQUESTS TODAY: --</span> | |
| </p> | |
| </div> | |
| <div style="display: flex; gap: 10px;"> | |
| <button class="btn btn-primary" onclick="switchView('ai')">🤖 AI ASSISTANT / مساعد ذكي</button> | |
| </div> | |
| </div> | |
| <div id="adPanel" | |
| style="display:none; margin-bottom: 24px; padding: 20px; border-radius: 16px; background: rgba(255,255,255,0.03); border: 1px dashed var(--border); text-align: center;"> | |
| </div> | |
| <div class="grid" id="cardsContainer"></div> | |
| </div> | |
| <div class="container" id="settingsView" style="display:none"> | |
| <div class="settings-panel"> | |
| <div class="settings-header"> | |
| <h2>⚙️ Settings / الإعدادات</h2> | |
| <p>Customize your experience / تخصيص تجربتك</p> | |
| </div> | |
| <div class="settings-section"> | |
| <div class="settings-section-title">🔔 Notifications / الإشعارات</div> | |
| <div class="settings-item"> | |
| <div class="settings-item-label"> | |
| <h4>Push Notifications</h4> | |
| <p>Receive real-time alerts</p> | |
| </div> | |
| <div class="toggle-switch active" onclick="this.classList.toggle('active')"></div> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-item-label"> | |
| <h4>Email Notifications</h4> | |
| <p>Get updates via email</p> | |
| </div> | |
| <div class="toggle-switch" onclick="this.classList.toggle('active')"></div> | |
| </div> | |
| </div> | |
| <div class="settings-section"> | |
| <div class="settings-section-title">🎨 Appearance / المظهر</div> | |
| <div class="settings-item"> | |
| <div class="settings-item-label"> | |
| <h4>Theme</h4> | |
| <p>Choose your preferred theme</p> | |
| </div> | |
| <select class="settings-select" style="width:150px; margin-bottom:0"> | |
| <option>Dark</option> | |
| <option>Light</option> | |
| <option>Auto</option> | |
| </select> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-item-label"> | |
| <h4>Language</h4> | |
| <p>Select interface language</p> | |
| </div> | |
| <select class="settings-select" style="width:150px; margin-bottom:0"> | |
| <option>العربية</option> | |
| <option>English</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="settings-section"> | |
| <div class="settings-section-title">� Subscription Plan / خطة الاشتراك</div> | |
| <div id="currentPlanInfo" style="margin-bottom: 20px;"> | |
| <div style="display: flex; justify-content: space-between; align-items: center; padding: 16px; background: rgba(10, 132, 255, 0.1); border-radius: 12px; border: 1px solid rgba(10, 132, 255, 0.3);"> | |
| <div> | |
| <h4 style="margin-bottom: 4px;">Current Plan: <span id="currentPlanName">Free</span></h4> | |
| <p style="color: var(--text-dim); font-size: 12px;">Bots: <span id="botsUsed">0</span>/<span id="botsMax">3</span></p> | |
| </div> | |
| <button class="btn btn-primary" onclick="showUpgradeModal()">Upgrade Plan</button> | |
| </div> | |
| </div> | |
| <div id="plansGrid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px;"></div> | |
| </div> | |
| <div class="settings-section"> | |
| <div class="settings-section-title">� Security / الأمان</div> | |
| <input type="password" class="settings-input" placeholder="Current Password"> | |
| <input type="password" class="settings-input" placeholder="New Password"> | |
| <input type="password" class="settings-input" placeholder="Confirm New Password"> | |
| <button class="btn btn-primary" style="width:100%" onclick="showNotification('Success', 'Password updated', 'success')">Update Password</button> | |
| </div> | |
| <div class="settings-section"> | |
| <div class="settings-section-title">💾 Data / البيانات</div> | |
| <div class="settings-item"> | |
| <div class="settings-item-label"> | |
| <h4>Export Data</h4> | |
| <p>Download your account data</p> | |
| </div> | |
| <button class="btn" onclick="showNotification('Info', 'Export started', 'info')">Export</button> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-item-label"> | |
| <h4>Delete Account</h4> | |
| <p>Permanently remove your account</p> | |
| </div> | |
| <button class="btn btn-danger" onclick="showNotification('Warning', 'This action is irreversible', 'warning')">Delete</button> | |
| </div> | |
| </div> | |
| <div class="settings-section"> | |
| <div class="settings-section-title">📋 Activity Log / سجل النشاطات</div> | |
| <div class="activity-log" id="userActivityLog"> | |
| <div class="activity-item"> | |
| <div class="activity-icon">🚀</div> | |
| <div class="activity-content"> | |
| <div class="activity-title">Created new server</div> | |
| <div class="activity-time">2 minutes ago</div> | |
| </div> | |
| <div class="activity-status success">Success</div> | |
| </div> | |
| <div class="activity-item"> | |
| <div class="activity-icon">📝</div> | |
| <div class="activity-content"> | |
| <div class="activity-title">Edited file: main.py</div> | |
| <div class="activity-time">15 minutes ago</div> | |
| </div> | |
| <div class="activity-status info">Info</div> | |
| </div> | |
| <div class="activity-item"> | |
| <div class="activity-icon">🔄</div> | |
| <div class="activity-content"> | |
| <div class="activity-title">Restarted server</div> | |
| <div class="activity-time">1 hour ago</div> | |
| </div> | |
| <div class="activity-status success">Success</div> | |
| </div> | |
| <div class="activity-item"> | |
| <div class="activity-icon">🔐</div> | |
| <div class="activity-content"> | |
| <div class="activity-title">Changed password</div> | |
| <div class="activity-time">3 hours ago</div> | |
| </div> | |
| <div class="activity-status info">Info</div> | |
| </div> | |
| <div class="activity-item"> | |
| <div class="activity-icon">📤</div> | |
| <div class="activity-content"> | |
| <div class="activity-title">Uploaded files</div> | |
| <div class="activity-time">5 hours ago</div> | |
| </div> | |
| <div class="activity-status success">Success</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="container" id="aiView" style="display:none"> | |
| <div class="view-header"> | |
| <div class="view-title"> | |
| <h1>WHITE WOLF AI</h1> | |
| <div style="color:var(--text-dim); font-size:13px; margin-top:4px;">POWERED BY OLLAMA FREE API</div> | |
| </div> | |
| <button class="btn" onclick="goHome()">BACK / رجوع</button> | |
| </div> | |
| <div class="ai-chat-container"> | |
| <div class="ai-chat-header"> | |
| <span style="font-weight: 700;">AI CHAT TERMINAL</span> | |
| <select id="aiModelSelect" class="btn" style="padding: 4px 8px; font-size: 11px;"> | |
| <option value="deepseek-r1:latest">DeepSeek R1 (Strong)</option> | |
| <option value="llama3.2:3b">Llama 3.2 3B (Fast)</option> | |
| <option value="mistral:latest">Mistral</option> | |
| <option value="gpt-oss:20b">Gemma 20B</option> | |
| </select> | |
| </div> | |
| <div class="ai-chat-messages" id="aiMessages"> | |
| <div class="ai-message bot">مرحباً! أنا المساعد الذكي لمنصة الذئب الأبيض. كيف يمكنني مساعدتك اليوم؟</div> | |
| </div> | |
| <div class="ai-chat-input-area"> | |
| <input type="text" id="aiInput" class="ai-chat-input" placeholder="Type your message / اكتب رسالتك هنا..." | |
| onkeypress="if(event.key==='Enter') sendAiMessage()"> | |
| <button class="btn btn-primary" onclick="sendAiMessage()">SEND</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="container" id="serverView"> | |
| <div class="view-header"> | |
| <div class="view-title"> | |
| <h1 id="srvHeader">OPERATIVE</h1> | |
| <div style="color:var(--text-dim); font-size:13px; margin-top:4px;" id="srvSub">ACTIVE SESSION / جلسة نشطة</div> | |
| </div> | |
| <div class="tab-group"> | |
| <div class="tab active" id="tabConsole" onclick="switchTab('console')">CONSOLE / موجه الأوامر</div> | |
| <div class="tab" id="tabFiles" onclick="switchTab('files')">FILE SYSTEM / الملفات</div> | |
| </div> | |
| </div> | |
| <div id="viewConsole"> | |
| <div class="manager-layout"> | |
| <div class="console-box"> | |
| <div class="console-nav"> | |
| <div class="dots"><span class="red"></span><span class="yellow"></span><span class="green"></span></div> | |
| <span>STDOUT STREAM</span> | |
| <span>UTF-8</span> | |
| </div> | |
| <div class="console-out" id="logOut">INITIALIZING VIRTUAL ENVIRONMENT...</div> | |
| </div> | |
| <div class="side-panel"> | |
| <button id="btnStart" class="btn btn-primary" style="width:100%; height:50px; font-size:14px;" | |
| onclick="srvAction('start')">EXECUTE / تشغيل</button> | |
| <button class="btn" style="width:100%; padding:14px;" onclick="srvAction('restart')">REBOOT / إعادة | |
| تشغيل</button> | |
| <button class="btn btn-danger" style="width:100%; padding:14px;" onclick="srvAction('stop')">HALT / | |
| إيقاف</button> | |
| <div class="side-card"> | |
| <div class="stat-row"> | |
| <div class="ico-box">⚡</div> | |
| <div class="stat-val"><span class="stat-label">STATUS</span><span class="stat-num" | |
| id="statusTxt">OFFLINE</span></div> | |
| </div> | |
| <div class="stat-row"> | |
| <div class="ico-box">💾</div> | |
| <div class="stat-val"><span class="stat-label">MEMORY</span><span class="stat-num" id="memTxt">0.0 | |
| MB</span></div> | |
| </div> | |
| <div class="stat-row"> | |
| <div class="ico-box">⚙️</div> | |
| <div class="stat-val"><span class="stat-label">CPU</span><span class="stat-num" id="cpuTxt">0%</span> | |
| </div> | |
| </div> | |
| <div class="stat-row"> | |
| <div class="ico-box">🌐</div> | |
| <div class="stat-val"><span class="stat-label">IP ADDRESS</span><span class="stat-num" | |
| id="ipTxt">0.0.0.0</span></div> | |
| </div> | |
| </div> | |
| <div class="side-card"> | |
| <div class="stat-label" style="margin-bottom:8px;">PROTOCOL ENTRYPOINT</div> | |
| <div | |
| style="font-family:var(--mono); font-size:13px; color:var(--primary); cursor:pointer; text-decoration:underline" | |
| onclick="changeStartup()" id="mainFileTxt">NOT SET</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="viewFiles" style="display:none" class="file-manager"> | |
| <div class="fm-header"> | |
| <div class="fm-path" id="pathBar"></div> | |
| <div class="fm-toolbar"> | |
| <input type="text" class="fm-search" placeholder="Search files... / بحث..." id="fmSearch" onkeyup="filterFiles()"> | |
| <div class="fm-view-toggle"> | |
| <button class="fm-view-btn active" onclick="setFileView('list')">📋</button> | |
| <button class="fm-view-btn" onclick="setFileView('grid')">⊞</button> | |
| </div> | |
| </div> | |
| <div class="nav-actions"> | |
| <button id="btnBack" class="btn" style="display:none" onclick="goUp()">BACK / رجوع</button> | |
| <button class="btn" onclick="newFolder()">+ DIR / مجلد جديد</button> | |
| <button class="btn btn-primary" onclick="document.getElementById('uplFiles').click()">UPLOAD / رفع | |
| ملف</button> | |
| <button class="btn" onclick="document.getElementById('uplFolder').click()">BUNDLE / رفع مجلد</button> | |
| </div> | |
| </div> | |
| <div class="fm-dropzone" id="fmDropzone" ondrop="handleDrop(event)" ondragover="handleDragOver(event)" ondragleave="handleDragLeave(event)"> | |
| <div class="fm-dropzone-icon">📁</div> | |
| <div>Drag & drop files here / اسحب الملفات هنا</div> | |
| </div> | |
| <input type="file" id="uplFiles" multiple hidden onchange="doUploadFiles(this)"> | |
| <input type="file" id="uplFolder" webkitdirectory directory multiple hidden onchange="doUploadFolder(this)"> | |
| <table class="fm-table"> | |
| <thead> | |
| <tr> | |
| <th>ENTITY NAME / اسم الملف</th> | |
| <th style="width:120px">SIZE / الحجم</th> | |
| <th style="width:280px">PROTOCOLS / العمليات</th> | |
| </tr> | |
| </thead> | |
| <tbody id="fileList"></tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <div class="editor-container" id="advancedEditor"> | |
| <div class="editor-header"> | |
| <div class="editor-title" id="advancedEditorTitle">main.py</div> | |
| <div class="editor-toolbar"> | |
| <button class="btn" onclick="formatCode()">🎨 Format</button> | |
| <button class="btn" onclick="toggleMinimap()">🗺️ Minimap</button> | |
| <button class="btn btn-primary" onclick="saveAdvancedFile()">💾 Save</button> | |
| <button class="btn btn-danger" onclick="closeAdvancedEditor()">✕ Close</button> | |
| </div> | |
| </div> | |
| <div class="editor-body"> | |
| <div class="editor-sidebar" id="fileTree"> | |
| <div class="file-tree-item active">📄 main.py</div> | |
| </div> | |
| <div class="editor-main"> | |
| <div class="code-editor-wrapper"> | |
| <textarea class="code-editor" id="advancedCodeEditor" spellcheck="false" placeholder="Start coding..."></textarea> | |
| </div> | |
| <div class="editor-statusbar"> | |
| <div class="editor-status-item"> | |
| <span id="cursorPosition">Ln 1, Col 1</span> | |
| <span id="fileSize">0 bytes</span> | |
| </div> | |
| <div class="editor-status-item"> | |
| <span id="encoding">UTF-8</span> | |
| <span id="language">Python</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="editor-view"> | |
| <div class="editor-top"> | |
| <div style="font-family:var(--mono); font-weight:600" id="ed-title">ENTITY</div> | |
| <div class="nav-actions"> | |
| <button class="btn" onclick="openAdvancedEditor()">🔧 Advanced Editor</button> | |
| <button class="btn btn-primary" onclick="saveFile()">WRITE TO DISK / حفظ</button> | |
| <button class="btn" onclick="closeEditor()">CLOSE / إغلاق</button> | |
| </div> | |
| </div> | |
| <textarea class="editor-area" id="ed-area" spellcheck="false"></textarea> | |
| </div> | |
| <div id="modalOverlay" class="modal-overlay"> | |
| <div class="modal-box"> | |
| <h3 id="mTitle">ACTION</h3> | |
| <input id="mIn" autocomplete="off" spellcheck="false"> | |
| <div class="nav-actions" style="justify-content:flex-end"> | |
| <button class="btn" onclick="closeM()">ABORT / إلغاء</button> | |
| <button id="mConfirm" class="btn btn-primary">PROCEED / تأكيد</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="fm-preview-modal" id="fmPreviewModal"> | |
| <div class="fm-preview-content" id="fmPreviewContent"></div> | |
| <button class="btn btn-danger" style="position:fixed; top:20px; right:20px;" onclick="closePreview()">✕ Close</button> | |
| </div> | |
| <script> | |
| let currentSrv = null, poll = null, currentFile = null, currentPath = ''; | |
| function escapeHtml(s) { return (s || '').replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); } | |
| function escapeAttr(s) { return escapeHtml(s).replace(/\\/g, "\\\\"); } | |
| async function loadServers() { | |
| const r = await fetch('/servers'); | |
| const d = await r.json(); | |
| const cont = document.getElementById('cardsContainer'); | |
| cont.innerHTML = ''; | |
| fetch('/admin').then(res => { if (!res.redirected && res.status === 200) document.getElementById('adminBtn').style.display = 'inline-flex'; }); | |
| fetch('/api/user/profile').then(res => res.json()).then(data => { | |
| if (data.success) { | |
| document.getElementById('billingPanel').style.display = 'flex'; | |
| document.getElementById('statsGrid').style.display = 'grid'; | |
| document.getElementById('chartContainer').style.display = 'block'; | |
| document.getElementById('pName').textContent = data.username.toUpperCase(); | |
| document.getElementById('pPlan').textContent = data.plan_label.toUpperCase(); | |
| document.getElementById('pBots').textContent = data.max_bots; | |
| document.getElementById('pMem').textContent = data.max_mem_mb + 'MB'; | |
| if (data.ai_usage) { | |
| const usage = data.ai_usage; | |
| document.getElementById('aiUsageTxt').textContent = `AI REQUESTS TODAY: ${usage.count || 0} / 20`; | |
| } | |
| } | |
| }); | |
| loadAds(); | |
| updateStats(d.servers || []); | |
| generateActivityChart(); | |
| (d.servers || []).forEach(s => { | |
| const div = document.createElement('div'); | |
| div.className = 'card'; | |
| const st = (s.status || 'Offline').toLowerCase(); | |
| let sub = s.subtitle || 'NO PROTOCOL'; | |
| let expHtml = ''; | |
| if (s.last_renewed) { | |
| const days = (Date.now() / 1000 - s.last_renewed) / (24 * 3600); | |
| if (days > 4) { | |
| sub = `<span style="color:var(--error)">EXPIRED / انتهت الصلاحية</span>`; | |
| expHtml = `<button class="btn btn-primary" style="margin-top:10px; width:100%" onclick="event.stopPropagation(); renewBot('${s.key}')">RENEW / تجديد</button>`; | |
| } else { | |
| const rem = (4 - days).toFixed(1); | |
| sub += ` <br><span style="font-size:10px; color:var(--text-dim)">RENEW IN: ${rem} DAYS</span>`; | |
| } | |
| } | |
| const cls = st === 'running' ? 'running' : (st === 'installing' || st === 'starting' ? 'installing' : (s.banned ? 'error' : '')); | |
| div.innerHTML = ` | |
| <div style="flex-grow:1"> | |
| <div class="srv-name">${escapeHtml(s.title)}</div> | |
| <div class="srv-meta">${sub}</div> | |
| ${expHtml} | |
| </div> | |
| <div class="status-pill ${cls}"><span class="dot"></span>${st.toUpperCase()}</div> | |
| `; | |
| div.onclick = () => openServer(s); | |
| cont.appendChild(div); | |
| }); | |
| } | |
| async function loadAds() { | |
| const res = await fetch('/api/ads'); | |
| const data = await res.json(); | |
| const adBox = document.getElementById('adPanel'); | |
| if (data.current_ad) { | |
| adBox.style.display = 'block'; | |
| adBox.innerHTML = data.current_ad; | |
| } else { | |
| adBox.style.display = 'block'; | |
| adBox.innerHTML = `<div style="color:var(--text-dim); font-size:14px">Your ad here? / أعلن هنا؟ <a href="${data.contact_link}" target="_blank" style="color:var(--primary); text-decoration:none">CONTACT DEVELOPER</a></div>`; | |
| } | |
| } | |
| async function renewBot(key) { | |
| const r = await fetch(`/api/server/renew/${encodeURIComponent(key)}`, { method: 'POST' }); | |
| const d = await r.json(); | |
| if (d.success) { toast('Bot Renewed!', 'success'); loadServers(); } | |
| } | |
| function showHelp() { | |
| const helpText = ` | |
| <div id="helpTxtInner" style="text-align:right; direction:rtl; line-height:1.6; margin-bottom:20px; font-size:14px; max-height: 300px; overflow-y: auto;"> | |
| <h2 style="color:var(--primary); margin-bottom:10px">📖 دليل استخدام المنصة</h2> | |
| <p>1. <b>البادئ:</b> اضغط "سيرفر جديد" وحدد اسماً لمشروعك.</p> | |
| <p>2. <b>الملفات:</b> داخل لوحة تحكم السيرفر، ارفع ملفاتك (بايثون أو PHP).</p> | |
| <p>3. <b>التشغيل:</b> اضغط على اسم ملف التشغيل واضبطه كـ Entrypoint.</p> | |
| <p>4. <b>الموارد:</b> الموارد حالياً محدودة، لذا احرص على كتابة كود فعال.</p> | |
| <p>5. <b>التجديد:</b> ⚠️ <b>هام جداً:</b> يجب الضغط على زر التنشيط كل 4 أيام وإلا سيتوقف البوت.</p> | |
| <p>6. <b>PHP:</b> ندعم الآن لغة PHP بشكل كامل.</p> | |
| <p>7. <b>الذكاء الاصطناعي:</b> لك 20 طلباً يومياً من المساعد الذكي.</p> | |
| </div> | |
| `; | |
| openM("Platform Guide / دليل المنصة", "", () => closeM()); | |
| document.getElementById('mIn').style.display = 'none'; | |
| document.getElementById('mTitle').insertAdjacentHTML('afterend', helpText); | |
| } | |
| function openServer(s) { | |
| currentSrv = s; | |
| switchView('server'); | |
| document.getElementById('homeBtn').style.display = 'inline-flex'; | |
| document.getElementById('newBtn').style.display = 'none'; | |
| document.getElementById('delBtn').style.display = 'inline-flex'; | |
| document.getElementById('srvHeader').textContent = s.title.toUpperCase(); | |
| document.getElementById('mainFileTxt').textContent = s.startup_file || "NOT SET"; | |
| switchTab('console'); | |
| } | |
| function goHome() { | |
| switchView('home'); | |
| document.getElementById('homeBtn').style.display = 'none'; | |
| document.getElementById('delBtn').style.display = 'none'; | |
| document.getElementById('newBtn').style.display = 'inline-flex'; | |
| clearInterval(poll); | |
| } | |
| function switchView(v) { | |
| document.getElementById('homeView').style.display = v === 'home' ? 'block' : 'none'; | |
| document.getElementById('serverView').style.display = v === 'server' ? 'block' : 'none'; | |
| document.getElementById('aiView').style.display = v === 'ai' ? 'block' : 'none'; | |
| document.getElementById('settingsView').style.display = v === 'settings' ? 'block' : 'none'; | |
| if (v === 'home') loadServers(); | |
| if (v === 'ai' || v === 'settings') { | |
| document.getElementById('homeBtn').style.display = 'inline-flex'; | |
| document.getElementById('newBtn').style.display = 'none'; | |
| } | |
| if (v === 'settings') { | |
| loadSubscriptionPlans(); | |
| loadCurrentSubscription(); | |
| } | |
| } | |
| async function sendAiMessage() { | |
| const input = document.getElementById('aiInput'); | |
| const msg = input.value.trim(); | |
| if (!msg) return; | |
| const model = document.getElementById('aiModelSelect').value; | |
| const msgsCont = document.getElementById('aiMessages'); | |
| const uDiv = document.createElement('div'); | |
| uDiv.className = 'ai-message user'; | |
| uDiv.textContent = msg; | |
| msgsCont.appendChild(uDiv); | |
| input.value = ''; | |
| msgsCont.scrollTop = msgsCont.scrollHeight; | |
| const bDiv = document.createElement('div'); | |
| bDiv.className = 'ai-message bot'; | |
| bDiv.textContent = 'Thinking... / جاري التفكير...'; | |
| msgsCont.appendChild(bDiv); | |
| msgsCont.scrollTop = msgsCont.scrollHeight; | |
| try { | |
| const r = await fetch('/api/ai/chat', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ message: msg, model }) | |
| }); | |
| const d = await r.json(); | |
| bDiv.textContent = d.success ? d.response : (d.message || 'Error'); | |
| if (!d.success) bDiv.style.color = 'var(--error)'; | |
| } catch (e) { | |
| bDiv.textContent = 'Connection error.'; | |
| bDiv.style.color = 'var(--error)'; | |
| } | |
| msgsCont.scrollTop = msgsCont.scrollHeight; | |
| } | |
| function switchTab(t) { | |
| document.getElementById('tabConsole').classList.toggle('active', t === 'console'); | |
| document.getElementById('tabFiles').classList.toggle('active', t === 'files'); | |
| document.getElementById('viewConsole').style.display = t === 'console' ? 'block' : 'none'; | |
| document.getElementById('viewFiles').style.display = t === 'files' ? 'block' : 'none'; | |
| if (t === 'console') startPolling(); else { clearInterval(poll); loadFiles(); } | |
| } | |
| async function startPolling() { | |
| if (poll) clearInterval(poll); | |
| const fn = async () => { | |
| try { | |
| const r = await fetch(`/server/stats/${encodeURIComponent(currentSrv.key || currentSrv.folder)}`); | |
| const d = await r.json(); | |
| document.getElementById('logOut').textContent = d.logs || "ESTABLISHING VIRTUAL LINK..."; | |
| document.getElementById('statusTxt').textContent = (d.status || 'OFFLINE').toUpperCase(); | |
| document.getElementById('memTxt').textContent = d.mem || '0.0 MB'; | |
| document.getElementById('cpuTxt').textContent = d.cpu || '0%'; | |
| document.getElementById('ipTxt').textContent = d.ip || '0.0.0.0'; | |
| const running = ['running', 'installing', 'starting'].includes(d.status.toLowerCase()); | |
| document.getElementById('btnStart').disabled = running; | |
| document.getElementById('btnStart').style.opacity = running ? 0.5 : 1; | |
| const lo = document.getElementById('logOut'); lo.scrollTop = lo.scrollHeight; | |
| } catch (e) { } | |
| }; | |
| fn(); poll = setInterval(fn, 2000); | |
| } | |
| async function srvAction(act) { await fetch(`/server/action/${encodeURIComponent(currentSrv.key || currentSrv.folder)}/${act}`, { method: 'POST' }); } | |
| async function loadFiles() { | |
| const r = await fetch(`/files/list/${encodeURIComponent(currentSrv.key || currentSrv.folder)}?path=${encodeURIComponent(currentPath)}`); | |
| const data = await r.json(); | |
| document.getElementById("btnBack").style.display = currentPath ? "inline-flex" : "none"; | |
| let crumbs = [`<span class="crumb"><a href="#" onclick="jumpPath('')">ROOT</a></span>`]; | |
| let acc = ''; | |
| (data.path || '').split('/').filter(Boolean).forEach(p => { | |
| acc = acc ? (acc + '/' + p) : p; | |
| crumbs.push('<span style="opacity:0.3"> / </span>' + `<span class="crumb"><a href="#" onclick="jumpPath('${escapeAttr(acc)}')">${escapeHtml(p)}</a></span>`); | |
| }); | |
| document.getElementById('pathBar').innerHTML = crumbs.join(''); | |
| let html = ''; | |
| (data.dirs || []).forEach(d => { | |
| html += `<tr><td><div class="fm-name" onclick="openFolder('${escapeAttr(d.name)}')">📁 ${escapeHtml(d.name)}</div></td><td style="color:var(--text-dim)">DIR</td><td> | |
| <div class="nav-actions"><button class="btn" style="padding:4px 8px" onclick="renameDir('${escapeAttr(d.name)}')">RENAME</button> | |
| <button class="btn btn-danger" style="padding:4px 8px" onclick="deleteDir('${escapeAttr(d.name)}')">DEL</button></div></td></tr>`; | |
| }); | |
| (data.files || []).forEach(f => { | |
| const rel = currentPath ? `${currentPath}/${f.name}` : f.name; | |
| html += `<tr><td><div class="fm-name" onclick="openEditor('${escapeAttr(rel)}')">📄 ${escapeHtml(f.name)}</div></td><td style="font-family:var(--mono);font-size:12px">${f.size}</td><td> | |
| <div class="nav-actions"><button class="btn" style="padding:4px 8px" onclick="renameFilePrompt('${escapeAttr(f.name)}')">RENAME</button> | |
| <button class="btn btn-danger" style="padding:4px 8px" onclick="deleteFilePrompt('${escapeAttr(f.name)}')">DEL</button></div></td></tr>`; | |
| }); | |
| document.getElementById('fileList').innerHTML = html; | |
| } | |
| function openFolder(name) { currentPath = currentPath ? (currentPath + '/' + name) : name; loadFiles(); } | |
| function jumpPath(p) { currentPath = p; loadFiles(); } | |
| function goUp() { let p = currentPath.split('/'); p.pop(); currentPath = p.join('/'); loadFiles(); } | |
| async function openEditor(name) { | |
| currentFile = name; document.getElementById('ed-title').textContent = name.toUpperCase(); | |
| const res = await fetch(`/files/content/${encodeURIComponent(currentSrv.key || currentSrv.folder)}?file=${encodeURIComponent(name)}`); | |
| const d = await res.json(); | |
| document.getElementById('ed-area').value = d.content || ''; | |
| document.getElementById('editor-view').style.display = 'flex'; | |
| } | |
| function closeEditor() { document.getElementById('editor-view').style.display = 'none'; } | |
| function showNotification(title, message, type = 'info', duration = 4000) { | |
| const container = document.getElementById('notificationContainer'); | |
| const notification = document.createElement('div'); | |
| notification.className = `notification ${type}`; | |
| const icons = { | |
| success: '✓', | |
| error: '✕', | |
| warning: '⚠', | |
| info: 'ℹ' | |
| }; | |
| notification.innerHTML = ` | |
| <div class="notification-icon">${icons[type] || icons.info}</div> | |
| <div class="notification-content"> | |
| <div class="notification-title">${title}</div> | |
| <div class="notification-message">${message}</div> | |
| </div> | |
| <div class="notification-close" onclick="this.parentElement.remove()">×</div> | |
| <div class="notification-progress"></div> | |
| `; | |
| container.appendChild(notification); | |
| setTimeout(() => { | |
| notification.style.animation = 'slideOut 0.3s cubic-bezier(0.4, 0, 0.2, 1)'; | |
| setTimeout(() => notification.remove(), 300); | |
| }, duration); | |
| } | |
| function toast(msg, type = 'info') { | |
| const titles = { | |
| success: 'Success', | |
| error: 'Error', | |
| warning: 'Warning', | |
| info: 'Info' | |
| }; | |
| showNotification(titles[type] || 'Info', msg, type); | |
| } | |
| function updateStats(servers) { | |
| const total = servers.length; | |
| const running = servers.filter(s => s.status === 'Running').length; | |
| const memory = servers.reduce((sum, s) => { | |
| if (s.mem) { | |
| const match = s.mem.match(/([\d.]+)\s*MB/i); | |
| if (match) return sum + parseFloat(match[1]); | |
| } | |
| return sum; | |
| }, 0); | |
| document.getElementById('statServers').textContent = total; | |
| document.getElementById('statRunning').textContent = running; | |
| document.getElementById('statMemory').textContent = memory.toFixed(1) + ' MB'; | |
| document.getElementById('statUptime').textContent = Math.floor(Math.random() * 24 + 1) + 'h'; | |
| } | |
| function generateActivityChart() { | |
| const chart = document.getElementById('activityChart'); | |
| chart.innerHTML = ''; | |
| const data = [45, 72, 38, 91, 65, 82, 58]; | |
| const max = Math.max(...data); | |
| data.forEach((value, index) => { | |
| const bar = document.createElement('div'); | |
| bar.className = 'chart-bar'; | |
| const height = (value / max) * 100; | |
| bar.style.height = height + '%'; | |
| bar.setAttribute('data-value', value); | |
| chart.appendChild(bar); | |
| }); | |
| } | |
| // Advanced Editor Functions | |
| function openAdvancedEditor() { | |
| const editor = document.getElementById('advancedEditor'); | |
| const codeArea = document.getElementById('ed-area'); | |
| const advancedEditor = document.getElementById('advancedCodeEditor'); | |
| document.getElementById('advancedEditorTitle').textContent = currentFile || 'Untitled'; | |
| advancedEditor.value = codeArea.value; | |
| editor.classList.add('active'); | |
| updateEditorStats(); | |
| advancedEditor.addEventListener('input', updateEditorStats); | |
| advancedEditor.addEventListener('click', updateCursorPosition); | |
| advancedEditor.addEventListener('keyup', updateCursorPosition); | |
| } | |
| function closeAdvancedEditor() { | |
| const editor = document.getElementById('advancedEditor'); | |
| const codeArea = document.getElementById('ed-area'); | |
| const advancedEditor = document.getElementById('advancedCodeEditor'); | |
| codeArea.value = advancedEditor.value; | |
| editor.classList.remove('active'); | |
| } | |
| function saveAdvancedFile() { | |
| const advancedEditor = document.getElementById('advancedCodeEditor'); | |
| document.getElementById('ed-area').value = advancedEditor.value; | |
| saveFile(); | |
| showNotification('Success', 'File saved successfully', 'success'); | |
| } | |
| function formatCode() { | |
| const editor = document.getElementById('advancedCodeEditor'); | |
| // Simple indentation formatting | |
| let code = editor.value; | |
| code = code.replace(/\n\s*\n/g, '\n'); // Remove extra empty lines | |
| editor.value = code; | |
| showNotification('Formatted', 'Code formatted', 'info'); | |
| } | |
| function toggleMinimap() { | |
| showNotification('Minimap', 'Minimap feature coming soon', 'info'); | |
| } | |
| function updateEditorStats() { | |
| const editor = document.getElementById('advancedCodeEditor'); | |
| const content = editor.value; | |
| const lines = content.split('\n').length; | |
| const chars = content.length; | |
| document.getElementById('fileSize').textContent = chars + ' bytes'; | |
| } | |
| function updateCursorPosition() { | |
| const editor = document.getElementById('advancedCodeEditor'); | |
| const pos = editor.selectionStart; | |
| const text = editor.value.substring(0, pos); | |
| const lines = text.split('\n'); | |
| const line = lines.length; | |
| const col = lines[lines.length - 1].length + 1; | |
| document.getElementById('cursorPosition').textContent = `Ln ${line}, Col ${col}`; | |
| } | |
| // Advanced File Manager Functions | |
| let currentFileView = 'list'; | |
| function setFileView(view) { | |
| currentFileView = view; | |
| const buttons = document.querySelectorAll('.fm-view-btn'); | |
| buttons.forEach(btn => btn.classList.remove('active')); | |
| event.target.classList.add('active'); | |
| loadFiles(); | |
| } | |
| function filterFiles() { | |
| const search = document.getElementById('fmSearch').value.toLowerCase(); | |
| const items = document.querySelectorAll('.fm-name'); | |
| items.forEach(item => { | |
| const text = item.textContent.toLowerCase(); | |
| item.closest('tr').style.display = text.includes(search) ? '' : 'none'; | |
| }); | |
| } | |
| function handleDragOver(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| document.getElementById('fmDropzone').classList.add('dragover'); | |
| } | |
| function handleDragLeave(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| document.getElementById('fmDropzone').classList.remove('dragover'); | |
| } | |
| function handleDrop(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| document.getElementById('fmDropzone').classList.remove('dragover'); | |
| const files = e.dataTransfer.files; | |
| if (files.length > 0) { | |
| uploadDroppedFiles(files); | |
| } | |
| } | |
| async function uploadDroppedFiles(files) { | |
| let fd = new FormData(); | |
| for (let f of files) { | |
| fd.append("files", f); | |
| } | |
| await fetch(`/files/upload/${encodeURIComponent(currentSrv.key || currentSrv.folder)}?path=${encodeURIComponent(currentPath)}`, { method: "POST", body: fd }); | |
| loadFiles(); | |
| showNotification('Success', `${files.length} file(s) uploaded`, 'success'); | |
| } | |
| function previewFile(name) { | |
| const ext = name.split('.').pop().toLowerCase(); | |
| const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg']; | |
| if (imageExts.includes(ext)) { | |
| showImagePreview(name); | |
| } else { | |
| showCodePreview(name); | |
| } | |
| } | |
| async function showImagePreview(name) { | |
| const modal = document.getElementById('fmPreviewModal'); | |
| const content = document.getElementById('fmPreviewContent'); | |
| const rel = currentPath ? `${currentPath}/${name}` : name; | |
| const res = await fetch(`/files/content/${encodeURIComponent(currentSrv.key || currentSrv.folder)}?file=${encodeURIComponent(rel)}`); | |
| const d = await res.json(); | |
| if (d.success) { | |
| content.innerHTML = `<img src="data:image/png;base64,${d.content}" class="fm-preview-image" alt="${name}">`; | |
| modal.classList.add('active'); | |
| } | |
| } | |
| async function showCodePreview(name) { | |
| const modal = document.getElementById('fmPreviewModal'); | |
| const content = document.getElementById('fmPreviewContent'); | |
| const rel = currentPath ? `${currentPath}/${name}` : name; | |
| const res = await fetch(`/files/content/${encodeURIComponent(currentSrv.key || currentSrv.folder)}?file=${encodeURIComponent(rel)}`); | |
| const d = await res.json(); | |
| if (d.success) { | |
| content.innerHTML = `<pre class="fm-preview-code">${escapeHtml(d.content || '')}</pre>`; | |
| modal.classList.add('active'); | |
| } | |
| } | |
| function closePreview() { | |
| document.getElementById('fmPreviewModal').classList.remove('active'); | |
| } | |
| // Subscription Plans Functions | |
| async function loadSubscriptionPlans() { | |
| try { | |
| const r = await fetch('/api/subscription/plans'); | |
| const d = await r.json(); | |
| if (d.success) { | |
| displayPlans(d.plans); | |
| } | |
| } catch (e) { console.error(e); } | |
| } | |
| async function loadCurrentSubscription() { | |
| try { | |
| const r = await fetch('/api/subscription/current'); | |
| const d = await r.json(); | |
| if (d.success) { | |
| document.getElementById('currentPlanName').textContent = d.limits.name; | |
| document.getElementById('botsUsed').textContent = d.usage.bots_used; | |
| document.getElementById('botsMax').textContent = d.limits.max_bots; | |
| } | |
| } catch (e) { console.error(e); } | |
| } | |
| function displayPlans(plans) { | |
| const grid = document.getElementById('plansGrid'); | |
| grid.innerHTML = ''; | |
| for (const [key, plan] of Object.entries(plans)) { | |
| const card = document.createElement('div'); | |
| card.style.cssText = ` | |
| background: rgba(255,255,255,0.03); | |
| border: 1px solid var(--border); | |
| border-radius: 12px; | |
| padding: 20px; | |
| text-align: center; | |
| transition: all 0.3s; | |
| `; | |
| card.onmouseover = () => card.style.borderColor = 'var(--primary)'; | |
| card.onmouseout = () => card.style.borderColor = 'var(--border)'; | |
| card.innerHTML = ` | |
| <h3 style="font-size: 18px; font-weight: 700; margin-bottom: 8px;">${plan.name}</h3> | |
| <div style="font-size: 32px; font-weight: 800; color: var(--primary); margin-bottom: 16px;"> | |
| $${plan.price}<span style="font-size: 14px; color: var(--text-dim); font-weight: 400;">/mo</span> | |
| </div> | |
| <ul style="list-style: none; padding: 0; margin-bottom: 16px; text-align: left;"> | |
| ${plan.features.map(f => `<li style="padding: 4px 0; font-size: 13px; color: var(--text-dim);">✓ ${f}</li>`).join('')} | |
| </ul> | |
| <button class="btn ${key === 'free' ? '' : 'btn-primary'}" style="width: 100%;" onclick="upgradePlan('${key}')"> | |
| ${key === 'free' ? 'Current' : 'Upgrade'} | |
| </button> | |
| `; | |
| grid.appendChild(card); | |
| } | |
| } | |
| async function upgradePlan(plan) { | |
| try { | |
| const r = await fetch('/api/subscription/upgrade', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ plan }) | |
| }); | |
| const d = await r.json(); | |
| if (d.success) { | |
| showNotification('Success', d.message, 'success'); | |
| loadCurrentSubscription(); | |
| } else { | |
| showNotification('Error', d.message, 'error'); | |
| } | |
| } catch (e) { showNotification('Error', 'Failed to upgrade', 'error'); } | |
| } | |
| function showUpgradeModal() { | |
| showNotification('Info', 'Contact admin to upgrade your plan', 'info'); | |
| } | |
| async function saveFile() { | |
| try { | |
| const r = await fetch(`/files/save/${encodeURIComponent(currentSrv.key || currentSrv.folder)}`, { | |
| method: 'POST', headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ file: currentFile, content: document.getElementById('ed-area').value }) | |
| }); | |
| const d = await r.json(); | |
| if (d.success) toast('FILE SAVED', 'success'); | |
| else toast(d.message || 'Save failed', 'error'); | |
| } catch (e) { toast('Network error', 'error'); } | |
| } | |
| function openM(t, v, cb) { | |
| document.getElementById('modalOverlay').style.display = 'flex'; | |
| document.getElementById('mTitle').textContent = t.toUpperCase(); | |
| const mIn = document.getElementById('mIn'); | |
| mIn.value = v || ''; | |
| mIn.style.display = 'block'; // Ensure it's normally visible | |
| const oldHelp = document.getElementById('helpTxtInner'); | |
| if (oldHelp) oldHelp.remove(); | |
| document.getElementById('mConfirm').onclick = () => cb(mIn.value); | |
| } | |
| function closeM() { | |
| document.getElementById('modalOverlay').style.display = 'none'; | |
| const oldHelp = document.getElementById('helpTxtInner'); | |
| if (oldHelp) oldHelp.remove(); | |
| } | |
| async function renameDir(n) { openM("Rename Directory", n, async v => { await fetch(`/files/rename/${encodeURIComponent(currentSrv.key || currentSrv.folder)}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path: currentPath, old: n, new: v }) }); loadFiles(); closeM(); toast('Renamed', 'success'); }); } | |
| async function deleteDir(n) { if (confirm(`PURGE DIRECTORY '${n}'?`)) { await fetch(`/files/delete/${encodeURIComponent(currentSrv.key || currentSrv.folder)}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path: currentPath, name: n, kind: 'dir' }) }); loadFiles(); toast('Directory deleted', 'success'); } } | |
| async function renameFilePrompt(n) { openM("Rename File", n, async v => { await fetch(`/files/rename/${encodeURIComponent(currentSrv.key || currentSrv.folder)}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path: currentPath, old: n, new: v }) }); loadFiles(); closeM(); toast('Renamed', 'success'); }); } | |
| async function deleteFilePrompt(n) { if (confirm(`PURGE FILE '${n}'?`)) { await fetch(`/files/delete/${encodeURIComponent(currentSrv.key || currentSrv.folder)}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path: currentPath, name: n, kind: 'file' }) }); loadFiles(); toast('File deleted', 'success'); } } | |
| async function doUploadFiles(inp) { let fd = new FormData(); for (let f of inp.files) fd.append("files", f); await fetch(`/files/upload/${encodeURIComponent(currentSrv.key || currentSrv.folder)}?path=${encodeURIComponent(currentPath)}`, { method: "POST", body: fd }); loadFiles(); toast(`${inp.files.length} file(s) uploaded`, 'success'); inp.value = ''; } | |
| async function doUploadFolder(inp) { let fd = new FormData(); for (let f of inp.files) { fd.append("files", f); fd.append("relpaths", f.webkitRelativePath || f.name); } await fetch(`/files/upload/${encodeURIComponent(currentSrv.key || currentSrv.folder)}?path=${encodeURIComponent(currentPath)}`, { method: "POST", body: fd }); loadFiles(); toast('Folder uploaded', 'success'); inp.value = ''; } | |
| async function changeStartup() { openM("Set Entrypoint", currentSrv.startup_file, async v => { await fetch(`/server/set-startup/${encodeURIComponent(currentSrv.key || currentSrv.folder)}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ file: v }) }); currentSrv.startup_file = v; document.getElementById('mainFileTxt').textContent = v; closeM(); toast('Entrypoint updated', 'success'); }); } | |
| async function deleteServer() { if (confirm("ABSOLUTE DATA DESTRUCTION?")) { await fetch(`/server/delete/${encodeURIComponent(currentSrv.key || currentSrv.folder)}`, { method: 'POST' }); goHome(); toast('Server deleted', 'success'); } } | |
| document.getElementById('newBtn').onclick = () => openM("INIT NEW ENGINE", "", async v => { | |
| const r = await fetch('/add', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: v }) }); | |
| const d = await r.json(); | |
| if (d.success) { closeM(); loadServers(); toast('Engine created', 'success'); } else toast(d.message, 'error'); | |
| }); | |
| document.addEventListener('DOMContentLoaded', () => { loadServers(); }); | |
| setInterval(() => { if (document.getElementById('homeView').style.display !== 'none') loadServers(); }, 10000); | |
| document.addEventListener('contextmenu', e => e.preventDefault()); | |
| document.onkeydown = function (e) { | |
| if (e.keyCode == 123) return false; | |
| if (e.ctrlKey && e.shiftKey && (e.keyCode == 'I'.charCodeAt(0) || e.keyCode == 'J'.charCodeAt(0) || e.keyCode == 'C'.charCodeAt(0))) return false; | |
| if (e.ctrlKey && e.keyCode == 'U'.charCodeAt(0)) return false; | |
| }; | |
| setInterval(() => { | |
| const start = performance.now(); | |
| debugger; | |
| if (performance.now() - start > 100) window.location.href = "about:blank"; | |
| }, 500); | |
| </script> | |
| </body> | |
| </html> |