Initial commit: VPN Telegram bot (sanitized defaults)
This commit is contained in:
+1087
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,678 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru" data-theme="dark" data-bs-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>VPN Service</title>
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem("ef_theme");
|
||||
if (t !== "light" && t !== "dark") {
|
||||
t = window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark";
|
||||
}
|
||||
document.documentElement.setAttribute("data-theme", t);
|
||||
document.documentElement.setAttribute("data-bs-theme", t);
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute("data-theme", "dark");
|
||||
document.documentElement.setAttribute("data-bs-theme", "dark");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||
<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@400;500;600;700&display=swap" rel="stylesheet" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
<link rel="stylesheet" href="/static/theme-bs.css" />
|
||||
<link rel="stylesheet" href="/static/styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-bg" aria-hidden="true"></div>
|
||||
|
||||
<div id="app">
|
||||
<header class="top app-header">
|
||||
<div class="header-brand">
|
||||
<span class="brand-mark" aria-hidden="true">🦊</span>
|
||||
<div>
|
||||
<p class="eyebrow">VPN Service</p>
|
||||
<h1 id="user-name">Загрузка…</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<div class="balance-pill" id="balance-pill" title="Баланс"><i class="fa-solid fa-wallet"></i> —</div>
|
||||
<button type="button" class="theme-toggle" id="btn-theme-toggle" title="Тема" aria-label="Переключить тему">
|
||||
<i class="fa-solid fa-moon icon-moon"></i>
|
||||
<i class="fa-solid fa-sun icon-sun"></i>
|
||||
</button>
|
||||
<button class="btn btn-icon ghost small-btn hidden" id="btn-logout" type="button" title="Выйти"><i class="fa-solid fa-right-from-bracket"></i></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="auth-panel" class="auth-panel auth-panel--hero hidden">
|
||||
<div class="auth-panel-glow" aria-hidden="true"></div>
|
||||
<div class="auth-brand-row" aria-hidden="true">
|
||||
<span class="auth-fox">🦊</span>
|
||||
</div>
|
||||
<p class="auth-welcome">С возвращением</p>
|
||||
<p class="muted small auth-sub">Войдите, чтобы управлять VPN, балансом и конфигами</p>
|
||||
|
||||
<div class="auth-tabs">
|
||||
<button type="button" class="auth-tab active" data-auth="login">Вход</button>
|
||||
<button type="button" class="auth-tab" data-auth="register">Регистрация</button>
|
||||
</div>
|
||||
|
||||
<form id="form-login" class="auth-form" autocomplete="on">
|
||||
<label>
|
||||
Логин
|
||||
<input name="login" type="text" required minlength="3" maxlength="32" autocomplete="username" placeholder="username" />
|
||||
</label>
|
||||
<label>
|
||||
Пароль
|
||||
<input name="password" type="password" required minlength="6" autocomplete="current-password" placeholder="••••••••" />
|
||||
</label>
|
||||
<button class="btn primary full btn-lg" type="submit"><i class="fa-solid fa-right-to-bracket"></i> Войти в кабинет</button>
|
||||
<button type="button" class="btn ghost small-btn" id="btn-forgot-password">Забыли пароль?</button>
|
||||
</form>
|
||||
|
||||
<form id="form-forgot" class="auth-form hidden" autocomplete="on">
|
||||
<p class="muted small" style="margin:0 0 4px">Укажите email из настроек аккаунта — пришлём ссылку для сброса.</p>
|
||||
<label>
|
||||
Email аккаунта
|
||||
<input name="email" type="email" required placeholder="you@example.com" />
|
||||
</label>
|
||||
<button class="btn primary full" type="submit" id="btn-forgot-submit"><i class="fa-solid fa-paper-plane"></i> Отправить ссылку</button>
|
||||
<button type="button" class="btn ghost small-btn" id="btn-forgot-back">Назад ко входу</button>
|
||||
<p id="forgot-status" class="muted small" style="margin:4px 0 0" role="status"></p>
|
||||
</form>
|
||||
|
||||
<form id="form-reset" class="auth-form hidden" autocomplete="on">
|
||||
<p class="muted small" style="margin:0 0 4px">Придумайте новый пароль (минимум 6 символов).</p>
|
||||
<label>
|
||||
Новый пароль
|
||||
<input name="password" type="password" required minlength="6" autocomplete="new-password" />
|
||||
</label>
|
||||
<button class="btn primary full" type="submit"><i class="fa-solid fa-key"></i> Сохранить пароль</button>
|
||||
<p id="reset-status" class="muted small" style="margin:4px 0 0" role="status"></p>
|
||||
</form>
|
||||
|
||||
<form id="form-register" class="auth-form hidden" autocomplete="on">
|
||||
<label>
|
||||
Логин
|
||||
<input name="login" type="text" required minlength="3" maxlength="32" pattern="[A-Za-z0-9_]{3,32}" autocomplete="username" placeholder="username" />
|
||||
</label>
|
||||
<label>
|
||||
Имя <span class="muted small">(необязательно)</span>
|
||||
<input name="full_name" type="text" maxlength="64" autocomplete="name" placeholder="Как к вам обращаться" />
|
||||
</label>
|
||||
<label>
|
||||
Пароль
|
||||
<input name="password" type="password" required minlength="6" autocomplete="new-password" placeholder="мин. 6 символов" />
|
||||
</label>
|
||||
<label class="auth-check">
|
||||
<input name="auto_renew" type="checkbox" checked />
|
||||
<span>Включить автопродление с баланса <span class="muted small">(можно отключить в любой момент)</span></span>
|
||||
</label>
|
||||
<label class="auth-check">
|
||||
<input name="accept_terms" type="checkbox" required />
|
||||
<span>
|
||||
Принимаю
|
||||
<a href="/offer" target="_blank" rel="noopener">оферту</a>,
|
||||
<a href="/privacy" target="_blank" rel="noopener">политику ПДн</a>,
|
||||
<a href="/rules" target="_blank" rel="noopener">правила сайта</a>,
|
||||
<a href="/vpn-usage" target="_blank" rel="noopener">правила VPN</a>,
|
||||
<a href="/delivery" target="_blank" rel="noopener">доставку</a>
|
||||
и
|
||||
<a href="/refund" target="_blank" rel="noopener">возврат</a>
|
||||
</span>
|
||||
</label>
|
||||
<button class="btn primary full btn-lg" type="submit"><i class="fa-solid fa-user-plus"></i> Создать аккаунт</button>
|
||||
</form>
|
||||
|
||||
<div class="auth-divider"><span>или</span></div>
|
||||
<div class="auth-alt-actions">
|
||||
<button type="button" class="btn secondary full" id="btn-auth-qr"><i class="fa-solid fa-qrcode"></i> Войти по QR (Telegram)</button>
|
||||
<button type="button" class="btn secondary full" id="btn-auth-passkey"><i class="fa-solid fa-fingerprint"></i> Войти с Passkey</button>
|
||||
</div>
|
||||
<div id="qr-auth-box" class="qr-auth-box hidden">
|
||||
<p class="muted small">
|
||||
Откройте на телефоне <strong>сканер QR-кодов</strong> (камера или приложение) и наведите на код ниже —
|
||||
откроется Telegram, подтвердите вход.
|
||||
</p>
|
||||
<img id="qr-auth-img" class="qr-auth-img" alt="QR-код для входа через Telegram" />
|
||||
<p class="muted small" id="qr-auth-status">Ожидание подтверждения в Telegram…</p>
|
||||
<a id="qr-auth-link" class="link-accent small" href="#" target="_blank" rel="noopener">Или открыть ссылку в Telegram</a>
|
||||
<button type="button" class="btn ghost small-btn" id="btn-qr-cancel">Отмена</button>
|
||||
</div>
|
||||
<div id="telegram-login-wrap" class="telegram-login-wrap">
|
||||
<p class="muted small">Быстрый вход через Telegram</p>
|
||||
<div id="telegram-login-slot"></div>
|
||||
</div>
|
||||
<p class="auth-foot muted small site-legal-links">
|
||||
<a href="/contacts" class="link-accent">Контакты</a>
|
||||
· <a href="/status" class="link-accent">Статус серверов</a>
|
||||
· <a href="/delivery" class="link-accent">Доставка</a>
|
||||
· <a href="/refund" class="link-accent">Возврат</a>
|
||||
· <a href="/offer" class="link-accent">Договор оферты</a>
|
||||
· <a href="/privacy" class="link-accent">Политика обработки персональных данных</a>
|
||||
· <a href="/help" class="link-accent">Помощь</a>
|
||||
· <a href="/support" class="link-accent">Поддержка</a>
|
||||
<br/>
|
||||
<a href="/cookies" class="link-accent">Настройки cookie</a>
|
||||
· <a href="/rules" class="link-accent">Правила сайта</a>
|
||||
· <a href="/vpn-usage" class="link-accent">Правила использования VPN</a>
|
||||
· <a href="/admin" class="link-accent">Админка</a>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<div id="guest-banner" class="guest-banner hidden">
|
||||
<span class="guest-banner-icon" aria-hidden="true">🦊</span>
|
||||
<span>Войдите — увидите баланс, подписку и сможете купить тариф.</span>
|
||||
</div>
|
||||
|
||||
<div id="cabinet" class="hidden cabinet">
|
||||
<aside class="cabinet-sidebar" aria-label="Меню кабинета">
|
||||
<div class="cabinet-sidebar-brand">
|
||||
<span class="cabinet-sidebar-kicker">Кабинет</span>
|
||||
<strong class="cabinet-sidebar-title">Разделы</strong>
|
||||
</div>
|
||||
<nav class="tabs tabs--sidebar" id="tabs" role="tablist">
|
||||
<button class="tab active" data-tab="home" type="button" role="tab">
|
||||
<span class="tab-icon" aria-hidden="true"><i class="fa-solid fa-house"></i></span>
|
||||
<span class="tab-label">Главная</span>
|
||||
</button>
|
||||
<button class="tab" data-tab="balance" type="button" role="tab">
|
||||
<span class="tab-icon" aria-hidden="true"><i class="fa-solid fa-wallet"></i></span>
|
||||
<span class="tab-label">Баланс</span>
|
||||
</button>
|
||||
<button class="tab" data-tab="configs" type="button" role="tab">
|
||||
<span class="tab-icon" aria-hidden="true"><i class="fa-solid fa-shield-halved"></i></span>
|
||||
<span class="tab-label">Конфиги</span>
|
||||
</button>
|
||||
<button class="tab" data-tab="extras" type="button" role="tab">
|
||||
<span class="tab-icon" aria-hidden="true"><i class="fa-solid fa-chart-column"></i></span>
|
||||
<span class="tab-label">Допы</span>
|
||||
</button>
|
||||
<button class="tab" data-tab="account" type="button" role="tab">
|
||||
<span class="tab-icon" aria-hidden="true"><i class="fa-solid fa-user"></i></span>
|
||||
<span class="tab-label">Аккаунт</span>
|
||||
</button>
|
||||
<button class="tab" data-tab="tariffs" type="button" role="tab">
|
||||
<span class="tab-icon" aria-hidden="true"><i class="fa-solid fa-tags"></i></span>
|
||||
<span class="tab-label">Тарифы</span>
|
||||
</button>
|
||||
<button class="tab" data-tab="clients" type="button" role="tab">
|
||||
<span class="tab-icon" aria-hidden="true"><i class="fa-solid fa-mobile-screen"></i></span>
|
||||
<span class="tab-label">Клиенты</span>
|
||||
</button>
|
||||
<button class="tab" data-tab="servers" type="button" role="tab">
|
||||
<span class="tab-icon" aria-hidden="true"><i class="fa-solid fa-server"></i></span>
|
||||
<span class="tab-label">Серверы</span>
|
||||
</button>
|
||||
<button class="tab" data-tab="faq" type="button" role="tab">
|
||||
<span class="tab-icon" aria-hidden="true"><i class="fa-solid fa-circle-question"></i></span>
|
||||
<span class="tab-label">FAQ</span>
|
||||
</button>
|
||||
<button class="tab" data-tab="tickets" type="button" role="tab">
|
||||
<span class="tab-icon" aria-hidden="true"><i class="fa-solid fa-ticket"></i></span>
|
||||
<span class="tab-label">Тикеты</span>
|
||||
</button>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<div class="cabinet-main">
|
||||
<main class="main-panels">
|
||||
<section class="panel active" id="tab-home">
|
||||
<div class="home-greeting" id="home-greeting">
|
||||
<p class="home-hello" id="home-hello">Привет!</p>
|
||||
<p class="muted small home-hello-sub" id="home-hello-sub">Здесь всё для безопасного интернета</p>
|
||||
</div>
|
||||
<article class="card onboarding-card hidden" id="onboarding-card">
|
||||
<div class="onboarding-badge">Старт за 2 минуты</div>
|
||||
<h2 class="onboarding-title">Начните с тарифа</h2>
|
||||
<p class="muted small onboarding-lead">
|
||||
База уже включена: <strong>1000 ГБ</strong> и <strong>10 устройств</strong>.
|
||||
Потом просто вставьте ссылку в приложение.
|
||||
</p>
|
||||
<ol class="steps-list steps-list--friendly">
|
||||
<li><span class="step-num">1</span><span>Выберите тариф и оплатите с баланса</span></li>
|
||||
<li><span class="step-num">2</span><span>Скачайте клиент во вкладке «Клиенты»</span></li>
|
||||
<li><span class="step-num">3</span><span>Скопируйте ссылку подписки и вставьте в приложение</span></li>
|
||||
</ol>
|
||||
<button type="button" class="btn primary full btn-lg" id="btn-onboarding-tariffs"><i class="fa-solid fa-tags"></i> Выбрать тариф</button>
|
||||
</article>
|
||||
<article class="card card-hero" id="sub-card">
|
||||
<div class="card-head">
|
||||
<span class="card-icon card-icon--shield" aria-hidden="true"><i class="fa-solid fa-shield-halved"></i></span>
|
||||
<div class="card-head-text">
|
||||
<div class="card-title-row">
|
||||
<h2>Подписка</h2>
|
||||
<span id="sub-badge" class="status-badge status-badge--off">Нет тарифа</span>
|
||||
</div>
|
||||
<p id="sub-status" class="sub-status muted">Загрузка…</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metrics-row" id="metrics-row">
|
||||
<div id="traffic-box" class="metric-chip hidden">
|
||||
<div class="metric-chip-top">
|
||||
<span class="metric-label">Трафик</span>
|
||||
<span id="traffic-label" class="metric-value">—</span>
|
||||
</div>
|
||||
<div class="traffic-bar"><div id="traffic-fill" class="traffic-fill"></div></div>
|
||||
<p id="traffic-left" class="muted small metric-hint"></p>
|
||||
</div>
|
||||
<div id="devices-box" class="metric-chip hidden">
|
||||
<div class="metric-chip-top">
|
||||
<span class="metric-label">Устройства</span>
|
||||
<span id="devices-label" class="metric-value">—</span>
|
||||
</div>
|
||||
<p id="devices-warn" class="alert-inline hidden"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="extras-billing-box" class="traffic-box extras-billing-box hidden">
|
||||
<div class="traffic-head">
|
||||
<span>Доп. опции</span>
|
||||
<span id="extras-fee-label">—</span>
|
||||
</div>
|
||||
<p id="extras-billing-text" class="muted small"></p>
|
||||
</div>
|
||||
|
||||
<div id="auto-renew-box" class="traffic-box auto-renew-box">
|
||||
<label class="cab-switch" for="auto-renew-toggle">
|
||||
<input type="checkbox" id="auto-renew-toggle" />
|
||||
<span class="cab-switch-slider" aria-hidden="true"></span>
|
||||
<span class="cab-switch-text">
|
||||
<strong>Автопродление</strong>
|
||||
<small id="auto-renew-hint">При достаточном балансе тариф продлится сам</small>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="sub-url-wrap hidden" id="sub-url-wrap">
|
||||
<p class="muted small url-label">Ссылка подписки — вставьте в приложение</p>
|
||||
<code id="sub-url"></code>
|
||||
<button class="btn secondary full" id="copy-sub" type="button"><i class="fa-solid fa-copy"></i> Скопировать ссылку</button>
|
||||
</div>
|
||||
|
||||
<div class="quick-actions" id="quick-actions">
|
||||
<button class="quick-action hidden" id="btn-renew-go" type="button">
|
||||
<span class="qa-icon" aria-hidden="true"><i class="fa-solid fa-rotate"></i></span>
|
||||
<span class="qa-text"><strong>Продлить</strong><small>с баланса</small></span>
|
||||
</button>
|
||||
<button class="quick-action hidden" id="btn-traffic-go" type="button">
|
||||
<span class="qa-icon" aria-hidden="true"><i class="fa-solid fa-gauge-high"></i></span>
|
||||
<span class="qa-text"><strong>Трафик</strong><small>+500 ГБ · 50 ₽</small></span>
|
||||
</button>
|
||||
<button class="quick-action hidden" id="btn-devices-go" type="button">
|
||||
<span class="qa-icon" aria-hidden="true"><i class="fa-solid fa-mobile-screen-button"></i></span>
|
||||
<span class="qa-text"><strong>Устройства</strong><small>+1 слот · 50 ₽</small></span>
|
||||
</button>
|
||||
<button class="quick-action hidden" id="btn-wg-go" type="button">
|
||||
<span class="qa-icon" aria-hidden="true"><i class="fa-solid fa-shield-halved"></i></span>
|
||||
<span class="qa-text"><strong>WireGuard</strong><small>до 10 конфигов</small></span>
|
||||
</button>
|
||||
<button class="quick-action hidden" id="btn-awg-go" type="button">
|
||||
<span class="qa-icon" aria-hidden="true"><i class="fa-solid fa-user-secret"></i></span>
|
||||
<span class="qa-text"><strong>AmneziaWG</strong><small>AWG 2.0</small></span>
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
<article class="card tip card-steps" id="howto-card">
|
||||
<div class="card-head compact">
|
||||
<span class="card-icon"><i class="fa-solid fa-rocket"></i></span>
|
||||
<div>
|
||||
<h2>Как подключиться</h2>
|
||||
<p class="muted small">Коротко для новичков</p>
|
||||
</div>
|
||||
</div>
|
||||
<ol class="steps-list steps-list--friendly">
|
||||
<li><span class="step-num">1</span><span>Купите или продлите тариф</span></li>
|
||||
<li><span class="step-num">2</span><span>Скачайте клиент во вкладке «Клиенты»</span></li>
|
||||
<li><span class="step-num">3</span><span>Вставьте ссылку подписки в приложение</span></li>
|
||||
</ol>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="panel" id="tab-balance">
|
||||
<p class="section-lead muted small">Пополнение и история операций</p>
|
||||
<article class="card tip" id="web-topup-card">
|
||||
<div class="card-head compact">
|
||||
<span class="card-icon"><i class="fa-solid fa-credit-card"></i></span>
|
||||
<div>
|
||||
<h2>Пополнить баланс</h2>
|
||||
<p class="muted small" id="web-topup-hint">От 10 до 3000 ₽ за одну оплату</p>
|
||||
</div>
|
||||
</div>
|
||||
<label class="topup-amount-label">
|
||||
Сумма, ₽
|
||||
<input
|
||||
id="web-topup-amount"
|
||||
type="number"
|
||||
min="10"
|
||||
max="3000"
|
||||
step="1"
|
||||
value="100"
|
||||
inputmode="numeric"
|
||||
/>
|
||||
</label>
|
||||
<div id="web-topup-presets" class="topup-presets"></div>
|
||||
<div id="web-topup-providers" class="stack stack-tight">
|
||||
<p class="muted small">Загрузка способов оплаты…</p>
|
||||
</div>
|
||||
<p id="web-topup-result" class="muted small hidden"></p>
|
||||
</article>
|
||||
<article class="card tip" id="stars-topup-card">
|
||||
<div class="card-head compact">
|
||||
<span class="card-icon"><i class="fa-solid fa-star"></i></span>
|
||||
<div>
|
||||
<h2>Telegram Stars</h2>
|
||||
<p class="muted small" id="stars-topup-hint">Пополнение прямо в Telegram (Web и приложение)</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="stars-packs" class="stack stack-tight"></div>
|
||||
<p id="stars-web-only" class="muted small hidden">
|
||||
Откройте кабинет из Telegram (кнопка «Кабинет» у бота), чтобы оплатить Stars.
|
||||
</p>
|
||||
</article>
|
||||
<article class="card tip" id="topup-code-card">
|
||||
<div class="card-head compact">
|
||||
<span class="card-icon"><i class="fa-solid fa-ticket"></i></span>
|
||||
<div>
|
||||
<h2>Пополнение по коду</h2>
|
||||
<p class="muted small" id="topup-code-hint">
|
||||
Карта, СБП и др. — на странице покупки 40+ способов оплаты. После оплаты введите код ниже.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<form id="form-topup-code" class="auth-form">
|
||||
<label>
|
||||
Код пополнения
|
||||
<input name="code" type="text" required placeholder="XXXX-XXXX-XXXX-XXXX" autocomplete="off" class="input-mono" />
|
||||
</label>
|
||||
<button class="btn primary full" type="submit"><i class="fa-solid fa-check"></i> Активировать код</button>
|
||||
</form>
|
||||
<a id="topup-code-buy" class="btn ghost full hidden" href="#" target="_blank" rel="noopener">🛒 Купить код</a>
|
||||
</article>
|
||||
<article class="card tip payment-info-card">
|
||||
<div class="card-head compact">
|
||||
<span class="card-icon"><i class="fa-solid fa-circle-info"></i></span>
|
||||
<div>
|
||||
<h2>Способы оплаты</h2>
|
||||
<p class="muted small">Пополнение на сайте и в боте · тарифы — с баланса</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="pay-methods-list">
|
||||
<li>
|
||||
<span class="pay-badge pay-badge--crypto">На сайте</span>
|
||||
<span><strong>Карта / СБП</strong> (Lava / AnyPay), <strong>крипта</strong> (Heleket / Crypto Bot) — от 10 до 3000 ₽ за раз.</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="pay-badge pay-badge--code">Код</span>
|
||||
<span>Опционально: купите <strong>код пополнения</strong> и активируйте выше.</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="pay-badge">Stars</span>
|
||||
<span>В Telegram Mini App — пополнение звёздами.</span>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
<article class="card tip balance-history-card" id="balance-history-card">
|
||||
<div class="card-head compact">
|
||||
<span class="card-icon"><i class="fa-solid fa-clock-rotate-left"></i></span>
|
||||
<div>
|
||||
<h2>История баланса</h2>
|
||||
<p class="muted small" id="balance-history-meta">Последние операции</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul id="transactions-list" class="tx-list tx-list--compact">
|
||||
<li class="muted small">Войдите, чтобы видеть историю</li>
|
||||
</ul>
|
||||
<div id="transactions-pager" class="tx-pager hidden" aria-label="Страницы истории">
|
||||
<button type="button" class="btn ghost small-btn" id="tx-prev" disabled>←</button>
|
||||
<span class="tx-pager-label muted small" id="tx-page-label">1 / 1</span>
|
||||
<button type="button" class="btn ghost small-btn" id="tx-next" disabled>→</button>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="panel" id="tab-configs">
|
||||
<p class="section-lead muted small">WireGuard и AmneziaWG конфиги</p>
|
||||
<article class="card tip hidden" id="wg-configs-card">
|
||||
<div class="card-head compact">
|
||||
<span class="card-icon"><i class="fa-solid fa-shield-halved"></i></span>
|
||||
<div>
|
||||
<h2>WireGuard</h2>
|
||||
<p class="muted small" id="wg-configs-hint">До 10 конфигов при активной подписке</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="wg-buy-box" class="auth-form stack stack-tight hidden">
|
||||
<label class="full-width">
|
||||
Сервер
|
||||
<select id="wg-server-select"></select>
|
||||
</label>
|
||||
<label class="full-width">
|
||||
Название <span class="muted small">(необязательно)</span>
|
||||
<input id="wg-remark" type="text" maxlength="80" placeholder="Телефон / ноут" />
|
||||
</label>
|
||||
<button type="button" class="btn primary full" id="btn-wg-buy"><i class="fa-solid fa-plus"></i> Создать конфиг</button>
|
||||
</div>
|
||||
<div id="wg-configs-list" class="stack stack-tight" style="margin-top:12px"></div>
|
||||
</article>
|
||||
<article class="card tip hidden" id="awg-configs-card">
|
||||
<div class="card-head compact">
|
||||
<span class="card-icon"><i class="fa-solid fa-user-secret"></i></span>
|
||||
<div>
|
||||
<h2>AmneziaWG 2.0</h2>
|
||||
<p class="muted small" id="awg-configs-hint">Обфусцированный WireGuard · клиент AmneziaVPN</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="awg-buy-box" class="auth-form stack stack-tight hidden">
|
||||
<label class="full-width">
|
||||
Сервер
|
||||
<select id="awg-server-select"></select>
|
||||
</label>
|
||||
<label class="full-width">
|
||||
Название <span class="muted small">(необязательно)</span>
|
||||
<input id="awg-remark" type="text" maxlength="80" placeholder="Телефон / ноут" />
|
||||
</label>
|
||||
<button type="button" class="btn primary full" id="btn-awg-buy"><i class="fa-solid fa-plus"></i> Создать AWG-конфиг</button>
|
||||
</div>
|
||||
<div id="awg-configs-list" class="stack stack-tight" style="margin-top:12px"></div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="panel" id="tab-extras">
|
||||
<p class="section-lead muted small">Дополнительный трафик и устройства</p>
|
||||
<article class="card tip hidden" id="traffic-packs-card">
|
||||
<div class="card-head compact">
|
||||
<span class="card-icon"><i class="fa-solid fa-chart-line"></i></span>
|
||||
<div>
|
||||
<h2>Пакеты трафика</h2>
|
||||
<p class="muted small">База 1000 ГБ · +500 ГБ = <strong>50 ₽/мес</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="traffic-packs" class="stack stack-tight"></div>
|
||||
</article>
|
||||
<article class="card tip hidden" id="device-packs-card">
|
||||
<div class="card-head compact">
|
||||
<span class="card-icon"><i class="fa-solid fa-mobile-screen"></i></span>
|
||||
<div>
|
||||
<h2>Доп. устройства</h2>
|
||||
<p class="muted small">База 10 · +1 слот = <strong>50 ₽/мес</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="device-packs" class="stack stack-tight"></div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="panel" id="tab-account">
|
||||
<p class="section-lead muted small">Почта, уведомления, Passkey и устройства</p>
|
||||
<article class="card security-card" id="security-card">
|
||||
<div class="card-head">
|
||||
<span class="card-icon" aria-hidden="true"><i class="fa-solid fa-lock"></i></span>
|
||||
<div class="card-head-text">
|
||||
<h2>Безопасность и уведомления</h2>
|
||||
<p class="muted small">Email, Passkey и вход с другого устройства</p>
|
||||
</div>
|
||||
</div>
|
||||
<form id="form-email" class="auth-form">
|
||||
<label>
|
||||
Email для важных писем
|
||||
<input id="account-email" name="email" type="email" maxlength="120" placeholder="you@example.com" autocomplete="email" />
|
||||
</label>
|
||||
<button class="btn secondary" type="submit">Сохранить email</button>
|
||||
</form>
|
||||
<div class="passkey-block">
|
||||
<label class="cab-switch" for="notify-tg-toggle">
|
||||
<input type="checkbox" id="notify-tg-toggle" checked />
|
||||
<span class="cab-switch-slider" aria-hidden="true"></span>
|
||||
<span class="cab-switch-text"><strong>Уведомления в Telegram</strong></span>
|
||||
</label>
|
||||
<label class="cab-switch" for="notify-email-toggle">
|
||||
<input type="checkbox" id="notify-email-toggle" checked />
|
||||
<span class="cab-switch-slider" aria-hidden="true"></span>
|
||||
<span class="cab-switch-text"><strong>Уведомления на email</strong></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="passkey-block">
|
||||
<div class="passkey-head">
|
||||
<strong>Рефералка</strong>
|
||||
<button type="button" class="btn ghost small-btn" id="btn-ref-copy">Копировать</button>
|
||||
</div>
|
||||
<p class="muted small" id="referral-link">—</p>
|
||||
<p class="muted small" id="referral-bonus-hint"></p>
|
||||
</div>
|
||||
<div class="passkey-block">
|
||||
<div class="passkey-head">
|
||||
<strong>Пробный период</strong>
|
||||
<button type="button" class="btn primary small-btn" id="btn-trial">Активировать</button>
|
||||
</div>
|
||||
<p class="muted small" id="trial-hint">Бесплатные дни для новых аккаунтов</p>
|
||||
</div>
|
||||
<div class="passkey-block">
|
||||
<div class="passkey-head">
|
||||
<strong>Устройства (HWID)</strong>
|
||||
<button type="button" class="btn ghost small-btn" id="btn-hwid-refresh">Обновить</button>
|
||||
</div>
|
||||
<ul id="hwid-list" class="passkey-list muted small"><li>—</li></ul>
|
||||
</div>
|
||||
<div class="passkey-block">
|
||||
<div class="passkey-head">
|
||||
<strong>Сессии</strong>
|
||||
<button type="button" class="btn ghost small-btn" id="btn-logout-all">Выйти везде кроме сюда</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="passkey-block">
|
||||
<div class="passkey-head">
|
||||
<strong>Passkey</strong>
|
||||
<button type="button" class="btn primary small-btn" id="btn-passkey-add">Добавить</button>
|
||||
</div>
|
||||
<ul id="passkey-list" class="passkey-list muted small">
|
||||
<li>Загрузка…</li>
|
||||
</ul>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="panel" id="tab-tariffs">
|
||||
<p class="section-lead muted small">Оплата с баланса. Пополнить можно в разделе «Баланс»: карта, СБП или крипта (10–3000 ₽).</p>
|
||||
<div id="tariffs-list" class="stack"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel" id="tab-clients">
|
||||
<p class="section-lead muted small">Скачайте приложение под ваше устройство</p>
|
||||
<div id="clients-list" class="stack"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel" id="tab-servers">
|
||||
<div class="servers-head card-toolbar">
|
||||
<p id="servers-summary" class="muted">Статус нод</p>
|
||||
<button class="btn secondary small-btn" id="refresh-servers" type="button">↻ Обновить</button>
|
||||
</div>
|
||||
<div id="servers-list" class="stack"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel" id="tab-faq">
|
||||
<p class="section-lead muted small">Ответы на частые вопросы</p>
|
||||
<div id="faq-list" class="stack"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel" id="tab-tickets">
|
||||
<div class="tickets-toolbar">
|
||||
<p class="section-lead muted small" id="tickets-lead">Обращения в поддержку</p>
|
||||
<button class="btn secondary small-btn" id="btn-ticket-new" type="button">+ Новый</button>
|
||||
</div>
|
||||
<form id="ticket-create-form" class="ticket-create card hidden">
|
||||
<label>
|
||||
Тема
|
||||
<input name="subject" type="text" maxlength="100" required placeholder="Кратко о проблеме" />
|
||||
</label>
|
||||
<label>
|
||||
Сообщение
|
||||
<textarea name="body" maxlength="2000" rows="4" required placeholder="Опишите, что случилось…"></textarea>
|
||||
</label>
|
||||
<div class="ticket-create-actions">
|
||||
<button type="button" class="btn ghost small-btn" id="btn-ticket-cancel">Отмена</button>
|
||||
<button type="submit" class="btn primary small-btn">Создать</button>
|
||||
</div>
|
||||
</form>
|
||||
<div id="tickets-list" class="stack"></div>
|
||||
<div id="ticket-thread" class="ticket-thread card hidden">
|
||||
<div class="ticket-thread-head">
|
||||
<button type="button" class="btn ghost small-btn" id="btn-ticket-back">← Назад</button>
|
||||
<div>
|
||||
<h3 id="ticket-thread-title">Тикет</h3>
|
||||
<p id="ticket-thread-meta" class="muted small"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ticket-messages" class="ticket-messages"></div>
|
||||
<form id="ticket-reply-form" class="ticket-reply">
|
||||
<textarea name="body" maxlength="2000" rows="3" required placeholder="Ваш ответ…"></textarea>
|
||||
<div class="ticket-reply-actions">
|
||||
<button type="button" class="btn ghost small-btn" id="btn-ticket-close">Закрыть</button>
|
||||
<button type="submit" class="btn primary small-btn">Отправить</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="site-footer muted small">
|
||||
<a href="/contacts">Контакты</a>
|
||||
· <a href="/status">Статус серверов</a>
|
||||
· <a href="/delivery">Доставка</a>
|
||||
· <a href="/refund">Возврат</a>
|
||||
· <a href="/offer">Договор оферты</a>
|
||||
· <a href="/privacy">Политика обработки персональных данных</a>
|
||||
· <a href="/help">Помощь</a>
|
||||
· <a href="/support">Поддержка</a>
|
||||
<br/>
|
||||
<a href="/cookies">Настройки cookie</a>
|
||||
· <a href="/rules">Правила сайта</a>
|
||||
· <a href="/vpn-usage">Правила использования VPN</a>
|
||||
</footer>
|
||||
|
||||
<div id="toast" class="toast hidden" role="status"></div>
|
||||
|
||||
<dialog id="wg-qr-dialog" class="wg-qr-dialog">
|
||||
<form method="dialog" class="wg-qr-dialog-inner">
|
||||
<h3 id="wg-qr-dialog-title">QR WireGuard</h3>
|
||||
<p class="muted small">Отсканируйте в приложении с поддержкой подписки</p>
|
||||
<img id="wg-qr-dialog-img" class="wg-qr-dialog-img" alt="QR код" />
|
||||
<code id="wg-qr-dialog-url" class="wg-sub-url"></code>
|
||||
<div class="wg-config-actions" style="justify-content:center;margin-top:12px">
|
||||
<button type="button" class="btn ghost small-btn" id="btn-wg-qr-copy">Копировать ссылку</button>
|
||||
<button type="submit" class="btn primary small-btn">Закрыть</button>
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
||||
<script src="/static/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,86 @@
|
||||
/* Bootstrap bridge for VPN Service light/dark */
|
||||
|
||||
html[data-bs-theme="dark"],
|
||||
html[data-theme="dark"] {
|
||||
--bs-body-bg: #0a0f0d;
|
||||
--bs-body-color: #eaf3ee;
|
||||
--bs-secondary-color: #8fa59a;
|
||||
--bs-tertiary-bg: #101714;
|
||||
--bs-border-color: rgba(180, 220, 200, 0.12);
|
||||
--bs-primary: #3dcf9a;
|
||||
--bs-primary-rgb: 61, 207, 154;
|
||||
--bs-link-color: #3dcf9a;
|
||||
--bs-link-hover-color: #6ee0b4;
|
||||
--bs-focus-ring-color: rgba(61, 207, 154, 0.3);
|
||||
--bs-card-bg: #141c18;
|
||||
--bs-card-border-color: rgba(180, 220, 200, 0.12);
|
||||
--bs-font-sans-serif: "Sora", system-ui, sans-serif;
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
html[data-bs-theme="light"],
|
||||
html[data-theme="light"] {
|
||||
--bs-body-bg: #eef3f0;
|
||||
--bs-body-color: #12201a;
|
||||
--bs-secondary-color: #5c7167;
|
||||
--bs-tertiary-bg: #e4ebe7;
|
||||
--bs-border-color: rgba(20, 40, 30, 0.1);
|
||||
--bs-primary: #0d9f6e;
|
||||
--bs-primary-rgb: 13, 159, 110;
|
||||
--bs-link-color: #0d9f6e;
|
||||
--bs-link-hover-color: #0a7a54;
|
||||
--bs-focus-ring-color: rgba(13, 159, 110, 0.28);
|
||||
--bs-card-bg: #ffffff;
|
||||
--bs-card-border-color: rgba(20, 40, 30, 0.1);
|
||||
--bs-font-sans-serif: "Sora", system-ui, sans-serif;
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--bs-body-bg);
|
||||
color: var(--bs-body-color);
|
||||
font-family: var(--bs-font-sans-serif);
|
||||
}
|
||||
|
||||
#app .card,
|
||||
#admin-app .card {
|
||||
--bs-card-bg: transparent;
|
||||
--bs-card-border-width: 0;
|
||||
--bs-card-spacer-y: 0;
|
||||
--bs-card-spacer-x: 0;
|
||||
}
|
||||
|
||||
#app .btn,
|
||||
#admin-app .btn {
|
||||
--bs-btn-font-weight: 600;
|
||||
text-transform: none;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
#app .form-control,
|
||||
#app .form-select,
|
||||
#admin-app .form-control,
|
||||
#admin-app .form-select {
|
||||
background-color: var(--bg-2, #101714);
|
||||
border-color: var(--line, rgba(180, 220, 200, 0.12));
|
||||
color: var(--text, inherit);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
#app .form-control:focus,
|
||||
#app .form-select:focus,
|
||||
#admin-app .form-control:focus,
|
||||
#admin-app .form-select:focus {
|
||||
background-color: var(--bg-2, #101714);
|
||||
border-color: var(--line-strong);
|
||||
color: var(--text, inherit);
|
||||
box-shadow: 0 0 0 0.2rem var(--accent-soft, rgba(61, 207, 154, 0.15));
|
||||
}
|
||||
|
||||
.tab-icon .fa-solid,
|
||||
.card-icon .fa-solid,
|
||||
.admin-nav-ico .fa-solid,
|
||||
.qa-icon .fa-solid,
|
||||
.btn .fa-solid {
|
||||
line-height: 1;
|
||||
}
|
||||
Reference in New Issue
Block a user