Files
sing-misc/prototype/index.html
NeoMody a3f0a3871c Redesign prototype to match Android app structure
4-tab layout (Dashboard/Proxies/Profiles/Tools) with dark theme.
New pages: rules.html (Custom Rules + Rule Sets tabs), profiles.html,
proxies.html, tools.html, logs.html. Removed: home, dashboard, nodes,
status, dns, firewall. Design system: #0F172A bg, #4F52B4 accent,
Inter font, card-based, no emoji icons.
2026-04-05 00:36:27 +08:00

149 lines
6.5 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Sing - Dashboard</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="app-shell">
<div class="page-content" id="page">
<!-- Page Header -->
<div class="page-header">
<h1>Dashboard</h1>
<div class="header-right">
<div class="status-dot online" id="statusDot"></div>
<span class="status-label online" id="statusLabel">Online</span>
</div>
</div>
<!-- Outbound Mode -->
<div class="section-header mt-8">
<svg class="icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3v18M3 12l9-9 9 9"/></svg>
<span>Outbound Mode</span>
</div>
<div class="card">
<div class="chip-row" id="modeChips">
<div class="chip active" data-mode="0">Rule-based</div>
<div class="chip" data-mode="1">Global proxy</div>
<div class="chip" data-mode="2">Direct</div>
</div>
</div>
<!-- Connect / Disconnect -->
<div class="toggle-card connected mt-12" id="toggleCard" onclick="toggleVPN()">
<div class="toggle-icon" id="toggleIcon">&#9632;</div>
<div class="toggle-info">
<div class="toggle-title" id="toggleTitle">Disconnect</div>
<div class="toggle-subtitle" id="toggleSubtitle">Tokyo-VLESS-Reality</div>
</div>
</div>
<!-- Traffic -->
<div class="section-header mt-16">
<svg class="icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
<span>Traffic</span>
</div>
<div class="card">
<div class="traffic-grid">
<div class="traffic-col">
<div class="arrow up">&#8593;</div>
<div class="speed" id="upSpeed">12.4 KB/s</div>
<div class="total" id="upTotal">1.24 GB</div>
</div>
<div class="traffic-col">
<div class="arrow down">&#8595;</div>
<div class="speed" id="downSpeed">156.8 KB/s</div>
<div class="total" id="downTotal">8.92 GB</div>
</div>
</div>
</div>
<!-- Connection / Node info grid -->
<div class="info-grid mt-12">
<div class="card">
<div class="section-header">
<svg class="icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
<span>Node</span>
</div>
<div style="font-size:15px;font-weight:500;margin-top:4px;" id="nodeNameInfo">Tokyo-VLESS-Reality</div>
<div style="font-size:12px;color:var(--text-secondary);margin-top:2px;" id="nodeProtoInfo">VLESS + Reality</div>
<div style="font-family:var(--font-mono);font-size:13px;color:var(--accent);margin-top:4px;" id="uptimeInfo">01:23:45</div>
</div>
<div class="card" style="cursor:pointer;" onclick="location.href='connections.html'">
<div class="section-header">
<svg class="icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/><circle cx="6" cy="6" r="1"/><circle cx="6" cy="18" r="1"/></svg>
<span>Connections</span>
</div>
<div style="font-family:var(--font-mono);font-size:28px;font-weight:600;color:var(--accent);margin-top:4px;" id="connCount">42</div>
<div style="font-size:12px;color:var(--accent);margin-top:2px;">View all &#8250;</div>
</div>
</div>
</div>
<!-- Bottom Tab Bar -->
<nav class="tab-bar">
<a href="index.html" class="active">
<span class="tab-icon"><svg viewBox="0 0 24 24"><path d="M4 13h6a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1zm0 8h6a1 1 0 0 0 1-1v-4a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1zm10 0h6a1 1 0 0 0 1-1v-8a1 1 0 0 0-1-1h-6a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1zm0-18v4a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1h-6a1 1 0 0 0-1 1z"/></svg></span>
Dashboard
</a>
<a href="proxies.html">
<span class="tab-icon"><svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></svg></span>
Proxies
</a>
<a href="profiles.html">
<span class="tab-icon"><svg viewBox="0 0 24 24"><path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/></svg></span>
Profiles
</a>
<a href="tools.html">
<span class="tab-icon"><svg viewBox="0 0 24 24"><path d="M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1.4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z"/></svg></span>
Tools
</a>
</nav>
</div>
<script>
// VPN toggle
let connected = true;
function toggleVPN() {
connected = !connected;
const card = document.getElementById('toggleCard');
const icon = document.getElementById('toggleIcon');
const title = document.getElementById('toggleTitle');
const subtitle = document.getElementById('toggleSubtitle');
const dot = document.getElementById('statusDot');
const label = document.getElementById('statusLabel');
if (connected) {
card.classList.add('connected');
icon.innerHTML = '\u25A0'; // stop square
title.textContent = 'Disconnect';
subtitle.textContent = 'Tokyo-VLESS-Reality';
dot.className = 'status-dot online';
label.className = 'status-label online';
label.textContent = 'Online';
} else {
card.classList.remove('connected');
icon.innerHTML = '\u25B6'; // play triangle
title.textContent = 'Connect';
subtitle.textContent = 'Not connected';
dot.className = 'status-dot offline';
label.className = 'status-label offline';
label.textContent = 'Offline';
}
}
// Outbound mode chips
document.getElementById('modeChips').addEventListener('click', function(e) {
const chip = e.target.closest('.chip');
if (!chip) return;
this.querySelectorAll('.chip').forEach(c => c.classList.remove('active'));
chip.classList.add('active');
});
</script>
</body>
</html>