Aqso commited on
Commit
e4dc24c
·
verified ·
1 Parent(s): 09d8a3b

Update ui_templates.py

Browse files
Files changed (1) hide show
  1. ui_templates.py +209 -155
ui_templates.py CHANGED
@@ -1,184 +1,238 @@
1
- # ==========================================
2
- # AQSO CYBER CORE v9.7 - UI TEMPLATE
3
- # ==========================================
4
-
5
  PANEL_UI = """
6
  <!DOCTYPE html>
7
- <html class="bg-[#050505] text-[#00f3ff]">
8
  <head>
9
- <meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
10
- <title>AQSO | CYBER CORE v9.7</title>
11
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.1.0/css/xterm.css" />
12
  <script src="https://cdn.tailwindcss.com"></script>
13
- <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.23.4/ace.js"></script>
14
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
 
 
 
 
15
  <style>
16
- @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;900&family=JetBrains+Mono&display=swap');
17
- body { font-family: 'JetBrains Mono', monospace; height: 100dvh; overflow: hidden; background: #050505; }
18
- .cyber-panel { background: rgba(10, 10, 10, 0.9); backdrop-filter: blur(20px); border: 1px solid rgba(0, 243, 255, 0.15); }
19
- .neon-pink { color: #ff00ff; text-shadow: 0 0 10px #ff00ff; }
20
- .neon-cyan { color: #00f3ff; text-shadow: 0 0 10px #00f3ff; }
21
- .tab-active { background: linear-gradient(90deg, rgba(0, 243, 255, 0.1), transparent); border-left: 3px solid #00f3ff; color: #fff; }
22
- .btn-core { font-size: 10px; font-weight: 900; padding: 10px 16px; border-radius: 4px; text-transform: uppercase; transition: all 0.2s; white-space: nowrap; }
23
- #terminal { height: 100%; width: 100%; }
24
- .custom-scroll::-webkit-scrollbar { width: 3px; }
25
- .custom-scroll::-webkit-scrollbar-thumb { background: #00f3ff; }
26
  </style>
27
  </head>
28
- <body class="flex flex-col">
29
- <div id="login-overlay" class="fixed inset-0 z-[1000] bg-black/95 flex items-center justify-center p-6" style="display:none;">
30
- <div class="cyber-panel p-10 rounded-lg w-full max-w-sm text-center border-[#00f3ff33]">
31
- <h1 class="font-black italic text-2xl mb-8 neon-cyan" style="font-family:'Orbitron'">AQSO<span class="neon-pink text-[10px] ml-1 opacity-80">v9.7</span></h1>
32
- <div class="space-y-4">
33
- <input id="u" placeholder="IDENTITY_CODE" class="w-full bg-black/50 border border-[#00f3ff33] p-4 text-xs outline-none focus:border-[#00f3ff] text-white">
34
- <input id="p" type="password" placeholder="ACCESS_CIPHER" class="w-full bg-black/50 border border-[#00f3ff33] p-4 text-xs outline-none focus:border-[#ff00ff] text-white">
35
- <button onclick="doLogin()" class="w-full bg-[#00f3ff11] border border-[#00f3ff] py-4 font-black text-[10px] uppercase tracking-[0.4em] hover:bg-[#00f3ff33]">Connect_Core</button>
36
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  </div>
38
  </div>
39
 
40
- <div id="panel-content" class="flex-1 flex flex-col overflow-hidden" style="display:none;">
41
- <header class="min-h-16 h-auto bg-[#0a0a0a] border-b border-[#00f3ff11] px-4 py-3 flex flex-wrap items-center justify-between gap-4 shrink-0 z-50">
42
- <div class="flex items-center gap-4">
43
- <h1 class="font-black italic text-lg neon-cyan" style="font-family:'Orbitron'">AQSO<span class="text-white/30 text-[9px] ml-1">v9.7</span></h1>
44
- <div class="hidden sm:flex gap-3 text-[8px] font-bold uppercase">
45
- <div class="border-l border-[#00f3ff] pl-2">CPU: <span id="cpu-stat">0%</span></div>
46
- <div class="border-l border-[#ff00ff] pl-2">RAM: <span id="ram-stat">0%</span></div>
47
  </div>
48
  </div>
49
- <div class="flex flex-wrap items-center gap-2">
50
- <input id="st_f" type="text" placeholder="main.py" class="bg-black border border-[#00f3ff33] text-[10px] px-3 py-2 rounded w-24 text-white outline-none focus:border-[#00f3ff]">
51
- <button onclick="runBot()" class="btn-core bg-[#00f3ff11] border border-[#00f3ff] text-[#00f3ff] hover:bg-[#00f3ff22]">RUN</button>
52
- <button onclick="stopBot()" class="btn-core bg-rose-950/20 border border-rose-600 text-rose-500 hover:bg-rose-600/30">STOP</button>
53
- <button onclick="logout()" class="btn-core bg-white/5 border border-white/20 text-white/50 hover:bg-white/10">EXIT</button>
54
  </div>
55
- </header>
56
-
57
- <div class="flex-1 flex flex-col lg:flex-row overflow-hidden relative">
58
- <nav class="w-full lg:w-48 bg-[#0a0a0a] border-r border-[#00f3ff0a] flex lg:flex-col shrink-0 z-40 overflow-x-auto">
59
- <button onclick="tab('term')" id="b-term" class="tab-active flex-1 lg:flex-none flex items-center p-4 gap-3 text-[10px] font-black tracking-widest"><i class="fas fa-terminal"></i>CONSOLE</button>
60
- <button onclick="tab('file')" id="b-file" class="flex-1 lg:flex-none flex items-center p-4 gap-3 text-gray-600 transition-all hover:text-[#00f3ff] text-[10px] font-black tracking-widest"><i class="fas fa-folder"></i>VAULT</button>
61
- </nav>
62
-
63
- <main class="flex-1 p-3 lg:p-6 overflow-hidden relative flex flex-col gap-4">
64
- <div id="v-term" class="h-full bg-black rounded border border-[#00f3ff11] p-1 overflow-hidden relative shadow-[0_0_40px_rgba(0,243,255,0.05)]">
65
- <div id="terminal"></div>
66
- <button onclick="pasteCli()" class="lg:hidden absolute bottom-4 right-4 bg-[#00f3ff] text-black w-10 h-10 rounded-full flex items-center justify-center active:scale-90"><i class="fas fa-paste"></i></button>
67
- </div>
68
-
69
- <div id="v-file" class="hidden h-full flex flex-col">
70
- <div class="flex justify-between items-center mb-4">
71
- <h2 class="font-black text-[10px] neon-pink uppercase italic tracking-[0.3em]">Isolated_Vault</h2>
72
- <div class="flex gap-2">
73
- <input type="file" id="uI" class="hidden" onchange="upload()">
74
- <button onclick="document.getElementById('uI').click()" class="border border-[#00f3ff22] p-2 rounded text-[#00f3ff]"><i class="fas fa-upload text-xs"></i></button>
75
- <button onclick="load()" class="border border-[#00f3ff22] p-2 rounded text-[#00f3ff]"><i class="fas fa-sync text-xs"></i></button>
76
- </div>
77
- </div>
78
- <div class="flex-1 overflow-y-auto bg-[#0a0a0a] border border-[#00f3ff0a] rounded custom-scroll">
79
- <table class="w-full text-[10px] text-left"><tbody id="ft"></tbody></table>
80
- </div>
81
- </div>
82
 
83
- <div id="v-edit" class="hidden absolute inset-0 bg-black z-[120] p-6 flex flex-col">
84
- <div class="flex justify-between mb-4 items-center">
85
- <span id="en" class="text-[9px] text-[#ff00ff] italic mono border-b border-[#ff00ff22]"></span>
86
- <div class="flex gap-4"><button onclick="tab('file')" class="text-xs font-bold text-gray-600">DISCARD</button><button onclick="save()" class="bg-[#00f3ff11] border border-[#00f3ff] px-6 py-1.5 rounded text-[9px] font-black uppercase text-white shadow-[0_0_15px_rgba(0,243,255,0.2)]">COMMIT</button></div>
 
 
 
 
 
 
 
 
 
 
87
  </div>
88
- <div id="editor" class="flex-1"></div>
89
  </div>
90
- </main>
 
91
  </div>
92
- <footer class="h-5 bg-[#00f3ff] text-black text-[7px] font-black flex items-center justify-center tracking-[0.5em] uppercase">SYSTEM_ENCRYPTED_FOR_USER: <span id="user-display" class="ml-2">GUEST</span></footer>
93
  </div>
94
 
95
- <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.2/socket.io.js"></script>
96
- <script src="https://cdn.jsdelivr.net/npm/xterm@5.1.0/lib/xterm.js"></script>
97
- <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.7.0/lib/xterm-addon-fit.js"></script>
98
- <script>
99
- let socket, term, fitAddon, editor, curFile = "";
100
-
101
- window.onload = function() {
102
- const token = localStorage.getItem('aqso_token');
103
- const user = localStorage.getItem('aqso_user');
104
- if(!token || !user) { document.getElementById('login-overlay').style.display = 'flex'; }
105
- else { initCore(token, user); }
106
- };
107
 
108
- async function doLogin() {
109
- const fd = new FormData();
110
- fd.append('username', document.getElementById('u').value);
111
- fd.append('password', document.getElementById('p').value);
112
- const r = await fetch('/login_api', { method: 'POST', body: fd });
113
- const d = await r.json();
114
- if(d.status === 'success') {
115
- localStorage.setItem('aqso_token', d.token);
116
- localStorage.setItem('aqso_user', d.user);
117
- initCore(d.token, d.user);
118
- } else { alert('ACCESS_DENIED'); }
119
- }
120
 
121
- function initCore(token, user) {
122
- document.getElementById('login-overlay').style.display = 'none';
123
- document.getElementById('panel-content').style.display = 'flex';
124
- document.getElementById('user-display').innerText = user;
125
- socket = io({ query: { token: token, user: user }, transports: ['websocket'] });
126
- term = new Terminal({ theme: { background: '#000000', foreground: '#00f3ff', cursor: '#ff00ff' }, fontSize: 13, fontFamily: 'JetBrains Mono', cursorBlink: true, convertEol: true });
127
- fitAddon = new FitAddon.FitAddon();
128
- term.loadAddon(fitAddon);
129
- term.open(document.getElementById('terminal'));
130
- socket.on('o', d => term.write(d));
131
- socket.on('stats', d => {
132
- document.getElementById('cpu-stat').innerText = d.cpu + '%';
133
- document.getElementById('ram-stat').innerText = d.ram + '%';
134
- });
135
- term.onData(d => socket.emit('i', d));
136
- editor = ace.edit("editor");
137
- editor.setTheme("ace/theme/monokai");
138
- editor.session.setMode("ace/mode/python");
139
- setInterval(() => { if(document.getElementById('v-term').offsetParent) fitAddon.fit(); }, 1000);
140
- load();
141
- }
142
 
143
- function tab(t) {
144
- ['term','file','edit'].forEach(v => { document.getElementById('v-'+v).classList.add('hidden'); document.getElementById('b-'+v)?.classList.remove('tab-active'); });
145
- document.getElementById('v-'+t).classList.remove('hidden');
146
- if(document.getElementById('b-'+t)) document.getElementById('b-'+t).classList.add('tab-active');
147
- if(t==='file') load();
148
- if(t==='term') setTimeout(() => fitAddon.fit(), 100);
149
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
 
151
- async function req(url, method='GET', body=null) {
152
- const opt = { method, headers: { 'Authorization': localStorage.getItem('aqso_token'), 'X-User-ID': localStorage.getItem('aqso_user') } };
153
- if(body && !(body instanceof FormData)) { opt.headers['Content-Type'] = 'application/json'; opt.body = JSON.stringify(body); }
154
- else if(body) { opt.body = body; }
155
- return await fetch(url, opt);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  }
 
 
157
 
158
- async function load() {
159
- const r = await req('/api/files'); const d = await r.json();
160
- document.getElementById('ft').innerHTML = d.map(f => `
161
- <tr class="hover:bg-[#00f3ff05] transition border-b border-[#00f3ff05]">
162
- <td class="px-6 py-3 cursor-pointer flex items-center gap-4 text-gray-500" onclick="${!f.d ? "edit('"+f.n+"')" : ""}">
163
- <i class="fas ${f.d ? 'fa-folder text-[#00f3ff]' : 'fa-file-code'} opacity-30"></i>
164
- <span class="${f.d ? 'text-white font-bold':''}">${f.n}</span>
165
- </td>
166
- <td class="px-6 py-3 text-right">
167
- <button onclick="del('${f.n}')" class="text-rose-600 opacity-20 hover:opacity-100 transition"><i class="fas fa-trash-alt"></i></button>
168
- </td>
169
- </tr>
170
- `).join('');
171
  }
172
- async function edit(n) { curFile=n; document.getElementById('en').innerText='vault://'+n; const r=await req('/api/get?n='+n); const d=await r.json(); editor.setValue(d.c, -1); tab('edit'); }
173
- async function save() { await req('/api/save', 'POST', {n:curFile, c:editor.getValue()}); tab('file'); }
174
- async function upload() { const fd=new FormData(); fd.append('file', document.getElementById('uI').files[0]); await req('/api/upload', 'POST', fd); load(); }
175
- async function del(n) { if(confirm('Erase?')){ await req('/api/delete/'+n, 'DELETE'); load(); } }
176
- function runBot() { socket.emit('run', document.getElementById('st_f').value || 'main.py'); }
177
- function stopBot() { if(confirm('Stop current process?')) socket.emit('stop'); }
178
- function logout() { localStorage.clear(); location.reload(); }
179
- function pasteCli() { navigator.clipboard.readText().then(t => socket.emit('i', t)); }
180
- window.addEventListener('resize', () => fitAddon?.fit());
181
- </script>
182
  </body>
183
  </html>
184
  """
 
 
 
 
 
1
  PANEL_UI = """
2
  <!DOCTYPE html>
3
+ <html lang="en">
4
  <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>AQSO ADMIN CORE</title>
8
  <script src="https://cdn.tailwindcss.com"></script>
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
10
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
11
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js"></script>
12
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@4.19.0/css/xterm.css">
13
+ <script src="https://cdn.jsdelivr.net/npm/xterm@4.19.0/lib/xterm.js"></script>
14
+ <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.5.0/lib/xterm-addon-fit.js"></script>
15
  <style>
16
+ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap');
17
+ body { font-family: 'JetBrains Mono', monospace; background-color: #0a0a0b; color: #e4e4e7; }
18
+ .glass { background: rgba(18, 18, 20, 0.8); backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.05); }
19
+ ::-webkit-scrollbar { width: 6px; height: 6px; }
20
+ ::-webkit-scrollbar-thumb { background: #27272a; border-radius: 10px; }
21
+ .editor-container { height: 500px; border-radius: 8px; overflow: hidden; }
22
+ #loading-overlay { display: none; background: rgba(0,0,0,0.8); position: fixed; inset: 0; z-index: 9999; }
23
+ .loader { border: 3px solid #18181b; border-top: 3px solid #3b82f6; border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite; }
24
+ @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
 
25
  </style>
26
  </head>
27
+ <body class="p-4 md:p-8">
28
+
29
+ <div id="loading-overlay" class="flex flex-col items-center justify-center">
30
+ <div class="loader mb-4"></div>
31
+ <p class="text-sm text-blue-400 animate-pulse">UPLOADING ENCRYPTED DATA...</p>
32
+ <div class="w-64 h-2 bg-zinc-800 rounded-full mt-4 overflow-hidden">
33
+ <div id="upload-bar" class="h-full bg-blue-500 transition-all duration-300" style="width: 0%"></div>
34
+ </div>
35
+ </div>
36
+
37
+ <div id="login-screen" class="max-w-md mx-auto mt-20 p-8 glass rounded-2xl shadow-2xl">
38
+ <div class="text-center mb-8">
39
+ <h1 class="text-3xl font-bold bg-gradient-to-r from-blue-400 to-emerald-400 bg-clip-text text-transparent">AQSO CORE</h1>
40
+ <p class="text-zinc-500 text-xs mt-2 uppercase tracking-widest">Restricted Access</p>
41
+ </div>
42
+ <div class="space-y-4">
43
+ <input type="text" id="l-user" placeholder="USERNAME" class="w-full bg-zinc-900/50 border border-zinc-800 p-3 rounded-xl focus:outline-none focus:border-blue-500 transition-all">
44
+ <input type="password" id="l-pass" placeholder="PASSWORD" class="w-full bg-zinc-900/50 border border-zinc-800 p-3 rounded-xl focus:outline-none focus:border-blue-500 transition-all">
45
+ <button onclick="login()" class="w-full bg-blue-600 hover:bg-blue-500 py-3 rounded-xl font-bold transition-all transform active:scale-95 shadow-lg shadow-blue-900/20">LOGIN SYSTEM</button>
46
+ </div>
47
+ </div>
48
+
49
+ <div id="panel" class="hidden max-w-7xl mx-auto space-y-6">
50
+ <div class="flex flex-col md:flex-row justify-between items-center gap-4 glass p-4 rounded-2xl">
51
+ <div class="flex items-center gap-3">
52
+ <div class="w-3 h-3 bg-emerald-500 rounded-full animate-ping"></div>
53
+ <h2 class="text-xl font-bold">SYSTEM_OPERATOR: <span id="display-user" class="text-blue-400"></span></h2>
54
+ </div>
55
+ <div class="flex gap-2">
56
+ <button onclick="logout()" class="px-4 py-2 bg-zinc-900 border border-zinc-800 rounded-xl hover:bg-red-900/20 hover:border-red-900 transition-all text-xs">LOGOUT</button>
57
  </div>
58
  </div>
59
 
60
+ <div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
61
+ <div class="lg:col-span-4 glass rounded-2xl p-4 flex flex-col h-[600px]">
62
+ <div class="flex justify-between items-center mb-4 pb-4 border-b border-zinc-800">
63
+ <h3 class="font-bold flex items-center gap-2"><i class="fa-solid fa-folder-tree text-blue-400"></i> WORKSPACE</h3>
64
+ <div class="flex gap-2">
65
+ <label class="cursor-pointer hover:text-blue-400 transition-all"><i class="fa-solid fa-cloud-arrow-up"></i><input type="file" id="f-up" class="hidden" onchange="upload(this.files[0])"></label>
66
+ <button onclick="refresh()" class="hover:text-emerald-400 transition-all"><i class="fa-solid fa-rotate"></i></button>
67
  </div>
68
  </div>
69
+
70
+ <div class="flex items-center gap-2 mb-3 text-[10px] text-zinc-500 bg-zinc-900/50 p-2 rounded-lg">
71
+ <input type="checkbox" id="select-all" onclick="toggleSelectAll(this)" class="rounded bg-zinc-800 border-zinc-700">
72
+ <span class="uppercase">Select All Files</span>
 
73
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
+ <div id="file-list" class="flex-grow overflow-y-auto space-y-1"></div>
76
+
77
+ <div class="mt-4 pt-4 border-t border-zinc-800 grid grid-cols-2 gap-2">
78
+ <button onclick="moveBatch()" class="bg-zinc-800 hover:bg-zinc-700 p-2 rounded-lg text-xs"><i class="fa-solid fa-file-export mr-2"></i>MOVE</button>
79
+ <button onclick="deleteBatch()" class="bg-zinc-800 hover:bg-red-900/30 p-2 rounded-lg text-xs text-red-400"><i class="fa-solid fa-trash mr-2"></i>DELETE</button>
80
+ </div>
81
+ </div>
82
+
83
+ <div class="lg:col-span-8 space-y-6">
84
+ <div class="glass rounded-2xl p-4 flex flex-col h-[600px]">
85
+ <div class="flex justify-between items-center mb-4">
86
+ <h3 id="edit-title" class="text-sm font-bold text-zinc-400">EDITOR_STANDBY</h3>
87
+ <div class="flex gap-3">
88
+ <button onclick="save()" id="btn-save" class="hidden px-4 py-1 bg-blue-600 hover:bg-blue-500 rounded-lg text-xs transition-all">SAVE_CHANGES</button>
89
  </div>
 
90
  </div>
91
+ <div id="editor" class="editor-container"></div>
92
+ </div>
93
  </div>
 
94
  </div>
95
 
96
+ <div class="glass rounded-2xl p-4">
97
+ <div class="flex justify-between items-center mb-3">
98
+ <h3 class="text-xs font-bold text-emerald-400 flex items-center gap-2"><i class="fa-solid fa-terminal text-xs"></i> USER_ROOT_TERMINAL</h3>
99
+ <div id="stats" class="text-[10px] text-zinc-500 flex gap-4"></div>
100
+ </div>
101
+ <div id="terminal" class="rounded-xl overflow-hidden border border-zinc-800"></div>
102
+ </div>
103
+ </div>
 
 
 
 
104
 
105
+ <script>
106
+ let ed = ace.edit("editor");
107
+ ed.setTheme("ace/theme/tomorrow_night_eighties");
108
+ ed.session.setMode("ace/mode/python");
109
+ ed.setOptions({ fontSize: "14px", useWorker: false });
 
 
 
 
 
 
 
110
 
111
+ let term = new Terminal({ theme: { background: '#0a0a0b' }, fontFamily: 'JetBrains Mono', cursorBlink: true });
112
+ let fit = new FitAddon.FitAddon();
113
+ term.loadAddon(fit);
114
+ term.open(document.getElementById('terminal'));
115
+ fit.fit();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
+ let cur_f = null;
118
+ let socket;
119
+
120
+ async function login() {
121
+ let fd = new FormData();
122
+ fd.append("u", document.getElementById('l-user').value);
123
+ fd.append("p", document.getElementById('l-pass').value);
124
+ let r = await fetch("/login_api", { method: "POST", body: fd });
125
+ let d = await r.json();
126
+ if(d.status == "success") {
127
+ localStorage.setItem("token", d.token);
128
+ localStorage.setItem("user", d.user);
129
+ showPanel();
130
+ } else { alert("ACCESS_DENIED: AUTH_FAILED"); }
131
+ }
132
+
133
+ function showPanel() {
134
+ document.getElementById('login-screen').classList.add('hidden');
135
+ document.getElementById('panel').classList.remove('hidden');
136
+ document.getElementById('display-user').innerText = localStorage.getItem("user");
137
+ initSocket();
138
+ refresh();
139
+ }
140
+
141
+ function initSocket() {
142
+ let u = localStorage.getItem("user");
143
+ let t = localStorage.getItem("token");
144
+ socket = io({ query: { token: t, user: u } });
145
+ socket.on('o', d => term.write(d));
146
+ socket.on('stats', d => {
147
+ document.getElementById('stats').innerHTML = `CPU: ${d.cpu}% | RAM: ${d.ram}%`;
148
+ });
149
+ term.onData(d => socket.emit('i', d));
150
+ }
151
+
152
+ async function refresh() {
153
+ let r = await fetch("/api/files", { headers: { "Authorization": localStorage.getItem("token"), "X-User-ID": localStorage.getItem("user") } });
154
+ let d = await r.json();
155
+ let h = "";
156
+ d.forEach(f => {
157
+ let i = f.d ? "fa-folder text-blue-400" : "fa-file-code text-zinc-500";
158
+ h += `<div class="flex items-center gap-3 p-2 hover:bg-zinc-900/50 rounded-lg group transition-all">
159
+ <input type="checkbox" value="${f.n}" class="f-check rounded bg-zinc-800 border-zinc-700">
160
+ <div class="flex-grow flex items-center gap-3 cursor-pointer" onclick="${f.d ? '' : `edit('${f.n}')`}">
161
+ <i class="fa-solid ${i}"></i>
162
+ <span class="text-xs truncate">${f.n}</span>
163
+ </div>
164
+ </div>`;
165
+ });
166
+ document.getElementById('file-list').innerHTML = h;
167
+ }
168
+
169
+ function toggleSelectAll(el) {
170
+ document.querySelectorAll('.f-check').forEach(c => c.checked = el.checked);
171
+ }
172
+
173
+ async function edit(n) {
174
+ cur_f = n;
175
+ let r = await fetch(`/api/get?n=${n}`, { headers: { "Authorization": localStorage.getItem("token"), "X-User-ID": localStorage.getItem("user") } });
176
+ let d = await r.json();
177
+ ed.setValue(d.c, -1);
178
+ document.getElementById('edit-title').innerText = `EDITING: ${n}`;
179
+ document.getElementById('btn-save').classList.remove('hidden');
180
+ }
181
 
182
+ async function save() {
183
+ if(!cur_f) return;
184
+ await fetch("/api/save", {
185
+ method: "POST",
186
+ headers: { "Content-Type": "application/json", "Authorization": localStorage.getItem("token"), "X-User-ID": localStorage.getItem("user") },
187
+ body: JSON.stringify({ n: cur_f, c: ed.getValue() })
188
+ });
189
+ alert("SAVED.");
190
+ }
191
+
192
+ function upload(f) {
193
+ let fd = new FormData();
194
+ fd.append("f", f);
195
+ document.getElementById('loading-overlay').style.display = 'flex';
196
+ let xhr = new XMLHttpRequest();
197
+ xhr.open("POST", "/api/upload", true);
198
+ xhr.setRequestHeader("Authorization", localStorage.getItem("token"));
199
+ xhr.setRequestHeader("X-User-ID", localStorage.getItem("user"));
200
+ xhr.upload.onprogress = e => {
201
+ let p = (e.loaded / e.total) * 100;
202
+ document.getElementById('upload-bar').style.width = p + '%';
203
+ };
204
+ xhr.onload = () => {
205
+ document.getElementById('loading-overlay').style.display = 'none';
206
+ document.getElementById('upload-bar').style.width = '0%';
207
+ refresh();
208
+ };
209
+ xhr.send(fd);
210
+ }
211
+
212
+ async function moveBatch() {
213
+ let n = prompt("TARGET NAME/PATH:");
214
+ if(!n) return;
215
+ for(let c of document.querySelectorAll('.f-check:checked')) {
216
+ await fetch("/api/move", {
217
+ method: "POST",
218
+ headers: { "Content-Type": "application/json", "Authorization": localStorage.getItem("token"), "X-User-ID": localStorage.getItem("user") },
219
+ body: JSON.stringify({ src: c.value, dst: n })
220
+ });
221
  }
222
+ refresh();
223
+ }
224
 
225
+ async function deleteBatch() {
226
+ if(!confirm("PURGE SELECTED FILES?")) return;
227
+ for(let c of document.querySelectorAll('.f-check:checked')) {
228
+ await fetch(`/api/delete/${c.value}`, { method: "DELETE", headers: { "Authorization": localStorage.getItem("token"), "X-User-ID": localStorage.getItem("user") } });
 
 
 
 
 
 
 
 
 
229
  }
230
+ refresh();
231
+ }
232
+
233
+ function logout() { localStorage.clear(); location.reload(); }
234
+ if(localStorage.getItem("token")) showPanel();
235
+ </script>
 
 
 
 
236
  </body>
237
  </html>
238
  """