feat: Реализован новый веб-интерфейс и бэкенд для управления VPN-клиентом, включая списки серверов, элементы управления прокси и опции конфигурации.

This commit is contained in:
2026-01-15 18:39:39 +03:00
parent c4915389a7
commit 6e97bb9f61
22 changed files with 2412 additions and 2275 deletions

View File

@@ -0,0 +1,37 @@
<!-- Connection Settings -->
<div class="bg-black border border-[#00ff41]/20 p-4 font-mono">
<div class="text-[11px] uppercase font-bold tracking-[0.3em] text-[#00ff41] mb-3 flex items-center gap-2">
<i data-lucide="plug" class="w-4 h-4"></i> Connection_Settings
</div>
<div class="grid grid-cols-1 gap-2">
<!-- HTTP Proxy -->
<div class="flex items-center gap-3 p-3 bg-[#0a0a0a] border border-[#00ff41]/10">
<span class="text-[11px] uppercase opacity-50 text-[#00ff41] w-16">HTTP</span>
<input type="text" id="httpProxyUrl" readonly value="Loading..."
class="flex-grow bg-transparent text-sm text-[#00ff41]/80 focus:outline-none cursor-pointer font-mono"
title="Click to copy" />
<button onclick="copyToClipboard('httpProxyUrl', this)"
class="text-[10px] text-[#00ff41]/50 hover:text-[#00ff41] transition-colors uppercase px-2 py-1 border border-[#00ff41]/20">
Copy
</button>
</div>
<!-- SOCKS5 Proxy -->
<div class="flex items-center gap-3 p-3 bg-[#0a0a0a] border border-[#00ff41]/10">
<span class="text-[11px] uppercase opacity-50 text-[#00ff41] w-16">SOCKS5</span>
<input type="text" id="socks5ProxyUrl" readonly value="Loading..."
class="flex-grow bg-transparent text-sm text-[#00ff41]/80 focus:outline-none cursor-pointer font-mono"
title="Click to copy" />
<button onclick="copyToClipboard('socks5ProxyUrl', this)"
class="text-[10px] text-[#00ff41]/50 hover:text-[#00ff41] transition-colors uppercase px-2 py-1 border border-[#00ff41]/20">
Copy
</button>
</div>
</div>
<div class="mt-2 text-[11px] opacity-40 text-[#00ff41] flex items-center gap-2">
<i data-lucide="info" class="w-3 h-3"></i>
Use these URLs in browser/app proxy settings
</div>
</div>

View File

@@ -0,0 +1,50 @@
<!-- Fallback Proxy Configuration (Expanded) -->
<div id="fallbackSection" class="flex flex-col bg-black border border-[#00ff41]/30 overflow-hidden font-mono">
<div class="bg-[#111] px-5 py-3 border-b border-[#00ff41]/10 flex justify-between items-center shrink-0">
<span class="text-[11px] uppercase font-bold tracking-[0.3em] flex items-center gap-2 text-[#00ff41]">
<i data-lucide="git-branch" class="w-4 h-4"></i> Fallback_Proxy_Settings
</span>
<div class="flex items-center gap-4">
<!-- Enable/Disable Toggle -->
<label class="flex items-center gap-3 cursor-pointer">
<span id="fallbackToggleLabel" class="text-[11px] opacity-50 uppercase text-[#00ff41]">OFF</span>
<div class="relative">
<input type="checkbox" id="fallbackToggle" class="sr-only peer">
<div
class="w-10 h-5 bg-[#1a1a1a] border border-[#00ff41]/20 rounded-full peer-checked:bg-[#00ff41]/20 peer-checked:border-[#00ff41]/50 transition-all">
</div>
<div
class="absolute left-0.5 top-0.5 w-4 h-4 bg-[#00ff41]/30 rounded-full peer-checked:translate-x-5 peer-checked:bg-[#00ff41] transition-all">
</div>
</div>
</label>
<button id="saveFallbackBtn"
class="text-[11px] opacity-50 hover:opacity-100 hover:text-[#00ff41] transition-opacity uppercase px-3 py-1 border border-[#00ff41]/20 hover:border-[#00ff41]/50">Save</button>
</div>
</div>
<div class="p-4 space-y-4">
<!-- Host/Port inputs -->
<div class="grid grid-cols-3 gap-3">
<div class="col-span-2">
<label class="text-[11px] opacity-50 uppercase text-[#00ff41] block mb-1">Host</label>
<input type="text" id="fallbackHost" placeholder="192.168.50.111"
class="w-full bg-[#0a0a0a] border border-[#00ff41]/20 p-3 text-sm text-[#00ff41] focus:outline-none focus:border-[#00ff41]/50 placeholder:text-[#00ff41]/20" />
</div>
<div>
<label class="text-[11px] opacity-50 uppercase text-[#00ff41] block mb-1">Port</label>
<input type="number" id="fallbackPort" placeholder="8080"
class="w-full bg-[#0a0a0a] border border-[#00ff41]/20 p-3 text-sm text-[#00ff41] focus:outline-none focus:border-[#00ff41]/50 placeholder:text-[#00ff41]/20" />
</div>
</div>
<!-- Info -->
<div class="text-[11px] opacity-50 text-[#00ff41] flex items-start gap-2">
<i data-lucide="info" class="w-4 h-4 shrink-0 mt-0.5"></i>
<span>URLTest auto-selects fastest proxy. Re-apply subscription after changes.</span>
</div>
<!-- Status -->
<div id="fallbackStatus" class="text-sm text-[#00ff41]/50 uppercase hidden"></div>
</div>
</div>

View File

@@ -0,0 +1,15 @@
<!-- Footer -->
<footer class="z-30 bg-[#0d0d0d] border-t border-[#00ff41]/10 py-2 mt-auto">
<div
class="max-w-[1400px] mx-auto px-6 flex justify-between items-center text-[10px] uppercase tracking-[0.2em] opacity-40 text-[#00ff41]">
<div class="flex gap-6">
<span>Core: 4.1.0-Release</span>
<span>Proxy: HTTP/8080</span>
</div>
<div class="hidden md:flex gap-6">
<span>AES-256-GCM</span>
<span class="text-[#00ff41] opacity-100 font-bold tracking-normal">SESSION: <span
id="sessionId">...</span></span>
</div>
</div>
</footer>

View File

@@ -0,0 +1,27 @@
<!-- Header -->
<header class="z-30 border-b border-[#00ff41]/20 bg-black/90 backdrop-blur-md sticky top-0">
<div class="max-w-[1400px] mx-auto px-4 md:px-6 py-3 flex justify-between items-center">
<div class="flex items-center gap-3">
<div class="relative p-1.5 border border-[#00ff41]/50 shadow-[0_0_10px_rgba(0,255,65,0.2)] bg-black">
<i data-lucide="terminal" class="w-5 h-5 animate-pulse text-[#00ff41]"></i>
</div>
<div>
<h1 class="text-base font-black tracking-[0.2em] uppercase text-[#00ff41]">
VPN<span class="text-white">_</span>CLIENT
</h1>
<p class="text-[10px] opacity-40 uppercase tracking-widest text-[#00ff41]">Secure Shell v4.2</p>
</div>
</div>
<div class="hidden md:flex items-center gap-6 text-[11px] uppercase">
<div class="flex flex-col items-end border-r border-[#00ff41]/20 pr-6">
<span class="opacity-30 text-[#00ff41]">Status</span>
<span id="headerStatus" class="text-white font-bold text-sm">STANDBY</span>
</div>
<div class="flex flex-col items-end">
<span class="opacity-30 text-[#00ff41]">Traffic_Used</span>
<span id="trafficValue" class="text-blue-400 font-bold text-sm">-- / --</span>
</div>
</div>
</div>
</header>

18
web/components/logs.html Normal file
View File

@@ -0,0 +1,18 @@
<!-- Terminal Logs -->
<div class="flex-grow flex flex-col bg-black border border-[#00ff41]/20 overflow-hidden font-mono min-h-[180px]">
<div class="bg-[#111] px-4 py-2 border-b border-[#00ff41]/10 flex justify-between items-center shrink-0">
<span class="text-[11px] uppercase font-bold tracking-[0.3em] flex items-center gap-2 text-[#00ff41]">
<div class="w-1.5 h-1.5 bg-[#00ff41] rounded-full animate-ping"></div> Logs
</span>
<button id="clearLogs"
class="text-[10px] opacity-30 hover:opacity-100 hover:text-[#00ff41] transition-opacity uppercase">Clear</button>
</div>
<div id="logsContainer"
class="flex-grow p-3 overflow-y-auto custom-scrollbar text-[11px] space-y-1 opacity-80 font-mono">
<div class="flex gap-2">
<span class="opacity-20 text-[#00ff41]">[SYSTEM]</span>
<span class="text-[#00ff41] animate-pulse">_</span>
</div>
</div>
</div>

4
web/components/map.html Normal file
View File

@@ -0,0 +1,4 @@
<!-- Placeholder for World Map Component -->
<div class="hidden p-4 bg-black border border-[#00ff41]/30">
<div class="text-[11px] uppercase opacity-50 text-[#00ff41]">Global_Map_View // Not_Implemented</div>
</div>

View File

@@ -0,0 +1,90 @@
<!-- Proxy Chain Visualization (Expanded) -->
<div id="proxyChainSection" class="bg-black border border-[#00ff41]/30 p-5 font-mono">
<div class="text-[11px] uppercase font-bold tracking-[0.3em] text-[#00ff41] mb-5 flex items-center gap-2">
<i data-lucide="git-branch" class="w-4 h-4"></i> Proxy_Chain_Visualization
</div>
<div id="proxyChain" class="flex items-stretch gap-4 text-sm justify-center py-4">
<!-- You -->
<div class="flex flex-col items-center justify-center gap-2">
<div
class="w-14 h-14 rounded-full border-2 border-[#00ff41] flex items-center justify-center bg-[#00ff41]/10">
<i data-lucide="user" class="w-6 h-6 text-[#00ff41]"></i>
</div>
<span class="uppercase opacity-60 text-[#00ff41] text-[10px]">You</span>
</div>
<!-- Arrow to branch -->
<div class="flex items-center">
<div class="w-8 h-[3px] bg-[#00ff41]"></div>
<i data-lucide="chevron-right" class="w-4 h-4 text-[#00ff41]"></i>
</div>
<!-- Branch: Fallback + VPN -->
<div id="chainBranch" class="flex flex-col gap-3 py-1">
<!-- Fallback branch -->
<div id="chainFallbackRow" class="flex items-center gap-3 transition-all duration-300 hidden">
<div class="w-5 h-[3px] bg-[#00ff41]/50 rounded-full"></div>
<div id="chainFallbackBox"
class="relative w-16 h-12 border-2 border-[#00ff41]/30 flex items-center justify-center bg-[#0a0a0a] transition-all">
<i data-lucide="server" class="w-5 h-5 text-[#00ff41]/50"></i>
<div id="chainFallbackX" class="absolute inset-0 hidden items-center justify-center bg-black/60">
<i data-lucide="x" class="w-6 h-6 text-red-500"></i>
</div>
</div>
<div class="flex flex-col">
<span id="chainFallbackLabel"
class="uppercase text-[10px] opacity-60 text-[#00ff41]">Fallback</span>
<span id="chainFallbackLatency" class="text-xs text-[#00ff41]/50">--ms</span>
</div>
</div>
<!-- VPN branch -->
<div id="chainVPNRow" class="flex items-center gap-3 transition-all duration-300">
<div class="w-5 h-[3px] bg-[#00ff41]/50 rounded-full"></div>
<div id="chainVPNBox"
class="relative w-16 h-12 border-2 border-[#00ff41]/30 flex items-center justify-center bg-[#0a0a0a] transition-all">
<i data-lucide="shield" class="w-5 h-5 text-[#00ff41]/50"></i>
<div id="chainVPNX" class="absolute inset-0 hidden items-center justify-center bg-black/60">
<i data-lucide="x" class="w-6 h-6 text-red-500"></i>
</div>
</div>
<div class="flex flex-col">
<span id="chainVPNLabel" class="uppercase text-[10px] opacity-60 text-[#00ff41]">VPN</span>
<span id="chainVPNLatency" class="text-xs text-[#00ff41]/50">--ms</span>
</div>
</div>
<!-- Direct branch (when proxy disabled) -->
<div id="chainDirectRow" class="flex items-center gap-3 transition-all duration-300 hidden">
<div class="w-5 h-[3px] bg-yellow-500/50 rounded-full"></div>
<div id="chainDirectBox"
class="relative w-16 h-12 border-2 border-yellow-500/50 flex items-center justify-center bg-yellow-500/5 transition-all">
<i data-lucide="zap" class="w-5 h-5 text-yellow-500/70"></i>
</div>
<span class="uppercase text-[10px] opacity-60 text-yellow-500">DIRECT</span>
</div>
</div>
<!-- Arrow from branch -->
<div class="flex items-center">
<i data-lucide="chevron-right" class="w-4 h-4 text-[#00ff41]"></i>
<div class="w-8 h-[3px] bg-[#00ff41]"></div>
</div>
<!-- Internet -->
<div class="flex flex-col items-center justify-center gap-2">
<div
class="w-14 h-14 rounded-full border-2 border-blue-400 flex items-center justify-center bg-blue-400/10">
<i data-lucide="globe" class="w-6 h-6 text-blue-400"></i>
</div>
<span class="uppercase opacity-60 text-blue-400 text-[10px]">Internet</span>
</div>
</div>
<!-- Chain Status -->
<div id="chainStatus"
class="mt-4 text-sm text-center py-2 px-4 bg-[#0a0a0a] border border-[#00ff41]/20 text-[#00ff41] uppercase">
No proxy configured
</div>
</div>

View File

@@ -0,0 +1,14 @@
<!-- Server List as Cards -->
<div class="flex flex-col bg-[#0a0a0a]/50 border border-[#00ff41]/10 overflow-hidden">
<div class="px-4 py-2 border-b border-[#00ff41]/10 bg-black flex justify-between items-center shrink-0">
<span class="text-[11px] uppercase tracking-[0.2em] font-bold text-[#00ff41]">Servers</span>
<span id="serverCount" class="text-[10px] opacity-40 text-[#00ff41]">0 endpoints</span>
</div>
<div id="serverListContainer" class="overflow-y-auto custom-scrollbar p-3 grid grid-cols-3 gap-2 max-h-[280px]">
<!-- Cards populated by JS -->
<div class="col-span-3 text-center py-6 text-[#00ff41]/30 text-xs uppercase">
No_Data // Awaiting_Sync
</div>
</div>
</div>

View File

@@ -0,0 +1,25 @@
<!-- Subscription Input -->
<div class="flex flex-col gap-2 p-4 bg-[#0a0a0a] border border-[#00ff41]/30 relative">
<label class="text-[11px] uppercase tracking-widest opacity-50 text-[#00ff41]">Subscription_URL</label>
<div class="flex gap-2">
<div class="relative flex-grow">
<i data-lucide="link" class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[#00ff41]/40"></i>
<!-- Hidden full URL input -->
<input type="hidden" id="subUrlFull" />
<!-- Masked display input -->
<input type="text" id="subUrlInput" placeholder="https://provider.com/..."
class="w-full bg-black border border-[#00ff41]/20 py-2.5 pl-10 pr-10 text-sm tracking-wider focus:outline-none focus:border-[#00ff41] transition-all placeholder:text-[#00ff41]/20 text-[#00ff41]" />
<!-- Toggle visibility -->
<button id="toggleUrlVisibility" type="button"
class="absolute right-3 top-1/2 -translate-y-1/2 text-[#00ff41]/40 hover:text-[#00ff41] transition-colors"
title="Show/Hide full URL">
<i data-lucide="eye-off" class="w-4 h-4" id="urlEyeIcon"></i>
</button>
</div>
<button id="fetchServersBtn"
class="flex items-center justify-center gap-2 bg-[#00ff41] text-black px-4 py-2.5 text-xs font-black uppercase tracking-widest hover:bg-white hover:shadow-[0_0_15px_rgba(0,255,65,0.4)] transition-all disabled:opacity-50 disabled:cursor-not-allowed">
<i data-lucide="download" class="w-4 h-4" id="fetchIcon"></i>
<span id="fetchText">Sync</span>
</button>
</div>
</div>

View File

@@ -0,0 +1,32 @@
<!-- Master Proxy Toggle + Status -->
<div class="bg-black border-2 border-[#00ff41]/30 p-5 relative">
<div class="flex items-center justify-between gap-6">
<!-- Toggle -->
<div class="flex items-center gap-5">
<label class="big-toggle">
<input type="checkbox" id="masterProxyToggle" checked>
<span class="slider"></span>
</label>
<div>
<div id="proxyModeLabel" class="text-xl font-black tracking-wider text-[#00ff41]">
VPN_MODE
</div>
<div id="proxyModeSubtitle" class="text-[11px] opacity-50 text-[#00ff41] uppercase">
Traffic routed via proxy
</div>
</div>
</div>
<!-- Quick Status -->
<div id="quickStatus" class="text-right hidden md:flex gap-6">
<div>
<div class="text-[11px] opacity-40 uppercase text-[#00ff41]">Uptime</div>
<div id="uptimeDisplay" class="text-lg font-bold text-[#00ff41]">00:00:00</div>
</div>
<div>
<div class="text-[11px] opacity-40 uppercase text-[#00ff41]">Current_IP</div>
<div id="currentIpDisplay" class="text-lg font-bold text-white">---.---.---.---</div>
</div>
</div>
</div>
</div>