991 lines
81 KiB
HTML
991 lines
81 KiB
HTML
<!DOCTYPE html>
|
||||
|
|
<html>
|
|||
|
|
<head>
|
|||
|
|
<meta charset="utf-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|||
|
|
<script src="./support.js"></script>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<x-dc>
|
|||
|
|
<helmet>
|
|||
|
|
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
|||
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|||
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous" />
|
|||
|
|
<link href="https://fonts.googleapis.com/css2?family=Commissioner:wght@300;400;500;600&family=Unbounded:wght@500;600&display=swap" rel="stylesheet" />
|
|||
|
|
<script>(function(){if(window.__veilixI18nSrc)return;window.__veilixI18nSrc="./i18n.js?v="+Date.now().toString(36)+Math.random().toString(36).slice(2,8);var s=document.createElement("script");s.src=window.__veilixI18nSrc;document.head.appendChild(s);})();</script>
|
|||
|
|
<style>
|
|||
|
|
:root{
|
|||
|
|
--bg: oklch(99% 0.005 296);
|
|||
|
|
--surface: oklch(100% 0 0);
|
|||
|
|
--surface-2: oklch(97.5% 0.01 296);
|
|||
|
|
--ink: oklch(24% 0.04 296);
|
|||
|
|
--ink-2: oklch(45% 0.03 296);
|
|||
|
|
--ink-3: oklch(60% 0.025 296);
|
|||
|
|
--border: oklch(92% 0.014 296);
|
|||
|
|
--accent: oklch(45% 0.17 296);
|
|||
|
|
--accent-hover: oklch(38% 0.17 296);
|
|||
|
|
--accent-soft: oklch(95.5% 0.028 296);
|
|||
|
|
--on-accent: oklch(99% 0.01 296);
|
|||
|
|
--glow-1: oklch(86% 0.1 296);
|
|||
|
|
--glow-2: oklch(89% 0.09 266);
|
|||
|
|
--glow-3: oklch(91% 0.08 332);
|
|||
|
|
--veil: oklch(100% 0 0 / 0.55);
|
|||
|
|
--warn: oklch(62% 0.14 62);
|
|||
|
|
--shadow: 0 1px 2px oklch(24% 0.04 296 / 0.05), 0 12px 32px -12px oklch(24% 0.04 296 / 0.14);
|
|||
|
|
}
|
|||
|
|
:root[data-veilix-theme="dark"]{
|
|||
|
|
--bg: oklch(17% 0.022 296);
|
|||
|
|
--surface: oklch(21% 0.026 296);
|
|||
|
|
--surface-2: oklch(24% 0.03 296);
|
|||
|
|
--ink: oklch(96% 0.01 296);
|
|||
|
|
--ink-2: oklch(79% 0.02 296);
|
|||
|
|
--ink-3: oklch(63% 0.025 296);
|
|||
|
|
--border: oklch(31% 0.032 296);
|
|||
|
|
--accent: oklch(74% 0.15 296);
|
|||
|
|
--accent-hover: oklch(80% 0.13 296);
|
|||
|
|
--accent-soft: oklch(27% 0.05 296);
|
|||
|
|
--on-accent: oklch(17% 0.03 296);
|
|||
|
|
--glow-1: oklch(45% 0.16 296);
|
|||
|
|
--glow-2: oklch(40% 0.14 266);
|
|||
|
|
--glow-3: oklch(42% 0.13 332);
|
|||
|
|
--veil: oklch(100% 0 0 / 0.07);
|
|||
|
|
--warn: oklch(78% 0.13 62);
|
|||
|
|
--shadow: 0 1px 2px oklch(10% 0.02 296 / 0.4), 0 16px 40px -16px oklch(8% 0.02 296 / 0.7);
|
|||
|
|
}
|
|||
|
|
*{ box-sizing: border-box; }
|
|||
|
|
input, textarea, select{ font-size: 16px; }
|
|||
|
|
[hidden]{ display: none !important; }
|
|||
|
|
body{ margin:0; background: var(--bg); color: var(--ink); font-family:"Commissioner", system-ui, sans-serif; -webkit-font-smoothing: antialiased; }
|
|||
|
|
a{ color: var(--accent); text-decoration: none; }
|
|||
|
|
a:hover{ color: var(--accent-hover); }
|
|||
|
|
input::placeholder{ color: var(--ink-3); }
|
|||
|
|
</style>
|
|||
|
|
</helmet>
|
|||
|
|
|
|||
|
|
<template id="__bundler_thumbnail" data-bg-color="#efeaf8">
|
|||
|
|
<svg viewBox="0 0 1200 800" xmlns="http://www.w3.org/2000/svg">
|
|||
|
|
<rect x="480" y="290" width="150" height="150" rx="48" fill="#5b32c9" />
|
|||
|
|
<rect x="570" y="360" width="150" height="150" rx="48" fill="#ffffff" fill-opacity="0.62" stroke="#5b32c9" stroke-width="6" />
|
|||
|
|
</svg>
|
|||
|
|
</template>
|
|||
|
|
<div style="background: var(--bg); color: var(--ink); font-family: 'Commissioner', system-ui, sans-serif; letter-spacing: -0.01em; min-height: 100vh;">
|
|||
|
|
|
|||
|
|
<div hidden="{{ appOff }}" style="display: grid; grid-template-rows: 1fr auto; min-height: 100vh;">
|
|||
|
|
<div style="display: flex; align-items: center; justify-content: center; padding: 24px;">
|
|||
|
|
<div style="width: 100%; max-width: 420px; padding: 36px; border-radius: 24px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 26px;">
|
|||
|
|
<span style="position: relative; width: 26px; height: 26px; display: block; flex: none;">
|
|||
|
|
<span style="position: absolute; left: 0; top: 3px; width: 19px; height: 19px; border-radius: 6px; background: linear-gradient(140deg, var(--accent), color-mix(in oklab, var(--accent) 55%, var(--glow-3))); display: block;"></span>
|
|||
|
|
<span style="position: absolute; right: 0; bottom: 3px; width: 19px; height: 19px; border-radius: 6px; background: var(--veil); border: 1px solid color-mix(in oklab, var(--accent) 35%, transparent); display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
<span style="font-family: 'Unbounded', 'Commissioner', sans-serif; font-weight: 600; font-size: 16px; letter-spacing: -0.02em;">Вейликс</span>
|
|||
|
|
</div>
|
|||
|
|
<h1 style="margin: 0 0 10px; font-size: 26px; font-weight: 600; letter-spacing: -0.03em;">Вход в кабинет</h1>
|
|||
|
|
<p style="margin: 0 0 22px; font-size: 15px; line-height: 1.55; color: var(--ink-2); font-weight: 300;">Введите почту, пришлём одноразовый код. Отдельной регистрации нет — кабинет создастся сам, если вы здесь впервые.</p>
|
|||
|
|
<div hidden="{{ otpSent }}" style="display: grid; gap: 10px;">
|
|||
|
|
<input type="email" placeholder="you@example.com" style="height: 50px; padding: 0 14px; border-radius: 12px; border: 1px solid var(--border); background: var(--bg); color: var(--ink); font-family: inherit; font-size: 15px; width: 100%;" />
|
|||
|
|
<button type="button" onClick="{{ sendOtp }}" style="height: 50px; border-radius: 12px; border: 0; background: var(--accent); color: var(--on-accent); font-family: inherit; font-size: 16px; font-weight: 500; cursor: pointer;" style-hover="background: var(--accent-hover);">Прислать код</button>
|
|||
|
|
</div>
|
|||
|
|
<div hidden="{{ otpNotSent }}" style="display: grid; gap: 10px;">
|
|||
|
|
<input type="text" inputmode="numeric" placeholder="6 цифр" style="height: 50px; padding: 0 14px; border-radius: 12px; border: 1px solid var(--border); background: var(--bg); color: var(--ink); font-family: inherit; font-size: 17px; letter-spacing: 0.28em; font-variant-numeric: tabular-nums; width: 100%;" />
|
|||
|
|
<button type="button" onClick="{{ signIn }}" style="height: 50px; border-radius: 12px; border: 0; background: var(--accent); color: var(--on-accent); font-family: inherit; font-size: 16px; font-weight: 500; cursor: pointer;" style-hover="background: var(--accent-hover);">Войти</button>
|
|||
|
|
<button type="button" onClick="{{ backToEmail }}" style="justify-self: start; border: 0; background: transparent; color: var(--ink-3); font-family: inherit; font-size: 14px; cursor: pointer; padding: 4px 0;">Другая почта</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<footer style="display: flex; flex-wrap: wrap; align-items: center; gap: 12px 20px; padding: 14px 24px; border-top: 1px solid var(--border); font-size: 13px; color: var(--ink-3);">
|
|||
|
|
<span>© 2026 Вейликс</span>
|
|||
|
|
<a href="#legal" style="color: var(--ink-3);" style-hover="color: var(--ink);">Условия</a>
|
|||
|
|
<a href="#legal" style="color: var(--ink-3);" style-hover="color: var(--ink);">Конфиденциальность</a>
|
|||
|
|
<a href="Support.dc.html" style="color: var(--ink-3);" style-hover="color: var(--ink);">Поддержка</a>
|
|||
|
|
<div style="margin-left: auto; display: flex; align-items: center; gap: 8px;">
|
|||
|
|
<div style="display: flex; width: max-content; padding: 3px; border-radius: 10px; border: 1px solid var(--border); background: var(--surface);">
|
|||
|
|
<button type="button" onClick="{{ setRu }}" style="padding: 6px 11px; border: 0; border-radius: 7px; background: {{ ruBg }}; color: {{ ruInk }}; font-family: inherit; font-size: 12px; cursor: pointer;">RU</button>
|
|||
|
|
<button type="button" onClick="{{ setEn }}" style="padding: 6px 11px; border: 0; border-radius: 7px; background: {{ enBg }}; color: {{ enInk }}; font-family: inherit; font-size: 12px; cursor: pointer;">EN</button>
|
|||
|
|
</div>
|
|||
|
|
<div style="display: flex; width: max-content; padding: 3px; border-radius: 10px; border: 1px solid var(--border); background: var(--surface);">
|
|||
|
|
<button type="button" onClick="{{ setLight }}" title="Светлая тема" style="display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: 0; border-radius: 7px; background: {{ lightBg }}; color: {{ lightInk }}; cursor: pointer;">
|
|||
|
|
<span style="position: relative; width: 16px; height: 16px; display: block;">
|
|||
|
|
<span style="position: absolute; left: 3.5px; top: 3.5px; width: 9px; height: 9px; border-radius: 50%; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; top: 0; width: 16px; height: 16px; border-radius: 50%; border: 1.5px solid currentColor; opacity: 0.45; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ setDark }}" title="Тёмная тема" style="display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: 0; border-radius: 7px; background: {{ darkBg }}; color: {{ darkInk }}; cursor: pointer;">
|
|||
|
|
<span style="width: 16px; height: 16px; border-radius: 50%; box-shadow: inset -5px -2px 0 0 currentColor; display: block;"></span>
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ setSystem }}" title="Как в системе" style="display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: 0; border-radius: 7px; background: {{ systemBg }}; color: {{ systemInk }}; cursor: pointer;">
|
|||
|
|
<span style="width: 16px; height: 16px; border-radius: 50%; border: 1.5px solid currentColor; background: linear-gradient(90deg, currentColor 50%, transparent 50%); display: block;"></span>
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</footer>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div hidden="{{ loginOff }}" style="display: grid; grid-template-columns: {{ shellCols }}; min-height: 100vh;">
|
|||
|
|
|
|||
|
|
<div hidden="{{ topbarOff }}" style="position: sticky; top: 0; z-index: 30; display: flex; align-items: center; gap: 10px; padding: 12px 16px; background: color-mix(in oklab, var(--bg) 85%, transparent); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); border-bottom: 1px solid var(--border);">
|
|||
|
|
<a href="Main.dc.html" style="display: flex; align-items: center; gap: 10px; color: var(--ink);">
|
|||
|
|
<span style="position: relative; width: 24px; height: 24px; display: block; flex: none;">
|
|||
|
|
<span style="position: absolute; left: 0; top: 3px; width: 18px; height: 18px; border-radius: 6px; background: linear-gradient(140deg, var(--accent), color-mix(in oklab, var(--accent) 55%, var(--glow-3))); display: block;"></span>
|
|||
|
|
<span style="position: absolute; right: 0; bottom: 3px; width: 18px; height: 18px; border-radius: 6px; background: var(--veil); border: 1px solid color-mix(in oklab, var(--accent) 35%, transparent); display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
<span style="font-family: 'Unbounded', 'Commissioner', sans-serif; font-weight: 600; font-size: 15px; letter-spacing: -0.02em;">Вейликс</span>
|
|||
|
|
</a>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<aside hidden="{{ asideOff }}" style="display: flex; flex-direction: column; gap: 24px; padding: 22px 16px; border-right: 1px solid var(--border); background: var(--surface-2); position: sticky; top: 0; height: 100vh;">
|
|||
|
|
<a href="Main.dc.html" style="display: flex; align-items: center; gap: 10px; padding: 4px 8px; color: var(--ink);">
|
|||
|
|
<span style="position: relative; width: 24px; height: 24px; display: block; flex: none;">
|
|||
|
|
<span style="position: absolute; left: 0; top: 3px; width: 18px; height: 18px; border-radius: 6px; background: linear-gradient(140deg, var(--accent), color-mix(in oklab, var(--accent) 55%, var(--glow-3))); display: block;"></span>
|
|||
|
|
<span style="position: absolute; right: 0; bottom: 3px; width: 18px; height: 18px; border-radius: 6px; background: var(--veil); border: 1px solid color-mix(in oklab, var(--accent) 35%, transparent); display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
<span style="font-family: 'Unbounded', 'Commissioner', sans-serif; font-weight: 600; font-size: 15px; letter-spacing: -0.02em;">Вейликс</span>
|
|||
|
|
</a>
|
|||
|
|
|
|||
|
|
<nav style="display: grid; gap: 4px;">
|
|||
|
|
<button type="button" onClick="{{ goHome }}" style="display: flex; align-items: center; gap: 12px; padding: 11px 12px; border-radius: 12px; border: 0; background: {{ homeBg }}; color: {{ homeInk }}; font-family: inherit; font-size: 15px; text-align: left; cursor: pointer;" style-hover="background: var(--surface);">
|
|||
|
|
<span style="position: relative; width: 18px; height: 18px; flex: none; display: block;">
|
|||
|
|
<span style="position: absolute; left: 0; top: 0; width: 8px; height: 8px; border-radius: 2px; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; right: 0; top: 0; width: 8px; height: 8px; border-radius: 2px; background: currentColor; opacity: 0.45; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; bottom: 0; width: 8px; height: 8px; border-radius: 2px; background: currentColor; opacity: 0.45; display: block;"></span>
|
|||
|
|
<span style="position: absolute; right: 0; bottom: 0; width: 8px; height: 8px; border-radius: 2px; background: currentColor; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
Главная
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ goKeys }}" style="display: flex; align-items: center; gap: 12px; padding: 11px 12px; border-radius: 12px; border: 0; background: {{ keysBg }}; color: {{ keysInk }}; font-family: inherit; font-size: 15px; text-align: left; cursor: pointer;" style-hover="background: var(--surface);">
|
|||
|
|
<span style="position: relative; width: 18px; height: 18px; flex: none; display: block;">
|
|||
|
|
<span style="position: absolute; left: 0; top: 2px; width: 18px; height: 4px; border-radius: 2px; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; top: 8px; width: 18px; height: 4px; border-radius: 2px; background: currentColor; opacity: 0.6; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; top: 14px; width: 18px; height: 4px; border-radius: 2px; background: currentColor; opacity: 0.3; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
Список ключей
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ goBuy }}" style="display: flex; align-items: center; gap: 12px; padding: 11px 12px; border-radius: 12px; border: 0; background: {{ buyBg }}; color: {{ buyInk }}; font-family: inherit; font-size: 15px; text-align: left; cursor: pointer;" style-hover="background: var(--surface);">
|
|||
|
|
<span style="position: relative; width: 18px; height: 18px; flex: none; display: block;">
|
|||
|
|
<span style="position: absolute; left: 7px; top: 0; width: 4px; height: 18px; border-radius: 2px; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; top: 7px; width: 18px; height: 4px; border-radius: 2px; background: currentColor; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
Купить ключ
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ goBilling }}" style="display: flex; align-items: center; gap: 12px; padding: 11px 12px; border-radius: 12px; border: 0; background: {{ billingBg }}; color: {{ billingInk }}; font-family: inherit; font-size: 15px; text-align: left; cursor: pointer;" style-hover="background: var(--surface);">
|
|||
|
|
<span style="position: relative; width: 18px; height: 18px; flex: none; display: block;">
|
|||
|
|
<span style="position: absolute; left: 0; top: 2px; width: 18px; height: 14px; border-radius: 4px; border: 2px solid currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; top: 6px; width: 18px; height: 3px; background: currentColor; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
Счёт и платежи
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ goRef }}" style="display: flex; align-items: center; gap: 12px; padding: 11px 12px; border-radius: 12px; border: 0; background: {{ refBg }}; color: {{ refInk }}; font-family: inherit; font-size: 15px; text-align: left; cursor: pointer;" style-hover="background: var(--surface);">
|
|||
|
|
<span style="position: relative; width: 18px; height: 18px; flex: none; display: block;">
|
|||
|
|
<span style="position: absolute; left: 0; top: 5px; width: 8px; height: 8px; border-radius: 50%; border: 2px solid currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; right: 0; top: 0; width: 8px; height: 8px; border-radius: 50%; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; right: 2px; bottom: 0; width: 8px; height: 8px; border-radius: 50%; background: currentColor; opacity: 0.45; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
Реферальная программа
|
|||
|
|
</button>
|
|||
|
|
</nav>
|
|||
|
|
|
|||
|
|
<div style="margin-top: auto; display: grid; gap: 14px; padding: 0 4px;">
|
|||
|
|
<a href="Support.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 11px 8px; border-radius: 12px; color: var(--ink-2); font-size: 15px;" style-hover="background: var(--surface); color: var(--ink);">
|
|||
|
|
<span style="position: relative; width: 18px; height: 18px; flex: none; display: block;">
|
|||
|
|
<span style="position: absolute; left: 1px; top: 1px; width: 16px; height: 16px; border-radius: 8px 8px 0 0; border: 2px solid currentColor; border-bottom: 0; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; top: 8px; width: 5px; height: 9px; border-radius: 2px; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; right: 0; top: 8px; width: 5px; height: 9px; border-radius: 2px; background: currentColor; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
Поддержка
|
|||
|
|
</a>
|
|||
|
|
<div>
|
|||
|
|
<div style="font-size: 12px; color: var(--ink-3); margin-bottom: 6px; padding: 0 4px;">Тема</div>
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; align-items: center; gap: 6px; width: max-content; max-width: 100%; align-self: start; padding: 3px; border-radius: 12px; border: 1px solid var(--border); background: var(--surface);">
|
|||
|
|
<button type="button" onClick="{{ setLight }}" title="Светлая тема" style="display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; border: 0; border-radius: 9px; background: {{ lightBg }}; color: {{ lightInk }}; cursor: pointer;">
|
|||
|
|
<span style="position: relative; width: 18px; height: 18px; display: block;">
|
|||
|
|
<span style="position: absolute; left: 4px; top: 4px; width: 10px; height: 10px; border-radius: 50%; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; top: 0; width: 18px; height: 18px; border-radius: 50%; border: 1.5px solid currentColor; opacity: 0.45; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ setDark }}" title="Тёмная тема" style="display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; border: 0; border-radius: 9px; background: {{ darkBg }}; color: {{ darkInk }}; cursor: pointer;">
|
|||
|
|
<span style="width: 18px; height: 18px; border-radius: 50%; box-shadow: inset -6px -2px 0 0 currentColor; display: block;"></span>
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ setSystem }}" title="Как в системе" style="display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; border: 0; border-radius: 9px; background: {{ systemBg }}; color: {{ systemInk }}; cursor: pointer;">
|
|||
|
|
<span style="width: 18px; height: 18px; border-radius: 50%; border: 1.5px solid currentColor; background: linear-gradient(90deg, currentColor 50%, transparent 50%); display: block;"></span>
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div>
|
|||
|
|
<div style="font-size: 12px; color: var(--ink-3); margin-bottom: 6px; padding: 0 4px;">Язык</div>
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; width: max-content; max-width: 100%; align-self: start; padding: 3px; border-radius: 12px; border: 1px solid var(--border); background: var(--surface);">
|
|||
|
|
<button type="button" onClick="{{ setRu }}" style="padding: 8px 14px; border: 0; border-radius: 9px; background: {{ ruBg }}; color: {{ ruInk }}; font-family: inherit; font-size: 13px; cursor: pointer;">RU</button>
|
|||
|
|
<button type="button" onClick="{{ setEn }}" style="padding: 8px 14px; border: 0; border-radius: 9px; background: {{ enBg }}; color: {{ enInk }}; font-family: inherit; font-size: 13px; cursor: pointer;">EN</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<button type="button" onClick="{{ signOut }}" style="justify-self: start; border: 0; background: transparent; color: var(--ink-3); font-family: inherit; font-size: 13px; cursor: pointer; padding: 4px 8px;">Выйти · anna@example.com</button>
|
|||
|
|
</div>
|
|||
|
|
</aside>
|
|||
|
|
|
|||
|
|
<main style="padding: {{ mainPad }}; max-width: 960px;">
|
|||
|
|
|
|||
|
|
<div hidden="{{ homeOff }}" style="display: grid; gap: 28px;">
|
|||
|
|
<div>
|
|||
|
|
<h1 style="margin: 0 0 6px; font-size: 30px; font-weight: 600; letter-spacing: -0.03em;">Ваши ключи</h1>
|
|||
|
|
<p style="margin: 0; font-size: 15px; color: var(--ink-2); font-weight: 300;">Два активных тарифа, каждый со своим индивидуальным IP.</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="display: grid; gap: 12px;">
|
|||
|
|
<sc-for list="{{ keys }}" as="key" hint-placeholder-count="2">
|
|||
|
|
<button type="button" onClick="{{ key.open }}" style="display: grid; gap: 16px; padding: 24px; border-radius: 20px; border: 1px solid var(--border); background: var(--surface); box-shadow: var(--shadow); color: var(--ink); font-family: inherit; text-align: left; cursor: pointer; width: 100%;" style-hover="border-color: var(--accent);">
|
|||
|
|
<span style="display: flex; flex-wrap: wrap; align-items: center; gap: 12px;">
|
|||
|
|
<span style="font-size: 19px; font-weight: 500; letter-spacing: -0.02em;">{{ key.title }}</span>
|
|||
|
|
<span style="padding: 4px 10px; border-radius: 8px; background: {{ key.badgeBg }}; color: {{ key.badgeInk }}; font-size: 12px;">{{ key.badge }}</span>
|
|||
|
|
<span style="margin-left: auto; font-size: 14px; color: var(--ink-3); font-variant-numeric: tabular-nums;">{{ key.ip }}</span>
|
|||
|
|
</span>
|
|||
|
|
<span style="display: flex; flex-wrap: wrap; gap: 8px 28px; font-size: 14px; color: var(--ink-2);">
|
|||
|
|
<span>Действует до {{ key.until }}</span>
|
|||
|
|
<span>{{ key.devices }}</span>
|
|||
|
|
<span>{{ key.payment }}</span>
|
|||
|
|
</span>
|
|||
|
|
</button>
|
|||
|
|
</sc-for>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px; padding: 24px; border-radius: 20px; background: var(--surface-2); border: 1px dashed var(--border);">
|
|||
|
|
<div style="display: grid; gap: 4px;">
|
|||
|
|
<div style="font-size: 17px; font-weight: 500;">Нужен ещё один IP или другая страна</div>
|
|||
|
|
<div style="font-size: 14px; color: var(--ink-2); font-weight: 300;">Новый ключ появится здесь же, оплата отдельная.</div>
|
|||
|
|
</div>
|
|||
|
|
<button type="button" onClick="{{ goBuy }}" style="height: 46px; padding: 0 22px; border-radius: 12px; border: 0; background: var(--accent); color: var(--on-accent); font-family: inherit; font-size: 15px; font-weight: 500; cursor: pointer;" style-hover="background: var(--accent-hover);">Купить ключ</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="display: grid; gap: 10px;">
|
|||
|
|
<h2 style="margin: 0 0 4px; font-size: 20px; font-weight: 600; letter-spacing: -0.025em;">Короткие ответы</h2>
|
|||
|
|
<sc-for list="{{ faq }}" as="item" hint-placeholder-count="3">
|
|||
|
|
<div style="border: 1px solid var(--border); border-radius: 16px; background: var(--surface); overflow: hidden;">
|
|||
|
|
<button type="button" onClick="{{ item.toggle }}" style="display: flex; align-items: center; gap: 16px; width: 100%; padding: 17px 20px; background: transparent; border: 0; color: var(--ink); font-family: inherit; font-size: 16px; font-weight: 500; text-align: left; cursor: pointer;">
|
|||
|
|
<span style="flex: 1;">{{ item.q }}</span>
|
|||
|
|
<span style="flex: none; width: 9px; height: 9px; border-right: 1.5px solid var(--ink-3); border-bottom: 1.5px solid var(--ink-3); transform: {{ item.rot }}; transition: transform 180ms ease; display: block;"></span>
|
|||
|
|
</button>
|
|||
|
|
<div hidden="{{ item.off }}" style="padding: 0 20px 20px; font-size: 15px; line-height: 1.6; color: var(--ink-2); font-weight: 300; max-width: 62ch;">{{ item.a }}</div>
|
|||
|
|
</div>
|
|||
|
|
</sc-for>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div hidden="{{ keysOff }}" style="display: grid; gap: 20px;">
|
|||
|
|
<h1 style="margin: 0; font-size: 30px; font-weight: 600; letter-spacing: -0.03em;">Список ключей</h1>
|
|||
|
|
<div style="display: grid; gap: 12px;">
|
|||
|
|
<sc-for list="{{ allKeys }}" as="key" hint-placeholder-count="3">
|
|||
|
|
<button type="button" onClick="{{ key.open }}" style="display: flex; flex-wrap: wrap; align-items: center; gap: 12px 20px; padding: 20px 24px; border-radius: 18px; border: 1px solid var(--border); background: var(--surface); color: var(--ink); font-family: inherit; text-align: left; cursor: pointer; width: 100%;" style-hover="border-color: var(--accent);">
|
|||
|
|
<span style="font-size: 17px; font-weight: 500;">{{ key.title }}</span>
|
|||
|
|
<span style="padding: 4px 10px; border-radius: 8px; background: {{ key.badgeBg }}; color: {{ key.badgeInk }}; font-size: 12px;">{{ key.badge }}</span>
|
|||
|
|
<span style="margin-left: auto; font-size: 14px; color: var(--ink-3); font-variant-numeric: tabular-nums;">{{ key.ip }}</span>
|
|||
|
|
<span style="font-size: 14px; color: var(--ink-2); font-variant-numeric: tabular-nums;">{{ key.untilLine }}</span>
|
|||
|
|
</button>
|
|||
|
|
</sc-for>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div hidden="{{ keyOff }}" style="display: grid; gap: 22px;">
|
|||
|
|
<button type="button" onClick="{{ goKeys }}" style="justify-self: start; border: 0; background: transparent; color: var(--ink-3); font-family: inherit; font-size: 14px; cursor: pointer; padding: 0;">← Все ключи</button>
|
|||
|
|
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; align-items: baseline; gap: 12px 20px;">
|
|||
|
|
<h1 style="margin: 0; font-size: 30px; font-weight: 600; letter-spacing: -0.03em;">{{ cur.title }}</h1>
|
|||
|
|
<span style="font-size: 15px; color: var(--ink-3); font-variant-numeric: tabular-nums;">{{ cur.ip }}</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px;">
|
|||
|
|
<div style="padding: 22px; border-radius: 18px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3); margin-bottom: 10px;">Действует до</div>
|
|||
|
|
<div style="font-size: 24px; font-weight: 600; letter-spacing: -0.025em;">{{ cur.until }}</div>
|
|||
|
|
<div style="margin-top: 8px; font-size: 14px; color: {{ cur.leftInk }};">{{ cur.left }}</div>
|
|||
|
|
</div>
|
|||
|
|
<div style="padding: 22px; border-radius: 18px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3); margin-bottom: 10px;">Оплата</div>
|
|||
|
|
<div style="font-size: 18px; font-variant-numeric: tabular-nums;">{{ cur.card }}</div>
|
|||
|
|
<div style="margin-top: 8px; font-size: 14px; color: var(--ink-2);">2 499 ₽ в месяц · карта аккаунта</div>
|
|||
|
|
<button type="button" onClick="{{ goBilling }}" style="margin-top: 14px; height: 40px; padding: 0 16px; border-radius: 10px; border: 1px solid var(--border); background: transparent; color: var(--ink); font-family: inherit; font-size: 14px; cursor: pointer;" style-hover="border-color: var(--ink-3);">Счёт и платежи</button>
|
|||
|
|
</div>
|
|||
|
|
<div style="padding: 22px; border-radius: 18px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3); margin-bottom: 10px;">Устройства</div>
|
|||
|
|
<div style="font-size: 24px; font-weight: 600; letter-spacing: -0.025em;">{{ cur.devices }}</div>
|
|||
|
|
<div style="margin-top: 8px; font-size: 14px; color: var(--ink-2);">Один и тот же IP на всех</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="padding: 26px; border-radius: 20px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 6px;">
|
|||
|
|
<h2 style="margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -0.025em;">WireGuard</h2>
|
|||
|
|
<span style="font-size: 13px; color: var(--ink-3);">5 конфигураций — по одной на устройство</span>
|
|||
|
|
</div>
|
|||
|
|
<p style="margin: 0 0 18px; font-size: 14px; color: var(--ink-2); font-weight: 300; max-width: 60ch;">На компьютере скачайте файл и откройте его в приложении. На телефоне — отсканируйте QR-код.</p>
|
|||
|
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 10px;">
|
|||
|
|
<sc-for list="{{ configs }}" as="cfg" hint-placeholder-count="5">
|
|||
|
|
<div style="display: grid; gap: 12px; padding: 16px; border-radius: 14px; background: var(--surface-2); border: 1px solid var(--border);">
|
|||
|
|
<div style="display: flex; align-items: center; justify-content: space-between; gap: 10px;">
|
|||
|
|
<span style="font-size: 15px; font-weight: 500;">{{ cfg.name }}</span>
|
|||
|
|
<span style="font-size: 12px; color: var(--ink-3);">{{ cfg.state }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div style="display: flex; gap: 8px;">
|
|||
|
|
<button type="button" style="flex: 1; height: 38px; border-radius: 10px; border: 0; background: var(--accent); color: var(--on-accent); font-family: inherit; font-size: 14px; cursor: pointer;" style-hover="background: var(--accent-hover);">Скачать</button>
|
|||
|
|
<button type="button" onClick="{{ cfg.showQr }}" style="height: 38px; padding: 0 14px; border-radius: 10px; border: 1px solid var(--border); background: var(--bg); color: var(--ink); font-family: inherit; font-size: 14px; cursor: pointer;" style-hover="border-color: var(--ink-3);">QR</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</sc-for>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="padding: 26px; border-radius: 20px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 6px;">
|
|||
|
|
<h2 style="margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -0.025em;">Xray</h2>
|
|||
|
|
<span style="font-size: 13px; color: var(--ink-3);">Для Happ и других клиентов</span>
|
|||
|
|
</div>
|
|||
|
|
<p style="margin: 0 0 18px; font-size: 14px; color: var(--ink-2); font-weight: 300; max-width: 60ch;">Запасной способ подключения. Скопируйте ссылку или отсканируйте код — настройки те же.</p>
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; gap: 10px; align-items: center;">
|
|||
|
|
<div style="flex: 1; min-width: 240px; padding: 14px 16px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border); font-size: 13px; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums;">{{ cur.xray }}</div>
|
|||
|
|
<button type="button" onClick="{{ copyXray }}" style="height: 46px; padding: 0 20px; border-radius: 12px; border: 0; background: var(--accent); color: var(--on-accent); font-family: inherit; font-size: 15px; cursor: pointer;" style-hover="background: var(--accent-hover);">{{ copyLabel }}</button>
|
|||
|
|
<button type="button" onClick="{{ showXrayQr }}" style="height: 46px; padding: 0 18px; border-radius: 12px; border: 1px solid var(--border); background: transparent; color: var(--ink); font-family: inherit; font-size: 15px; cursor: pointer;" style-hover="border-color: var(--ink-3);">QR</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div hidden="{{ buyOff }}" style="display: grid; gap: 22px;">
|
|||
|
|
<div>
|
|||
|
|
<h1 style="margin: 0 0 6px; font-size: 30px; font-weight: 600; letter-spacing: -0.03em;">Купить ключ</h1>
|
|||
|
|
<p style="margin: 0; font-size: 15px; color: var(--ink-2); font-weight: 300;">Базовая цена: 4 900 ₽ первый месяц, далее 2 499 ₽. В редких локациях — выше.</p>
|
|||
|
|
</div>
|
|||
|
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px;">
|
|||
|
|
<sc-for list="{{ locations }}" as="loc" hint-placeholder-count="12">
|
|||
|
|
<div role="button" tabindex="0" onClick="{{ loc.pick }}" style="display: grid; align-content: start; gap: 14px; padding: 20px; border-radius: 18px; border: 1px solid {{ loc.border }}; background: {{ loc.bg }}; color: var(--ink); cursor: pointer;" style-hover="border-color: var(--ink-3);">
|
|||
|
|
<span style="display: flex; align-items: center; justify-content: space-between; gap: 14px;">
|
|||
|
|
{{ loc.flag }}
|
|||
|
|
<span style="display: flex; align-items: center; gap: 12px; flex: none; min-height: 32px;">
|
|||
|
|
<span hidden="{{ loc.buyOff }}" style="display: flex; align-items: center; justify-content: center; height: 32px; padding: 0 16px; border-radius: 10px; background: var(--accent); color: var(--on-accent); font-size: 14px; font-weight: 500; cursor: pointer;">Купить</span>
|
|||
|
|
<span hidden="{{ loc.dotOff }}" style="width: 11px; height: 11px; border-radius: 50%; background: {{ loc.dot }}; display: block; flex: none;"></span>
|
|||
|
|
</span>
|
|||
|
|
</span>
|
|||
|
|
<span style="display: grid; gap: 5px;">
|
|||
|
|
<span style="font-size: 17px; font-weight: 500; letter-spacing: -0.02em;">{{ loc.country }}</span>
|
|||
|
|
<span style="font-size: 14px; color: var(--ink-3);">{{ loc.city }}</span>
|
|||
|
|
</span>
|
|||
|
|
<span style="font-size: 13px; color: {{ loc.statusInk }};">{{ loc.status }}</span>
|
|||
|
|
<span style="display: grid; gap: 12px; padding-top: 14px; border-top: 1px solid var(--border);">
|
|||
|
|
<span style="display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; font-size: 13px; color: var(--ink-2); font-variant-numeric: tabular-nums;">
|
|||
|
|
<span style="font-size: 17px; font-weight: 500; color: var(--ink);">{{ loc.setup }}</span>
|
|||
|
|
первый месяц · далее
|
|||
|
|
<span style="font-weight: 500; color: var(--ink);">{{ loc.month }}</span>
|
|||
|
|
</span>
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
</sc-for>
|
|||
|
|
</div>
|
|||
|
|
<div style="padding: 24px; border-radius: 18px; background: var(--surface); border: 1px solid var(--border);">
|
|||
|
|
<h2 id="lead" style="margin: 0 0 8px; font-size: 19px; font-weight: 600; letter-spacing: -0.02em; scroll-margin-top: 24px;">Нужны индивидуальные условия</h2>
|
|||
|
|
<p style="margin: 0 0 18px; max-width: 60ch; font-size: 14px; line-height: 1.55; color: var(--ink-2); font-weight: 300;">Команда, много адресов, редкая страна или свой сценарий маршрутизации. Оставьте заявку — ответим в течение дня.</p>
|
|||
|
|
<button type="button" onClick="{{ openLead }}" hidden="{{ leadOpen }}" style="display: inline-flex; align-items: center; height: 46px; padding: 0 20px; border-radius: 12px; border: 1px solid var(--accent); background: transparent; color: var(--accent); font-family: inherit; font-size: 15px; font-weight: 500; cursor: pointer;" style-hover="background: var(--accent-soft);">Оставить заявку</button>
|
|||
|
|
<div hidden="{{ leadClosed }}" style="display: grid; gap: 10px; max-width: 460px;">
|
|||
|
|
<input type="text" placeholder="Имя" style="height: 48px; padding: 0 14px; border-radius: 12px; border: 1px solid var(--border); background: var(--bg); color: var(--ink); font-family: inherit; font-size: 15px; width: 100%;" />
|
|||
|
|
<input type="email" placeholder="Email" style="height: 48px; padding: 0 14px; border-radius: 12px; border: 1px solid var(--border); background: var(--bg); color: var(--ink); font-family: inherit; font-size: 15px; width: 100%;" />
|
|||
|
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px;">
|
|||
|
|
<input type="text" placeholder="Telegram" style="height: 48px; padding: 0 14px; border-radius: 12px; border: 1px solid var(--border); background: var(--bg); color: var(--ink); font-family: inherit; font-size: 15px; width: 100%;" />
|
|||
|
|
<input type="text" placeholder="WhatsApp" style="height: 48px; padding: 0 14px; border-radius: 12px; border: 1px solid var(--border); background: var(--bg); color: var(--ink); font-family: inherit; font-size: 15px; width: 100%;" />
|
|||
|
|
</div>
|
|||
|
|
<textarea rows="3" placeholder="Коротко о задаче" style="padding: 12px 14px; border-radius: 12px; border: 1px solid var(--border); background: var(--bg); color: var(--ink); font-family: inherit; font-size: 15px; resize: vertical; width: 100%;"></textarea>
|
|||
|
|
<button type="button" onClick="{{ sendLead }}" style="display: inline-flex; align-items: center; justify-content: center; height: 48px; padding: 0 22px; border-radius: 12px; border: 0; background: var(--accent); color: var(--on-accent); font-family: inherit; font-size: 15px; font-weight: 500; cursor: pointer;" style-hover="background: var(--accent-hover);">{{ leadButton }}</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div hidden="{{ billingOff }}" style="display: grid; gap: 22px;">
|
|||
|
|
<div>
|
|||
|
|
<h1 style="margin: 0 0 6px; font-size: 30px; font-weight: 600; letter-spacing: -0.03em;">Счёт и платежи</h1>
|
|||
|
|
<p style="margin: 0; max-width: 62ch; font-size: 15px; line-height: 1.55; color: var(--ink-2); font-weight: 300;">Карта привязана к аккаунту, а не к отдельному ключу. Списания за все ключи идут с неё — или с баланса, если на нём есть деньги.</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px;">
|
|||
|
|
<div style="display: grid; align-content: start; gap: 8px; padding: 22px; border-radius: 18px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3);">Баланс</div>
|
|||
|
|
<div style="font-size: 30px; font-weight: 600; letter-spacing: -0.03em; font-variant-numeric: tabular-nums;">1 250 ₽</div>
|
|||
|
|
<div style="font-size: 14px; color: var(--ink-2);">Списывается в первую очередь</div>
|
|||
|
|
<button type="button" onClick="{{ openTopup }}" style="justify-self: start; margin-top: 6px; height: 40px; padding: 0 16px; border-radius: 10px; border: 0; background: var(--accent); color: var(--on-accent); font-family: inherit; font-size: 14px; font-weight: 500; cursor: pointer;" style-hover="background: var(--accent-hover);">Пополнить</button>
|
|||
|
|
</div>
|
|||
|
|
<div style="display: grid; align-content: start; gap: 8px; padding: 22px; border-radius: 18px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3);">Способ оплаты</div>
|
|||
|
|
<div style="font-size: 20px; font-weight: 500; font-variant-numeric: tabular-nums;">Карта ···· 4242</div>
|
|||
|
|
<div style="font-size: 14px; color: var(--ink-2);">Основная для всех ключей аккаунта</div>
|
|||
|
|
<button type="button" style="justify-self: start; margin-top: 6px; height: 40px; padding: 0 16px; border-radius: 10px; border: 1px solid var(--border); background: transparent; color: var(--ink); font-family: inherit; font-size: 14px; cursor: pointer;" style-hover="border-color: var(--ink-3);">Изменить карту</button>
|
|||
|
|
</div>
|
|||
|
|
<div style="display: grid; align-content: start; gap: 8px; padding: 22px; border-radius: 18px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3);">Следующее списание</div>
|
|||
|
|
<div style="font-size: 30px; font-weight: 600; letter-spacing: -0.03em; font-variant-numeric: tabular-nums;">2 499 ₽</div>
|
|||
|
|
<div style="font-size: 14px; color: var(--ink-2);">21 сентября · США · Нью-Йорк</div>
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3);">Далее 14 октября · Нидерланды</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div hidden="{{ topupOff }}" style="display: grid; gap: 16px; padding: 26px; border-radius: 20px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 12px;">
|
|||
|
|
<h2 style="margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -0.025em;">Пополнить баланс</h2>
|
|||
|
|
<button type="button" onClick="{{ closeTopup }}" style="border: 0; background: transparent; color: var(--ink-3); font-family: inherit; font-size: 14px; cursor: pointer; padding: 0;">Свернуть</button>
|
|||
|
|
</div>
|
|||
|
|
<div style="display: grid; gap: 8px;">
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3);">Сумма</div>
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; gap: 8px;">
|
|||
|
|
<sc-for list="{{ sums }}" as="sum" hint-placeholder-count="4">
|
|||
|
|
<button type="button" onClick="{{ sum.pick }}" style="height: 44px; padding: 0 18px; border-radius: 12px; border: 1px solid {{ sum.border }}; background: {{ sum.bg }}; color: var(--ink); font-family: inherit; font-size: 15px; font-variant-numeric: tabular-nums; cursor: pointer;">{{ sum.label }}</button>
|
|||
|
|
</sc-for>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div style="display: grid; gap: 8px;">
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3);">Способ</div>
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; gap: 8px;">
|
|||
|
|
<sc-for list="{{ methods }}" as="m" hint-placeholder-count="3">
|
|||
|
|
<button type="button" onClick="{{ m.pick }}" style="height: 44px; padding: 0 18px; border-radius: 12px; border: 1px solid {{ m.border }}; background: {{ m.bg }}; color: var(--ink); font-family: inherit; font-size: 15px; cursor: pointer;">{{ m.label }}</button>
|
|||
|
|
</sc-for>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div hidden="{{ cryptoOff }}" style="display: grid; gap: 10px; padding: 18px; border-radius: 14px; background: var(--surface-2); border: 1px solid var(--border);">
|
|||
|
|
<div style="font-size: 15px; font-weight: 500;">USDT (TRC-20), BTC, ETH</div>
|
|||
|
|
<p style="margin: 0; max-width: 60ch; font-size: 14px; line-height: 1.55; color: var(--ink-2); font-weight: 300;">Покажем адрес и сумму в выбранной монете. Курс фиксируется на 15 минут, баланс пополнится после одного подтверждения сети.</p>
|
|||
|
|
</div>
|
|||
|
|
<button type="button" onClick="{{ sendTopup }}" style="justify-self: start; height: 48px; padding: 0 22px; border-radius: 12px; border: 0; background: var(--accent); color: var(--on-accent); font-family: inherit; font-size: 15px; font-weight: 500; cursor: pointer;" style-hover="background: var(--accent-hover);">{{ topupButton }}</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="display: grid; gap: 10px;">
|
|||
|
|
<h2 style="margin: 0 0 4px; font-size: 20px; font-weight: 600; letter-spacing: -0.025em;">История платежей</h2>
|
|||
|
|
<sc-for list="{{ payments }}" as="p" hint-placeholder-count="5">
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; align-items: center; gap: 10px 20px; padding: 18px 20px; border-radius: 16px; background: var(--surface); border: 1px solid var(--border);">
|
|||
|
|
<span style="width: 116px; flex: none; font-size: 14px; color: var(--ink-3); font-variant-numeric: tabular-nums;">{{ p.date }}</span>
|
|||
|
|
<span style="flex: 1; min-width: 180px; display: grid; gap: 3px;">
|
|||
|
|
<span style="font-size: 15px;">{{ p.title }}</span>
|
|||
|
|
<span style="font-size: 13px; color: var(--ink-3);">{{ p.method }}</span>
|
|||
|
|
</span>
|
|||
|
|
<span style="font-size: 13px; color: var(--ink-3);">{{ p.status }}</span>
|
|||
|
|
<span style="width: 104px; flex: none; text-align: right; font-size: 16px; font-weight: 500; color: {{ p.ink }}; font-variant-numeric: tabular-nums;">{{ p.amount }}</span>
|
|||
|
|
</div>
|
|||
|
|
</sc-for>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div hidden="{{ refOff }}" style="display: grid; gap: 20px;">
|
|||
|
|
<div>
|
|||
|
|
<h1 style="margin: 0 0 6px; font-size: 30px; font-weight: 600; letter-spacing: -0.03em;">Реферальная программа</h1>
|
|||
|
|
<p style="margin: 0; max-width: 62ch; font-size: 15px; line-height: 1.55; color: var(--ink-2); font-weight: 300;">Приведите друга — вы оба получите по месяцу в подарок.</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px;">
|
|||
|
|
<div style="padding: 22px; border-radius: 18px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3); margin-bottom: 10px;">Приглашено</div>
|
|||
|
|
<div style="font-size: 30px; font-weight: 600; letter-spacing: -0.03em; font-variant-numeric: tabular-nums;">3</div>
|
|||
|
|
</div>
|
|||
|
|
<div style="padding: 22px; border-radius: 18px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3); margin-bottom: 10px;">Месяцев начислено</div>
|
|||
|
|
<div style="font-size: 30px; font-weight: 600; letter-spacing: -0.03em; font-variant-numeric: tabular-nums;">2</div>
|
|||
|
|
</div>
|
|||
|
|
<div style="padding: 22px; border-radius: 18px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3); margin-bottom: 10px;">Ожидает подтверждения</div>
|
|||
|
|
<div style="font-size: 30px; font-weight: 600; letter-spacing: -0.03em; font-variant-numeric: tabular-nums;">1</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="display: grid; gap: 14px; padding: 26px; border-radius: 20px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="font-size: 16px; font-weight: 500;">Ваша ссылка</div>
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; gap: 10px; align-items: center;">
|
|||
|
|
<div style="flex: 1; min-width: 220px; padding: 14px 16px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border); font-size: 14px; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">veilix.com/r/anna-7f2c</div>
|
|||
|
|
<button type="button" onClick="{{ copyRef }}" style="height: 46px; padding: 0 20px; border-radius: 12px; border: 0; background: var(--accent); color: var(--on-accent); font-family: inherit; font-size: 15px; cursor: pointer;" style-hover="background: var(--accent-hover);">{{ refLabel }}</button>
|
|||
|
|
</div>
|
|||
|
|
<div style="font-size: 13px; color: var(--ink-3); line-height: 1.5;">Месяц начисляется вам и другу после его первой оплаты и применяется к ближайшему списанию.</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="display: grid; gap: 10px;">
|
|||
|
|
<div style="font-size: 16px; font-weight: 500;">Приглашённые</div>
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 20px; border-radius: 16px; background: var(--surface); border: 1px solid var(--border);">
|
|||
|
|
<span style="font-size: 15px;">m···@gmail.com</span>
|
|||
|
|
<span style="font-size: 14px; color: var(--accent);">Месяц начислен</span>
|
|||
|
|
</div>
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 20px; border-radius: 16px; background: var(--surface); border: 1px solid var(--border);">
|
|||
|
|
<span style="font-size: 15px;">d···@yandex.ru</span>
|
|||
|
|
<span style="font-size: 14px; color: var(--accent);">Месяц начислен</span>
|
|||
|
|
</div>
|
|||
|
|
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 20px; border-radius: 16px; background: var(--surface); border: 1px solid var(--border);">
|
|||
|
|
<span style="font-size: 15px;">k···@icloud.com</span>
|
|||
|
|
<span style="font-size: 14px; color: var(--ink-3);">Ждём оплаты</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div hidden="{{ moreOff }}" style="display: grid; gap: 16px;">
|
|||
|
|
<h1 style="margin: 0; font-size: 26px; font-weight: 600; letter-spacing: -0.03em;">Ещё</h1>
|
|||
|
|
<button type="button" onClick="{{ goBilling }}" style="display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 56px; padding: 14px 18px; border-radius: 16px; border: 1px solid var(--border); background: var(--surface); color: var(--ink); font-family: inherit; font-size: 16px; text-align: left; cursor: pointer;">
|
|||
|
|
<span>Счёт и платежи</span>
|
|||
|
|
<span style="color: var(--ink-3);">›</span>
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ goRef }}" style="display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 56px; padding: 14px 18px; border-radius: 16px; border: 1px solid var(--border); background: var(--surface); color: var(--ink); font-family: inherit; font-size: 16px; text-align: left; cursor: pointer;">
|
|||
|
|
<span>Реферальная программа</span>
|
|||
|
|
<span style="color: var(--ink-3);">›</span>
|
|||
|
|
</button>
|
|||
|
|
<a href="Support.dc.html" style="display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 56px; padding: 14px 18px; border-radius: 16px; border: 1px solid var(--border); background: var(--surface); color: var(--ink); font-size: 16px;">
|
|||
|
|
<span>Поддержка</span>
|
|||
|
|
<span style="color: var(--ink-3);">›</span>
|
|||
|
|
</a>
|
|||
|
|
<div style="display: grid; gap: 12px; padding: 14px 18px; border-radius: 16px; border: 1px solid var(--border); background: var(--surface);">
|
|||
|
|
<div style="display: flex; align-items: center; justify-content: space-between; gap: 12px;">
|
|||
|
|
<div style="font-size: 15px;">Тема</div>
|
|||
|
|
<div style="display: flex; padding: 3px; border-radius: 11px; border: 1px solid var(--border); flex: none;">
|
|||
|
|
<button type="button" onClick="{{ setLight }}" title="Светлая тема" style="display: flex; align-items: center; justify-content: center; width: 40px; height: 34px; border: 0; border-radius: 8px; background: {{ lightBg }}; color: var(--ink); cursor: pointer;">
|
|||
|
|
<span style="position: relative; width: 16px; height: 16px; display: block;">
|
|||
|
|
<span style="position: absolute; left: 4px; top: 4px; width: 8px; height: 8px; border-radius: 50%; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; top: 0; width: 16px; height: 16px; border-radius: 50%; border: 1.5px solid currentColor; opacity: 0.45; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ setDark }}" title="Тёмная тема" style="display: flex; align-items: center; justify-content: center; width: 40px; height: 34px; border: 0; border-radius: 8px; background: {{ darkBg }}; color: var(--ink); cursor: pointer;">
|
|||
|
|
<span style="width: 16px; height: 16px; border-radius: 50%; box-shadow: inset -5px -2px 0 0 currentColor; display: block;"></span>
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ setSystem }}" title="Как в системе" style="display: flex; align-items: center; justify-content: center; width: 40px; height: 34px; border: 0; border-radius: 8px; background: {{ systemBg }}; color: var(--ink); cursor: pointer;">
|
|||
|
|
<span style="width: 16px; height: 16px; border-radius: 50%; border: 1.5px solid currentColor; background: linear-gradient(90deg, currentColor 50%, transparent 50%); display: block;"></span>
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div style="display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 12px; border-top: 1px solid var(--border);">
|
|||
|
|
<div style="font-size: 15px;">Язык</div>
|
|||
|
|
<div style="display: flex; padding: 3px; border-radius: 11px; border: 1px solid var(--border); flex: none;">
|
|||
|
|
<button type="button" onClick="{{ setRu }}" style="height: 34px; padding: 0 16px; border: 0; border-radius: 8px; background: {{ ruBg }}; color: {{ ruInk }}; font-family: inherit; font-size: 14px; cursor: pointer;">RU</button>
|
|||
|
|
<button type="button" onClick="{{ setEn }}" style="height: 34px; padding: 0 16px; border: 0; border-radius: 8px; background: {{ enBg }}; color: {{ enInk }}; font-family: inherit; font-size: 14px; cursor: pointer;">EN</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<button type="button" onClick="{{ signOut }}" style="justify-self: start; min-height: 48px; padding: 0 16px; border-radius: 12px; border: 1px solid var(--border); background: transparent; color: var(--ink-2); font-family: inherit; font-size: 15px; cursor: pointer;">Выйти · anna@example.com</button>
|
|||
|
|
</div>
|
|||
|
|
</main>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div hidden="{{ pillOff }}" style="position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%); z-index: 50; display: flex; gap: 4px; padding: 6px; border-radius: 999px; background: color-mix(in oklab, var(--surface) 62%, transparent); backdrop-filter: blur(24px) saturate(1.8); -webkit-backdrop-filter: blur(24px) saturate(1.8); border: 1px solid color-mix(in oklab, var(--ink) 8%, transparent); box-shadow: 0 10px 30px -10px color-mix(in oklab, var(--ink) 40%, transparent);">
|
|||
|
|
<button type="button" onClick="{{ goHome }}" style="display: grid; justify-items: center; gap: 4px; min-width: 76px; min-height: 52px; padding: 8px 12px; border: 0; border-radius: 999px; background: {{ tabHomeBg }}; color: {{ tabHomeInk }}; font-family: inherit; font-size: 11px; cursor: pointer;">
|
|||
|
|
<span style="position: relative; width: 20px; height: 20px; display: block;">
|
|||
|
|
<span style="position: absolute; left: 0; top: 0; width: 9px; height: 9px; border-radius: 2px; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; right: 0; top: 0; width: 9px; height: 9px; border-radius: 2px; background: currentColor; opacity: 0.45; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; bottom: 0; width: 9px; height: 9px; border-radius: 2px; background: currentColor; opacity: 0.45; display: block;"></span>
|
|||
|
|
<span style="position: absolute; right: 0; bottom: 0; width: 9px; height: 9px; border-radius: 2px; background: currentColor; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
Главная
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ goKeys }}" style="display: grid; justify-items: center; gap: 4px; min-width: 76px; min-height: 52px; padding: 8px 12px; border: 0; border-radius: 999px; background: {{ tabKeysBg }}; color: {{ tabKeysInk }}; font-family: inherit; font-size: 11px; cursor: pointer;">
|
|||
|
|
<span style="position: relative; width: 20px; height: 20px; display: block;">
|
|||
|
|
<span style="position: absolute; left: 0; top: 2px; width: 20px; height: 4px; border-radius: 2px; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; top: 9px; width: 20px; height: 4px; border-radius: 2px; background: currentColor; opacity: 0.6; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; top: 16px; width: 20px; height: 4px; border-radius: 2px; background: currentColor; opacity: 0.3; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
Ключи
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ goBuy }}" style="display: grid; justify-items: center; gap: 4px; min-width: 76px; min-height: 52px; padding: 8px 12px; border: 0; border-radius: 999px; background: {{ tabBuyBg }}; color: {{ tabBuyInk }}; font-family: inherit; font-size: 11px; cursor: pointer;">
|
|||
|
|
<span style="position: relative; width: 20px; height: 20px; display: block;">
|
|||
|
|
<span style="position: absolute; left: 8px; top: 0; width: 4px; height: 20px; border-radius: 2px; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 0; top: 8px; width: 20px; height: 4px; border-radius: 2px; background: currentColor; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
Купить
|
|||
|
|
</button>
|
|||
|
|
<button type="button" onClick="{{ goMore }}" style="display: grid; justify-items: center; gap: 4px; min-width: 76px; min-height: 52px; padding: 8px 12px; border: 0; border-radius: 999px; background: {{ tabMoreBg }}; color: {{ tabMoreInk }}; font-family: inherit; font-size: 11px; cursor: pointer;">
|
|||
|
|
<span style="position: relative; width: 20px; height: 20px; display: block;">
|
|||
|
|
<span style="position: absolute; left: 0; top: 8px; width: 4px; height: 4px; border-radius: 50%; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 8px; top: 8px; width: 4px; height: 4px; border-radius: 50%; background: currentColor; display: block;"></span>
|
|||
|
|
<span style="position: absolute; left: 16px; top: 8px; width: 4px; height: 4px; border-radius: 50%; background: currentColor; display: block;"></span>
|
|||
|
|
</span>
|
|||
|
|
Ещё
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div hidden="{{ qrOff }}" onClick="{{ closeQr }}" style="position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center; padding: 24px; background: color-mix(in oklab, var(--ink) 45%, transparent); backdrop-filter: blur(6px);">
|
|||
|
|
<div style="display: grid; gap: 16px; justify-items: center; padding: 28px; border-radius: 22px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);">
|
|||
|
|
<div style="font-size: 16px; font-weight: 500;">{{ qrTitle }}</div>
|
|||
|
|
{{ qrImage }}
|
|||
|
|
<div style="max-width: 260px; text-align: center; font-size: 13px; line-height: 1.5; color: var(--ink-3);">Откройте приложение на телефоне и наведите камеру на код.</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</x-dc>
|
|||
|
|
<script type="text/x-dc" data-dc-script data-props="{"defaultTheme":{"editor":"enum","options":["light","dark","system"],"default":"light","tsType":"'light' | 'dark' | 'system'","section":"Тема"}}">
|
|||
|
|
class Component extends DCLogic {
|
|||
|
|
state = { theme: null, sysDark: false, view: "home", key: 0, faq: 0, loc: 0, lead: false, leadSent: false, qr: null, copied: false, signedIn: true, otp: false, lang: "ru", narrow: false, refCopied: false, topup: false, sum: 1, method: 0, topupSent: false };
|
|||
|
|
|
|||
|
|
data() {
|
|||
|
|
const base = { setup: "4 900 ₽", month: "2 499 ₽" };
|
|||
|
|
const rare = { setup: "6 900 ₽", month: "3 499 ₽" };
|
|||
|
|
const far = { setup: "9 900 ₽", month: "4 999 ₽" };
|
|||
|
|
const L = (country, city, code, lng, lat, ready, tier) => ({ country, city, code, lng, lat, ready, setup: tier.setup, month: tier.month, rare: tier !== base });
|
|||
|
|
return [
|
|||
|
|
L("Нидерланды", "Амстердам", "nl", 4.9, 52.37, true, base),
|
|||
|
|
L("Германия", "Франкфурт", "de", 8.68, 50.11, true, base),
|
|||
|
|
L("США", "Нью-Йорк", "us", -74.01, 40.71, true, base),
|
|||
|
|
L("Великобритания", "Лондон", "gb", -0.13, 51.51, true, base),
|
|||
|
|
L("Франция", "Париж", "fr", 2.35, 48.86, true, base),
|
|||
|
|
L("Финляндия", "Хельсинки", "fi", 24.94, 60.17, true, base),
|
|||
|
|
L("Швеция", "Стокгольм", "se", 18.07, 59.33, true, base),
|
|||
|
|
L("Норвегия", "Осло", "no", 10.75, 59.91, false, base),
|
|||
|
|
L("Дания", "Копенгаген", "dk", 12.57, 55.68, false, base),
|
|||
|
|
L("Швейцария", "Цюрих", "ch", 8.54, 47.37, true, rare),
|
|||
|
|
L("Австрия", "Вена", "at", 16.37, 48.21, true, base),
|
|||
|
|
L("Испания", "Мадрид", "es", -3.7, 40.42, true, base),
|
|||
|
|
L("Италия", "Милан", "it", 9.19, 45.46, true, base),
|
|||
|
|
L("Польша", "Варшава", "pl", 21.01, 52.23, true, base),
|
|||
|
|
L("Чехия", "Прага", "cz", 14.44, 50.08, true, base),
|
|||
|
|
L("Румыния", "Бухарест", "ro", 26.1, 44.43, false, base),
|
|||
|
|
L("Литва", "Вильнюс", "lt", 25.28, 54.69, true, base),
|
|||
|
|
L("Латвия", "Рига", "lv", 24.11, 56.95, true, base),
|
|||
|
|
L("Эстония", "Таллин", "ee", 24.75, 59.44, false, base),
|
|||
|
|
L("Турция", "Стамбул", "tr", 28.98, 41.01, true, base),
|
|||
|
|
L("Казахстан", "Алматы", "kz", 76.89, 43.24, false, base),
|
|||
|
|
L("Армения", "Ереван", "am", 44.51, 40.18, false, base),
|
|||
|
|
L("Грузия", "Тбилиси", "ge", 44.8, 41.72, false, base),
|
|||
|
|
L("ОАЭ", "Дубай", "ae", 55.27, 25.2, true, rare),
|
|||
|
|
L("Сингапур", "Сингапур", "sg", 103.82, 1.35, true, rare),
|
|||
|
|
L("Япония", "Токио", "jp", 139.69, 35.69, true, rare),
|
|||
|
|
L("Южная Корея", "Сеул", "kr", 126.98, 37.57, false, rare),
|
|||
|
|
L("Канада", "Торонто", "ca", -79.38, 43.65, true, base),
|
|||
|
|
L("Австралия", "Сидней", "au", 151.21, -33.87, false, far),
|
|||
|
|
L("Бразилия", "Сан-Паулу", "br", -46.63, -23.55, false, far)
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
flagSpecs() {
|
|||
|
|
return {
|
|||
|
|
nl: { rows: ["#AE1C28", "#FFFFFF", "#21468B"] },
|
|||
|
|
de: { rows: ["#000000", "#DD0000", "#FFCE00"] },
|
|||
|
|
us: { rows: ["#B22234", "#FFFFFF", "#B22234", "#FFFFFF", "#B22234", "#FFFFFF"], marks: [{ l: 0, t: 0, w: 22, h: 17, bg: "#3C3B6E" }] },
|
|||
|
|
gb: { bg: "#012169", marks: [{ l: 17, t: 0, w: 12, h: 32, bg: "#FFFFFF" }, { l: 0, t: 10, w: 46, h: 12, bg: "#FFFFFF" }, { l: 20, t: 0, w: 6, h: 32, bg: "#C8102E" }, { l: 0, t: 13, w: 46, h: 6, bg: "#C8102E" }] },
|
|||
|
|
fr: { cols: ["#002395", "#FFFFFF", "#ED2939"] },
|
|||
|
|
fi: { bg: "#FFFFFF", marks: [{ l: 13, t: 0, w: 8, h: 32, bg: "#003580" }, { l: 0, t: 12, w: 46, h: 8, bg: "#003580" }] },
|
|||
|
|
se: { bg: "#006AA7", marks: [{ l: 13, t: 0, w: 6, h: 32, bg: "#FECC00" }, { l: 0, t: 13, w: 46, h: 6, bg: "#FECC00" }] },
|
|||
|
|
no: { bg: "#BA0C2F", marks: [{ l: 12, t: 0, w: 10, h: 32, bg: "#FFFFFF" }, { l: 0, t: 11, w: 46, h: 10, bg: "#FFFFFF" }, { l: 15, t: 0, w: 4, h: 32, bg: "#00205B" }, { l: 0, t: 14, w: 46, h: 4, bg: "#00205B" }] },
|
|||
|
|
dk: { bg: "#C8102E", marks: [{ l: 13, t: 0, w: 6, h: 32, bg: "#FFFFFF" }, { l: 0, t: 13, w: 46, h: 6, bg: "#FFFFFF" }] },
|
|||
|
|
ch: { bg: "#D52B1E", marks: [{ l: 20, t: 8, w: 6, h: 16, bg: "#FFFFFF" }, { l: 15, t: 13, w: 16, h: 6, bg: "#FFFFFF" }] },
|
|||
|
|
at: { rows: ["#ED2939", "#FFFFFF", "#ED2939"] },
|
|||
|
|
es: { rows: ["#AA151B", "#F1BF00", "#AA151B"], sizes: "1fr 2fr 1fr" },
|
|||
|
|
it: { cols: ["#008C45", "#F4F5F0", "#CD212A"] },
|
|||
|
|
pl: { rows: ["#FFFFFF", "#DC143C"] },
|
|||
|
|
cz: { rows: ["#FFFFFF", "#D7141A"], marks: [{ l: 0, t: 0, w: 18, h: 32, bg: "#11457E", clip: "polygon(0 0, 100% 50%, 0 100%)" }] },
|
|||
|
|
ro: { cols: ["#002B7F", "#FCD116", "#CE1126"] },
|
|||
|
|
lt: { rows: ["#FDB913", "#006A44", "#C1272D"] },
|
|||
|
|
lv: { rows: ["#9E3039", "#FFFFFF", "#9E3039"], sizes: "2fr 1fr 2fr" },
|
|||
|
|
ee: { rows: ["#0072CE", "#000000", "#FFFFFF"] },
|
|||
|
|
tr: { bg: "#E30A17", marks: [{ l: 11, t: 8, w: 16, h: 16, r: "50%", bg: "#FFFFFF" }, { l: 16, t: 8, w: 16, h: 16, r: "50%", bg: "#E30A17" }] },
|
|||
|
|
kz: { bg: "#00AFCA", marks: [{ l: 16, t: 8, w: 15, h: 15, r: "50%", bg: "#FEC50C" }] },
|
|||
|
|
am: { rows: ["#D90012", "#0033A0", "#F2A800"] },
|
|||
|
|
ge: { bg: "#FFFFFF", marks: [{ l: 20, t: 0, w: 6, h: 32, bg: "#FF0000" }, { l: 0, t: 13, w: 46, h: 6, bg: "#FF0000" }] },
|
|||
|
|
ae: { rows: ["#00732F", "#FFFFFF", "#000000"], marks: [{ l: 0, t: 0, w: 11, h: 32, bg: "#FF0000" }] },
|
|||
|
|
sg: { rows: ["#EF3340", "#FFFFFF"], marks: [{ l: 5, t: 3, w: 11, h: 11, r: "50%", bg: "#FFFFFF" }, { l: 9, t: 3, w: 11, h: 11, r: "50%", bg: "#EF3340" }] },
|
|||
|
|
jp: { bg: "#FFFFFF", marks: [{ l: 16, t: 9, w: 14, h: 14, r: "50%", bg: "#BC002D" }] },
|
|||
|
|
kr: { bg: "#FFFFFF", marks: [{ l: 16, t: 9, w: 14, h: 14, r: "50%", bg: "#CD2E3A" }, { l: 16, t: 9, w: 14, h: 14, r: "50%", bg: "#0047A0", clip: "polygon(0 50%, 100% 50%, 100% 100%, 0 100%)" }] },
|
|||
|
|
ca: { cols: ["#D80621", "#FFFFFF", "#D80621"], sizes: "1fr 2fr 1fr", marks: [{ l: 20, t: 9, w: 7, h: 13, bg: "#D80621", clip: "polygon(50% 0, 100% 100%, 0 100%)" }] },
|
|||
|
|
au: { bg: "#00247D", marks: [{ l: 9, t: 0, w: 4, h: 16, bg: "#FFFFFF" }, { l: 0, t: 6, w: 22, h: 4, bg: "#FFFFFF" }, { l: 30, t: 19, w: 7, h: 7, r: "50%", bg: "#FFFFFF" }] },
|
|||
|
|
br: { bg: "#009739", marks: [{ l: 9, t: 4, w: 28, h: 24, bg: "#FEDD00", clip: "polygon(50% 0, 100% 50%, 50% 100%, 0 50%)" }, { l: 18, t: 11, w: 10, h: 10, r: "50%", bg: "#012169" }] }
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
flag(code) {
|
|||
|
|
const h = React.createElement;
|
|||
|
|
const spec = this.flagSpecs()[code] || {};
|
|||
|
|
const style = {
|
|||
|
|
width: "46px", height: "32px", borderRadius: "6px", overflow: "hidden",
|
|||
|
|
display: "grid", border: "1px solid var(--border)", position: "relative", flex: "none"
|
|||
|
|
};
|
|||
|
|
let bands = [];
|
|||
|
|
if (spec.rows) {
|
|||
|
|
bands = spec.rows;
|
|||
|
|
style.gridTemplateRows = spec.sizes || "repeat(" + bands.length + ", 1fr)";
|
|||
|
|
} else if (spec.cols) {
|
|||
|
|
bands = spec.cols;
|
|||
|
|
style.gridAutoFlow = "column";
|
|||
|
|
style.gridTemplateColumns = spec.sizes || "repeat(" + bands.length + ", 1fr)";
|
|||
|
|
} else {
|
|||
|
|
style.background = spec.bg || "var(--surface-2)";
|
|||
|
|
}
|
|||
|
|
const kids = bands.map((c, i) => h("span", { key: "b" + i, style: { background: c, display: "block" } }));
|
|||
|
|
(spec.marks || []).forEach((m, i) => kids.push(h("span", {
|
|||
|
|
key: "m" + i,
|
|||
|
|
style: {
|
|||
|
|
position: "absolute", left: m.l + "px", top: m.t + "px", width: m.w + "px", height: m.h + "px",
|
|||
|
|
borderRadius: m.r || 0, background: m.bg, clipPath: m.clip || "none", display: "block"
|
|||
|
|
}
|
|||
|
|
})));
|
|||
|
|
return h("span", { style: style }, kids);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
componentDidMount() {
|
|||
|
|
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|||
|
|
this.mq = mq;
|
|||
|
|
this.onSys = () => this.setState({ sysDark: mq.matches });
|
|||
|
|
mq.addEventListener("change", this.onSys);
|
|||
|
|
this.onResize = () => {
|
|||
|
|
const n = window.innerWidth < 900;
|
|||
|
|
if (n !== this.state.narrow) this.setState({ narrow: n, view: this.state.view === "more" && !n ? "home" : this.state.view });
|
|||
|
|
if (!n && this.state.view === "more") this.setState({ view: "home" });
|
|||
|
|
};
|
|||
|
|
window.addEventListener("resize", this.onResize);
|
|||
|
|
this.onResize();
|
|||
|
|
let saved = null;
|
|||
|
|
try { saved = localStorage.getItem("veilix.theme"); } catch (e) {}
|
|||
|
|
let savedLang = null;
|
|||
|
|
try { savedLang = localStorage.getItem("veilix.lang"); } catch (e) {}
|
|||
|
|
this.setState({ sysDark: mq.matches, theme: saved || this.props.defaultTheme || "light", lang: savedLang || "ru" }, () => { this.apply(); this.applyLang(); });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
applyLang() {
|
|||
|
|
const lang = this.state.lang || "ru";
|
|||
|
|
if (window.VEILIX_APPLY_LANG) window.VEILIX_APPLY_LANG(document.body, lang);
|
|||
|
|
else setTimeout(() => this.applyLang(), 150);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setLang(l) {
|
|||
|
|
try { localStorage.setItem("veilix.lang", l); } catch (e) {}
|
|||
|
|
this.setState({ lang: l }, () => this.applyLang());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
componentWillUnmount() {
|
|||
|
|
if (this.mq) this.mq.removeEventListener("change", this.onSys);
|
|||
|
|
if (this.onResize) window.removeEventListener("resize", this.onResize);
|
|||
|
|
}
|
|||
|
|
componentDidUpdate() { this.apply(); this.applyLang(); }
|
|||
|
|
|
|||
|
|
apply() {
|
|||
|
|
const theme = this.state.theme || this.props.defaultTheme || "light";
|
|||
|
|
const dark = theme === "dark" || (theme === "system" && this.state.sysDark);
|
|||
|
|
document.documentElement.setAttribute("data-veilix-theme", dark ? "dark" : "light");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setTheme(t) {
|
|||
|
|
try { localStorage.setItem("veilix.theme", t); } catch (e) {}
|
|||
|
|
this.setState({ theme: t }, () => this.apply());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
qrImage(seed) {
|
|||
|
|
const n = 21;
|
|||
|
|
let h = 0;
|
|||
|
|
for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) >>> 0;
|
|||
|
|
const cells = [];
|
|||
|
|
const finder = (r, c) => (r < 7 && c < 7) || (r < 7 && c >= n - 7) || (r >= n - 7 && c < 7);
|
|||
|
|
for (let r = 0; r < n; r++) {
|
|||
|
|
for (let c = 0; c < n; c++) {
|
|||
|
|
let on;
|
|||
|
|
if (finder(r, c)) {
|
|||
|
|
const rr = r < 7 ? r : n - 1 - r;
|
|||
|
|
const cc = c < 7 ? c : n - 1 - c;
|
|||
|
|
const d = Math.max(Math.abs(rr - 3), Math.abs(cc - 3));
|
|||
|
|
on = d !== 2;
|
|||
|
|
} else {
|
|||
|
|
h = (h * 1103515245 + 12345) >>> 0;
|
|||
|
|
on = ((h >>> 16) & 1) === 1;
|
|||
|
|
}
|
|||
|
|
cells.push(React.createElement("span", {
|
|||
|
|
key: r + "-" + c,
|
|||
|
|
style: { background: on ? "var(--ink)" : "transparent", display: "block" }
|
|||
|
|
}));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return React.createElement("div", {
|
|||
|
|
style: {
|
|||
|
|
display: "grid",
|
|||
|
|
gridTemplateColumns: "repeat(" + n + ", 1fr)",
|
|||
|
|
width: "220px",
|
|||
|
|
height: "220px",
|
|||
|
|
padding: "12px",
|
|||
|
|
borderRadius: "14px",
|
|||
|
|
background: "var(--bg)",
|
|||
|
|
border: "1px solid var(--border)"
|
|||
|
|
}
|
|||
|
|
}, cells);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
renderVals() {
|
|||
|
|
const s = this.state;
|
|||
|
|
const sel = "var(--accent-soft)";
|
|||
|
|
const theme = s.theme || this.props.defaultTheme || "light";
|
|||
|
|
const keyData = [
|
|||
|
|
{ title: "Нидерланды · Амстердам", ip: "185.72.14.203", until: s.lang === "en" ? "14 October 2026" : "14 октября 2026", badge: "Активен", warn: false, devices: "3 из 5 устройств", payment: "Карта ···· 4242", card: "···· 4242", left: "Продлится автоматически через 31 день", xray: "vless://8f2a…@nl1.veilix.net:443?type=xhttp#Veilix-NL" },
|
|||
|
|
{ title: "США · Нью-Йорк", ip: "23.105.61.44", until: s.lang === "en" ? "21 September 2026" : "21 сентября 2026", badge: "Истекает", warn: true, devices: "1 из 5 устройств", payment: "Карта ···· 8801", card: "···· 8801", left: "Осталось 8 дней", xray: "vless://c41d…@us1.veilix.net:443?type=xhttp#Veilix-US" }
|
|||
|
|
];
|
|||
|
|
const cur = keyData[s.key];
|
|||
|
|
const mk = (i) => ({
|
|||
|
|
title: keyData[i].title,
|
|||
|
|
ip: keyData[i].ip,
|
|||
|
|
until: keyData[i].until,
|
|||
|
|
untilLine: (s.lang === "en" ? "until " : "до ") + keyData[i].until,
|
|||
|
|
badge: keyData[i].badge,
|
|||
|
|
devices: keyData[i].devices,
|
|||
|
|
payment: keyData[i].payment,
|
|||
|
|
badgeBg: keyData[i].warn ? "color-mix(in oklab, var(--warn) 18%, transparent)" : sel,
|
|||
|
|
badgeInk: keyData[i].warn ? "var(--warn)" : "var(--accent)",
|
|||
|
|
open: () => this.setState({ view: "key", key: i })
|
|||
|
|
});
|
|||
|
|
const faqData = [
|
|||
|
|
["Как подключить новое устройство?", "Откройте ключ, скачайте любую свободную конфигурацию WireGuard или отсканируйте её QR-код. Каждая конфигурация рассчитана на одно устройство."],
|
|||
|
|
["Что делать, если подключение перестало работать?", "Переключитесь на Xray в том же ключе — он настроен заранее. Если не помогло, напишите в поддержку, ответим в течение часа."],
|
|||
|
|
["Как отменить продление?", "На странице ключа нажмите «Изменить карту» и отвяжите её. Ключ доработает оплаченный месяц."]
|
|||
|
|
];
|
|||
|
|
const locData = [
|
|||
|
|
["Нидерланды", "Амстердам", true],
|
|||
|
|
["Германия", "Франкфурт", true],
|
|||
|
|
["США", "Нью-Йорк", true],
|
|||
|
|
["Финляндия", "Хельсинки", false],
|
|||
|
|
["Турция", "Стамбул", false],
|
|||
|
|
["Япония", "Токио", false]
|
|||
|
|
];
|
|||
|
|
const cfgNames = [
|
|||
|
|
["Ноутбук", "подключено"],
|
|||
|
|
["Телефон", "подключено"],
|
|||
|
|
["Планшет", "подключено"],
|
|||
|
|
["Рабочий ноутбук", "не занят"],
|
|||
|
|
["Свободный слот", "не занят"]
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
appOff: s.signedIn,
|
|||
|
|
loginOff: !s.signedIn,
|
|||
|
|
otpSent: s.otp,
|
|||
|
|
otpNotSent: !s.otp,
|
|||
|
|
sendOtp: () => this.setState({ otp: true }),
|
|||
|
|
signIn: () => this.setState({ signedIn: true, otp: false, view: "home" }),
|
|||
|
|
backToEmail: () => this.setState({ otp: false }),
|
|||
|
|
signOut: () => this.setState({ signedIn: false, otp: false }),
|
|||
|
|
|
|||
|
|
goHome: () => this.setState({ view: "home" }),
|
|||
|
|
goKeys: () => this.setState({ view: "keys" }),
|
|||
|
|
goBuy: () => this.setState({ view: "buy" }),
|
|||
|
|
goMore: () => this.setState({ view: "more" }),
|
|||
|
|
goBilling: () => this.setState({ view: "billing" }),
|
|||
|
|
billingOff: s.view !== "billing",
|
|||
|
|
billingBg: s.view === "billing" ? sel : "transparent",
|
|||
|
|
billingInk: s.view === "billing" ? "var(--accent)" : "var(--ink-2)",
|
|||
|
|
openTopup: () => this.setState({ topup: true }),
|
|||
|
|
closeTopup: () => this.setState({ topup: false }),
|
|||
|
|
topupOff: !s.topup,
|
|||
|
|
sums: ["2 500 ₽", "5 000 ₽", "10 000 ₽", "Своя сумма"].map((label, i) => ({
|
|||
|
|
label: label,
|
|||
|
|
bg: s.sum === i ? sel : "transparent",
|
|||
|
|
border: s.sum === i ? "var(--accent)" : "var(--border)",
|
|||
|
|
pick: () => this.setState({ sum: i })
|
|||
|
|
})),
|
|||
|
|
methods: ["Карта ···· 4242", "СБП", "Криптовалюта"].map((label, i) => ({
|
|||
|
|
label: label,
|
|||
|
|
bg: s.method === i ? sel : "transparent",
|
|||
|
|
border: s.method === i ? "var(--accent)" : "var(--border)",
|
|||
|
|
pick: () => this.setState({ method: i })
|
|||
|
|
})),
|
|||
|
|
cryptoOff: s.method !== 2,
|
|||
|
|
sendTopup: () => this.setState({ topupSent: true }),
|
|||
|
|
topupButton: s.topupSent ? "Счёт выставлен" : "Пополнить",
|
|||
|
|
payments: [
|
|||
|
|
{ date: "14 сентября", title: "Продление · Нидерланды · Амстердам", method: "Карта ···· 4242", status: "Оплачено", amount: "−2 499 ₽", ink: "var(--ink)" },
|
|||
|
|
{ date: "6 сентября", title: "Пополнение баланса", method: "USDT (TRC-20)", status: "Зачислено", amount: "+5 000 ₽", ink: "var(--accent)" },
|
|||
|
|
{ date: "21 августа", title: "Первый месяц · США · Нью-Йорк", method: "Карта ···· 4242", status: "Оплачено", amount: "−4 900 ₽", ink: "var(--ink)" },
|
|||
|
|
{ date: "14 августа", title: "Продление · Нидерланды · Амстердам", method: "С баланса", status: "Оплачено", amount: "−2 499 ₽", ink: "var(--ink)" },
|
|||
|
|
{ date: "2 августа", title: "Реферальный бонус", method: "Месяц в подарок", status: "Начислено", amount: "+2 499 ₽", ink: "var(--accent)" }
|
|||
|
|
],
|
|||
|
|
goRef: () => this.setState({ view: "ref" }),
|
|||
|
|
refOff: s.view !== "ref",
|
|||
|
|
refBg: s.view === "ref" ? sel : "transparent",
|
|||
|
|
refInk: s.view === "ref" ? "var(--accent)" : "var(--ink-2)",
|
|||
|
|
setRu: () => this.setLang("ru"),
|
|||
|
|
setEn: () => this.setLang("en"),
|
|||
|
|
ruBg: s.lang === "en" ? "transparent" : sel,
|
|||
|
|
enBg: s.lang === "en" ? sel : "transparent",
|
|||
|
|
ruInk: s.lang === "en" ? "var(--ink-3)" : "var(--ink)",
|
|||
|
|
enInk: s.lang === "en" ? "var(--ink)" : "var(--ink-3)",
|
|||
|
|
homeOff: s.view !== "home",
|
|||
|
|
keysOff: s.view !== "keys",
|
|||
|
|
keyOff: s.view !== "key",
|
|||
|
|
buyOff: s.view !== "buy",
|
|||
|
|
moreOff: s.view !== "more",
|
|||
|
|
shellCols: s.narrow ? "minmax(0, 1fr)" : "248px minmax(0, 1fr)",
|
|||
|
|
mainPad: s.narrow ? "20px 16px 110px" : "36px 40px 64px",
|
|||
|
|
asideOff: s.narrow,
|
|||
|
|
topbarOff: !s.narrow,
|
|||
|
|
pillOff: !s.narrow,
|
|||
|
|
tabHomeBg: s.view === "home" ? sel : "transparent",
|
|||
|
|
tabKeysBg: (s.view === "keys" || s.view === "key") ? sel : "transparent",
|
|||
|
|
tabBuyBg: s.view === "buy" ? sel : "transparent",
|
|||
|
|
tabMoreBg: s.view === "more" ? sel : "transparent",
|
|||
|
|
tabHomeInk: s.view === "home" ? "var(--accent)" : "var(--ink-2)",
|
|||
|
|
tabKeysInk: (s.view === "keys" || s.view === "key") ? "var(--accent)" : "var(--ink-2)",
|
|||
|
|
tabBuyInk: s.view === "buy" ? "var(--accent)" : "var(--ink-2)",
|
|||
|
|
tabMoreInk: s.view === "more" ? "var(--accent)" : "var(--ink-2)",
|
|||
|
|
homeBg: s.view === "home" ? sel : "transparent",
|
|||
|
|
keysBg: (s.view === "keys" || s.view === "key") ? sel : "transparent",
|
|||
|
|
buyBg: s.view === "buy" ? sel : "transparent",
|
|||
|
|
homeInk: s.view === "home" ? "var(--accent)" : "var(--ink-2)",
|
|||
|
|
keysInk: (s.view === "keys" || s.view === "key") ? "var(--accent)" : "var(--ink-2)",
|
|||
|
|
buyInk: s.view === "buy" ? "var(--accent)" : "var(--ink-2)",
|
|||
|
|
|
|||
|
|
keys: [mk(0), mk(1)],
|
|||
|
|
allKeys: [mk(0), mk(1)],
|
|||
|
|
cur: {
|
|||
|
|
title: cur.title,
|
|||
|
|
ip: cur.ip,
|
|||
|
|
until: cur.until,
|
|||
|
|
card: cur.card,
|
|||
|
|
devices: cur.devices,
|
|||
|
|
left: cur.left,
|
|||
|
|
leftInk: cur.warn ? "var(--warn)" : "var(--ink-2)",
|
|||
|
|
xray: cur.xray
|
|||
|
|
},
|
|||
|
|
configs: cfgNames.map((c, i) => ({
|
|||
|
|
name: c[0],
|
|||
|
|
state: c[1],
|
|||
|
|
showQr: () => this.setState({ qr: { title: "WireGuard · " + c[0], seed: cur.ip + c[0] } })
|
|||
|
|
})),
|
|||
|
|
refStats: s.lang === "en" ? "Invited: 3 · Months earned: 2" : "Приглашено: 3 · Месяцев начислено: 2",
|
|||
|
|
copyRef: () => this.setState({ refCopied: true }),
|
|||
|
|
refLabel: s.refCopied ? "Ссылка скопирована" : "Копировать ссылку",
|
|||
|
|
copyXray: () => this.setState({ copied: true }),
|
|||
|
|
copyLabel: s.copied ? "Скопировано" : "Копировать",
|
|||
|
|
showXrayQr: () => this.setState({ qr: { title: "Xray · Happ", seed: cur.xray } }),
|
|||
|
|
qrOff: !s.qr,
|
|||
|
|
qrTitle: s.qr ? s.qr.title : "",
|
|||
|
|
qrImage: s.qr ? this.qrImage(s.qr.seed) : null,
|
|||
|
|
closeQr: () => this.setState({ qr: null }),
|
|||
|
|
|
|||
|
|
faq: faqData.map((row, i) => ({
|
|||
|
|
q: row[0],
|
|||
|
|
a: row[1],
|
|||
|
|
off: s.faq !== i,
|
|||
|
|
rot: s.faq === i ? "rotate(-135deg) translateY(2px)" : "rotate(45deg) translateY(-2px)",
|
|||
|
|
toggle: () => this.setState(st => ({ faq: st.faq === i ? -1 : i }))
|
|||
|
|
})),
|
|||
|
|
|
|||
|
|
locations: this.data().map((d, i) => ({
|
|||
|
|
country: d.country,
|
|||
|
|
city: d.city,
|
|||
|
|
flag: this.flag(d.code),
|
|||
|
|
status: d.ready ? "Серверы в наличии" : "Установим за 24 часа",
|
|||
|
|
statusInk: d.ready ? "var(--accent)" : "var(--ink-3)",
|
|||
|
|
bg: s.loc === i ? sel : "var(--surface)",
|
|||
|
|
border: s.loc === i ? "var(--accent)" : "var(--border)",
|
|||
|
|
dot: s.loc === i ? "var(--accent)" : "transparent",
|
|||
|
|
dotOff: s.loc === i,
|
|||
|
|
setup: d.setup,
|
|||
|
|
month: d.month,
|
|||
|
|
buyOff: s.loc !== i,
|
|||
|
|
pick: () => this.setState({ loc: i })
|
|||
|
|
})),
|
|||
|
|
openLead: () => this.setState({ lead: true }),
|
|||
|
|
sendLead: () => this.setState({ leadSent: true }),
|
|||
|
|
leadOpen: s.lead,
|
|||
|
|
leadClosed: !s.lead,
|
|||
|
|
leadButton: s.leadSent ? "Заявка отправлена" : "Отправить",
|
|||
|
|
pickedTitle: locData[s.loc][0] + " · " + locData[s.loc][1],
|
|||
|
|
pickedHint: locData[s.loc][2] ? "Доступ выдадим сразу после оплаты" : "Установим сервер под вас, доступ в течение 24 часов",
|
|||
|
|
|
|||
|
|
toggleLang: () => this.setLang(s.lang === "ru" ? "en" : "ru"),
|
|||
|
|
langTitle: s.lang === "ru" ? "Язык: русский" : "Язык: английский",
|
|||
|
|
langLabel: s.lang === "ru" ? "RU" : "EN",
|
|||
|
|
setLight: () => this.setTheme("light"),
|
|||
|
|
setDark: () => this.setTheme("dark"),
|
|||
|
|
setSystem: () => this.setTheme("system"),
|
|||
|
|
lightBg: theme === "light" ? sel : "transparent",
|
|||
|
|
darkBg: theme === "dark" ? sel : "transparent",
|
|||
|
|
systemBg: theme === "system" ? sel : "transparent",
|
|||
|
|
lightInk: theme === "light" ? "var(--ink)" : "var(--ink-3)",
|
|||
|
|
darkInk: theme === "dark" ? "var(--ink)" : "var(--ink-3)",
|
|||
|
|
systemInk: theme === "system" ? "var(--ink)" : "var(--ink-3)"
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
</body>
|
|||
|
|
</html>
|