Clear sysproxy on core death; probe+reconnect; subscription prune; Best ignores soft UDP; Windows tray; Android protocol gate; CI workflows. Co-authored-by: Cursor <cursoragent@cursor.com>
249 lines
11 KiB
HTML
249 lines
11 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Navis</title>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||
<link href="https://fonts.googleapis.com/css2?family=Sora:wght@500;600;700;800&family=Figtree:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||
<link rel="stylesheet" href="app.css" />
|
||
|
||
<script>
|
||
(function () {
|
||
try {
|
||
var key = "navis.theme";
|
||
var saved = localStorage.getItem(key);
|
||
var theme = saved === "dark" || saved === "light"
|
||
? saved
|
||
: (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
|
||
document.documentElement.setAttribute("data-theme", theme);
|
||
} catch (_) {}
|
||
})();
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<main class="shell">
|
||
<div class="update-banner" id="updateBanner">
|
||
<strong id="updateTitle">Доступно обновление</strong>
|
||
<p id="updateNotes"></p>
|
||
<div class="update-actions">
|
||
<button class="action primary" id="updateBtn" type="button">Обновить</button>
|
||
<button class="action secondary" id="skipUpdateBtn" type="button">Пропустить эту версию</button>
|
||
</div>
|
||
</div>
|
||
|
||
<header class="top">
|
||
<div class="logo" aria-hidden="true">
|
||
<svg viewBox="0 0 32 32" fill="none">
|
||
<!-- Bold N -->
|
||
<path fill="#f4fff9" d="M8 25.2V7.6h4.4l7.4 11.2V7.6H24v17.6h-4.4L12.2 14V25.2H8z"/>
|
||
<!-- Plug prongs on left stem -->
|
||
<rect x="9.05" y="4.2" width="1.55" height="3.6" rx=".45" fill="#f4fff9"/>
|
||
<rect x="11.55" y="4.2" width="1.55" height="3.6" rx=".45" fill="#f4fff9"/>
|
||
</svg>
|
||
</div>
|
||
<div class="brand-wrap">
|
||
<div class="brand-row">
|
||
<h1 class="brand">Navis</h1>
|
||
<span class="badge-ver" id="badgeVer">3.8.2</span>
|
||
</div>
|
||
<p class="tagline">Быстрый клиент · Naive · Hy2 · AWG · Xray</p>
|
||
</div>
|
||
<button class="theme-btn" id="themeBtn" type="button" title="Тема" aria-label="Переключить тему">
|
||
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||
<path d="M15.5 3.5a8.5 8.5 0 1 0 5 14.2A7 7 0 1 1 15.5 3.5Z" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/>
|
||
</svg>
|
||
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||
<circle cx="12" cy="12" r="4" stroke="currentColor" stroke-width="1.8"/>
|
||
<path d="M12 2.5v2.2M12 19.3v2.2M2.5 12h2.2M19.3 12h2.2M5.2 5.2l1.6 1.6M17.2 17.2l1.6 1.6M18.8 5.2l-1.6 1.6M6.8 17.2l-1.6 1.6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
|
||
</svg>
|
||
</button>
|
||
</header>
|
||
|
||
<section class="hero" id="hero">
|
||
<div class="status-row">
|
||
<div class="status">
|
||
<span class="dot" id="dot"></span>
|
||
<span id="statusText">Отключено</span>
|
||
</div>
|
||
<span class="proto-chip" id="protoChip">протокол</span>
|
||
</div>
|
||
<div class="hero-actions">
|
||
<button class="action primary cta" id="toggleBtn" type="button">Подключить</button>
|
||
</div>
|
||
<p class="hero-hint" id="heroHint">Выберите профиль и нажмите Подключить</p>
|
||
</section>
|
||
|
||
<section class="section">
|
||
<div class="server-toolbar">
|
||
<div class="section-title"><span>Серверы</span></div>
|
||
<div class="server-actions">
|
||
<button class="mini" id="pingBtn" type="button">Пинг</button>
|
||
<button class="mini accent" id="bestBtn" type="button">Лучший</button>
|
||
<button class="icon-btn" id="addBtn" type="button" title="Новый профиль" style="width:34px;height:34px;font-size:1rem">+</button>
|
||
<button class="icon-btn danger" id="delBtn" type="button" title="Удалить" style="width:34px;height:34px;font-size:1rem">×</button>
|
||
</div>
|
||
</div>
|
||
<label class="auto-best">
|
||
<input id="autoBest" type="checkbox" />
|
||
Авто: пинг + подключение к лучшему
|
||
</label>
|
||
<div class="server-list" id="serverList"></div>
|
||
<select id="profile" hidden></select>
|
||
|
||
<details class="profile-edit" id="profileEdit">
|
||
<summary>Редактировать выбранный / подписка</summary>
|
||
<div class="stack" style="margin-top:8px">
|
||
<div>
|
||
<label class="field" for="name">Название</label>
|
||
<input id="name" type="text" placeholder="Например: DE-1 / Home" spellcheck="false" />
|
||
</div>
|
||
<div>
|
||
<label class="field" for="proxy">Ссылка / конфиг</label>
|
||
<textarea id="proxy" rows="3" placeholder="vless:// · vmess:// · trojan:// · hy2:// · naive+https:// · AWG .conf" spellcheck="false"></textarea>
|
||
</div>
|
||
<div>
|
||
<label class="field" for="subUrl">Подписка</label>
|
||
<div class="sub-bar">
|
||
<input id="subUrl" type="text" placeholder="https://…/sub" spellcheck="false" />
|
||
<button class="icon-btn wide" id="subBtn" type="button" title="Обновить подписку">Обновить</button>
|
||
</div>
|
||
</div>
|
||
<button class="action secondary" id="saveBtn" type="button">Сохранить профиль</button>
|
||
</div>
|
||
</details>
|
||
</section>
|
||
|
||
<div class="row">
|
||
<span>Системный прокси</span>
|
||
<label class="switch">
|
||
<input id="sysproxy" type="checkbox" checked />
|
||
<span class="slider"></span>
|
||
</label>
|
||
</div>
|
||
<div class="row">
|
||
<span>Подключать при запуске</span>
|
||
<label class="switch">
|
||
<input id="bootConnect" type="checkbox" />
|
||
<span class="slider"></span>
|
||
</label>
|
||
</div>
|
||
<div class="row">
|
||
<span>Автопереподключение</span>
|
||
<label class="switch">
|
||
<input id="autoReconnect" type="checkbox" />
|
||
<span class="slider"></span>
|
||
</label>
|
||
</div>
|
||
|
||
<details class="panel" id="logBox">
|
||
<summary>Логи ядра</summary>
|
||
<pre class="log-tail" id="logTail">—</pre>
|
||
<div class="row-actions">
|
||
<button class="action secondary" id="logRefreshBtn" type="button">Обновить лог</button>
|
||
<button class="action secondary" id="probeBtn" type="button">Проверить туннель</button>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="panel hy2" id="hy2Box">
|
||
<summary>Hysteria 2 · BBR / obfuscation</summary>
|
||
<div class="grid2">
|
||
<div>
|
||
<label class="field" for="hy2Congestion">Congestion</label>
|
||
<select id="hy2Congestion">
|
||
<option value="bbr">BBR</option>
|
||
<option value="reno">Reno</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="field" for="hy2Bbr">BBR profile</label>
|
||
<select id="hy2Bbr">
|
||
<option value="standard">standard</option>
|
||
<option value="conservative">conservative</option>
|
||
<option value="aggressive">aggressive</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="field" for="hy2Up">Brutal up</label>
|
||
<input id="hy2Up" type="text" placeholder="пусто = BBR" />
|
||
</div>
|
||
<div>
|
||
<label class="field" for="hy2Down">Brutal down</label>
|
||
<input id="hy2Down" type="text" placeholder="пусто = BBR" />
|
||
</div>
|
||
<div>
|
||
<label class="field" for="hy2Obfs">Obfs</label>
|
||
<select id="hy2Obfs">
|
||
<option value="">нет</option>
|
||
<option value="salamander">salamander</option>
|
||
<option value="gecko">gecko</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="field" for="hy2ObfsPass">Obfs password</label>
|
||
<input id="hy2ObfsPass" type="text" placeholder="пароль" />
|
||
</div>
|
||
<div>
|
||
<label class="field" for="hy2Sni">SNI</label>
|
||
<input id="hy2Sni" type="text" placeholder="cdn.example.com" />
|
||
</div>
|
||
<div>
|
||
<label class="field" for="hy2Pin">pinSHA256</label>
|
||
<input id="hy2Pin" type="text" placeholder="опционально" />
|
||
</div>
|
||
<div>
|
||
<label class="field" for="hy2Hop">Hop interval</label>
|
||
<input id="hy2Hop" type="text" placeholder="30s" />
|
||
</div>
|
||
</div>
|
||
<label class="check"><input id="hy2Insecure" type="checkbox" /> TLS insecure</label>
|
||
<label class="check"><input id="hy2Fast" type="checkbox" /> Fast Open</label>
|
||
<label class="check"><input id="hy2Lazy" type="checkbox" /> Lazy connect</label>
|
||
</details>
|
||
|
||
<details class="panel" id="toolsBox">
|
||
<summary>Сервис · cores, обновления</summary>
|
||
<div class="tools">
|
||
<button class="action secondary" id="updCheckBtn" type="button">Проверить обновление</button>
|
||
<button class="action secondary" id="coreBtn" type="button">Установить cores</button>
|
||
</div>
|
||
</details>
|
||
|
||
<p class="meta" id="meta">Загрузка…</p>
|
||
|
||
<section class="shop" aria-label="Купить подключение">
|
||
<h3>Нужен доступ?</h3>
|
||
<p>Ключи и тарифы на evilfox.win — демо от 30₽.</p>
|
||
<button class="action primary" id="shopBtn" type="button">Открыть магазин</button>
|
||
<button class="shop-link" id="shopLink" type="button">https://evilfox.win/</button>
|
||
</section>
|
||
<p class="ver" id="verLabel">Navis</p>
|
||
<button class="shop-link" id="quitBtn" type="button" hidden style="display:none;margin:8px auto 0;width:auto">Выйти</button>
|
||
</main>
|
||
|
||
<div class="modal-backdrop" id="modal">
|
||
<div class="modal">
|
||
<h2>Новый профиль</h2>
|
||
<div class="stack">
|
||
<div>
|
||
<label class="field" for="newName">Название</label>
|
||
<input id="newName" type="text" placeholder="Server EU" />
|
||
</div>
|
||
<div>
|
||
<label class="field" for="newProxy">Ссылка / конфиг</label>
|
||
<textarea id="newProxy" rows="4" placeholder="vpn:// · awg:// · vless:// · hy2:// · naive · или текст [Interface]" style="min-height:88px;resize:vertical;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.78rem"></textarea>
|
||
<p class="meta" id="modalErr" style="display:none;margin-top:8px;min-height:0"></p>
|
||
</div>
|
||
</div>
|
||
<div class="actions">
|
||
<button class="action secondary" id="cancelNew" type="button">Отмена</button>
|
||
<button class="action primary" id="createNew" type="button">Создать</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="app.js"></script>
|
||
</body>
|
||
</html>
|