Update ui_templates.py
Browse files- 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
|
| 8 |
<head>
|
| 9 |
-
<meta charset="UTF-8">
|
| 10 |
-
<
|
| 11 |
-
<
|
| 12 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 13 |
-
<
|
| 14 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
<style>
|
| 16 |
-
@import url('https://fonts.googleapis.com/css2?family=
|
| 17 |
-
body { font-family: 'JetBrains Mono', monospace;
|
| 18 |
-
.
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
.
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
.custom-scroll::-webkit-scrollbar-thumb { background: #00f3ff; }
|
| 26 |
</style>
|
| 27 |
</head>
|
| 28 |
-
<body class="
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
</div>
|
| 38 |
</div>
|
| 39 |
|
| 40 |
-
<div
|
| 41 |
-
<
|
| 42 |
-
<div class="flex items-center
|
| 43 |
-
<
|
| 44 |
-
<div class="
|
| 45 |
-
<
|
| 46 |
-
<
|
| 47 |
</div>
|
| 48 |
</div>
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
<
|
| 52 |
-
<
|
| 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 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
</div>
|
| 88 |
-
<div id="editor" class="flex-1"></div>
|
| 89 |
</div>
|
| 90 |
-
|
|
|
|
| 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 |
-
<
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 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 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 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 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 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 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
}
|
|
|
|
|
|
|
| 157 |
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 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 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 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 |
"""
|