Compare commits

Author SHA1 Message Date
DenozordecandClaude Sonnet 5.5 6756d2fca5 android: version 2.18.1 (166)
Android / pre-check (push) Failing after 5s
Android / android (push) Skipped
CIFuzz / pre-check (push) Failing after 4s
CIFuzz / fuzzing (address) (push) Skipped
CIFuzz / fuzzing (undefined) (push) Skipped
CodeQL / pre-check (push) Failing after 5s
CodeQL / analyze (python) (push) Skipped
CodeQL / analyze (ruby) (push) Skipped
CodeQL / analyze-cpp (push) Skipped
FreeBSD / pre-check (push) Failing after 3s
FreeBSD / freebsd (14.4) (push) Skipped
FreeBSD / freebsd (15.0) (push) Skipped
Linux / pre-check (push) Failing after 4s
Linux / latest (apidoc) (push) Skipped
Linux / latest (clang, no, all) (push) Skipped
Linux / latest (clang, no, default) (push) Skipped
Linux / latest (clang, no, printf-builtin) (push) Skipped
Linux / latest (clang, no-dbg) (push) Skipped
Linux / latest (clang, no-testable-ke) (push) Skipped
Linux / latest (clang, yes, all) (push) Skipped
Linux / latest (clang, yes, default) (push) Skipped
Linux / latest (clang, yes, fuzzing) (push) Skipped
Linux / latest (coverage) (push) Skipped
Linux / latest (dist) (push) Skipped
Linux / latest (gcc, no, all) (push) Skipped
Linux / latest (gcc, no, default) (push) Skipped
Linux / latest (gcc, no, printf-builtin) (push) Skipped
Linux / latest (gcc, yes, all) (push) Skipped
Linux / latest (gcc, yes, default) (push) Skipped
Linux / latest (nm) (push) Skipped
Linux / latest (no-dbg) (push) Skipped
Linux / latest (no-testable-ke) (push) Skipped
Linux / latest (yes, ld) (push) Skipped
Linux / crypto (ubuntu-22.04, openssl-sys) (push) Skipped
Linux / crypto (ubuntu-latest, botan) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-3) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-4) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-awslc) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-sys) (push) Skipped
Linux / crypto (ubuntu-latest, wolfssl) (push) Skipped
Linux / older (clang, ubuntu-22.04, all) (push) Skipped
Linux / older (gcc, ubuntu-22.04, all) (push) Skipped
Linux / older (gcc, ubuntu-22.04, nm) (push) Skipped
Linux / alpine (push) Skipped
macOS / pre-check (push) Failing after 4s
macOS / macos (macos-14) (push) Skipped
macOS / macos (macos-latest) (push) Skipped
SonarCloud / pre-check (push) Failing after 4s
SonarCloud / sonarcloud (push) Skipped
TKM / pre-check (push) Failing after 3s
TKM / tkm (push) Skipped
Windows / pre-check (push) Failing after 3s
Windows / cross-compile (win32) (push) Skipped
Windows / cross-compile (win64) (push) Skipped
Windows / native (i686, mingw32, win32) (push) Skipped
Windows / native (x86_64, mingw64, win64) (push) Skipped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 01:52:12 +07:00
DenozordecandClaude Sonnet 5.5 5998c0fc46 android: Home view model no longer re-reads the Wi-Fi SSID on every signal-strength tick (state recomputed only when the transports change); energy plan: no shared network-callback hub, why
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 01:44:03 +07:00
DenozordecandClaude Sonnet 5.5 f5b15a0394 android: health check skips probes while inbound tunnel traffic proves liveness (adaptive mode, real probe at least every 5 min) and probes a single target with the screen off; unit tests; energy plan notes keepalive stays at 45 s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 01:22:09 +07:00
DenozordecandClaude Sonnet 5.5 38e5fd84bb android: less idle CPU work: TUN reader waits on poll+eventfd instead of a 1 s select; scenario app polling stops with the screen and slows down when idle; site DNS refresh waits for the screen; ServerActivity and rememberNow loops follow the lifecycle; energy plan
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 01:18:15 +07:00
DenozordecandClaude Opus 5.5 e0113e3413 android docs: the Final 2026 mockup (143 artboard sources and canvas.json) with an artboard-to-code map; app overview, code map, localization and release guide; AGENTS.md updated; old UI plan marked as archive
Android / pre-check (push) Failing after 6s
Android / android (push) Skipped
CIFuzz / pre-check (push) Failing after 4s
CIFuzz / fuzzing (address) (push) Skipped
CIFuzz / fuzzing (undefined) (push) Skipped
CodeQL / pre-check (push) Failing after 4s
CodeQL / analyze (python) (push) Skipped
CodeQL / analyze (ruby) (push) Skipped
CodeQL / analyze-cpp (push) Skipped
FreeBSD / pre-check (push) Failing after 4s
FreeBSD / freebsd (14.4) (push) Skipped
FreeBSD / freebsd (15.0) (push) Skipped
Linux / pre-check (push) Failing after 4s
Linux / latest (apidoc) (push) Skipped
Linux / latest (clang, no, all) (push) Skipped
Linux / latest (clang, no, default) (push) Skipped
Linux / latest (clang, no, printf-builtin) (push) Skipped
Linux / latest (clang, no-dbg) (push) Skipped
Linux / latest (clang, no-testable-ke) (push) Skipped
Linux / latest (clang, yes, all) (push) Skipped
Linux / latest (clang, yes, default) (push) Skipped
Linux / latest (clang, yes, fuzzing) (push) Skipped
Linux / latest (coverage) (push) Skipped
Linux / latest (dist) (push) Skipped
Linux / latest (gcc, no, all) (push) Skipped
Linux / latest (gcc, no, default) (push) Skipped
Linux / latest (gcc, no, printf-builtin) (push) Skipped
Linux / latest (gcc, yes, all) (push) Skipped
Linux / latest (gcc, yes, default) (push) Skipped
Linux / latest (nm) (push) Skipped
Linux / latest (no-dbg) (push) Skipped
Linux / latest (no-testable-ke) (push) Skipped
Linux / latest (yes, ld) (push) Skipped
Linux / crypto (ubuntu-22.04, openssl-sys) (push) Skipped
Linux / crypto (ubuntu-latest, botan) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-3) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-4) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-awslc) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-sys) (push) Skipped
Linux / crypto (ubuntu-latest, wolfssl) (push) Skipped
Linux / older (clang, ubuntu-22.04, all) (push) Skipped
Linux / older (gcc, ubuntu-22.04, all) (push) Skipped
Linux / older (gcc, ubuntu-22.04, nm) (push) Skipped
Linux / alpine (push) Skipped
macOS / pre-check (push) Failing after 4s
macOS / macos (macos-14) (push) Skipped
macOS / macos (macos-latest) (push) Skipped
SonarCloud / pre-check (push) Failing after 4s
SonarCloud / sonarcloud (push) Skipped
TKM / pre-check (push) Failing after 4s
TKM / tkm (push) Skipped
Windows / pre-check (push) Failing after 4s
Windows / cross-compile (win32) (push) Skipped
Windows / cross-compile (win64) (push) Skipped
Windows / native (i686, mingw32, win32) (push) Skipped
Windows / native (x86_64, mingw64, win64) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:31:05 +07:00
157 changed files with 14014 additions and 45 deletions

No files matched your search

+27 -1
View File
@@ -1,6 +1,25 @@
# Память проекта # Память проекта
## Android-приложение: сборка и выкладка (src/frontends/android) Основная работа в репозитории — Android-приложение SHX VPN (`src/frontends/android`), форк клиента strongSwan.
Описание приложения, кода, локализации и релиза: `src/frontends/android/docs/README.md`.
Дизайн: `src/frontends/android/docs/design/README.md` (макет «Финал 2026»).
## Android-приложение: дизайн и UI
- **Эталон — макет «Финал 2026»** (артборды `F_*`, тёмная тема `D_*`): живой холст https://claude.ai/artifact/UCC88C9hkU3hDU2YwMck1a,
копия исходников в `docs/design/final-2026/`. Экраны делаются строго по макету; новый экран сначала появляется на холсте.
- UI собирается только из компонентов макета: `ui/compose/design/ShxKit.kt`, `ShxIcons.kt`, цвета и шрифты `ui/compose/theme/ShxDesign.kt`
(`LocalShxColors`, `ShxType`). Сторонние цвета, размеры и стандартные M3-диалоги не использовать.
- Изменили экран в коде — обновите `F_*` и парный `D_*` на холсте и копию в `docs/design/final-2026/`.
## Android-приложение: строки и переводы
- Языки: en (база), ru, de, pl, uk, zh-rCN, zh-rTW. Новая строка добавляется сразу во все семь `values*/strings.xml`.
- Плейсхолдеры и `\n` как в английской строке; кавычки и plurals по языку — см. раздел «Локализация» в `docs/README.md`.
- После правок строк смотреть de и uk на эмуляторе (`adb shell cmd locale set-app-locales one.shx.strongswan.ext --locales de-DE`):
длинные слова не должны переноситься в навигации и заголовках. Сброс — `--locales ""`.
## Android-приложение: сборка и выкладка
- **Бакет S3 (Selectel, `shx-app`) ПРИВАТНЫЙ.** Публичного чтения нет и включать его не нужно: - **Бакет S3 (Selectel, `shx-app`) ПРИВАТНЫЙ.** Публичного чтения нет и включать его не нужно:
`GET https://s3.ru-7.storage.selcloud.ru/shx-app/latest.json` всегда отдаёт `AccessDenied` — это норма, а не ошибка выкладки. `GET https://s3.ru-7.storage.selcloud.ru/shx-app/latest.json` всегда отдаёт `AccessDenied` — это норма, а не ошибка выкладки.
@@ -8,9 +27,16 @@
- Сборка и публикация — скриптом `build-local.sh` (Git Bash) или `build-local.ps1` в `src/frontends/android`: - Сборка и публикация — скриптом `build-local.sh` (Git Bash) или `build-local.ps1` в `src/frontends/android`:
он читает `.env`, собирает `assembleRelease`, подписывает keystore'ом из `.env`, генерирует `latest.json` он читает `.env`, собирает `assembleRelease`, подписывает keystore'ом из `.env`, генерирует `latest.json`
(sha256/size/versionCode) и заливает `shx-vpn.apk` + `latest.json` в корень бакета с `Cache-Control: no-cache`. (sha256/size/versionCode) и заливает `shx-vpn.apk` + `latest.json` в корень бакета с `Cache-Control: no-cache`.
- **Порядок релиза:** `--skip-upload` → smoke-тест APK на эмуляторе (AVD `shx36`, все вкладки, `adb logcat -b crash`) →
выгрузка именно проверенного `build/publish/shx-vpn.apk` и `latest.json` через `aws s3 cp` → сверка `latest.json` в бакете.
Выгрузка в S3 — только с подтверждения владельца.
- **`.env` нельзя парсить через `source`/`eval`**: значения `NOTES_RU` и `AWS_CA_BUNDLE` содержат пробелы и - **`.env` нельзя парсить через `source`/`eval`**: значения `NOTES_RU` и `AWS_CA_BUNDLE` содержат пробелы и
обратные слэши. Разбирать только построчно `KEY=...` (как в `build-local.sh`). обратные слэши. Разбирать только построчно `KEY=...` (как в `build-local.sh`).
- aws cli установлен через pip: `%APPDATA%\Python\Python313\Scripts\aws` (скрипт сам добавляет путь в PATH). - aws cli установлен через pip: `%APPDATA%\Python\Python313\Scripts\aws` (скрипт сам добавляет путь в PATH).
- `versionCode` растёт вручную в `app/build.gradle`; перед сборкой сверять с `versionCode` в `latest.json` бакета. - `versionCode` растёт вручную в `app/build.gradle`; перед сборкой сверять с `versionCode` в `latest.json` бакета.
- `NOTES_RU` в `.env` — заметки релиза (попадают в `latest.json` → диалог обновления в приложении); обновлять под релиз. - `NOTES_RU` в `.env` — заметки релиза (попадают в `latest.json` → диалог обновления в приложении); обновлять под релиз.
`.env` не в git: в worktree лежит своя копия, после релиза перенести `NOTES_RU` в `.env` основного checkout.
- **Сборка из worktree:** скопировать игнорируемые входы из основного checkout (`.env` с абсолютным `KEYSTORE_FILE`,
`local.properties`, `Android.common.mk`, `app/src/main/jni/openssl/`, сгенерированные исходники libstrongswan — список в `docs/README.md`)
и собирать с `ORG_GRADLE_PROJECT_shortNdkCommands=true` (иначе линковка упирается в лимит длины команды Windows).
- Автообновление приложения: `logic/updates/UpdateManager.kt` качает манифест/APK, сверяет SHA-256 и подпись. - Автообновление приложения: `logic/updates/UpdateManager.kt` качает манифест/APK, сверяет SHA-256 и подпись.
+2 -2
View File
@@ -45,8 +45,8 @@ android {
minSdk = 24 minSdk = 24
targetSdk = 36 targetSdk = 36
versionCode 165 versionCode 166
versionName "2.18.0" versionName "2.18.1"
/* Base URL of the update storage, trailing slash included */ /* Base URL of the update storage, trailing slash included */
buildConfigField "String", "UPDATE_BASE_URL", "\"${updateBaseUrl}\"" buildConfigField "String", "UPDATE_BASE_URL", "\"${updateBaseUrl}\""
@@ -30,6 +30,7 @@ import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.IBinder import android.os.IBinder
import android.os.Looper import android.os.Looper
import android.os.SystemClock
import android.os.PowerManager import android.os.PowerManager
import android.util.Log import android.util.Log
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@@ -43,6 +44,7 @@ import kotlinx.coroutines.sync.Mutex
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import org.strongswan.android.logic.CharonVpnService
import org.strongswan.android.logic.VpnStateService import org.strongswan.android.logic.VpnStateService
import org.strongswan.android.logic.events.Events import org.strongswan.android.logic.events.Events
@@ -130,6 +132,9 @@ class HealthCheckManager private constructor(
private var tunnelAttempts = 0 private var tunnelAttempts = 0
private var fastPollShifts = 0 private var fastPollShifts = 0
private var powerState = PowerState() private var powerState = PowerState()
/* tunnel inbound bytes at the previous cycle (-1: unknown) and when the last real probe ran */
private var lastCycleInbound = -1L
private var lastProbeAt = 0L
/* tracks screen/battery state so probing can back off while the device sleeps */ /* tracks screen/battery state so probing can back off while the device sleeps */
private val powerReceiver = object : BroadcastReceiver() private val powerReceiver = object : BroadcastReceiver()
@@ -360,7 +365,31 @@ class HealthCheckManager private constructor(
return return
} }
val gateway = svc.profile?.gateway val gateway = svc.profile?.gateway
val targets = config.targets val adapted = adaptToPowerState(config, powerState)
val nowMs = SystemClock.elapsedRealtime()
/* passive liveness: payload that came back through the tunnel since the
* previous cycle proves it works without waking the radio for probes */
val inbound = tunnelInboundBytes()
val inboundDelta = if (lastCycleInbound >= 0 && inbound >= 0) inbound - lastCycleInbound else -1L
lastCycleInbound = inbound
if (trafficProvesAlive(
adapted, serverAttempts + tunnelAttempts, fastPollShifts, pendingDecision != null,
inboundDelta, nowMs - lastProbeAt,
))
{
scheduleCycle(effectiveIntervalSec(adapted) * 1000L)
return
}
lastProbeAt = nowMs
/* screen off: one target is enough (the confirmation probe uses it too) */
val targets = if (adapted.adaptiveMode && !powerState.screenOn && config.targets.size > 1)
{
setOf(config.targets.first())
}
else
{
config.targets
}
val mode = config.serverCheckMode val mode = config.serverCheckMode
val timeout = config.timeoutMs val timeout = config.timeoutMs
@@ -609,6 +638,21 @@ class HealthCheckManager private constructor(
tunnelAttempts = 0 tunnelAttempts = 0
fastPollShifts = 0 fastPollShifts = 0
pendingDecision = null pendingDecision = null
lastCycleInbound = -1L
lastProbeAt = 0L
}
/** Inbound byte counter of the tunnel's CHILD_SAs, -1 when unavailable. */
private fun tunnelInboundBytes(): Long
{
return try
{
CharonVpnService.queryTraffic()?.getOrNull(0) ?: -1L
}
catch (_: Throwable)
{
-1L
}
} }
private fun registerVpnCallback() private fun registerVpnCallback()
@@ -705,6 +749,32 @@ class HealthCheckManager private constructor(
private const val FAST_POLL_MAX_SHIFTS = 3 private const val FAST_POLL_MAX_SHIFTS = 3
private const val AGGRESSIVE_INTERVAL_SEC = 5 private const val AGGRESSIVE_INTERVAL_SEC = 5
/** Inbound tunnel payload since the last cycle that counts as proof of life. */
internal const val PASSIVE_MIN_INBOUND_BYTES = 4096L
/** Even with traffic flowing a real probe runs at least this often. */
internal const val PASSIVE_MAX_PROBE_AGE_MS = 5 * 60 * 1000L
/**
* Pure function: whether the cycle may skip its probes because the
* tunnel carried inbound data since the previous cycle. Only in
* adaptive mode, never in aggressive mode, never while a failure is
* being observed, and never for longer than [PASSIVE_MAX_PROBE_AGE_MS].
* Outbound-only traffic proves nothing, so it does not count.
*/
fun trafficProvesAlive(
adapted: HealthConfig,
failedAttempts: Int,
fastPollShifts: Int,
decisionPending: Boolean,
inboundDelta: Long,
sinceLastProbeMs: Long,
): Boolean =
adapted.adaptiveMode && !adapted.aggressiveMode &&
failedAttempts == 0 && fastPollShifts == 0 && !decisionPending &&
inboundDelta >= PASSIVE_MIN_INBOUND_BYTES &&
sinceLastProbeMs in 0 until PASSIVE_MAX_PROBE_AGE_MS
/** Minimum probe interval in adaptive mode while the screen is off. */ /** Minimum probe interval in adaptive mode while the screen is off. */
internal const val SCREEN_OFF_MIN_INTERVAL_SEC = 60 internal const val SCREEN_OFF_MIN_INTERVAL_SEC = 60
@@ -542,10 +542,22 @@ class RoutingManager private constructor(private val context: Context)
break break
} }
delay(SITE_REFRESH_MS) delay(SITE_REFRESH_MS)
/* nobody looks at the screen: resolving only wakes the radio and
* CPU, so wait for it to come on (re-checked every few minutes),
* but never let the answers get older than the cap */
var waited = SITE_REFRESH_MS
while (waited < SITE_REFRESH_SCREEN_OFF_MAX_MS && !isScreenOn())
{
delay(SITE_SCREEN_RECHECK_MS)
waited += SITE_SCREEN_RECHECK_MS
}
} }
} }
} }
private fun isScreenOn(): Boolean =
(context.getSystemService(Context.POWER_SERVICE) as? android.os.PowerManager)?.isInteractive ?: true
/** /**
* Like [updateConfig], but force prefixes apply on the fly through the * Like [updateConfig], but force prefixes apply on the fly through the
* atomic set swap of the userspace router - no reconnect needed. * atomic set swap of the userspace router - no reconnect needed.
@@ -833,6 +845,9 @@ class RoutingManager private constructor(private val context: Context)
private const val KEY_NOTICE_ONLY = "notice_only_profiles" private const val KEY_NOTICE_ONLY = "notice_only_profiles"
private const val RECONNECT_DEBOUNCE_MS = 2000L private const val RECONNECT_DEBOUNCE_MS = 2000L
const val SITE_REFRESH_MS = 30L * 60 * 1000 const val SITE_REFRESH_MS = 30L * 60 * 1000
/* with the screen off the refresh waits for it, up to this age */
private const val SITE_REFRESH_SCREEN_OFF_MAX_MS = 3L * 60 * 60 * 1000
private const val SITE_SCREEN_RECHECK_MS = 5L * 60 * 1000
/** Config schema: 1 = rule sets, 2 = direct apps + categories + patterns. */ /** Config schema: 1 = rule sets, 2 = direct apps + categories + patterns. */
const val CONFIG_VERSION = 2 const val CONFIG_VERSION = 2
@@ -21,6 +21,7 @@ import android.app.usage.UsageStatsManager
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager import android.net.ConnectivityManager
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import android.net.VpnService import android.net.VpnService
@@ -161,6 +162,9 @@ object ScenarioEngine
private const val TAG = "Scenarios" private const val TAG = "Scenarios"
private const val FILE_NAME = "scenarios.json" private const val FILE_NAME = "scenarios.json"
private const val POLL_MS = 4000L private const val POLL_MS = 4000L
/* the foreground app did not change for a minute: poll half as often */
private const val SLOW_AFTER_POLLS = 15
private const val SLOW_POLL_MS = 8000L
private const val PREF_APPLIED = "pref_scenario_applied" private const val PREF_APPLIED = "pref_scenario_applied"
private const val PREF_WAS_ON = "pref_scenario_was_on" private const val PREF_WAS_ON = "pref_scenario_was_on"
private const val PREF_WAS_PROFILE = "pref_scenario_was_profile" private const val PREF_WAS_PROFILE = "pref_scenario_was_profile"
@@ -174,6 +178,7 @@ object ScenarioEngine
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
private var appContext: Context? = null private var appContext: Context? = null
private var polling = false private var polling = false
private var unchangedPolls = 0
private var lastForeground: String? = null private var lastForeground: String? = null
fun flow(context: Context): StateFlow<List<Scenario>> fun flow(context: Context): StateFlow<List<Scenario>>
@@ -203,35 +208,84 @@ object ScenarioEngine
if (needPoll && !polling) if (needPoll && !polling)
{ {
polling = true polling = true
handler.post(poll) registerScreenReceiver(app)
if (isScreenOn(app))
{
handler.post(poll)
}
} }
else if (!needPoll) else if (!needPoll)
{ {
polling = false polling = false
handler.removeCallbacks(poll) handler.removeCallbacks(poll)
unregisterScreenReceiver(app)
} }
} }
private fun isScreenOn(context: Context): Boolean =
(context.getSystemService(Context.POWER_SERVICE) as? PowerManager)?.isInteractive ?: true
/* the foreground app only changes while the screen is on: no polling (and no
* wake-ups for it) while it is off, one immediate poll when it comes back */
private val screenReceiver = object : BroadcastReceiver()
{
override fun onReceive(context: Context, intent: Intent)
{
handler.removeCallbacks(poll)
if (polling && intent.action == Intent.ACTION_SCREEN_ON)
{
unchangedPolls = 0
handler.post(poll)
}
}
}
private var screenReceiverRegistered = false
private fun registerScreenReceiver(app: Context)
{
if (screenReceiverRegistered)
{
return
}
val filter = IntentFilter().apply {
addAction(Intent.ACTION_SCREEN_ON)
addAction(Intent.ACTION_SCREEN_OFF)
}
runCatching { app.registerReceiver(screenReceiver, filter, null, handler) }
.onSuccess { screenReceiverRegistered = true }
}
private fun unregisterScreenReceiver(app: Context)
{
if (!screenReceiverRegistered)
{
return
}
runCatching { app.unregisterReceiver(screenReceiver) }
screenReceiverRegistered = false
}
private val poll = object : Runnable private val poll = object : Runnable
{ {
override fun run() override fun run()
{ {
val app = appContext ?: return val app = appContext ?: return
if (!polling) if (!polling || !isScreenOn(app))
{ { /* resumed by the screen-on broadcast */
return return
} }
val screenOn = (app.getSystemService(Context.POWER_SERVICE) as? PowerManager)?.isInteractive ?: true val fg = foregroundApp(app)
if (screenOn) if (fg != null && fg != lastForeground)
{ {
val fg = foregroundApp(app) lastForeground = fg
if (fg != null && fg != lastForeground) unchangedPolls = 0
{ evaluate(app)
lastForeground = fg
evaluate(app)
}
} }
handler.postDelayed(this, POLL_MS) else
{
unchangedPolls++
}
handler.postDelayed(this, if (unchangedPolls >= SLOW_AFTER_POLLS) SLOW_POLL_MS else POLL_MS)
} }
} }
@@ -71,6 +71,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.repeatOnLifecycle
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanOptions import com.journeyapps.barcodescanner.ScanOptions
@@ -193,19 +194,24 @@ private fun ServerScreen(uuid: String, checkOnOpen: Boolean, onBack: () -> Unit)
val extras by remember { ProfileExtras.flow(context) }.collectAsStateWithLifecycle() val extras by remember { ProfileExtras.flow(context) }.collectAsStateWithLifecycle()
val extra = extras[uuid] ?: ProfileExtra(uuid) val extra = extras[uuid] ?: ProfileExtra(uuid)
/* the live state of the tunnel and a direct ping of the server */ /* the live state of the tunnel and a direct ping of the server */
val vpn by produceState<Pair<VpnStateService.State, String?>?>(null) { val vpn by produceState<Pair<VpnStateService.State, String?>?>(null, owner) {
while (true) /* only while the page is on screen */
{ owner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
val service = VpnStateService.getLiveInstance() while (true)
value = service?.let { it.state to it.profile?.getUUID()?.toString() } {
delay(1500) val service = VpnStateService.getLiveInstance()
value = service?.let { it.state to it.profile?.getUUID()?.toString() }
delay(1500)
}
} }
} }
val rtt by produceState<Long?>(null, profile.gateway) { val rtt by produceState<Long?>(null, profile.gateway, owner) {
while (true) owner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
{ while (true)
value = withContext(Dispatchers.IO) { ConnectivityProbe.pingServerDirect(context, profile.gateway, 1500)?.first } {
delay(30_000) value = withContext(Dispatchers.IO) { ConnectivityProbe.pingServerDirect(context, profile.gateway, 1500)?.first }
delay(30_000)
}
} }
} }
val active = vpn?.second == uuid val active = vpn?.second == uuid
@@ -199,7 +199,14 @@ class HomeViewModel(app: Application) : AndroidViewModel(app), VpnStateService.V
{ {
synchronized(underlyingNetworks) synchronized(underlyingNetworks)
{ {
underlyingNetworks[network] = capabilities val previous = underlyingNetworks.put(network, capabilities)
/* fired on every signal-strength tick: the published state (network
* kinds, SSID) only depends on the transports, and reading the SSID
* is a system call, so unchanged transports end here */
if (previous != null && sameTransports(previous, capabilities))
{
return
}
publishNetworks() publishNetworks()
} }
} }
@@ -214,6 +221,10 @@ class HomeViewModel(app: Application) : AndroidViewModel(app), VpnStateService.V
} }
} }
private fun sameTransports(a: NetworkCapabilities, b: NetworkCapabilities): Boolean =
a.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == b.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
a.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == b.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
private fun publishNetworks() private fun publishNetworks()
{ {
_networkAvailable.value = underlyingNetworks.isNotEmpty() _networkAvailable.value = underlyingNetworks.isNotEmpty()
@@ -40,6 +40,9 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import org.strongswan.android.R import org.strongswan.android.R
import org.strongswan.android.logic.PauseManager import org.strongswan.android.logic.PauseManager
@@ -103,12 +106,16 @@ internal fun HomeProblem.titleRes(): Int = when (this)
internal fun rememberNow(): Long internal fun rememberNow(): Long
{ {
var now by remember { mutableLongStateOf(System.currentTimeMillis()) } var now by remember { mutableLongStateOf(System.currentTimeMillis()) }
LaunchedEffect(Unit) val lifecycle = LocalLifecycleOwner.current.lifecycle
{ LaunchedEffect(lifecycle)
while (true) { /* no ticking while the app is in the background */
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED)
{ {
now = System.currentTimeMillis() while (true)
delay(1000L - now % 1000L) {
now = System.currentTimeMillis()
delay(1000L - now % 1000L)
}
} }
} }
return now return now
@@ -17,6 +17,9 @@
*/ */
#include <errno.h> #include <errno.h>
#include <poll.h>
#include <stdint.h>
#include <sys/eventfd.h>
#include <unistd.h> #include <unistd.h>
#include "android_jni.h" #include "android_jni.h"
@@ -70,6 +73,12 @@ struct private_android_service_t {
*/ */
int tunfd; int tunfd;
/**
* eventfd that wakes the TUN reader whenever tunfd is replaced or closed
* (-1 if it could not be created, then the reader falls back to a 1 s poll)
*/
int wakefd;
/** /**
* MTU of TUN device * MTU of TUN device
*/ */
@@ -136,6 +145,21 @@ static void engine_write_packet(void *ctx, ip_packet_t *packet)
deliver_plain(ctx, packet); deliver_plain(ctx, packet);
} }
/**
* Wake the TUN reader so it picks up a replaced or closed tunfd. Call it
* after this->tunfd was changed (the eventfd counter stays readable until the
* reader drains it, so a wake-up before the reader polls is not lost).
*/
static void wake_reader(private_android_service_t *this)
{
uint64_t one = 1;
if (this->wakefd >= 0 && write(this->wakefd, &one, sizeof(one)) < 0)
{
DBG1(DBG_DMN, "waking the TUN reader failed: %s", strerror(errno));
}
}
/** /**
* Job handling outbound plaintext packets * Job handling outbound plaintext packets
*/ */
@@ -143,16 +167,10 @@ static job_requeue_t handle_plain(private_android_service_t *this)
{ {
ip_packet_t *packet; ip_packet_t *packet;
chunk_t raw; chunk_t raw;
fd_set set; struct pollfd fds[2];
ssize_t len; ssize_t len;
int tunfd; int tunfd, wakefd, nfds = 1, timeout;
bool old, dns_proxy; bool old, dns_proxy;
timeval_t tv = {
/* check every second if tunfd is still valid */
.tv_sec = 1,
};
FD_ZERO(&set);
this->lock->read_lock(this->lock); this->lock->read_lock(this->lock);
if (this->tunfd < 0) if (this->tunfd < 0)
@@ -161,28 +179,60 @@ static job_requeue_t handle_plain(private_android_service_t *this)
return JOB_REQUEUE_NONE; return JOB_REQUEUE_NONE;
} }
tunfd = this->tunfd; tunfd = this->tunfd;
FD_SET(tunfd, &set); wakefd = this->wakefd;
/* cache this while we have the lock */ /* cache this while we have the lock */
dns_proxy = this->use_dns_proxy; dns_proxy = this->use_dns_proxy;
this->lock->unlock(this->lock); this->lock->unlock(this->lock);
fds[0].fd = tunfd;
fds[0].events = POLLIN;
fds[0].revents = 0;
if (wakefd >= 0)
{ /* a replaced or closed tunfd wakes us, so the timeout is only a
* safety net; without the eventfd re-check every second as before */
fds[1].fd = wakefd;
fds[1].events = POLLIN;
fds[1].revents = 0;
nfds = 2;
timeout = 60000;
}
else
{
timeout = 1000;
}
old = thread_cancelability(TRUE); old = thread_cancelability(TRUE);
len = select(tunfd + 1, &set, NULL, NULL, &tv); len = poll(fds, nfds, timeout);
thread_cancelability(old); thread_cancelability(old);
if (len < 0) if (len < 0)
{ {
if (errno == EBADF) if (errno == EBADF)
{ /* the TUN device got closed just before calling select(), retry */ { /* the TUN device got closed just before calling poll(), retry */
return JOB_REQUEUE_FAIR; return JOB_REQUEUE_FAIR;
} }
DBG1(DBG_DMN, "select on TUN device failed: %s", strerror(errno)); DBG1(DBG_DMN, "poll on TUN device failed: %s", strerror(errno));
return JOB_REQUEUE_NONE; return JOB_REQUEUE_NONE;
} }
else if (len == 0) else if (len == 0)
{ /* timeout, check again right away */ { /* timeout, check again right away */
return JOB_REQUEUE_DIRECT; return JOB_REQUEUE_DIRECT;
} }
if (nfds == 2 && (fds[1].revents & POLLIN))
{ /* tunfd was replaced or closed: drain the counter and start over with
* the current fd (pending TUN data stays, poll is level-triggered) */
uint64_t cnt;
if (read(wakefd, &cnt, sizeof(cnt)) < 0 && errno != EAGAIN)
{
DBG1(DBG_DMN, "reading the wake-up fd failed: %s", strerror(errno));
}
return JOB_REQUEUE_DIRECT;
}
if (fds[0].revents & POLLNVAL)
{ /* the fd was closed while polling, retry with the current one */
return JOB_REQUEUE_FAIR;
}
raw = chunk_alloc(this->mtu); raw = chunk_alloc(this->mtu);
len = read(tunfd, raw.ptr, raw.len); len = read(tunfd, raw.ptr, raw.len);
@@ -375,6 +425,8 @@ static bool setup_tun_device(private_android_service_t *this,
} }
this->tunfd = tunfd; this->tunfd = tunfd;
this->lock->unlock(this->lock); this->lock->unlock(this->lock);
/* a reader polling the previous fd must switch to the new one */
wake_reader(this);
DBG1(DBG_DMN, "successfully created TUN device"); DBG1(DBG_DMN, "successfully created TUN device");
@@ -422,6 +474,7 @@ static bool setup_tun_device_without_dns(private_android_service_t *this)
} }
this->tunfd = tunfd; this->tunfd = tunfd;
this->lock->unlock(this->lock); this->lock->unlock(this->lock);
wake_reader(this);
/* the fd changed, re-bind the userspace router to the new TUN */ /* the fd changed, re-bind the userspace router to the new TUN */
direct_engine_set_tun(this, engine_write_packet, this->mtu); direct_engine_set_tun(this, engine_write_packet, this->mtu);
@@ -446,6 +499,8 @@ static void close_tun_device(private_android_service_t *this)
tunfd = this->tunfd; tunfd = this->tunfd;
this->tunfd = -1; this->tunfd = -1;
this->lock->unlock(this->lock); this->lock->unlock(this->lock);
/* let the reader notice tunfd < 0 and quit instead of polling a dead fd */
wake_reader(this);
/* drop the remembered binding too, so a lazily created engine does not /* drop the remembered binding too, so a lazily created engine does not
* attach to the dead TUN, and flush the engine if it exists */ * attach to the dead TUN, and flush the engine if it exists */
@@ -977,6 +1032,10 @@ METHOD(android_service_t, destroy, void,
close_tun_device(this); close_tun_device(this);
this->dns_proxy->destroy(this->dns_proxy); this->dns_proxy->destroy(this->dns_proxy);
this->lock->destroy(this->lock); this->lock->destroy(this->lock);
if (this->wakefd >= 0)
{
close(this->wakefd);
}
this->settings->destroy(this->settings); this->settings->destroy(this->settings);
free(this); free(this);
} }
@@ -1005,6 +1064,7 @@ android_service_t *android_service_create(android_creds_t *creds,
.settings = settings, .settings = settings,
.creds = creds, .creds = creds,
.tunfd = -1, .tunfd = -1,
.wakefd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC),
.mtu = settings->get_int(settings, "global.mtu", ANDROID_DEFAULT_MTU), .mtu = settings->get_int(settings, "global.mtu", ANDROID_DEFAULT_MTU),
); );
/* only allow queries for the VPN gateway */ /* only allow queries for the VPN gateway */
@@ -242,4 +242,30 @@ class HealthCheckManagerTest
assertThat(HealthCheckManager.shouldProbeServer(ServerCheckMode.WITH_TUNNEL, 0, 3)).isTrue() assertThat(HealthCheckManager.shouldProbeServer(ServerCheckMode.WITH_TUNNEL, 0, 3)).isTrue()
assertThat(HealthCheckManager.shouldProbeServer(ServerCheckMode.WITH_TUNNEL, 0, 0)).isFalse() assertThat(HealthCheckManager.shouldProbeServer(ServerCheckMode.WITH_TUNNEL, 0, 0)).isFalse()
} }
@Test
fun inboundTrafficSkipsProbesInAdaptiveMode()
{
assertThat(HealthCheckManager.trafficProvesAlive(config, 0, 0, false, 10_000, 60_000)).isTrue()
}
@Test
fun noPassiveSkipWithoutInboundOrAfterCap()
{
assertThat(HealthCheckManager.trafficProvesAlive(config, 0, 0, false, 100, 60_000)).isFalse()
assertThat(HealthCheckManager.trafficProvesAlive(config, 0, 0, false, -1, 60_000)).isFalse()
assertThat(
HealthCheckManager.trafficProvesAlive(config, 0, 0, false, 10_000, HealthCheckManager.PASSIVE_MAX_PROBE_AGE_MS)
).isFalse()
}
@Test
fun noPassiveSkipWhileFailureIsObservedOrNotAdaptive()
{
assertThat(HealthCheckManager.trafficProvesAlive(config, 1, 0, false, 10_000, 1000)).isFalse()
assertThat(HealthCheckManager.trafficProvesAlive(config, 0, 2, false, 10_000, 1000)).isFalse()
assertThat(HealthCheckManager.trafficProvesAlive(config, 0, 0, true, 10_000, 1000)).isFalse()
assertThat(HealthCheckManager.trafficProvesAlive(config.copy(adaptiveMode = false), 0, 0, false, 10_000, 1000)).isFalse()
assertThat(HealthCheckManager.trafficProvesAlive(config.copy(aggressiveMode = true), 0, 0, false, 10_000, 1000)).isFalse()
}
} }
+85
View File
@@ -0,0 +1,85 @@
# SHX VPN для Android
Форк Android-клиента strongSwan (IKEv2/IPsec), пакет `one.shx.strongswan.ext`. Текущая версия — **2.18.1 (versionCode 166)**.
Распространяется вне Google Play: APK и манифест обновлений лежат в приватном бакете S3, приложение обновляется само.
- Дизайн: [design/README.md](design/README.md) — макет «Финал 2026» и соответствие артбордов коду.
- История UI-плана (до 2.15, устарела): [ui-ux-plan.md](ui-ux-plan.md).
## Что умеет приложение
| Раздел | Возможности |
|---|---|
| Главная | Кнопка подключения, шаги подключения из журнала демона, пауза (минуты, до утра, до смены сети), трафик за сегодня, карточки проблем (нет сети, сервер не отвечает, вход отклонён, белые списки, истекает сертификат) с действием в один тап, подсказки сценариев |
| Серверы | Один сервер = один профиль `.sswan`. Добавление по QR, ссылке, файлу или вручную; проверка профиля перед добавлением; «Поделиться» QR-кодом без пароля; страница сервера: источник профиля, ежедневная проверка ссылки и лист изменений, запасные порты, резервный сервер, мост при белых списках, DNS, MTU, фрагментация IKE |
| Маршруты | Раздельный туннель, сайты РФ напрямую (база адресов, режимы «Стабильно»/«Гибко»), приложения напрямую, правила (сайт, адрес/сеть, шаблон пакета), недавние приложения, недоступные хосты, «Как ходит трафик» |
| Сценарии | Правила для сетей (доверенная Wi-Fi / мобильная или чужая сеть) и свои сценарии: Wi-Fi, мобильная сеть, приложение открыто, время, роуминг, белые списки → включить, выключить, пауза, сменить сервер. Общий порядок, верхний важнее; ручное действие перекрывает сценарий до его окончания |
| Защита | DNS через туннель: из профиля, Cloudflare, AdGuard (реклама и трекеры), Cloudflare 1.1.1.2 (фишинг), свой адрес; «Без VPN — без сети» (инструкция к системному Always-on) |
| Статистика | Трафик по дням/неделям/месяцам: через VPN и напрямую, по приложениям (нужен доступ к статистике использования), итоги недели |
| Диагностика | Интернет, сайты РФ и зарубежные, сервер, DNS, белые списки за ~10 секунд; проверка сайта; отчёт в поддержку |
| События | Центр событий в приложении и push по каналам (статус, проблемы, новые приложения, обновления, итоги недели) |
| Система | Виджеты трёх размеров (Glance), плитка быстрых настроек, ярлыки профилей, автообновление с проверкой SHA-256 и подписи |
Профиль без сохранённого пароля никогда не запускается сам (watchdog, правила, сценарии, резерв, мост): вместо этого приходит событие со ссылкой на сервер.
## Устройство кода
`app/src/main/java/org/strongswan/android/`:
| Пакет | Что внутри |
|---|---|
| `logic/` | `CharonVpnService` (туннель и уведомление), `VpnStateService`, `WatchdogReceiver`, `PauseManager` |
| `logic/autoconnect` | Правила для сетей: `AutoConnectManager`, `NetworkMonitor`, `SsidReader` |
| `logic/scenarios` | `ScenarioEngine`: условия, порядок, ручной приоритет |
| `logic/profiles` | `ProfileExtras` (настройки поверх `.sswan`), `ProfileUpdater` (ссылка и diff), `Resilience` (порты, резерв, мост) |
| `logic/routing` | `RoutingManager`, база адресов РФ (`RuIpListManager`), правила и шаблоны пакетов, `RouteCheck`, `AppTraffic` |
| `logic/connectivity` | Проверки сети и сервера, `HealthCheckManager`, детект белых списков |
| `logic/protection` | Выбор DNS и фильтрации |
| `logic/stats` | `TrafficHistory`, `WeeklySummary` |
| `logic/events` | `EventLog` (центр событий), `Events` (push) |
| `logic/updates` | `UpdateManager`, загрузка и установка APK, проверка подписи |
| `ui/compose` | Экраны на Compose; `design/` — компоненты макета (`ShxKit`, `ShxIcons`), `theme/` — цвета и шрифты макета, `home/`, `routing/` |
| `ui/` | Activity вторичных экранов, `VpnTileService`, `widget/ShxWidget` |
Нативная часть (libcharon, libstrongswan, OpenSSL) собирается NDK из `app/src/main/jni`.
## Тулчейн
AGP 9.1.1, Gradle 9.3.1, Kotlin 2.2.21, Java 11, compileSdk 37, targetSdk 36, **minSdk 24**, NDK 27.3,
Compose BOM 2026.09.00, material3 1.5.0-beta01 (закреплена явно до стабильной 1.5.0), Glance 1.2.
## Сборка и тесты
Из `src/frontends/android`:
```bash
ORG_GRADLE_PROJECT_shortNdkCommands=true ./gradlew :app:assembleDebug :app:testDebugUnitTest -PshortNdkCommands
```
`shortNdkCommands` нужен на Windows в глубоких путях (worktree): иначе команда линковки libstrongswan длиннее лимита CreateProcess.
В worktree нет git-игнорируемых входов — их копируют из основного checkout: `.env`, `local.properties`, `Android.common.mk`,
`app/src/main/jni/openssl/`, сгенерированные `oid.{c,h}`, `proposal_keywords_static.{c,h}`, `settings_{lexer.c,parser.c,parser.h}`.
`lintDebug` пока падает на старых ошибках (NewApi в `FgsStartRetry`, MissingTranslation у неиспользуемых строк) — это не регресс.
## Локализация
Языки: en (база, `values/`), ru, de, pl, uk, zh-CN, zh-TW. Каждая новая строка добавляется сразу во все семь.
Правила перевода:
- плейсхолдеры (`%1$s`, `%1$d%%`) и `\n` сохраняются как в английской строке;
- кавычки по языку: ru/uk «…», de „…“, pl „…”, zh “…” / 「…」; апостроф — ’;
- plurals: de — one/other, pl/uk/ru — one/few/many/other, zh — other;
- системные термины как в Android: «Постоянный VPN», «Durchgehend aktives VPN», «Stały VPN», «Постійно ввімкнена VPN», «始终开启的 VPN», «永久連線的 VPN»;
- после правок посмотреть de и uk на эмуляторе: длинные слова не должны переноситься в нижней навигации и заголовках.
## Релиз
1. Сверить `versionCode` с бакетом: `aws s3 cp s3://shx-app/latest.json -` (endpoint и ключи из `.env`). Публичный GET отдаёт `AccessDenied` — это норма, бакет приватный.
2. Поднять `versionCode`/`versionName` в `app/build.gradle`.
3. Обновить `NOTES_RU` в `.env` (одна строка; текст попадёт в диалог обновления). `.env` читается построчно, без `source`/`eval`.
4. Собрать без выгрузки: `ORG_GRADLE_PROJECT_shortNdkCommands=true ./build-local.sh --skip-upload` (или `build-local.ps1 -SkipUpload`). Успех — строки `BUILD SUCCESSFUL` и `==> Built`.
5. Smoke-тест: установить `build/publish/shx-vpn.apk` на эмулятор (AVD `shx36`), пройти онбординг и все вкладки, проверить `adb logcat -b crash`.
6. Выложить именно проверенный APK: `aws s3 cp` сначала `shx-vpn.apk`, потом `latest.json` (оба с `--cache-control no-cache`, json ещё с `--content-type application/json`), затем прочитать `latest.json` из бакета и сверить sha256.
Известное ограничение Android 13+: приложению, установленному не из магазина, система блокирует «Статистику использования» («Контролируется настройками с ограниченным доступом»). Обычно снимается в «Информации о приложении» → ⋮ → «Разрешить ограниченные настройки» (пункт появляется после попытки включить разрешение); на Samsung может мешать «Автоблокировщик», крайний вариант — `adb shell appops set one.shx.strongswan.ext GET_USAGE_STATS allow`.
@@ -0,0 +1,78 @@
# Макет «Финал 2026»
Утверждённый дизайн SHX VPN. Все экраны приложения сделаны строго по нему.
- **Живой холст (смотреть и править):** https://claude.ai/artifact/UCC88C9hkU3hDU2YwMck1a. Это артефакт типа «Design» в Claude, доступ только у владельца.
- **Копия в репозитории:** `final-2026/` — исходники артбордов и раскладка холста (`canvas.json`) на 2026-10-13, версия 2.18.0.
## Как устроены файлы
- Каждый артборд — отдельный `*.dc.html`: разметка с инлайн-стилями плюс `class Component extends DCLogic`, у которого `renderVals()` отдаёт данные для `{{…}}`, `<sc-for>` и `<sc-if>`.
- Скрипт `./support.js`, который подключают файлы, — среда выполнения редактора Design. В репозиторий она не входит, поэтому вне холста файлы не отрисуются. Это исходник для чтения и сравнения, а не самостоятельные страницы.
- `canvas.json` хранит страницы холста, координаты и подписи артбордов.
- Шрифт — Manrope (Google Fonts), в приложении — `res/font/manrope_*.ttf`.
## Страницы холста
| Префикс | Страница | Что это |
|---|---|---|
| `O_*` | Обзор | Анализ, фичи по приоритетам, решения по дизайну, карта экранов |
| `F_*` | Финал 2026 | 57 артбордов светлой темы — **эталон** |
| `D_*` | Финал 2026 · тёмная | 54 артборда тёмной темы, те же экраны |
| остальные | Исследование | Ранние варианты (Главная 2.0, простой режим, «Для опытных»). Не реализуются, оставлены для истории |
`D_*` не рисуются вручную: они получаются из `F_*` заменой цветов светлой палитры на тёмную (`LightShxColors` → `DarkShxColors` в `ShxDesign.kt`). Исключение — `D_QsTile`, он правился руками. Когда меняется `F_*`, обновите и парный `D_*`.
## Артборд → код
Пути относительно `app/src/main/java/org/strongswan/android/`.
| Артборд | Экран | Код |
|---|---|---|
| `F_Home`, `F_HomeConnecting`, `F_HomePaused`, `F_HomeEmpty` | Главная | `ui/compose/home/HomeContent.kt`, `HomeParts.kt`, `ConnectSteps.kt` |
| `F_HomeAlert`, `F_HomeOffline`, `F_HomeUnreachable`, `F_ErrAuth` | Главная с проблемой | `ui/compose/home/HomeStatus.kt` |
| `F_HomeScenario`, `F_ScenarioSuggest` | Подсказки сценариев | `ui/compose/home/ScenarioHints.kt` |
| `F_CertExpiry` | Сертификат истекает | `ui/compose/home/CertExpiry.kt` |
| `F_Pause` | Пауза | `ui/compose/home/HomeStatus.kt`, `logic/PauseManager.kt` |
| `F_Servers`, `F_ServerDelete` | Серверы | `ui/compose/ProfilesScreen.kt` |
| `F_Profile`, `F_ProfileFile`, `F_ProfileUpdate` | Страница сервера | `ui/ServerActivity.kt`, `logic/profiles/*` |
| `F_Import`, `F_ImportQR` | Добавить сервер | `ui/compose/AddServerSheet.kt` |
| `F_ImportPreview`, `F_ErrImport` | Проверка профиля | `ui/compose/ImportScreen.kt` |
| `F_ManualAdd` | Сервер вручную | `ui/compose/ProfileFormScreen.kt` |
| `F_Share` | Поделиться по QR | `ui/compose/ShareProfileScreen.kt` |
| `F_Stats`, `F_StatsEmpty` | Статистика | `ui/StatsActivity.kt`, `logic/stats/*` |
| `F_Diag` | Диагностика | `ui/compose/DiagnosticsScreen.kt` |
| `F_Check` | Как ходит трафик | `ui/compose/RouteCheckScreen.kt` |
| `F_Routing` | Маршруты | `ui/compose/routing/RoutingHub.kt` |
| `F_Apps`, `F_AppPicker` | Приложения напрямую | `ui/compose/routing/DirectAppsScreen.kt` |
| `F_Rules`, `F_RulesEmpty`, `F_RuleAdd` | Правила | `ui/compose/routing/RulesScreen.kt` |
| `F_Recent`, `F_RecentEmpty` | Недавние приложения | `ui/compose/routing/RecentAppsScreen.kt` |
| `F_Automation`, `F_ScenarioAdd` | Сценарии | `ui/ScenariosActivity.kt`, `logic/scenarios/Scenarios.kt` |
| `F_Settings` | Настройки | `ui/compose/SettingsScreen.kt` |
| `F_Protection` | DNS и реклама | `ui/compose/SettingsScreen.kt`, `SettingsPages.kt`, `logic/protection/Protection.kt` |
| `F_KillSwitch`, `F_NotifSettings`, `F_Appearance`, `F_Update`, `F_UpdateInstall`, `F_Help` | Страницы настроек | `ui/compose/SettingsPages.kt` |
| `F_Log` | Журнал | `ui/LogActivity.kt` |
| `F_Certs` | Сертификаты | `ui/TrustedCertificatesActivity.kt` |
| `F_Battery` | Экономия батареи | `ui/BatteryActivity.kt` |
| `F_Onboarding` | Онбординг | `ui/OnboardingActivity.kt` |
| `F_Permissions` | Разрешения | `ui/compose/PermissionsScreen.kt` |
| `F_VpnConsent` | Подсказка к системному запросу VPN | `ui/compose/VpnDialogs.kt` |
| `F_Inbox` | События в приложении | `ui/compose/InboxScreen.kt`, `logic/events/*` |
| `F_Shade`, `F_SysNotifs` | Уведомления Android | `logic/CharonVpnService.java`, `logic/events/Events.kt` |
| `F_Widgets` | Виджеты | `ui/widget/ShxWidget.kt` |
| `F_QsTile` | Плитка быстрых настроек | `ui/VpnTileService.java` |
| `Logo` | Логотип «Щит-S» | `res/drawable/ic_launcher_*.xml`, `res/mipmap-anydpi*` |
## Дизайн-система в коде
- `ui/compose/theme/ShxDesign.kt` — цвета макета (`LocalShxColors`, `LightShxColors`/`DarkShxColors`) и типографика `ShxType`.
- `ui/compose/design/ShxKit.kt` — компоненты макета: `ShxScreenTitle`, `ShxPageHeader`, `ShxPanel`, `ShxRow`, `ShxToggleRow`, `ShxSwitch`, `ShxButton`, `ShxTabs`, `ShxChip`, `ShxField`/`ShxFormField`, `ShxSheet`, `ShxDialog`/`ShxAlertDialog`, `ShxDialogButton`, `ShxNote`.
- `ui/compose/design/ShxIcons.kt` — линейные иконки макета.
Новый экран сначала рисуется на холсте как `F_*` (и `D_*`), потом собирается из этих компонентов, без сторонних цветов и размеров.
## Как обновить копию в репозитории
1. Правки делаются на холсте (или публикацией файлов в артефакт).
2. Скачать `project/*` текущей версии артефакта (в Claude Code: Artifact `read` с `paths`) и заменить `final-2026/`.
3. Если появились новые артборды — дописать их в таблицу выше.
@@ -0,0 +1,114 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Приложения без VPN</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1200px; box-sizing: border-box; background: #F3F0F7; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<div style="display: flex; align-items: center; justify-content: space-between; padding: 14px 16px 0">
<a href="AdvRouting.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.8); box-shadow: 0 1px 2px rgba(28,27,32,0.08); display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<button style="flex: none; white-space: nowrap; height: 44px; padding: 0 16px; border: 0; border-radius: 22px; background: rgba(255,255,255,0.8); box-shadow: 0 1px 2px rgba(28,27,32,0.08); color: #6D4AFF; font: 700 14px 'Manrope', sans-serif">Системные</button>
</div>
<header style="padding: 44px 24px 18px">
<h1 style="margin: 0; font-size: 34px; font-weight: 800; letter-spacing: -0.03em">Приложения</h1>
<p style="margin: 6px 0 0; font-size: 14px; color: #6E6A78">24 из 111 работают без VPN</p>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 18px">
<label style="display: flex; align-items: center; gap: 8px; height: 44px; padding: 0 14px; border-radius: 14px; background: #E8E4EE; color: #6E6A78">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
<input type="text" placeholder="Поиск" aria-label="Поиск приложений" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 500 16px 'Manrope', sans-serif; color: #1C1B20; outline: none">
</label>
<div role="tablist" aria-label="Фильтр" style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 3px; border-radius: 14px; background: #E8E4EE">
<button role="tab" aria-selected="true" style="height: 36px; border: 0; border-radius: 11px; background: #FFFFFF; color: #1C1B20; font: 800 13px 'Manrope', sans-serif; box-shadow: 0 1px 3px rgba(28,27,32,0.14)">Напрямую</button>
<button role="tab" style="height: 36px; border: 0; border-radius: 11px; background: transparent; color: #49454F; font: 600 13px 'Manrope', sans-serif">Через VPN</button>
<button role="tab" style="height: 36px; border: 0; border-radius: 11px; background: transparent; color: #49454F; font: 600 13px 'Manrope', sans-serif">Все</button>
</div>
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 0 12px; font-size: 13px; font-weight: 700; color: #6E6A78">Наборы</h2>
<div style="display: flex; gap: 8px; overflow: hidden">
<sc-for list="{{sets}}" as="s" hint-placeholder-count="4">
<button style="flex: none; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; width: 104px; padding: 12px; border-radius: 20px; border: 0; background: {{s.bg}}; color: {{s.fg}}; font-family: 'Manrope', sans-serif; text-align: left">
<span style="font-size: 13px; font-weight: 800">{{s.name}}</span>
<span style="font-size: 12px; font-weight: 600; opacity: 0.85">{{s.state}}</span>
</button>
</sc-for>
</div>
</section>
<sc-for list="{{groups}}" as="g" hint-placeholder-count="3">
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 0 12px; font-size: 13px; font-weight: 700; color: #6E6A78">{{g.title}}</h2>
<div style="border-radius: 24px; background: #FFFFFF; overflow: hidden">
<sc-for list="{{g.apps}}" as="a" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 14px; padding-left: 16px; height: 64px">
<span style="flex: none; width: 36px; height: 36px; border-radius: 10px; background: {{a.color}}; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">{{a.letter}}</span>
<span style="flex: 1; height: 64px; display: flex; align-items: center; gap: 10px; padding-right: 14px; border-bottom: {{a.divider}}; min-width: 0">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 16px; font-weight: 600">{{a.name}}</span>
<span style="font-size: 12px; color: {{a.reasonColor}}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">{{a.reason}}</span>
</span>
<button aria-pressed="{{a.on}}" aria-label="{{a.name}}: напрямую" style="flex: none; width: 50px; height: 30px; border: 0; border-radius: 15px; background: {{a.track}}; padding: 3px; display: flex; justify-content: {{a.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #FFFFFF; box-shadow: 0 1px 3px rgba(0,0,0,0.2)"></span></button>
</span>
</div>
</sc-for>
</div>
</section>
</sc-for>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1200}}'>
class Component extends DCLogic {
renderVals() {
var set = function (name, state, done) {
return { name: name, state: state, bg: done ? '#6D4AFF' : '#FFFFFF', fg: done ? '#FFFFFF' : '#1C1B20' };
};
var reasons = { me: ['добавлено вами', '#6E6A78'], tpl: ['по правилу ', '#6E6A78'], over: ['исключение из ', '#B45309'] };
var grp = function (title, apps) {
return { title: title, apps: apps.map(function (a, i) {
var on = a[3] !== 'over';
return { name: a[0], letter: a[1], color: a[2],
reason: reasons[a[3]][0] + (a[4] ? '«' + a[4] + '»' : ''), reasonColor: reasons[a[3]][1],
on: on ? 'true' : 'false', track: on ? '#6D4AFF' : '#D6D2DD', align: on ? 'flex-end' : 'flex-start',
divider: i < apps.length - 1 ? '1px solid #EEEAF2' : '0' };
}) };
};
return {
sets: [set('Банки', '8 из 8', true), set('Госуслуги', '3 из 3', true), set('Магазины', '2 из 5', false), set('Связь', '0 из 4', false)],
groups: [
grp('Банки', [
['СберБанк Онлайн', 'С', '#21A038', 'tpl', 'ru.*'],
['Т-Банк', 'Т', '#3A3A3A', 'me'],
['Альфа-Банк', 'А', '#C62828', 'tpl', 'ru.*']
]),
grp('Госуслуги и сервисы', [
['Госуслуги', 'Г', '#1F5FBF', 'tpl', 'ru.*'],
['Яндекс Карты', 'Я', '#D84315', 'tpl', '*yandex*'],
['Яндекс Браузер', 'Я', '#5E35B1', 'over', '*yandex*']
]),
grp('Магазины', [
['Wildberries', 'W', '#7B2CBF', 'me'],
['Ozon', 'O', '#1565C0', 'me']
])
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,99 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Диагностика</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1100px; box-sizing: border-box; background: #F3F0F7; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<div style="display: flex; align-items: center; justify-content: space-between; padding: 14px 16px 0">
<a href="AdvHub.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.8); box-shadow: 0 1px 2px rgba(28,27,32,0.08); display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<button style="flex: none; white-space: nowrap; height: 44px; padding: 0 16px; border: 0; border-radius: 22px; background: rgba(255,255,255,0.8); box-shadow: 0 1px 2px rgba(28,27,32,0.08); color: #6D4AFF; font: 700 14px 'Manrope', sans-serif">Журнал</button>
</div>
<header style="padding: 44px 24px 18px">
<h1 style="margin: 0; font-size: 34px; font-weight: 800; letter-spacing: -0.03em">Диагностика</h1>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 22px">
<section style="border-radius: 24px; background: #FFFFFF; padding: 14px; display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; gap: 8px">
<label style="flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; height: 44px; padding: 0 12px; border-radius: 14px; background: #F3F0F7; color: #6E6A78">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
<input type="text" value="kinopoisk.ru" aria-label="Домен" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 600 16px 'Manrope', sans-serif; color: #1C1B20; outline: none">
</label>
<button style="flex: none; white-space: nowrap; height: 44px; padding: 0 16px; border: 0; border-radius: 14px; background: #6D4AFF; color: #FFFFFF; font: 700 14px 'Manrope', sans-serif">Проверить</button>
</div>
<div style="display: flex; align-items: center; gap: 12px; padding: 4px 4px 0">
<span style="width: 36px; height: 36px; border-radius: 18px; background: #E2F5EA; color: #148A45; display: flex; align-items: center; justify-content: center">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 1px">
<span style="font-size: 16px; font-weight: 800">Напрямую, мимо VPN</span>
<span style="font-size: 13px; color: #6E6A78">2 адреса · RU-диапазон</span>
</span>
<a href="AdvRules.dc.html" style="font-size: 14px; font-weight: 700; text-decoration: none; color: #6D4AFF">В VPN</a>
</div>
</section>
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 0 12px; font-size: 13px; font-weight: 700; color: #6E6A78">Последнее подключение</h2>
<div style="border-radius: 24px; background: #FFFFFF; padding: 6px 16px">
<sc-for list="{{steps}}" as="s" hint-placeholder-count="4">
<div style="display: flex; align-items: center; gap: 12px; height: 48px">
<span style="width: 10px; height: 10px; border-radius: 5px; background: {{s.dot}}"></span>
<span style="flex: 1; font-size: 15px; font-weight: 600">{{s.title}}</span>
<span style="font-size: 14px; color: #6E6A78">{{s.value}}</span>
</div>
</sc-for>
</div>
</section>
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 0 12px; display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 700; color: #6E6A78">Недоступные хосты<span style="padding: 1px 7px; border-radius: 6px; background: #FFE2B8; color: #7A3A06; font-size: 11px; font-weight: 800">3</span></h2>
<div style="border-radius: 24px; background: #FFFFFF; overflow: hidden">
<sc-for list="{{hosts}}" as="h" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 10px; margin-left: 16px; padding-right: 12px; height: 60px; border-bottom: {{h.divider}}">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 14px; font-weight: 700; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace">{{h.host}}</span>
<span style="font-size: 12px; color: #6E6A78">{{h.meta}}</span>
</span>
<button style="height: 34px; padding: 0 14px; border: 0; border-radius: 17px; background: #EFEAFF; color: #6D4AFF; font: 700 13px 'Manrope', sans-serif">В VPN</button>
</div>
</sc-for>
</div>
</section>
<button style="height: 52px; border: 0; border-radius: 18px; background: #FFFFFF; color: #6D4AFF; font: 700 16px 'Manrope', sans-serif">Отправить отчёт</button>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1100}}'>
class Component extends DCLogic {
renderVals() {
var ok = '#148A45';
var hs = [['95.163.•••.12:443', 'отказов 14 · пауза 4 мин'], ['178.248.•••.70:443', 'отказов 9 · пауза 2 мин'], ['212.193.•••.5:5222', 'отказов 6 · пауза 40 с']];
return {
steps: [
{ dot: ok, title: 'Сеть', value: 'Wi-Fi' },
{ dot: ok, title: 'Сервер ответил', value: '38 мс · порт 4500' },
{ dot: ok, title: 'Вход', value: 'сертификат принят' },
{ dot: ok, title: 'Туннель', value: 'MTU 1400' }
],
hosts: hs.map(function (h, i) { return { host: h[0], meta: h[1], divider: i < hs.length - 1 ? '1px solid #EEEAF2' : '0' }; })
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,94 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Для опытных</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1120px; box-sizing: border-box; background: #F3F0F7; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<div style="display: flex; align-items: center; justify-content: space-between; padding: 14px 16px 0">
<a href="SimpleSettings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.8); box-shadow: 0 1px 2px rgba(28,27,32,0.08), inset 0 0 0 1px rgba(255,255,255,0.9); display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
</div>
<header style="padding: 44px 24px 20px">
<h1 style="margin: 0; font-size: 34px; font-weight: 800; letter-spacing: -0.03em">Для опытных</h1>
<p style="margin: 6px 0 0; font-size: 14px; color: #6E6A78">Всё, что спрятано из простого режима</p>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 22px">
<label style="display: flex; align-items: center; gap: 8px; height: 44px; padding: 0 14px; border-radius: 14px; background: #E8E4EE; color: #6E6A78">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
<input type="text" placeholder="Поиск по настройкам" aria-label="Поиск по настройкам" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 500 16px 'Manrope', sans-serif; color: #1C1B20; outline: none">
</label>
<sc-for list="{{groups}}" as="g" hint-placeholder-count="5">
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 0 12px; font-size: 13px; font-weight: 700; color: #6E6A78">{{g.title}}</h2>
<div style="border-radius: 24px; background: #FFFFFF; overflow: hidden">
<sc-for list="{{g.rows}}" as="r" hint-placeholder-count="2">
<a href="{{r.href}}" style="display: flex; align-items: center; gap: 14px; padding-left: 16px; height: 56px; text-decoration: none; color: #1C1B20">
<span style="flex: none; width: 30px; height: 30px; border-radius: 9px; background: {{r.tile}}; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 800">{{r.tag}}</span>
<span style="flex: 1; height: 56px; display: flex; align-items: center; gap: 8px; padding-right: 14px; border-bottom: {{r.divider}}">
<span style="flex: 1; font-size: 16px; font-weight: 600">{{r.title}}</span>
<span style="font-size: 14px; color: {{r.valueColor}}; font-weight: {{r.valueWeight}}">{{r.value}}</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#B3AFBC" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</span>
</a>
</sc-for>
</div>
</section>
</sc-for>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1120}}'>
class Component extends DCLogic {
renderVals() {
var P = '#6D4AFF', G = '#148A45', A = '#C2620E', S = '#5E5A7D', B = '#2F6FDB';
var grp = function (title, rows) {
return { title: title, rows: rows.map(function (r, i) {
return { tag: r[0], tile: r[1], title: r[2], value: r[3], href: r[4],
valueColor: r[5] ? '#B45309' : '#6E6A78', valueWeight: r[5] ? '800' : '500',
divider: i < rows.length - 1 ? '1px solid #EEEAF2' : '0' };
}) };
};
return {
groups: [
grp('Маршрутизация', [
['RU', P, 'Маршруты', 'Стабильно', 'AdvRouting.dc.html'],
['APP', G, 'Приложения без VPN', '24', 'AdvApps.dc.html'],
['≡', S, 'Правила', '5', 'AdvRules.dc.html']
]),
grp('Подключение', [
['NL', B, 'Профили', '3', 'AdvProfile.dc.html'],
['↻', P, 'Устойчивость', 'Резерв + мост', 'AdvProfile.dc.html']
]),
grp('Сеть', [
['DNS', B, 'DNS', 'Cloudflare', 'Protection.dc.html'],
['MTU', S, 'MTU и фрагментация', 'Авто', 'AdvProfile.dc.html']
]),
grp('Диагностика', [
['?', P, 'Проверка сайта', '', 'AdvDiag.dc.html'],
['!', A, 'Недоступные хосты', '3', 'AdvDiag.dc.html', true],
['LOG', S, 'Журнал', '', 'AdvDiag.dc.html']
]),
grp('Безопасность', [
['CA', S, 'Сертификаты', '2', 'AdvHub.dc.html']
])
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,93 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Профиль</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1240px; box-sizing: border-box; background: #F3F0F7; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<div style="display: flex; align-items: center; justify-content: space-between; padding: 14px 16px 0">
<a href="AdvHub.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.8); box-shadow: 0 1px 2px rgba(28,27,32,0.08); display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<button aria-label="Поделиться по QR" style="width: 44px; height: 44px; border: 0; border-radius: 22px; background: rgba(255,255,255,0.8); box-shadow: 0 1px 2px rgba(28,27,32,0.08); display: flex; align-items: center; justify-content: center; color: #6D4AFF">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="4" width="6" height="6" rx="1"/><rect x="14" y="4" width="6" height="6" rx="1"/><rect x="4" y="14" width="6" height="6" rx="1"/><path d="M14 14h2v2M20 14v6h-6"/></svg>
</button>
</div>
<header style="padding: 44px 24px 18px; display: flex; align-items: flex-end; gap: 14px">
<span style="width: 56px; height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: 800">NL</span>
<span style="display: flex; flex-direction: column; gap: 4px">
<h1 style="margin: 0; font-size: 30px; font-weight: 800; letter-spacing: -0.03em">Амстердам</h1>
<span style="display: flex; align-items: center; gap: 6px; font-size: 14px; color: #0E6B35; font-weight: 700"><span style="width: 8px; height: 8px; border-radius: 4px; background: #148A45"></span>Подключён · 38 мс</span>
</span>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 22px">
<sc-for list="{{groups}}" as="g" hint-placeholder-count="4">
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 0 12px; display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 700; color: #6E6A78">{{g.title}}<sc-if value="{{g.isNew}}" hint-placeholder-val="{{ false }}"><span style="padding: 1px 7px; border-radius: 6px; background: #6D4AFF; color: #FFFFFF; font-size: 10px; font-weight: 800">НОВОЕ</span></sc-if></h2>
<div style="border-radius: 24px; background: #FFFFFF; overflow: hidden">
<sc-for list="{{g.rows}}" as="r" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 10px; margin-left: 16px; padding-right: 14px; min-height: 56px; border-bottom: {{r.divider}}">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; padding: 8px 0">
<span style="font-size: 16px; font-weight: 600">{{r.title}}</span>
<sc-if value="{{r.hasSub}}" hint-placeholder-val="{{ false }}"><span style="font-size: 12px; line-height: 1.35; color: #6E6A78">{{r.sub}}</span></sc-if>
</span>
<sc-if value="{{r.isToggle}}" hint-placeholder-val="{{ false }}">
<button aria-pressed="{{r.on}}" aria-label="{{r.title}}" style="flex: none; width: 50px; height: 30px; border: 0; border-radius: 15px; background: {{r.track}}; padding: 3px; display: flex; justify-content: {{r.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #FFFFFF; box-shadow: 0 1px 3px rgba(0,0,0,0.2)"></span></button>
</sc-if>
<sc-if value="{{r.isValue}}" hint-placeholder-val="{{ true }}">
<span style="font-size: 15px; color: #6E6A78; text-align: right; max-width: 170px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap">{{r.value}}</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#B3AFBC" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</sc-if>
</div>
</sc-for>
</div>
</section>
</sc-for>
<div style="border-radius: 24px; background: #FFFFFF; overflow: hidden">
<button style="width: 100%; height: 56px; border: 0; border-bottom: 1px solid #EEEAF2; background: transparent; color: #6D4AFF; font: 700 16px 'Manrope', sans-serif">Экспорт .sswan</button>
<button style="width: 100%; height: 56px; border: 0; background: transparent; color: #C62828; font: 700 16px 'Manrope', sans-serif">Удалить профиль</button>
</div>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1240}}'>
class Component extends DCLogic {
renderVals() {
var v = function (title, value, sub) { return { title: title, value: value, sub: sub || '', hasSub: !!sub, isValue: true, isToggle: false }; };
var t = function (title, on, sub) {
return { title: title, sub: sub || '', hasSub: !!sub, isValue: false, isToggle: true,
on: on ? 'true' : 'false', track: on ? '#6D4AFF' : '#D6D2DD', align: on ? 'flex-end' : 'flex-start' };
};
var grp = function (title, rows, isNew) {
rows.forEach(function (r, i) { r.divider = i < rows.length - 1 ? '1px solid #EEEAF2' : '0'; });
return { title: title, rows: rows, isNew: !!isNew };
};
return {
groups: [
grp('Сервер', [v('Адрес', 'nl1.[ваш-домен]'), v('Порт', '4500'), v('Вход', 'Сертификат')]),
grp('Устойчивость', [
v('Запасные порты', '443, 53', 'Пробуем по очереди, если основной не отвечает'),
v('Резервный профиль', 'Хельсинки'),
t('Мост при белых списках', true, 'Переключаться на сервер с российским IP')
], true),
grp('Сеть', [v('DNS', 'Из профиля'), v('MTU', 'Авто · 1400'), t('Фрагментация IKE', true)]),
grp('Маршруты профиля', [t('Использовать общие правила', true, 'Иначе — свои подсети для этого профиля')])
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,106 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Маршруты</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #F3F0F7; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<div style="display: flex; align-items: center; justify-content: space-between; padding: 14px 16px 0">
<a href="AdvHub.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.8); box-shadow: 0 1px 2px rgba(28,27,32,0.08); display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<button aria-pressed="true" aria-label="Раздельный туннель" style="width: 56px; height: 34px; border: 0; border-radius: 17px; background: #6D4AFF; padding: 4px; display: flex; justify-content: flex-end"><span style="width: 26px; height: 26px; border-radius: 13px; background: #FFFFFF; box-shadow: 0 1px 3px rgba(0,0,0,0.2)"></span></button>
</div>
<header style="padding: 44px 24px 20px">
<h1 style="margin: 0; font-size: 34px; font-weight: 800; letter-spacing: -0.03em">Маршруты</h1>
<p style="margin: 6px 0 0; font-size: 14px; color: #6E6A78">Что идёт мимо VPN</p>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 22px">
<section style="padding: 18px; border-radius: 24px; background: #FFFFFF; display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; height: 10px; border-radius: 5px; overflow: hidden; gap: 3px">
<span style="width: 72%; background: #6D4AFF; border-radius: 5px"></span>
<span style="flex: 1; background: #3FBF7F; border-radius: 5px"></span>
</div>
<div style="display: flex; justify-content: space-between; font-size: 13px; font-weight: 700">
<span style="display: flex; align-items: center; gap: 6px; color: #3B2C88"><span style="width: 8px; height: 8px; border-radius: 4px; background: #6D4AFF"></span>Через VPN · 72%</span>
<span style="display: flex; align-items: center; gap: 6px; color: #0E6B35"><span style="width: 8px; height: 8px; border-radius: 4px; background: #3FBF7F"></span>Напрямую · 28%</span>
</div>
<span style="font-size: 14px; line-height: 1.45; color: #49454F">Напрямую идут сайты РФ, 24 приложения и 2 ваших правила.</span>
</section>
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 0 12px; font-size: 13px; font-weight: 700; color: #6E6A78">Сайты и сервисы РФ</h2>
<div style="border-radius: 24px; background: #FFFFFF; padding: 14px; display: flex; flex-direction: column; gap: 12px">
<div role="radiogroup" aria-label="Сайты РФ" style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 3px; border-radius: 14px; background: #EEEAF2">
<button style="height: 40px; border: 0; border-radius: 11px; background: transparent; color: #49454F; font: 600 14px 'Manrope', sans-serif">Выкл</button>
<button aria-pressed="true" style="height: 40px; border: 0; border-radius: 11px; background: #FFFFFF; color: #1C1B20; font: 800 14px 'Manrope', sans-serif; box-shadow: 0 1px 3px rgba(28,27,32,0.14)">Стабильно</button>
<button style="height: 40px; border: 0; border-radius: 11px; background: transparent; color: #49454F; font: 600 14px 'Manrope', sans-serif">Гибко <span style="font-size: 10px; font-weight: 800; color: #B45309">β</span></button>
</div>
<span style="padding: 0 4px; font-size: 13px; line-height: 1.4; color: #6E6A78">Надёжно. Новые адреса применяются после переподключения.</span>
<div style="display: flex; align-items: center; gap: 10px; padding: 10px 4px 0; border-top: 1px solid #EEEAF2">
<span style="flex: 1; display: flex; flex-direction: column; gap: 1px">
<span style="font-size: 15px; font-weight: 600">База адресов</span>
<span style="font-size: 13px; color: #6E6A78">12 480 сетей · сегодня в 09:12</span>
</span>
<button style="height: 36px; padding: 0 14px; border: 0; border-radius: 18px; background: #EFEAFF; color: #6D4AFF; font: 700 14px 'Manrope', sans-serif">Обновить</button>
</div>
</div>
</section>
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 0 12px; font-size: 13px; font-weight: 700; color: #6E6A78">Исключения</h2>
<div style="border-radius: 24px; background: #FFFFFF; overflow: hidden">
<a href="AdvApps.dc.html" style="display: flex; align-items: center; gap: 14px; padding-left: 16px; height: 64px; text-decoration: none; color: #1C1B20">
<span style="flex: none; width: 30px; height: 30px; border-radius: 9px; background: #148A45; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 800">APP</span>
<span style="flex: 1; height: 64px; display: flex; align-items: center; gap: 8px; padding-right: 14px; border-bottom: 1px solid #EEEAF2">
<span style="flex: 1; font-size: 16px; font-weight: 600">Приложения</span>
<span style="display: flex">
<span style="width: 24px; height: 24px; border-radius: 7px; background: #21A038; border: 2px solid #FFFFFF"></span>
<span style="margin-left: -8px; width: 24px; height: 24px; border-radius: 7px; background: #1F5FBF; border: 2px solid #FFFFFF"></span>
<span style="margin-left: -8px; width: 24px; height: 24px; border-radius: 7px; background: #7B2CBF; border: 2px solid #FFFFFF"></span>
</span>
<span style="font-size: 14px; color: #6E6A78">24</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#B3AFBC" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</span>
</a>
<a href="AdvRules.dc.html" style="display: flex; align-items: center; gap: 14px; padding-left: 16px; height: 64px; text-decoration: none; color: #1C1B20">
<span style="flex: none; width: 30px; height: 30px; border-radius: 9px; background: #5E5A7D; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">≡</span>
<span style="flex: 1; height: 64px; display: flex; align-items: center; gap: 8px; padding-right: 14px">
<span style="flex: 1; display: flex; flex-direction: column; gap: 1px">
<span style="font-size: 16px; font-weight: 600">Правила</span>
<span style="font-size: 13px; color: #6E6A78">Домены, сети и шаблоны пакетов</span>
</span>
<span style="font-size: 14px; color: #6E6A78">5</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#B3AFBC" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</span>
</a>
</div>
</section>
<a href="AdvDiag.dc.html" style="display: flex; align-items: center; gap: 10px; height: 52px; padding: 0 16px; border-radius: 18px; background: #E8E4EE; color: #6E6A78; text-decoration: none">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
<span style="font-size: 16px; font-weight: 500">Проверить, как идёт сайт</span>
</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
return {};
}
}
</script>
</body>
</html>
@@ -0,0 +1,96 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Правила</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 940px; box-sizing: border-box; background: #F3F0F7; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<div style="display: flex; align-items: center; justify-content: space-between; padding: 14px 16px 0">
<a href="AdvRouting.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.8); box-shadow: 0 1px 2px rgba(28,27,32,0.08); display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
</div>
<header style="padding: 44px 24px 18px">
<h1 style="margin: 0; font-size: 34px; font-weight: 800; letter-spacing: -0.03em">Правила</h1>
<p style="margin: 6px 0 0; font-size: 14px; line-height: 1.4; color: #6E6A78">Сайты, сети и приложения — куда им идти. Правило важнее базы РФ.</p>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 20px">
<div role="tablist" aria-label="Тип" style="display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); padding: 3px; border-radius: 14px; background: #E8E4EE">
<button aria-selected="true" role="tab" style="height: 36px; border: 0; border-radius: 11px; background: #FFFFFF; color: #1C1B20; font: 800 13px 'Manrope', sans-serif; box-shadow: 0 1px 3px rgba(28,27,32,0.14)">Все</button>
<button role="tab" style="height: 36px; border: 0; border-radius: 11px; background: transparent; color: #49454F; font: 600 13px 'Manrope', sans-serif">Сайты</button>
<button role="tab" style="height: 36px; border: 0; border-radius: 11px; background: transparent; color: #49454F; font: 600 13px 'Manrope', sans-serif">Сети</button>
<button role="tab" style="height: 36px; border: 0; border-radius: 11px; background: transparent; color: #49454F; font: 600 13px 'Manrope', sans-serif">Пакеты</button>
</div>
<sc-for list="{{groups}}" as="g" hint-placeholder-count="2">
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 0 12px; display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 700; color: #6E6A78"><span style="width: 8px; height: 8px; border-radius: 4px; background: {{g.dot}}"></span>{{g.title}}</h2>
<div style="border-radius: 24px; background: #FFFFFF; overflow: hidden">
<sc-for list="{{g.rows}}" as="r" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 14px; padding-left: 16px; height: 64px">
<span style="flex: none; width: 30px; height: 30px; border-radius: 9px; background: {{r.tile}}; color: {{r.tileFg}}; display: flex; align-items: center; justify-content: center; font-size: 9px; font-weight: 800">{{r.kind}}</span>
<span style="flex: 1; height: 64px; display: flex; align-items: center; gap: 10px; padding-right: 14px; border-bottom: {{r.divider}}; min-width: 0">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 15px; font-weight: 700; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">{{r.value}}</span>
<span style="font-size: 12px; color: #6E6A78">{{r.sub}}</span>
</span>
<button aria-pressed="{{r.on}}" aria-label="Включить правило" style="flex: none; width: 50px; height: 30px; border: 0; border-radius: 15px; background: {{r.track}}; padding: 3px; display: flex; justify-content: {{r.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #FFFFFF; box-shadow: 0 1px 3px rgba(0,0,0,0.2)"></span></button>
</span>
</div>
</sc-for>
</div>
</section>
</sc-for>
</div>
<div style="position: absolute; left: 50%; bottom: 28px; transform: translateX(-50%); display: flex; align-items: center; gap: 6px; padding: 6px; border-radius: 30px; background: rgba(255,255,255,0.78); box-shadow: 0 8px 28px rgba(59,44,136,0.18), inset 0 0 0 1px rgba(255,255,255,0.9)">
<button style="height: 48px; padding: 0 22px; border: 0; border-radius: 24px; background: #6D4AFF; color: #FFFFFF; font: 800 15px 'Manrope', sans-serif; display: flex; align-items: center; gap: 8px">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>Правило
</button>
<a href="AdvDiag.dc.html" aria-label="Проверить сайт" style="width: 48px; height: 48px; border-radius: 24px; display: flex; align-items: center; justify-content: center; color: #3B2C88">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":940}}'>
class Component extends DCLogic {
renderVals() {
var tiles = { WEB: ['#E3ECFF', '#2F6FDB'], NET: ['#EEEAF2', '#49454F'], PKG: ['#E2F5EA', '#148A45'] };
var grp = function (title, dot, rows) {
return { title: title, dot: dot, rows: rows.map(function (r, i) {
return { kind: r[0], tile: tiles[r[0]][0], tileFg: tiles[r[0]][1], value: r[1], sub: r[2],
on: r[3] ? 'true' : 'false', track: r[3] ? '#6D4AFF' : '#D6D2DD', align: r[3] ? 'flex-end' : 'flex-start',
divider: i < rows.length - 1 ? '1px solid #EEEAF2' : '0' };
}) };
};
return {
groups: [
grp('Всегда через VPN', '#6D4AFF', [
['WEB', 'chatgpt.com', 'домен и поддомены', true],
['NET', '130.49.213.176', 'адрес', true],
['NET', '10.8.0.0/24', 'подсеть', false]
]),
grp('Всегда напрямую', '#3FBF7F', [
['PKG', 'ru.*', 'пакеты · 14 приложений', true],
['PKG', '*yandex*', 'пакеты · 6 приложений, 1 исключение', true],
['WEB', '*.mos.ru', 'домен и поддомены', true]
])
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,74 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Сценарии</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="Main.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Сценарии</h1>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 10px">
<p style="margin: 0 4px 4px; font-size: 14px; line-height: 1.45; color: #49454F">VPN сам включается и выключается по условиям. Сценарии выше в списке важнее.</p>
<sc-for list="{{rules}}" as="r" hint-placeholder-count="4">
<div style="display: flex; align-items: center; gap: 12px; padding: 14px; border-radius: 22px; background: #FFFFFF; border: 1px solid #EAE6EE">
<span style="width: 44px; height: 44px; border-radius: 14px; background: {{r.iconBg}}; color: {{r.iconFg}}; display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 800">{{r.tag}}</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 6px; min-width: 0">
<span style="font-size: 13px; color: #5E5A7D; font-weight: 600">{{r.when}}</span>
<span style="display: flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 800">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>{{r.then}}
</span>
</span>
<button aria-pressed="{{r.on}}" aria-label="{{r.when}}" style="width: 52px; height: 32px; border: 0; border-radius: 16px; background: {{r.track}}; padding: 4px; display: flex; justify-content: {{r.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #FFFFFF"></span></button>
</div>
</sc-for>
<section style="margin-top: 6px; padding: 14px; border-radius: 22px; background: #F6F2FA; display: flex; flex-direction: column; gap: 10px">
<h2 style="margin: 0; font-size: 15px; font-weight: 800">Быстрые шаблоны</h2>
<div style="display: flex; flex-wrap: wrap; gap: 8px">
<button style="height: 36px; padding: 0 14px; border-radius: 12px; border: 1px solid #C9C5D0; background: #FFFFFF; color: #1C1B20; font: 600 13px 'Manrope', sans-serif">Дома без VPN</button>
<button style="height: 36px; padding: 0 14px; border-radius: 12px; border: 1px solid #C9C5D0; background: #FFFFFF; color: #1C1B20; font: 600 13px 'Manrope', sans-serif">В роуминге всегда</button>
<button style="height: 36px; padding: 0 14px; border-radius: 12px; border: 1px solid #C9C5D0; background: #FFFFFF; color: #1C1B20; font: 600 13px 'Manrope', sans-serif">Ночью пауза</button>
<button style="height: 36px; padding: 0 14px; border-radius: 12px; border: 1px solid #C9C5D0; background: #FFFFFF; color: #1C1B20; font: 600 13px 'Manrope', sans-serif">Для приложения</button>
</div>
</section>
</div>
<button style="position: absolute; right: 16px; bottom: 24px; height: 64px; padding: 0 22px; border: 0; border-radius: 20px; background: #6D4AFF; color: #FFFFFF; font: 800 16px 'Manrope', sans-serif; display: flex; align-items: center; gap: 10px; box-shadow: 0 6px 18px rgba(109,74,255,0.35)">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>Новый сценарий
</button>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var r = function (tag, bg, fg, when, then, on) {
return { tag: tag, iconBg: bg, iconFg: fg, when: when, then: then, on: on ? 'true' : 'false', track: on ? '#6D4AFF' : '#C9C5D0', align: on ? 'flex-end' : 'flex-start' };
};
return {
rules: [
r('Wi-Fi', '#E7DFFF', '#3B2C88', 'Подключён к Wi-Fi «Home_5G»', 'Выключить VPN', true),
r('LTE', '#E7DFFF', '#3B2C88', 'Мобильная сеть или чужой Wi-Fi', 'Включить VPN', true),
r('APP', '#FFE2B8', '#7A3A06', 'Открыт Telegram или YouTube', 'Включить VPN', true),
r('01:00', '#F0ECF4', '#49454F', 'Каждую ночь 01:00–07:00', 'Пауза', false)
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,55 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Выбор приложений</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_ScenarioAdd.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Приложения</h1>
<span style="font-size: 14px; font-weight: 700; color: #B69DFF; padding-right: 8px">Выбрано 2</span>
</header>
<div style="flex: 1; padding: 0 16px 24px; display: flex; flex-direction: column; gap: 12px">
<label style="display: flex; align-items: center; gap: 10px; height: 52px; padding: 0 16px; border-radius: 26px; background: #2B2930; color: #A9A3BF">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
<input type="text" placeholder="Поиск приложений" aria-label="Поиск приложений" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 500 16px 'Manrope', sans-serif; color: #E5E1E9; outline: none">
</label>
<span style="padding: 0 6px; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ЧАСТО ОТКРЫВАЕТЕ</span>
<div style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{apps}}" as="a" hint-placeholder-count="7">
<label style="display: flex; align-items: center; gap: 12px; padding: 0 16px; height: 60px; border-bottom: {{a.divider}}; cursor: pointer">
<span style="flex: none; width: 36px; height: 36px; border-radius: 10px; background: {{a.c}}; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">{{a.l}}</span>
<span style="flex: 1; font-size: 15px; font-weight: 700">{{a.n}}</span>
<input type="checkbox" checked="{{a.on}}" aria-label="{{a.n}}" style="width: 22px; height: 22px; accent-color: #6D4AFF; margin: 0">
</label>
</sc-for>
</div>
<div style="flex: 1"></div>
<a href="D_ScenarioAdd.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Готово</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var A = [['Telegram', 'T', '#1E88C8', true], ['YouTube', 'Y', '#C62828', true], ['Chrome', 'C', '#2E7D32'], ['WhatsApp', 'W', '#25A244'], ['Instagram', 'I', '#C13584'], ['Discord', 'D', '#5865F2'], ['Spotify', 'S', '#1DB954']];
return { apps: A.map(function (x, i) { return { n: x[0], l: x[1], c: x[2], on: !!x[3], divider: i < A.length - 1 ? '1px solid #2B2930' : '0' }; }) };
}
}
</script>
</body>
</html>
@@ -0,0 +1,66 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Оформление</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Settings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Оформление</h1>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<span style="padding: 0 6px; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ТЕМА</span>
<div role="radiogroup" aria-label="Тема" style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px">
<sc-for list="{{themes}}" as="t" hint-placeholder-count="3">
<button aria-pressed="{{t.on}}" style="display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 10px; border-radius: 20px; border: {{t.border}}; background: #1F1D24; font-family: 'Manrope', sans-serif; color: #E5E1E9">
<span style="width: 100%; height: 120px; border-radius: 14px; background: {{t.bg}}; border: 1px solid #36333D; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; box-sizing: border-box">
<span style="width: 34px; height: 34px; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: {{t.accent}}"></span>
<span style="width: 56px; height: 8px; border-radius: 4px; background: {{t.line}}"></span>
<span style="width: 40px; height: 8px; border-radius: 4px; background: {{t.line}}"></span>
</span>
<span style="font-size: 13px; font-weight: 700">{{t.name}}</span>
</button>
</sc-for>
</div>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden; margin-top: 4px">
<div style="display: flex; align-items: center; gap: 12px; padding: 12px 14px 12px 16px; border-bottom: 1px solid #2B2930">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 700">Цвета обоев (Material You)</span>
<span style="font-size: 12px; color: #A9A3BF">Вместо фиолетового — цвета вашего телефона. Статусы остаются прежними.</span>
</span>
<button aria-pressed="false" aria-label="Цвета обоев" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: #48454E; padding: 4px; display: flex; justify-content: flex-start"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
<div style="display: flex; align-items: center; gap: 12px; padding: 0 14px 0 16px; height: 60px">
<span style="flex: 1; font-size: 15px; font-weight: 700">Язык</span>
<span style="font-size: 14px; font-weight: 600; color: #A9A3BF">Как в системе</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#938F99" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</div>
</section>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var t = function (name, bg, accent, line, on) { return { name: name, bg: bg, accent: accent, line: line, on: on ? 'true' : 'false', border: on ? '2px solid #6D4AFF' : '1px solid #EDE8F2' }; };
return { themes: [t('Как в системе', 'linear-gradient(90deg, #FCF8FF 50%, #141318 50%)', '#6D4AFF', '#C9C5D0', true), t('Светлая', '#FCF8FF', '#6D4AFF', '#E5E1E9'), t('Тёмная', '#141318', '#9C7CFF', '#36333D')] };
}
}
</script>
</body>
</html>
@@ -0,0 +1,126 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Приложения напрямую</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1380px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Routing.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Приложения напрямую</h1>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 12px">
<p style="margin: 0 4px; font-size: 14px; line-height: 1.45; color: #CAC4D0">Включённые приложения ходят в сеть напрямую, мимо VPN. Банки и сервисы РФ часто не работают через VPN.</p>
<label style="display: flex; align-items: center; gap: 10px; height: 52px; padding: 0 16px; border-radius: 26px; background: #2B2930; color: #A9A3BF">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
<input type="text" placeholder="Поиск приложений" aria-label="Поиск приложений" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 500 16px 'Manrope', sans-serif; color: #E5E1E9; outline: none">
</label>
<div style="display: flex; gap: 8px">
<button aria-pressed="true" style="height: 36px; padding: 0 12px; border-radius: 10px; border: 0; background: #36334A; color: #E0DAF5; font: 700 13px 'Manrope', sans-serif; display: flex; align-items: center; gap: 6px">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg>Напрямую · 24
</button>
<button style="height: 36px; padding: 0 12px; border-radius: 10px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 600 13px 'Manrope', sans-serif">Через VPN · 87</button>
<button style="height: 36px; padding: 0 12px; border-radius: 10px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 600 13px 'Manrope', sans-serif">Все</button>
</div>
<div style="display: flex; flex-direction: column; gap: 8px">
<span style="padding: 0 4px; font-size: 13px; font-weight: 700; color: #CAC4D0">Быстро добавить</span>
<div style="display: flex; flex-wrap: wrap; gap: 8px">
<sc-for list="{{quick}}" as="q" hint-placeholder-count="7">
<button style="height: 34px; padding: 0 12px; border-radius: 10px; border: {{q.border}}; background: {{q.bg}}; color: {{q.fg}}; font: 700 13px 'Manrope', sans-serif">{{q.label}}</button>
</sc-for>
</div>
</div>
<sc-for list="{{groups}}" as="g" hint-placeholder-count="3">
<section style="display: flex; flex-direction: column; gap: 6px">
<h2 style="margin: 4px 6px 0; font-size: 12px; font-weight: 800; color: #B69DFF; letter-spacing: 0.06em">{{g.title}}</h2>
<div style="border-radius: 22px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{g.apps}}" as="a" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 12px; padding: 10px 14px; min-height: 60px; box-sizing: border-box; border-bottom: 1px solid #2B2930">
<span style="width: 36px; height: 36px; border-radius: 10px; background: {{a.color}}; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">{{a.letter}}</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 15px; font-weight: 700">{{a.name}}</span>
<span style="font-size: 12px; color: {{a.reasonColor}}">{{a.reason}}</span>
</span>
<button aria-pressed="{{a.on}}" aria-label="{{a.name}}: напрямую, без VPN" style="width: 52px; height: 32px; border: 0; border-radius: 16px; background: {{a.track}}; padding: 4px; display: flex; justify-content: {{a.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
</sc-for>
</div>
</section>
</sc-for>
<label style="display: flex; align-items: center; gap: 12px; padding: 8px 6px; font-size: 14px; font-weight: 600; color: #E0DAF5">
<input type="checkbox" style="width: 20px; height: 20px; accent-color: #6D4AFF; margin: 0">Показывать системные приложения
</label>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1380}}'>
class Component extends DCLogic {
renderVals() {
var chip = function (label, done) {
return {
label: done ? '✓ ' + label : label,
bg: done ? '#3B2C88' : '#1F1D24',
fg: done ? '#D0C2FF' : '#E5E1E9',
border: done ? '0' : '1px solid #48454E'
};
};
var app = function (name, letter, color, kind, tpl) {
var reasons = {
added: ['Напрямую · добавлено вами', '#7CE3B0'],
tpl: ['Напрямую · по шаблону «' + tpl + '»', '#7CE3B0'],
vpn: ['Через VPN', '#A9A3BF'],
over: ['Исключение: через VPN (шаблон «' + tpl + '» не действует)', '#FFD8A8']
};
var on = kind === 'added' || kind === 'tpl';
return {
name: name, letter: letter, color: color,
reason: reasons[kind][0], reasonColor: reasons[kind][1],
on: on ? 'true' : 'false', track: on ? '#6D4AFF' : '#48454E', align: on ? 'flex-end' : 'flex-start'
};
};
return {
quick: [chip('Банки', true), chip('Госуслуги', true), chip('Маркетплейсы', true), chip('Связь', false), chip('Транспорт', false), chip('Сервисы', false), chip('Все приложения РФ', false)],
groups: [
{ title: 'БАНКИ', apps: [
app('СберБанк Онлайн', 'С', '#21A038', 'tpl', 'ru.*'),
app('Т-Банк', 'Т', '#3A3A3A', 'added'),
app('Альфа-Банк', 'А', '#C62828', 'tpl', 'ru.*')
] },
{ title: 'ГОСУСЛУГИ И СЕРВИСЫ', apps: [
app('Госуслуги', 'Г', '#1F5FBF', 'tpl', 'ru.*'),
app('Яндекс Карты', 'Я', '#D84315', 'tpl', '*yandex*'),
app('Яндекс Браузер', 'Я', '#5E35B1', 'over', '*yandex*')
] },
{ title: 'МАРКЕТПЛЕЙСЫ', apps: [
app('Wildberries', 'W', '#7B2CBF', 'added'),
app('Ozon', 'O', '#1565C0', 'added')
] },
{ title: 'ДРУГИЕ', apps: [
app('Telegram', 'T', '#1E88C8', 'vpn'),
app('YouTube', 'Y', '#C62828', 'vpn')
] }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,80 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Сценарии</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Settings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Сценарии</h1>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 10px">
<p style="margin: 0 4px 4px; font-size: 14px; line-height: 1.45; color: #CAC4D0">VPN сам включается, выключается или встаёт на паузу. Верхние сценарии важнее нижних.</p>
<sc-for list="{{rules}}" as="r" hint-placeholder-count="4">
<div style="display: flex; align-items: center; gap: 12px; padding: 14px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35">
<span style="flex: none; width: 44px; height: 44px; border-radius: 14px; background: {{r.bg}}; color: {{r.fg}}; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{r.icon}}"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 4px; min-width: 0">
<span style="font-size: 13px; color: #A9A3BF; font-weight: 600">{{r.when}}</span>
<span style="display: flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 800"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6D4AFF" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>{{r.then}}</span>
</span>
<button aria-pressed="{{r.on}}" aria-label="{{r.when}}" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: {{r.track}}; padding: 4px; display: flex; justify-content: {{r.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
</sc-for>
<a href="D_Servers.dc.html" style="display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: 18px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9">
<span style="flex: 1; font-size: 14px; font-weight: 700">Сервер для этих правил</span>
<span style="font-size: 14px; font-weight: 600; color: #A9A3BF">Амстердам</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#A9A3BF" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</a>
<h2 style="margin: 10px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ДОВЕРЕННЫЕ СЕТИ</h2>
<div style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{nets}}" as="n" hint-placeholder-count="2">
<div style="display: flex; align-items: center; gap: 12px; padding: 0 16px; height: 56px; border-bottom: 1px solid #2B2930">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#D0C2FF" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M2 9a15 15 0 0 1 20 0M5 13a10 10 0 0 1 14 0M9 17a4 4 0 0 1 6 0"/></svg>
<span style="flex: 1; font-size: 15px; font-weight: 700">{{n}}</span>
<button aria-label="Удалить сеть" style="width: 40px; height: 40px; border: 0; border-radius: 20px; background: transparent; color: #938F99; font: 700 18px 'Manrope', sans-serif">×</button>
</div>
</sc-for>
<button style="width: 100%; height: 56px; border: 0; background: transparent; color: #B69DFF; font: 700 15px 'Manrope', sans-serif">+ Добавить текущую сеть</button>
</div>
</div>
<a href="D_ScenarioAdd.dc.html" style="position: absolute; right: 16px; bottom: 24px; height: 60px; padding: 0 22px; border-radius: 20px; background: #6D4AFF; color: #FFFFFF; font-size: 16px; font-weight: 800; text-decoration: none; display: flex; align-items: center; box-shadow: 0 6px 18px rgba(109,74,255,0.35)">+ Сценарий</a>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var r = function (icon, bg, fg, when, then, on) {
return { icon: icon, bg: bg, fg: fg, when: when, then: then, on: on ? 'true' : 'false', track: on ? '#6D4AFF' : '#48454E', align: on ? 'flex-end' : 'flex-start' };
};
return {
rules: [
r('M2 9a15 15 0 0 1 20 0M5 13a10 10 0 0 1 14 0M9 17a4 4 0 0 1 6 0', '#3B2C88', '#D0C2FF', 'В доверенной Wi-Fi сети', 'Выключить VPN', true),
r('M7 3h10v18H7zM11 18h2', '#3B2C88', '#D0C2FF', 'Мобильная сеть или чужой Wi-Fi', 'Включить VPN', true),
r('M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z', '#4A3416', '#FFD8A8', 'Открыт Telegram или YouTube', 'Включить VPN', true),
r('M12 7v5l3 2M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18', '#2B2930', '#CAC4D0', 'Каждую ночь 01:00–07:00', 'Пауза', false)
],
nets: ['Home_5G', 'Office']
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,75 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Экономия батареи</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Permissions.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Без экономии батареи</h1>
</header>
<div style="flex: 1; padding: 0 16px 28px; display: flex; flex-direction: column; gap: 12px">
<p style="margin: 0 4px; font-size: 15px; line-height: 1.5; color: #E0DAF5">VPN почти не тратит заряд, но Android этого не знает и усыпляет его в фоне. Два шага:</p>
<section style="padding: 16px; border-radius: 24px; background: #1F1D24; border: 1px solid #4B3D99; display: flex; flex-direction: column; gap: 10px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 28px; height: 28px; border-radius: 14px; background: #6D4AFF; color: #FFFFFF; font-size: 13px; font-weight: 800; display: flex; align-items: center; justify-content: center">1</span><span style="font-size: 16px; font-weight: 800">Системное разрешение</span></span>
<span style="font-size: 13px; line-height: 1.45; color: #CAC4D0">Появится окно «Разрешить работу в фоне?» — нажмите «Разрешить».</span>
<button style="height: 48px; border: 0; border-radius: 14px; background: #6D4AFF; color: #FFFFFF; font: 800 14px 'Manrope', sans-serif">Разрешить</button>
</section>
<section style="padding: 16px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; display: flex; flex-direction: column; gap: 12px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 28px; height: 28px; border-radius: 14px; background: #6D4AFF; color: #FFFFFF; font-size: 13px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span><span style="font-size: 16px; font-weight: 800">Настройка телефона</span></span>
<div style="display: flex; gap: 6px; flex-wrap: wrap">
<sc-for list="{{brands}}" as="b" hint-placeholder-count="5">
<button aria-pressed="{{b.on}}" style="height: 32px; padding: 0 12px; border-radius: 10px; border: {{b.border}}; background: {{b.bg}}; color: {{b.fg}}; font: 700 12px 'Manrope', sans-serif">{{b.name}}</button>
</sc-for>
</div>
<span style="font-size: 12px; font-weight: 700; color: #B69DFF">Определили: Xiaomi · HyperOS</span>
<ol style="margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px">
<sc-for list="{{steps}}" as="s" hint-placeholder-count="3">
<li style="display: flex; gap: 10px; font-size: 14px; line-height: 1.45"><span style="flex: none; width: 22px; height: 22px; border-radius: 11px; background: #2B2930; color: #D0C2FF; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center">{{s.n}}</span><span>{{s.t}}</span></li>
</sc-for>
</ol>
<button style="height: 48px; border-radius: 14px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 700 14px 'Manrope', sans-serif">Открыть настройки приложения</button>
</section>
<div style="flex: 1"></div>
<div style="display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: 18px; background: #3A2A12; color: #F5C892; font-size: 13px; line-height: 1.45">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#FFB869" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex: none"><path d="M12 4l9 16H3zM12 10v4M12 17.5v.5"/></svg>
<span>Шаг 1 ещё не сделан — VPN может отключаться в фоне</span>
</div>
<a href="D_Permissions.dc.html" style="height: 56px; border-radius: 18px; background: #36334A; color: #E0DAF5; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Проверить снова</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var b = function (name, on) { return { name: name, on: on ? 'true' : 'false', bg: on ? '#3B2C88' : '#1F1D24', fg: on ? '#FFFFFF' : '#E5E1E9', border: on ? '0' : '1px solid #48454E' }; };
return {
brands: [b('Xiaomi', true), b('Samsung'), b('Honor / Huawei'), b('Realme / OPPO'), b('Другой')],
steps: [
{ n: 1, t: 'Откройте настройки приложения кнопкой ниже' },
{ n: 2, t: 'Экономия заряда → «Нет ограничений»' },
{ n: 3, t: 'Включите «Автозапуск»' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,98 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Главная — сертификат истекает</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #B69DFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="D_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #141318; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="D_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Отключить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #3B2C88, 0 0 0 28px #2A2343; margin: 28px 0 22px; cursor: pointer">
<svg width="68" height="68" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M12 3v9"/><path d="M6.3 6.3a8 8 0 1 0 11.4 0"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Защищено</span>
<span style="display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; color: #A9A3BF"><span style="width: 8px; height: 8px; border-radius: 4px; background: #148A45"></span>01:24:37 · РФ-сайты напрямую</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="D_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #3B2C88; color: #D0C2FF; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #A9A3BF">IP 185.•••.•••.12 · 38 мс</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #B69DFF">Сменить</span>
</a>
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px">
<sc-for list="{{actions}}" as="q" hint-placeholder-count="3">
<a href="{{q.href}}" style="height: 72px; border-radius: 20px; background: #2B2930; color: #E0DAF5; text-decoration: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; font-size: 12px; font-weight: 700; text-align: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{q.icon}}"/></svg>{{q.label}}
</a>
</sc-for>
</div>
<section role="status" style="padding: 16px; border-radius: 24px; background: #3A2A12; border: 1px solid #5A4220; display: flex; flex-direction: column; gap: 10px">
<span style="font-size: 15px; font-weight: 800; color: #FFD8A8">Сертификат истекает через 7 дней</span>
<span style="font-size: 13px; line-height: 1.45; color: #F5C892">«Амстердам» перестанет подключаться 18 октября. Попросите у администратора новый профиль и добавьте его.</span>
<div style="display: flex; gap: 8px"><a href="D_ProfileUpdate.dc.html" style="height: 44px; padding: 0 14px; border-radius: 14px; background: #B45309; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; box-sizing: border-box; flex: 2">Обновить сейчас</a><a href="D_Home.dc.html" style="height: 44px; padding: 0 14px; border-radius: 14px; border: 1px solid #7A5A30; color: #FFD8A8; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; box-sizing: border-box; flex: 1">Позже</a></div>
</section>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
}),
actions: [
{ label: 'Пауза 15 мин', href: 'D_Pause.dc.html', icon: 'M9 5v14M15 5v14' },
{ label: 'Быстрейший', href: 'D_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'D_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,68 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Сертификаты</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Settings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Сертификаты</h1>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 12px">
<p style="margin: 0 4px; font-size: 14px; line-height: 1.45; color: #CAC4D0">Нужны, чтобы убедиться, что вы подключаетесь к настоящему серверу. Обычно приходят вместе с профилем — трогать ничего не нужно.</p>
<div role="tablist" aria-label="Источник" style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 4px; border-radius: 16px; background: #2B2930">
<button role="tab" aria-selected="true" style="height: 40px; border: 0; border-radius: 12px; background: #1F1D24; color: #E5E1E9; font: 800 13px 'Manrope', sans-serif; box-shadow: 0 1px 3px rgba(28,27,32,0.12)">Из профилей · 2</button>
<button role="tab" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #CAC4D0; font: 600 13px 'Manrope', sans-serif">Добавленные</button>
<button role="tab" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #CAC4D0; font: 600 13px 'Manrope', sans-serif">Системные</button>
</div>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{certs}}" as="c" hint-placeholder-count="2">
<div style="display: flex; align-items: center; gap: 12px; padding: 12px 14px 12px 16px; border-bottom: {{c.divider}}">
<span style="flex: none; width: 40px; height: 40px; border-radius: 14px; background: {{c.bg}}; color: {{c.fg}}; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5h16v10H4zM8 19l4-2 4 2v-4H8z"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 15px; font-weight: 700">{{c.name}}</span>
<span style="font-size: 12px; color: #A9A3BF">{{c.used}}</span>
<span style="font-size: 12px; font-weight: 700; color: {{c.expColor}}">{{c.exp}}</span>
</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#938F99" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</div>
</sc-for>
</section>
<button style="display: flex; align-items: center; justify-content: center; gap: 8px; height: 52px; border-radius: 18px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 700 14px 'Manrope', sans-serif">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>Добавить сертификат (.crt, .pem)
</button>
<p style="margin: 0 6px; font-size: 12px; line-height: 1.45; color: #A9A3BF">Системные — те, которым доверяет Android.</p>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var C = [
['SHX Root CA', 'Амстердам, Хельсинки, Франкфурт', 'действует до 01.2028', '#7CE3B0', '#12321F', '#7CE3B0'],
['SHX Bridge CA', 'Москва (мост)', 'истекает через 7 дней — 18.10.2026', '#B45309', '#4A3416', '#FFD8A8']
];
return { certs: C.map(function (x, i) { return { name: x[0], used: 'используют: ' + x[1], exp: x[2], expColor: x[3], bg: x[4], fg: x[5], divider: i < C.length - 1 ? '1px solid #2B2930' : '0' }; }) };
}
}
</script>
</body>
</html>
@@ -0,0 +1,123 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Как ходит трафик</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1420px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Routing.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Как ходит трафик</h1>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<div role="tablist" aria-label="Что проверить" style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 4px; border-radius: 16px; background: #2B2930">
<button role="tab" aria-selected="true" style="height: 40px; border: 0; border-radius: 12px; background: #1F1D24; color: #E5E1E9; font: 800 14px 'Manrope', sans-serif; box-shadow: 0 1px 3px rgba(28,27,32,0.12)">Сайт</button>
<button role="tab" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #CAC4D0; font: 600 14px 'Manrope', sans-serif">IP / сеть</button>
<button role="tab" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #CAC4D0; font: 600 14px 'Manrope', sans-serif">Приложение</button>
</div>
<div style="display: flex; gap: 8px">
<label style="flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; height: 52px; padding: 0 14px; border-radius: 16px; background: #1F1D24; border: 2px solid #6D4AFF; box-sizing: border-box">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#A9A3BF" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18"/></svg>
<input type="text" value="youtube.com" aria-label="Сайт" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 700 16px 'Manrope', sans-serif; color: #E5E1E9; outline: none">
</label>
<button style="flex: none; white-space: nowrap; height: 52px; padding: 0 16px; border: 0; border-radius: 16px; background: #6D4AFF; color: #FFFFFF; font: 700 14px 'Manrope', sans-serif">Проверить</button>
</div>
<div style="display: flex; gap: 6px; flex-wrap: wrap">
<sc-for list="{{recent}}" as="r" hint-placeholder-count="4">
<button style="height: 32px; padding: 0 12px; border-radius: 10px; border: 1px solid #3A3740; background: transparent; color: #CAC4D0; font: 600 12px 'Manrope', sans-serif">{{r}}</button>
</sc-for>
</div>
<section style="padding: 16px; border-radius: 24px; background: #3B2C88; display: flex; flex-direction: column; gap: 14px">
<div style="display: flex; align-items: center; justify-content: space-between">
<span style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 12px; font-weight: 800; color: #D0C2FF; letter-spacing: 0.04em">ИТОГ</span>
<span style="font-size: 22px; font-weight: 800; color: #EADDFF">Через VPN</span>
</span>
<span style="padding: 6px 12px; border-radius: 999px; background: #1F1D24; color: #D0C2FF; font-size: 13px; font-weight: 800">открывается · 41 мс</span>
</div>
<div style="display: flex; align-items: center; gap: 6px">
<span style="flex: none; padding: 8px 10px; border-radius: 12px; background: #1F1D24; font-size: 12px; font-weight: 800">Телефон</span>
<span style="flex: 1; height: 3px; border-radius: 2px; background: #6D4AFF"></span>
<span style="flex: none; padding: 8px 10px; border-radius: 12px; background: #6D4AFF; color: #FFFFFF; font-size: 12px; font-weight: 800">VPN · NL</span>
<span style="flex: 1; height: 3px; border-radius: 2px; background: #6D4AFF"></span>
<span style="flex: none; padding: 8px 10px; border-radius: 12px; background: #1F1D24; font-size: 12px; font-weight: 800">youtube.com</span>
</div>
<span style="font-size: 13px; line-height: 1.45; color: #D0C2FF">Почему: адресов нет в базе РФ, своих правил для сайта нет — значит, по умолчанию через VPN.</span>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ПРЯМОЙ ПУТЬ ДЛЯ СРАВНЕНИЯ</h2>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; padding: 4px 16px">
<sc-for list="{{compare}}" as="c" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 10px; height: 52px; border-bottom: {{c.divider}}">
<span style="flex: 1; font-size: 14px; font-weight: 600">{{c.t}}</span>
<span style="font-size: 13px; font-weight: 800; color: {{c.color}}">{{c.v}}</span>
</div>
</sc-for>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">DNS</h2>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; padding: 12px 16px; display: flex; flex-direction: column; gap: 10px">
<div style="display: flex; flex-direction: column; gap: 3px">
<span style="font-size: 13px; font-weight: 700; color: #CAC4D0">Через туннель</span>
<span style="font-size: 14px; font-weight: 600; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace">142.250.•••.14 · 142.250.•••.46</span>
</div>
<div style="display: flex; flex-direction: column; gap: 3px">
<span style="font-size: 13px; font-weight: 700; color: #CAC4D0">Через провайдера</span>
<span style="font-size: 14px; font-weight: 600; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace">195.208.•••.3</span>
</div>
<span style="padding: 8px 12px; border-radius: 12px; background: #3A2A12; color: #F5C892; font-size: 13px; line-height: 1.4"><b>Ответы различаются.</b> Похоже, провайдер подменяет DNS — поэтому используем DNS туннеля.</span>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">АДРЕСА · 2</h2>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{ips}}" as="i" hint-placeholder-count="2">
<div style="display: flex; align-items: center; gap: 10px; padding: 10px 14px 10px 16px; border-bottom: {{i.divider}}">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 14px; font-weight: 700; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace">{{i.ip}}</span>
<span style="font-size: 12px; color: #A9A3BF">{{i.why}}</span>
</span>
<span style="flex: none; padding: 4px 10px; border-radius: 999px; background: #3B2C88; color: #D0C2FF; font-size: 12px; font-weight: 800">через VPN</span>
</div>
</sc-for>
</section>
<section style="display: flex; flex-direction: column; gap: 8px; padding-top: 4px">
<span style="padding: 0 6px; font-size: 13px; font-weight: 700; color: #CAC4D0">Изменить для youtube.com</span>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px">
<a href="D_Rules.dc.html" style="height: 52px; border-radius: 16px; background: #12321F; color: #7CE3B0; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">Всегда напрямую</a>
<a href="D_Rules.dc.html" style="height: 52px; border-radius: 16px; background: #36334A; color: #E0DAF5; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">Всегда через VPN</a>
</div>
</section>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1420}}'>
class Component extends DCLogic {
renderVals() {
var cmp = [['Напрямую', 'не открывается', '#B3261E'], ['Через VPN', '41 мс', '#7CE3B0'], ['Скорость напрямую', 'замедлено ~90%', '#B45309']];
var ips = [['142.250.•••.14', 'не в базе РФ · по умолчанию'], ['142.250.•••.46', 'не в базе РФ · по умолчанию']];
return {
recent: ['gosuslugi.ru', '95.163.•••.12', 'Telegram', 'chatgpt.com'],
compare: cmp.map(function (c, i) { return { t: c[0], v: c[1], color: c[2], divider: i < cmp.length - 1 ? '1px solid #2B2930' : '0' }; }),
ips: ips.map(function (x, i) { return { ip: x[0], why: x[1], divider: i < ips.length - 1 ? '1px solid #2B2930' : '0' }; })
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,106 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Диагностика</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1240px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Home.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Диагностика</h1>
<a href="D_Log.dc.html" style="flex: none; height: 40px; padding: 0 14px; border-radius: 20px; background: #2B2930; color: #D0C2FF; font-size: 13px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Журнал</a>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 14px">
<section style="padding: 16px; border-radius: 24px; background: #0F3D24; display: flex; gap: 12px; align-items: center">
<span style="flex: none; width: 40px; height: 40px; border-radius: 20px; background: #148A45; color: #FFFFFF; display: flex; align-items: center; justify-content: center">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 17px; font-weight: 800; color: #A8F0C8">VPN работает нормально</span>
<span style="font-size: 13px; color: #7CE3B0">Проверено 10 с назад</span>
</span>
</section>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; padding: 4px 16px">
<sc-for list="{{steps}}" as="s" hint-placeholder-count="5">
<div style="display: flex; align-items: center; gap: 12px; height: 50px; border-bottom: {{s.divider}}">
<span style="width: 22px; height: 22px; border-radius: 11px; background: {{s.bg}}; color: {{s.fg}}; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 800">{{s.mark}}</span>
<span style="flex: 1; font-size: 15px; font-weight: 600">{{s.title}}</span>
<span style="font-size: 13px; color: #A9A3BF">{{s.value}}</span>
</div>
</sc-for>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ЧТО-ТО НЕ ОТКРЫВАЕТСЯ?</h2>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; padding: 14px; display: flex; flex-direction: column; gap: 14px">
<div style="display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px">
<sc-for list="{{apps}}" as="a" hint-placeholder-count="5">
<button style="display: flex; flex-direction: column; align-items: center; gap: 5px; border: 0; background: transparent; padding: 0; font-family: 'Manrope', sans-serif; color: #E5E1E9">
<span style="width: 48px; height: 48px; border-radius: 15px; background: {{a.c}}; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 17px; font-weight: 800; box-shadow: {{a.ring}}">{{a.l}}</span>
<span style="font-size: 11px; font-weight: 600; max-width: 62px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap">{{a.n}}</span>
</button>
</sc-for>
</div>
<div style="display: flex; gap: 8px">
<label style="flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; height: 48px; padding: 0 12px; border-radius: 16px; background: #2B2930; color: #A9A3BF">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
<input type="text" placeholder="или сайт" aria-label="Сайт" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 600 15px 'Manrope', sans-serif; color: #E5E1E9; outline: none">
</label>
<a href="D_Check.dc.html" style="flex: none; white-space: nowrap; height: 48px; padding: 0 16px; border-radius: 16px; background: #6D4AFF; color: #FFFFFF; font-size: 14px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Проверить</a>
</div>
<div role="status" style="padding: 12px; border-radius: 18px; background: #2A2343; display: flex; align-items: center; gap: 10px">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 14px; font-weight: 800">СберБанк пущен напрямую</span>
<span style="font-size: 12px; color: #CAC4D0">Банк не пускал через VPN</span>
</span>
<button style="flex: none; height: 36px; padding: 0 12px; border: 0; border-radius: 12px; background: #1F1D24; color: #D0C2FF; font: 700 13px 'Manrope', sans-serif">Отменить</button>
</div>
</section>
<h2 style="margin: 6px 6px 0; display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">НЕДОСТУПНЫЕ ХОСТЫ<span style="padding: 1px 7px; border-radius: 6px; background: #4A3416; color: #FFD8A8; font-size: 11px; letter-spacing: 0">3</span></h2>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{hosts}}" as="h" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 10px; padding: 0 12px 0 16px; height: 60px; border-bottom: {{h.divider}}">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 14px; font-weight: 700; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace">{{h.host}}</span>
<span style="font-size: 12px; color: #A9A3BF">{{h.meta}}</span>
</span>
<button style="flex: none; height: 36px; padding: 0 12px; border: 0; border-radius: 12px; background: #4A3416; color: #FFD8A8; font: 700 13px 'Manrope', sans-serif">Через VPN</button>
</div>
</sc-for>
</section>
<a href="D_Log.dc.html" style="height: 52px; border-radius: 18px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font-size: 15px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Отправить отчёт</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1240}}'>
class Component extends DCLogic {
renderVals() {
var ok = { bg: '#0F3D24', fg: '#7CE3B0', mark: '✓' };
var steps = [['Интернет', 'Wi-Fi'], ['Российские сайты', '21 мс'], ['Зарубежные сайты', 'через VPN'], ['Сервер VPN', '38 мс · порт 4500'], ['DNS', 'туннель']];
var a = function (n, l, c, sel) { return { n: n, l: l, c: c, ring: sel ? '0 0 0 2px #1F1D24, 0 0 0 4px #6D4AFF' : 'none' }; };
var hs = [['95.163.•••.12:443', 'отказов 14 · пауза 4 мин'], ['178.248.•••.70:443', 'отказов 9 · пауза 2 мин'], ['212.193.•••.5:5222', 'отказов 6 · пауза 40 с']];
return {
steps: steps.map(function (s, i) { return { bg: ok.bg, fg: ok.fg, mark: ok.mark, title: s[0], value: s[1], divider: i < steps.length - 1 ? '1px solid #2B2930' : '0' }; }),
apps: [a('СберБанк', 'С', '#21A038', true), a('Госуслуги', 'Г', '#1F5FBF'), a('YouTube', 'Y', '#C62828'), a('Telegram', 'T', '#1E88C8'), a('Ещё', '+', '#938F99')],
hosts: hs.map(function (h, i) { return { host: h[0], meta: h[1], divider: i < hs.length - 1 ? '1px solid #2B2930' : '0' }; })
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,93 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Главная — вход отклонён</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #B69DFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="D_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #141318; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="D_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Повторить подключение" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #4A1C1C; color: #FFB4AB; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #3A1A1A, 0 0 0 28px #2C1616; margin: 28px 0 22px; cursor: pointer">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 4l9 16H3zM12 10v4M12 17.5v.5"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em; color: #FFB4AB">Вход отклонён</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: #FFB4AB">Амстердам · ошибка аутентификации</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="D_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #3B2C88; color: #D0C2FF; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #A9A3BF">IP 185.•••.•••.12 · 38 мс</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #B69DFF">Сменить</span>
</a>
<section role="status" style="padding: 16px; border-radius: 24px; background: #3A1A1A; border: 1px solid #6B2A2A; display: flex; flex-direction: column; gap: 10px">
<span style="font-size: 15px; font-weight: 800; color: #FFB4AB">Сервер не принял сертификат</span>
<span style="font-size: 13px; line-height: 1.45; color: #FFB4AB">Скорее всего, у профиля закончился срок действия или администратор выпустил новый. Обновите профиль или выберите другой сервер.</span>
<div style="display: flex; gap: 8px"><a href="D_ProfileUpdate.dc.html" style="height: 44px; padding: 0 14px; border-radius: 14px; background: #B3261E; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; box-sizing: border-box; flex: 2">Обновить профиль</a><a href="D_Log.dc.html" style="height: 44px; padding: 0 14px; border-radius: 14px; border: 1px solid #6B2A2A; color: #FFB4AB; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; box-sizing: border-box; flex: 1">Журнал</a></div>
</section>
<a href="D_Servers.dc.html" style="height: 52px; border-radius: 18px; background: #2B2930; color: #E0DAF5; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700">Подключиться к другому серверу</a>
<a href="D_Home.dc.html" style="height: 44px; border-radius: 14px; color: #B69DFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700">Отключить VPN</a>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
}),
actions: [
{ label: 'Пауза 15 мин', href: 'D_Pause.dc.html', icon: 'M9 5v14M15 5v14' },
{ label: 'Быстрейший', href: 'D_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'D_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,61 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Профиль не добавлен</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end">
<section role="alertdialog" aria-label="Профиль не добавлен" style="border-radius: 32px 32px 0 0; background: #141318; padding: 12px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 36px; height: 4px; border-radius: 2px; background: #48454E"></span>
<div style="display: flex; align-items: center; gap: 14px; padding: 4px 4px 0">
<span style="flex: none; width: 52px; height: 52px; border-radius: 26px; background: #4A1C1C; color: #FFB4AB; display: flex; align-items: center; justify-content: center">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 14a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1 1M14 10a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1-1M4 4l16 16"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<h1 style="margin: 0; font-size: 22px; font-weight: 800; letter-spacing: -0.02em">Не удалось скачать профиль</h1>
<span style="font-size: 13px; color: #A9A3BF; font-family: ui-monospace, Menlo, monospace">vpn.[ваш-домен]/nl1.sswan</span>
</span>
</div>
<section style="padding: 14px 16px; border-radius: 22px; background: #1F1D24; border: 1px solid #2E2B35; display: flex; flex-direction: column; gap: 8px">
<span style="font-size: 12px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ВОЗМОЖНЫЕ ПРИЧИНЫ</span>
<sc-for list="{{reasons}}" as="r" hint-placeholder-count="3">
<span style="display: flex; gap: 10px; font-size: 14px; line-height: 1.45"><span style="flex: none; width: 6px; height: 6px; margin-top: 8px; border-radius: 3px; background: #B3261E"></span><span><b>{{r.t}}</b> — <span style="color: #CAC4D0">{{r.d}}</span></span></span>
</sc-for>
</section>
<div style="padding: 12px 14px; border-radius: 18px; background: #2A2343; font-size: 13px; line-height: 1.45; color: #E0DAF5">Попросите у администратора файл .sswan или QR — их можно добавить без интернета.</div>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px">
<a href="D_Import.dc.html" style="height: 52px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">Повторить</a>
<a href="D_ImportQR.dc.html" style="height: 52px; border-radius: 18px; background: #36334A; color: #E0DAF5; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700">Сканировать QR</a>
</div>
<a href="D_Log.dc.html" style="align-self: center; font-size: 13px; font-weight: 700; text-decoration: none">Подробности для поддержки</a>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {
reasons: [
{ t: 'Сайт заблокирован', d: 'ссылка не открывается без VPN' },
{ t: 'Нет интернета', d: 'проверьте мобильную сеть или Wi-Fi' },
{ t: 'Ошибка сертификата сайта', d: 'HTTPS-соединение не прошло проверку' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,92 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Помощь</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1240px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Settings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Помощь</h1>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 12px">
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px">
<a href="D_Diag.dc.html" style="height: 84px; padding: 14px; box-sizing: border-box; border-radius: 22px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; flex-direction: column; justify-content: space-between">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
<span style="font-size: 14px; font-weight: 800">Проверить подключение</span>
</a>
<a href="D_Log.dc.html" style="height: 84px; padding: 14px; box-sizing: border-box; border-radius: 22px; background: #3B2C88; color: #EADDFF; text-decoration: none; display: flex; flex-direction: column; justify-content: space-between">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 4h16v12H8l-4 4z"/></svg>
<span style="font-size: 14px; font-weight: 800">Написать в поддержку</span>
</a>
</div>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ЧАСТЫЕ ВОПРОСЫ</h2>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{faq}}" as="q" hint-placeholder-count="6">
<div style="border-bottom: {{q.divider}}">
<button aria-expanded="{{q.openStr}}" style="width: 100%; display: flex; align-items: center; gap: 10px; padding: 0 16px; min-height: 58px; border: 0; background: transparent; text-align: left; font: 700 15px 'Manrope', sans-serif; color: #E5E1E9">
<span style="flex: 1">{{q.q}}</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#938F99" stroke-width="2.4" stroke-linecap="round" aria-hidden="true" style="transform: {{q.rot}}"><path d="M6 9l6 6 6-6"/></svg>
</button>
<sc-if value="{{q.open}}" hint-placeholder-val="{{ false }}">
<p style="margin: 0; padding: 0 16px 16px; font-size: 14px; line-height: 1.5; color: #CAC4D0">{{q.a}}</p>
</sc-if>
</div>
</sc-for>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">О ПРИЛОЖЕНИИ</h2>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<div style="display: flex; align-items: center; gap: 14px; padding: 16px">
<span style="flex: none; width: 52px; height: 52px; border-radius: 15px; background: #6D4AFF; display: flex; align-items: center; justify-content: center">
<svg width="36" height="36" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.3" stroke-linecap="round"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 17px; font-weight: 800">SHX VPN 2.17.0</span>
<span style="font-size: 12px; color: #A9A3BF">сборка 172 · на основе strongSwan · GPLv2</span>
</span>
</div>
<sc-for list="{{links}}" as="l" hint-placeholder-count="3">
<a href="{{l.href}}" style="display: flex; align-items: center; gap: 10px; padding: 0 16px; height: 52px; border-top: 1px solid #2B2930; text-decoration: none; color: #E5E1E9; font-size: 15px; font-weight: 600">
<span style="flex: 1">{{l.t}}</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#938F99" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</a>
</sc-for>
</section>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1240}}'>
class Component extends DCLogic {
renderVals() {
var Q = [
['Банк или Госуслуги не открываются', 'Многие российские сервисы не пускают зарубежные адреса. Откройте «Не открывается?» на главной и выберите приложение — мы пустим его напрямую, мимо VPN.', true],
['Где взять профиль .sswan?', 'Его выдаёт администратор вашего VPN: файлом, ссылкой или QR-кодом. Можно отсканировать QR с экрана друга.'],
['Что такое мост?', 'Сервер с российским адресом. Когда оператор включает белые списки, обычные серверы недоступны, а мост — работает. Включите «Мост при белых списках» на странице сервера.'],
['VPN сам отключается', 'Скорее всего, Android экономит батарею. Откройте Настройки → Стабильная работа и снимите ограничения.'],
['Стабильный или Гибкий режим?', 'Стабильный надёжнее: новые адреса применяются после переподключения. Гибкий обновляет маршруты на лету, но пока в бете.'],
['Видит ли SHX мои сайты?', 'Нет. С доступом к статистике приложение считает только объём трафика по приложениям; сайты и содержимое не сохраняются и никуда не отправляются.']
];
return {
faq: Q.map(function (x, i) { return { q: x[0], a: x[1], open: !!x[2], openStr: x[2] ? 'true' : 'false', rot: x[2] ? 'rotate(180deg)' : 'none', divider: i < Q.length - 1 ? '1px solid #2B2930' : '0' }; }),
links: [{ t: 'Проверить обновления', href: 'D_Update.dc.html' }, { t: 'Лицензии открытого ПО', href: 'D_Help.dc.html' }, { t: 'Исходный код strongSwan', href: 'D_Help.dc.html' }]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,101 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Главная</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #B69DFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="D_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #141318; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="D_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Отключить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #3B2C88, 0 0 0 28px #2A2343; margin: 28px 0 22px; cursor: pointer">
<svg width="68" height="68" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M12 3v9"/><path d="M6.3 6.3a8 8 0 1 0 11.4 0"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Защищено</span>
<span style="display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; color: #A9A3BF"><span style="width: 8px; height: 8px; border-radius: 4px; background: #148A45"></span>01:24:37 · РФ-сайты напрямую</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="D_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #3B2C88; color: #D0C2FF; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #A9A3BF">IP 185.•••.•••.12 · 38 мс</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #B69DFF">Сменить</span>
</a>
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px">
<sc-for list="{{actions}}" as="q" hint-placeholder-count="3">
<a href="{{q.href}}" style="height: 72px; border-radius: 20px; background: #2B2930; color: #E0DAF5; text-decoration: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; font-size: 12px; font-weight: 700; text-align: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{q.icon}}"/></svg>{{q.label}}
</a>
</sc-for>
</div>
<a href="D_Stats.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 14px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9">
<span style="flex: 1; display: flex; flex-direction: column; gap: 8px">
<span style="display: flex; align-items: baseline; gap: 8px"><span style="font-size: 20px; font-weight: 800">1,24 ГБ</span><span style="font-size: 13px; color: #A9A3BF">сегодня</span></span>
<span style="display: flex; height: 6px; border-radius: 3px; overflow: hidden; gap: 2px"><span style="width: 72%; background: #6D4AFF; border-radius: 3px"></span><span style="flex: 1; background: #3FBF7F; border-radius: 3px"></span></span>
<span style="font-size: 12px; font-weight: 600; color: #A9A3BF">72% через VPN · 342 трекера заблокировано</span>
</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#A9A3BF" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</a>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
}),
actions: [
{ label: 'Пауза 15 мин', href: 'D_Pause.dc.html', icon: 'M9 5v14M15 5v14' },
{ label: 'Быстрейший', href: 'D_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'D_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,81 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Главная — проблема</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #B69DFF">vpn</span></span></span>
<a href="D_Diag.dc.html" aria-label="Диагностика: есть проблема" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
<span style="position: absolute; top: 8px; right: 8px; width: 10px; height: 10px; border-radius: 5px; background: #B45309; border: 2px solid #2B2930"></span>
</a>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Подключить сейчас" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #4A3416; color: #FFB869; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #33260F, 0 0 0 28px #2A2010; margin: 28px 0 22px; cursor: pointer">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
</button>
<span style="font-size: 22px; font-weight: 800; letter-spacing: -0.02em; color: #FFD8A8">Оператор включил белые списки</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; line-height: 1.45; color: #F5C892">Работают только российские сайты — банки и Госуслуги открываются. VPN подключится сам.</span>
</section>
<div style="padding: 20px 16px 0; display: flex; flex-direction: column; gap: 10px">
<div role="status" style="display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 24px; background: #1F1D24; border: 1px solid #5A4220">
<span style="width: 10px; height: 10px; border-radius: 5px; background: #B45309"></span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 700; color: #FFD8A8">Пробуем резервный сервер</span>
<span style="font-size: 12px; color: #F5C892">Хельсинки · попытка 2 из 3</span>
</span>
<button style="flex: none; height: 40px; padding: 0 14px; border-radius: 12px; border: 1px solid #7A5A30; background: transparent; color: #FFD8A8; font: 700 13px 'Manrope', sans-serif">Стоп</button>
</div>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px">
<a href="D_Diag.dc.html" style="height: 52px; border-radius: 18px; background: #B45309; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">Что делать</a>
<button style="height: 52px; border: 0; border-radius: 18px; background: #2B2930; color: #E0DAF5; font: 700 14px 'Manrope', sans-serif">Через Wi-Fi</button>
</div>
<div role="status" style="display: flex; align-items: center; gap: 10px; padding: 10px 12px 10px 14px; border-radius: 18px; background: #211F26">
<span style="flex: 1; font-size: 13px; font-weight: 600; color: #E0DAF5">Постоянный VPN выключен</span>
<a href="D_KillSwitch.dc.html" style="flex: none; height: 36px; padding: 0 12px; border-radius: 12px; background: #3B2C88; color: #D0C2FF; font-size: 13px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Включить</a>
</div>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_HomeAlert.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
return {
tabs: tabs.map(function (t, i) {
var on = i === 0;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#4A3416' : 'transparent' };
})
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,88 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Главная — подключаемся</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #B69DFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="D_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #141318; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="D_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Отменить подключение" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #3B2C88; color: #B69DFF; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #2A2343, 0 0 0 28px #221D33; margin: 28px 0 22px; cursor: pointer">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em; color: #E5E1E9">Подключаемся…</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: #A9A3BF">Амстердам · шаг 3 из 4</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="D_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #3B2C88; color: #D0C2FF; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #A9A3BF">IP 185.•••.•••.12 · 38 мс</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #B69DFF">Сменить</span>
</a>
<section style="padding: 8px 16px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35"><div style="display: flex; align-items: center; gap: 12px; height: 40px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #12321F; color: #7CE3B0; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center">✓</span><span style="flex: 1; font-size: 14px; font-weight: 600; color: #E5E1E9">Сеть</span><span style="font-size: 13px; color: #A9A3BF">LTE</span></div><div style="display: flex; align-items: center; gap: 12px; height: 40px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #12321F; color: #7CE3B0; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center">✓</span><span style="flex: 1; font-size: 14px; font-weight: 600; color: #E5E1E9">Сервер ответил</span><span style="font-size: 13px; color: #A9A3BF">38 мс</span></div><div style="display: flex; align-items: center; gap: 12px; height: 40px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #6D4AFF; color: #FFFFFF; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center">…</span><span style="flex: 1; font-size: 14px; font-weight: 800; color: #E5E1E9">Проверка входа</span><span style="font-size: 13px; color: #A9A3BF"></span></div><div style="display: flex; align-items: center; gap: 12px; height: 40px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #2B2930; color: #938F99; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center"></span><span style="flex: 1; font-size: 14px; font-weight: 600; color: #938F99">Туннель и маршруты</span><span style="font-size: 13px; color: #A9A3BF"></span></div></section>
<a href="D_Home.dc.html" style="height: 48px; border-radius: 16px; background: #2B2930; color: #E0DAF5; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700">Отменить</a>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
}),
actions: [
{ label: 'Пауза 15 мин', href: 'D_Pause.dc.html', icon: 'M9 5v14M15 5v14' },
{ label: 'Быстрейший', href: 'D_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'D_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,79 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Главная — нет серверов</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #B69DFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="D_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #141318; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="D_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Добавить сервер" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #2B2930; color: #938F99; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #211F26, 0 0 0 28px #1A1820; margin: 28px 0 22px; cursor: pointer">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em; color: #E5E1E9">Добавьте сервер</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: #A9A3BF">Чтобы подключиться, нужен профиль .sswan</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="D_ImportQR.dc.html" style="height: 60px; border-radius: 20px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; gap: 10px; font-size: 16px; font-weight: 800"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 8V5a1 1 0 0 1 1-1h3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3M4 12h16"/></svg>Сканировать QR</a>
<a href="D_Import.dc.html" style="height: 56px; border-radius: 18px; background: #36334A; color: #E0DAF5; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700">Ссылка, файл или вручную</a>
<div style="padding: 14px 16px; border-radius: 20px; background: #1F1D24; border: 1px solid #2E2B35; display: flex; flex-direction: column; gap: 4px"><span style="font-size: 14px; font-weight: 800">Где взять профиль?</span><span style="font-size: 13px; line-height: 1.45; color: #A9A3BF">Его присылает администратор вашего VPN — файлом .sswan, ссылкой или QR-кодом. Можно отсканировать с экрана друга.</span></div>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
}),
actions: [
{ label: 'Пауза 15 мин', href: 'D_Pause.dc.html', icon: 'M9 5v14M15 5v14' },
{ label: 'Быстрейший', href: 'D_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'D_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,70 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Главная — нет интернета</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #B69DFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="D_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #141318; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="D_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Отключить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #2B2930; color: #CAC4D0; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #211F26, 0 0 0 28px #1A1820; margin: 28px 0 22px; cursor: pointer"><svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 8.8a15 15 0 0 1 4.4-2.7M10 5.1A15 15 0 0 1 22 8.8M5 12.9a10 10 0 0 1 4.6-2.6M14.6 10.5A10 10 0 0 1 19 12.9M8.5 16.4a5 5 0 0 1 7 0M12 20h.01M3 3l18 18"/></svg></button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Нет интернета</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: #A9A3BF">Проблема не в VPN. Подключимся сами, как только появится сеть</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<section style="padding: 6px 16px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35"><div style="display: flex; align-items: center; gap: 12px; height: 38px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #4A1C1C; color: #FFB4AB; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center">×</span><span style="flex: 1; font-size: 14px; font-weight: 600">Wi-Fi</span><span style="font-size: 13px; color: #A9A3BF">выключен</span></div><div style="display: flex; align-items: center; gap: 12px; height: 38px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #4A1C1C; color: #FFB4AB; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center">×</span><span style="flex: 1; font-size: 14px; font-weight: 600">Мобильные данные</span><span style="font-size: 13px; color: #A9A3BF">нет сигнала</span></div><div style="display: flex; align-items: center; gap: 12px; height: 38px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #2B2930; color: #938F99; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center"></span><span style="flex: 1; font-size: 14px; font-weight: 600">Сервер Амстердам</span><span style="font-size: 13px; color: #A9A3BF">ждёт сеть</span></div></section>
<section role="status" style="padding: 16px; border-radius: 24px; background: #2A2343; border: 1px solid #4B3D99; display: flex; flex-direction: column; gap: 10px"><span style="font-size: 15px; font-weight: 800; color: #D0C2FF">Приложения без сети — так и задумано</span><span style="font-size: 13px; line-height: 1.45; color: #D0C2FF">Включено «Без VPN — без сети»: пока туннеля нет, трафик не уйдёт напрямую.</span><div style="display: flex; gap: 8px"><a href="D_Settings.dc.html" style="flex: 1; min-width: 0; height: 48px; padding: 0 14px; border-radius: 16px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; white-space: nowrap; box-sizing: border-box">Настройки сети</a><a href="D_KillSwitch.dc.html" style="flex: none; min-width: 0; height: 48px; padding: 0 14px; border-radius: 16px; background: #2B2930; color: #E0DAF5; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; white-space: nowrap; box-sizing: border-box">Подробнее</a></div></section>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
return {
tabs: tabs.map(function (t, i) {
var on = i === 0;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
})
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,88 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Главная — пауза</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #B69DFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="D_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #141318; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="D_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Включить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #2B2930; color: #CAC4D0; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #211F26, 0 0 0 28px #1A1820; margin: 28px 0 22px; cursor: pointer">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 5v14M15 5v14"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em; color: #E5E1E9">Пауза · 12:40</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: #A9A3BF">VPN включится сам в 14:37</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="D_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #3B2C88; color: #D0C2FF; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #A9A3BF">IP 185.•••.•••.12 · 38 мс</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #B69DFF">Сменить</span>
</a>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px"><a href="D_Home.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Включить сейчас</a><a href="D_Pause.dc.html" style="height: 56px; border-radius: 18px; background: #2B2930; color: #E0DAF5; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700">+15 минут</a></div>
<div style="padding: 12px 14px; border-radius: 18px; background: #3A2A12; color: #F5C892; font-size: 13px; line-height: 1.45">Весь трафик сейчас идёт напрямую, без защиты. Банки и РФ-сервисы работают как обычно.</div>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
}),
actions: [
{ label: 'Пауза 15 мин', href: 'D_Pause.dc.html', icon: 'M9 5v14M15 5v14' },
{ label: 'Быстрейший', href: 'D_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'D_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,106 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Главная — сценарий</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #B69DFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="D_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #141318; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="D_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Включить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #36333D; color: #CAC4D0; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #2B2930, 0 0 0 28px #211F26; margin: 28px 0 22px; cursor: pointer">
<svg width="68" height="68" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M12 3v9"/><path d="M6.3 6.3a8 8 0 1 0 11.4 0"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em">VPN выключен</span>
<a href="D_Automation.dc.html" style="display: flex; align-items: center; gap: 8px; height: 40px; padding: 0 8px 0 14px; border-radius: 20px; background: #3B2C88; color: #EADDFF; text-decoration: none; font-size: 14px; font-weight: 700">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 9a15 15 0 0 1 20 0M5 13a10 10 0 0 1 14 0M9 17a4 4 0 0 1 6 0"/></svg>
Сценарий · Home_5G
<span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24; display: flex; align-items: center; justify-content: center"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6D4AFF" stroke-width="2.6" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg></span>
</a>
<span style="font-size: 13px; color: #A9A3BF">Включится сам, когда уйдёте из этой сети</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="D_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #3B2C88; color: #D0C2FF; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #A9A3BF">подключится при выходе из Home_5G</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #B69DFF">Сменить</span>
</a>
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px">
<sc-for list="{{actions}}" as="q" hint-placeholder-count="3">
<a href="{{q.href}}" style="height: 72px; border-radius: 20px; background: #2B2930; color: #E0DAF5; text-decoration: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; font-size: 12px; font-weight: 700; text-align: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{q.icon}}"/></svg>{{q.label}}
</a>
</sc-for>
</div>
<a href="D_Stats.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 14px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9">
<span style="flex: 1; display: flex; flex-direction: column; gap: 8px">
<span style="display: flex; align-items: baseline; gap: 8px"><span style="font-size: 20px; font-weight: 800">1,24 ГБ</span><span style="font-size: 13px; color: #A9A3BF">сегодня</span></span>
<span style="display: flex; height: 6px; border-radius: 3px; overflow: hidden; gap: 2px"><span style="width: 72%; background: #6D4AFF; border-radius: 3px"></span><span style="flex: 1; background: #3FBF7F; border-radius: 3px"></span></span>
<span style="font-size: 12px; font-weight: 600; color: #A9A3BF">72% через VPN · 28% напрямую</span>
</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#A9A3BF" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</a>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
}),
actions: [
{ label: 'Включить сейчас', href: 'D_Home.dc.html', icon: 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0' },
{ label: 'Быстрейший', href: 'D_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'D_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,71 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Главная — сервер не отвечает</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #B69DFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="D_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #141318; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="D_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Отключить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #4A3416; color: #FFD8A8; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #33260F, 0 0 0 28px #2A2010; margin: 28px 0 22px; cursor: pointer"><svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 8v5M12 16.5v.5M10.3 3.9L2.4 18a2 2 0 0 0 1.7 3h15.8a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg></button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Сервер не отвечает</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: #A9A3BF">Амстердам молчит 40 с · снова пробуем через 12 с</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<section role="status" style="padding: 16px; border-radius: 24px; background: #3A2A12; border: 1px solid #5A4220; display: flex; flex-direction: column; gap: 10px"><span style="font-size: 15px; font-weight: 800; color: #F5C892">Интернет есть — не отвечает сам сервер</span><span style="font-size: 13px; line-height: 1.45; color: #F5C892">Возможно, он перегружен или недоступен из вашей сети. Франкфурт сейчас отвечает за 41 мс.</span><div style="display: flex; gap: 8px"><a href="D_Home.dc.html" style="flex: 1; min-width: 0; height: 48px; padding: 0 14px; border-radius: 16px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; white-space: nowrap; box-sizing: border-box">Перейти на Франкфурт</a><a href="D_HomeConnecting.dc.html" style="flex: none; min-width: 0; height: 48px; padding: 0 14px; border-radius: 16px; background: #2B2930; color: #E0DAF5; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; white-space: nowrap; box-sizing: border-box">Повторить</a></div></section>
<a href="D_Settings.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 20px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9"><span style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 700">Переключаться автоматически</span><span style="font-size: 13px; color: #A9A3BF; line-height: 1.4">Если сервер молчит дольше минуты — на ближайший рабочий</span></span><span style="flex: none; width: 52px; height: 32px; border-radius: 16px; background: #36333D; display: flex; align-items: center; padding: 0 4px; box-sizing: border-box; justify-content: flex-start"><span style="width: 24px; height: 24px; border-radius: 12px; background: #79767F"></span></span></a>
<a href="D_Diag.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 20px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9"><span style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 700">Проверить, в чём дело</span><span style="font-size: 13px; color: #A9A3BF; line-height: 1.4">Сеть, сервер, DNS и белые списки за 10 секунд</span></span><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#A9A3BF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg></a>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
return {
tabs: tabs.map(function (t, i) {
var on = i === 0;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
})
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,63 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Добавить сервер</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end">
<section role="dialog" aria-label="Добавить сервер" style="border-radius: 32px 32px 0 0; background: #141318; padding: 12px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 36px; height: 4px; border-radius: 2px; background: #48454E"></span>
<div style="display: flex; align-items: center; justify-content: space-between; padding: 0 4px">
<h1 style="margin: 0; font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Добавить сервер</h1>
<a href="D_Servers.dc.html" aria-label="Закрыть" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #CAC4D0">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg>
</a>
</div>
<a href="D_ImportQR.dc.html" style="display: flex; align-items: center; gap: 14px; padding: 18px; border-radius: 24px; background: #6D4AFF; color: #FFFFFF; text-decoration: none">
<span style="width: 48px; height: 48px; border-radius: 16px; background: rgba(255,255,255,0.18); display: flex; align-items: center; justify-content: center">
<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 8V5a1 1 0 0 1 1-1h3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3M4 12h16"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 17px; font-weight: 800">Сканировать QR</span>
<span style="font-size: 13px; color: #E7DFFF">С экрана друга или с сайта</span>
</span>
</a>
<div style="display: flex; flex-direction: column; gap: 8px; padding: 14px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35">
<label for="fi-url" style="font-size: 15px; font-weight: 800">Ссылка на профиль</label>
<div style="display: flex; gap: 8px">
<span style="flex: 1; min-width: 0; display: flex; align-items: center; height: 48px; padding: 0 12px; border-radius: 14px; background: #2B2930">
<input id="fi-url" type="url" placeholder="https://…/profile.sswan" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 500 15px 'Manrope', sans-serif; color: #E5E1E9; outline: none">
</span>
<a href="D_ImportPreview.dc.html" style="flex: none; white-space: nowrap; height: 48px; padding: 0 16px; border-radius: 14px; background: #36334A; color: #E0DAF5; text-decoration: none; display: flex; align-items: center; font-size: 14px; font-weight: 700">Вставить</a>
</div>
<span style="font-size: 12px; line-height: 1.4; color: #A9A3BF">Ссылку запомним и будем подтягивать изменения профиля</span>
</div>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px">
<a href="D_ImportPreview.dc.html" style="height: 56px; border-radius: 18px; border: 1px solid #48454E; color: #E5E1E9; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700; box-sizing: border-box">Файл .sswan</a>
<a href="D_ManualAdd.dc.html" style="height: 56px; border-radius: 18px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font-size: 14px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Вручную</a>
</div>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {};
}
}
</script>
</body>
</html>
@@ -0,0 +1,73 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Проверка профиля</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end">
<section role="dialog" aria-label="Добавить сервер" style="border-radius: 32px 32px 0 0; background: #141318; padding: 12px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 36px; height: 4px; border-radius: 2px; background: #48454E"></span>
<div style="display: flex; align-items: center; gap: 14px; padding: 4px 4px 0">
<span style="width: 56px; height: 56px; border-radius: 28px; background: #3B2C88; color: #D0C2FF; display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: 800">NL</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<h1 style="margin: 0; font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Добавить сервер?</h1>
<span style="font-size: 13px; color: #A9A3BF">Профиль прочитан, всё в порядке</span>
</span>
</div>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<label style="display: flex; flex-direction: column; gap: 4px; padding: 12px 16px; border-bottom: 1px solid #2B2930">
<span style="font-size: 12px; font-weight: 700; color: #A9A3BF">Название</span>
<input type="text" value="Амстердам" style="border: 0; background: transparent; padding: 0; font: 700 16px 'Manrope', sans-serif; color: #E5E1E9; outline: none; min-width: 0; width: 100%">
</label>
<sc-for list="{{rows}}" as="r" hint-placeholder-count="4">
<div style="display: flex; align-items: center; gap: 10px; padding: 0 16px; height: 52px; border-bottom: {{r.divider}}">
<span style="flex: 1; font-size: 14px; font-weight: 600; color: #CAC4D0">{{r.k}}</span>
<span style="font-size: 14px; font-weight: 700; color: {{r.color}}">{{r.v}}</span>
</div>
</sc-for>
</section>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<div style="display: flex; align-items: center; gap: 10px; padding: 12px 14px 12px 16px; border-bottom: 1px solid #2B2930">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 700">Обновлять по ссылке</span>
<span style="font-size: 12px; color: #A9A3BF">Есть только у профилей, добавленных по ссылке</span>
</span>
<button aria-pressed="true" aria-label="Обновлять по ссылке" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: #6D4AFF; padding: 4px; display: flex; justify-content: flex-end"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
<div style="display: flex; align-items: center; gap: 10px; padding: 12px 14px 12px 16px">
<span style="flex: 1; font-size: 15px; font-weight: 700">Подключиться сразу</span>
<button aria-pressed="true" aria-label="Подключиться сразу" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: #6D4AFF; padding: 4px; display: flex; justify-content: flex-end"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
</section>
<div style="padding: 12px 14px; border-radius: 18px; background: #2A2343; font-size: 13px; line-height: 1.45; color: #E0DAF5"><b>Такой сервер уже есть</b> («Амстердам», добавлен 12 окт.). Новый профиль заменит его, ваши настройки останутся.</div>
<div style="display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 10px">
<a href="D_Import.dc.html" style="height: 56px; border-radius: 18px; border: 1px solid #48454E; color: #E5E1E9; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700; box-sizing: border-box">Отмена</a>
<a href="D_Servers.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Обновить сервер</a>
</div>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var r = [['Сервер', 'nl1.[ваш-домен]', '#E5E1E9'], ['Тип', 'IKEv2', '#E5E1E9'], ['Вход', 'Сертификат в профиле', '#E5E1E9'], ['Источник', 'ссылка', '#E5E1E9'], ['Сертификат CA', 'входит в профиль', '#7CE3B0']];
return { rows: r.map(function (x, i) { return { k: x[0], v: x[1], color: x[2], divider: i < r.length - 1 ? '1px solid #2B2930' : '0' }; }) };
}
}
</script>
</body>
</html>
@@ -0,0 +1,60 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Сканер QR</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#C4B2FF}a:hover{color:#FFFFFF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #0F0E13; font-family: 'Manrope', system-ui, sans-serif; color: #FFFFFF; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 16px 12px">
<a href="D_Import.dc.html" aria-label="Закрыть" style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.12); display: flex; align-items: center; justify-content: center; color: #FFFFFF">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg>
</a>
<button aria-label="Фонарик" style="width: 44px; height: 44px; border: 0; border-radius: 22px; background: rgba(255,255,255,0.12); color: #FFFFFF; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3h8l-2 6v11h-4V9z"/></svg>
</button>
</header>
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 28px">
<div style="position: relative; width: 260px; height: 260px">
<span style="position: absolute; left: 0; top: 0; width: 56px; height: 56px; border-left: 5px solid #9C7CFF; border-top: 5px solid #9C7CFF; border-radius: 22px 0 0 0"></span>
<span style="position: absolute; right: 0; top: 0; width: 56px; height: 56px; border-right: 5px solid #9C7CFF; border-top: 5px solid #9C7CFF; border-radius: 0 22px 0 0"></span>
<span style="position: absolute; left: 0; bottom: 0; width: 56px; height: 56px; border-left: 5px solid #9C7CFF; border-bottom: 5px solid #9C7CFF; border-radius: 0 0 0 22px"></span>
<span style="position: absolute; right: 0; bottom: 0; width: 56px; height: 56px; border-right: 5px solid #9C7CFF; border-bottom: 5px solid #9C7CFF; border-radius: 0 0 22px 0"></span>
<span style="position: absolute; left: 24px; right: 24px; top: 118px; height: 3px; border-radius: 2px; background: #9C7CFF; box-shadow: 0 0 18px #9C7CFF"></span>
</div>
<span style="max-width: 280px; text-align: center; font-size: 16px; font-weight: 700; line-height: 1.4">Наведите на QR с профилем .sswan или ссылкой на него</span>
</div>
<div style="padding: 0 16px 28px; display: flex; flex-direction: column; gap: 10px">
<a href="D_ImportPreview.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 22px; background: #1F1D24; color: #E5E1E9; text-decoration: none">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #148A45; color: #FFFFFF; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 800">Найден профиль «Амстердам»</span>
<span style="font-size: 12px; color: #A9A3BF">Нажмите, чтобы проверить и добавить</span>
</span>
</a>
<button style="height: 48px; border: 0; border-radius: 16px; background: rgba(255,255,255,0.12); color: #FFFFFF; font: 700 14px 'Manrope', sans-serif">Выбрать картинку из галереи</button>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {};
}
}
</script>
</body>
</html>
@@ -0,0 +1,108 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · События</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1300px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Home.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">События</h1>
<button style="flex: none; height: 40px; padding: 0 12px; border: 0; border-radius: 20px; background: transparent; color: #B69DFF; font: 700 13px 'Manrope', sans-serif">Прочитать все</button>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; gap: 8px; flex-wrap: wrap">
<button aria-pressed="true" style="height: 34px; padding: 0 12px; border-radius: 12px; border: 0; background: #3B2C88; color: #FFFFFF; font: 700 13px 'Manrope', sans-serif">Все</button>
<button style="height: 34px; padding: 0 12px; border-radius: 12px; border: 0; background: #4A3416; color: #FFD8A8; font: 700 13px 'Manrope', sans-serif">Ждут решения · 2</button>
<button style="height: 34px; padding: 0 12px; border-radius: 12px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 600 13px 'Manrope', sans-serif">Подключение</button>
<button style="height: 34px; padding: 0 12px; border-radius: 12px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 600 13px 'Manrope', sans-serif">Маршруты</button>
</div>
<sc-for list="{{days}}" as="d" hint-placeholder-count="2">
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">{{d.title}}</h2>
<sc-for list="{{d.items}}" as="e" hint-placeholder-count="3">
<article style="display: flex; gap: 12px; padding: 14px; border-radius: 22px; background: {{e.bg}}; border: 1px solid {{e.border}}">
<span style="flex: none; width: 36px; height: 36px; border-radius: 12px; background: {{e.iconBg}}; color: {{e.iconFg}}; display: flex; align-items: center; justify-content: center">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{e.icon}}"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 4px; min-width: 0">
<span style="display: flex; align-items: baseline; gap: 8px">
<span style="flex: 1; font-size: 15px; font-weight: 800">{{e.title}}</span>
<span style="flex: none; font-size: 12px; color: #A9A3BF">{{e.time}}</span>
</span>
<span style="font-size: 13px; line-height: 1.4; color: #CAC4D0">{{e.text}}</span>
<sc-if value="{{e.hasActions}}" hint-placeholder-val="{{ false }}">
<span style="display: flex; gap: 8px; padding-top: 6px">
<a href="{{e.href1}}" style="height: 36px; padding: 0 14px; border-radius: 12px; background: {{e.primaryBg}}; color: #FFFFFF; font-size: 13px; font-weight: 800; text-decoration: none; display: flex; align-items: center">{{e.primary}}</a>
<sc-if value="{{e.hasSecondary}}" hint-placeholder-val="{{ false }}">
<a href="{{e.href2}}" style="height: 36px; padding: 0 12px; border-radius: 12px; border: 1px solid #48454E; color: #E5E1E9; font-size: 13px; font-weight: 700; text-decoration: none; display: flex; align-items: center; box-sizing: border-box">{{e.secondary}}</a>
</sc-if>
</span>
</sc-if>
</span>
</article>
</sc-for>
</section>
</sc-for>
<p style="margin: 4px 6px 0; font-size: 12px; line-height: 1.45; color: #A9A3BF">Храним 30 дней на устройстве. Что приходит пушем, а что только сюда — в Настройки → Уведомления.</p>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1300}}'>
class Component extends DCLogic {
renderVals() {
var K = {
warn: { bg: '#3A2A12', border: '#5A4220', iconBg: '#B45309', iconFg: '#FFFFFF', primaryBg: '#B45309' },
ask: { bg: '#1F1D24', border: '#4B3D99', iconBg: '#6D4AFF', iconFg: '#FFFFFF', primaryBg: '#6D4AFF' },
info: { bg: '#1F1D24', border: '#2E2B35', iconBg: '#2B2930', iconFg: '#D0C2FF', primaryBg: '#6D4AFF' },
ok: { bg: '#1F1D24', border: '#2E2B35', iconBg: '#12321F', iconFg: '#7CE3B0', primaryBg: '#6D4AFF' }
};
var I = {
alert: 'M12 4l9 16H3zM12 10v4M12 17.5v.5',
swap: 'M4 8h13l-3-3M20 16H7l3 3',
app: 'M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z',
route: 'M4 12h6l4-6h6M10 12l4 6h6',
db: 'M4 6c0-1.7 3.6-3 8-3s8 1.3 8 3-3.6 3-8 3-8-1.3-8-3zM4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6',
shield: 'M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z',
down: 'M12 4v12M7 11l5 5 5-5M5 20h14'
};
var e = function (kind, icon, title, time, text, primary, secondary, href1, href2) {
var k = K[kind];
return { bg: k.bg, border: k.border, iconBg: k.iconBg, iconFg: k.iconFg, primaryBg: k.primaryBg, icon: I[icon],
title: title, time: time, text: text, hasActions: !!primary, primary: primary || '', hasSecondary: !!secondary, secondary: secondary || '', href1: href1 || 'D_Inbox.dc.html', href2: href2 || 'D_Inbox.dc.html' };
};
return {
days: [
{ title: 'СЕГОДНЯ', items: [
e('warn', 'alert', 'Белые списки у оператора', '14:02', 'Включили мост «Москва» — банки и Госуслуги работают, остальное через VPN.', 'Подробнее', null, 'D_Diag.dc.html'),
e('ask', 'app', 'Новое приложение: ВкусВилл', '13:40', 'Похоже на российский сервис. Пустить напрямую, мимо VPN?', 'Да, напрямую', 'Нет', 'D_Recent.dc.html', 'D_Inbox.dc.html'),
e('ask', 'route', 'Госуслуги не открываются через VPN', '12:15', '7 неудачных соединений за 5 минут.', 'Пустить напрямую', 'Проверить', 'D_Recent.dc.html', 'D_Check.dc.html'),
e('info', 'swap', 'Переключились на резервный сервер', '09:31', 'Амстердам не ответил за 15 с → Хельсинки. Через 10 минут вернулись обратно.')
] },
{ title: 'ВЧЕРА', items: [
e('ok', 'db', 'База адресов РФ обновлена', '22:00', '+214 сетей, всего 12 480.'),
e('info', 'down', 'Доступна версия 2.17.0', '18:44', 'Серверы, история трафика, новые правила.', 'Обновить', null, 'D_Update.dc.html'),
e('ok', 'shield', 'Итоги недели', '10:00', '18,4 ГБ трафика · 1 284 трекера заблокировано · 0 утечек без VPN.')
] }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,68 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Без VPN — без сети</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Settings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Без VPN — без сети</h1>
</header>
<div style="flex: 1; padding: 4px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<section style="display: flex; align-items: center; gap: 12px; padding: 16px; border-radius: 24px; background: #3A2A12; border: 1px solid #5A4220">
<span style="flex: none; width: 44px; height: 44px; border-radius: 14px; background: #B45309; color: #FFFFFF; display: flex; align-items: center; justify-content: center">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 11V8a6 6 0 0 1 12 0v3M5 11h14v10H5z"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 17px; font-weight: 800; color: #FFD8A8">Сейчас выключено</span>
<span style="font-size: 13px; line-height: 1.4; color: #F5C892">При обрыве VPN приложения на секунды выйдут в сеть напрямую</span>
</span>
</section>
<p style="margin: 0 4px; font-size: 15px; line-height: 1.5; color: #E0DAF5">Android может блокировать интернет, пока VPN не подключён. Включается в системных настройках — это займёт 20 секунд.</p>
<ol style="margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 10px">
<sc-for list="{{steps}}" as="s" hint-placeholder-count="3">
<li style="display: flex; align-items: flex-start; gap: 12px; padding: 14px; border-radius: 20px; background: #1F1D24; border: 1px solid #2E2B35">
<span style="flex: none; width: 28px; height: 28px; border-radius: 14px; background: #6D4AFF; color: #FFFFFF; font-size: 13px; font-weight: 800; display: flex; align-items: center; justify-content: center">{{s.n}}</span>
<span style="font-size: 14px; line-height: 1.45; color: #E5E1E9">{{s.t}}</span>
</li>
</sc-for>
</ol>
<div style="padding: 12px 14px; border-radius: 18px; background: #2A2343; font-size: 13px; line-height: 1.45; color: #E0DAF5">Приложения из списка «напрямую» продолжат работать через обычную сеть. Всё остальное, включая сайты РФ, будет ждать VPN.</div>
<div style="flex: 1"></div>
<button style="height: 56px; border: 0; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; font: 800 15px 'Manrope', sans-serif">Открыть настройки Android</button>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {
steps: [
{ n: 1, t: 'Нажмите кнопку ниже — откроется раздел VPN в настройках Android.' },
{ n: 2, t: 'Нажмите на шестерёнку рядом с «SHX VPN».' },
{ n: 3, t: 'Включите «Постоянный VPN» и «Блокировать подключения без VPN».' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,65 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Журнал</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Diag.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Журнал</h1>
<button aria-label="Скопировать журнал" style="width: 44px; height: 44px; border: 0; border-radius: 22px; background: #2B2930; color: #D0C2FF; display: flex; align-items: center; justify-content: center">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2"/><path d="M16 8V5a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h3"/></svg>
</button>
</header>
<div style="flex: 1; padding: 0 16px 24px; display: flex; flex-direction: column; gap: 12px; min-height: 0">
<div style="display: flex; gap: 8px">
<button aria-pressed="true" style="height: 34px; padding: 0 12px; border-radius: 12px; border: 0; background: #3B2C88; color: #FFFFFF; font: 700 13px 'Manrope', sans-serif">Важное</button>
<button aria-pressed="false" style="height: 34px; padding: 0 12px; border-radius: 12px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 600 13px 'Manrope', sans-serif">Всё</button>
<button aria-pressed="false" style="height: 34px; padding: 0 12px; border-radius: 12px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 600 13px 'Manrope', sans-serif">Ошибки</button>
</div>
<section style="flex: 1; min-height: 0; border-radius: 22px; background: #1C1B20; padding: 14px; display: flex; flex-direction: column; gap: 6px; overflow: hidden">
<sc-for list="{{lines}}" as="l" hint-placeholder-count="14">
<div style="display: flex; gap: 10px; font: 500 12px/1.45 ui-monospace, 'Cascadia Mono', Menlo, monospace">
<span style="flex: none; color: #938F99">{{l.t}}</span>
<span style="color: {{l.c}}">{{l.m}}</span>
</div>
</sc-for>
</section>
<div style="padding: 12px 14px; border-radius: 18px; background: #2A2343; font-size: 13px; line-height: 1.45; color: #E0DAF5">В отчёт попадут журнал подключения и версия приложения.</div>
<a href="D_Share.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Отправить отчёт</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var W = '#36333D', G = '#7CE3B0', A = '#FFB869', P = '#C4B2FF';
var L = [
['14:02:11', 'Сеть: мобильная (LTE)', W], ['14:02:12', 'IKE_SA_INIT → nl1 :4500', W], ['14:02:27', 'Нет ответа 15 с — таймаут', A],
['14:02:27', 'Проверка: только сайты РФ отвечают', A], ['14:02:28', 'Белые списки обнаружены', A], ['14:02:28', 'Переключение на «Москва (мост)»', P],
['14:02:29', 'IKE_SA_INIT → msk-bridge :4500', W], ['14:02:29', 'IKE_AUTH: сертификат принят', G], ['14:02:30', 'CHILD_SA установлен', G],
['14:02:30', 'Маршруты: РФ напрямую, 12 480 сетей', W], ['14:02:30', 'Приложений напрямую: 24', W], ['14:02:31', 'Туннель работает · 52 мс', G],
['14:05:40', 'Госуслуги: 7 отказов через VPN', A], ['14:05:41', 'Подсказка: пустить напрямую', P]
];
return { lines: L.map(function (x) { return { t: x[0], m: x[1], c: x[2] }; }) };
}
}
</script>
</body>
</html>
@@ -0,0 +1,67 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Сервер вручную</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Import.dc.html" aria-label="Закрыть" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Сервер вручную</h1>
</header>
<div style="flex: 1; padding: 0 16px 24px; display: flex; flex-direction: column; gap: 12px">
<sc-for list="{{fields}}" as="f" hint-placeholder-count="3">
<label style="display: flex; flex-direction: column; gap: 4px; padding: 10px 14px; border-radius: 16px; background: #1F1D24; border: {{f.border}}">
<span style="font-size: 12px; font-weight: 700; color: {{f.labelColor}}">{{f.label}}</span>
<input type="text" value="{{f.value}}" placeholder="{{f.ph}}" style="border: 0; background: transparent; padding: 0; font: 600 16px 'Manrope', sans-serif; color: #E5E1E9; outline: none; min-width: 0; width: 100%">
</label>
</sc-for>
<span style="padding: 4px 4px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ВХОД</span>
<div role="radiogroup" aria-label="Вход" style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 4px; border-radius: 16px; background: #2B2930">
<button aria-pressed="true" style="height: 40px; border: 0; border-radius: 12px; background: #1F1D24; color: #E5E1E9; font: 800 13px 'Manrope', sans-serif; box-shadow: 0 1px 3px rgba(28,27,32,0.12)">Логин</button>
<button aria-pressed="false" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #CAC4D0; font: 600 13px 'Manrope', sans-serif">Сертификат</button>
<button aria-pressed="false" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #CAC4D0; font: 600 13px 'Manrope', sans-serif">Оба</button>
</div>
<label style="display: flex; flex-direction: column; gap: 4px; padding: 10px 14px; border-radius: 16px; background: #1F1D24; border: 1px solid #2E2B35">
<span style="font-size: 12px; font-weight: 700; color: #A9A3BF">Имя пользователя</span>
<input type="text" value="denis" style="border: 0; background: transparent; padding: 0; font: 600 16px 'Manrope', sans-serif; color: #E5E1E9; outline: none; min-width: 0; width: 100%">
</label>
<label style="display: flex; flex-direction: column; gap: 4px; padding: 10px 14px; border-radius: 16px; background: #1F1D24; border: 1px solid #2E2B35">
<span style="font-size: 12px; font-weight: 700; color: #A9A3BF">Пароль</span>
<input type="password" value="••••••••" style="border: 0; background: transparent; padding: 0; font: 600 16px 'Manrope', sans-serif; color: #E5E1E9; outline: none; min-width: 0; width: 100%">
</label>
<button style="display: flex; align-items: center; gap: 10px; height: 52px; padding: 0 16px; border-radius: 16px; border: 1px solid #2E2B35; background: #1F1D24; font: 700 14px 'Manrope', sans-serif; color: #E5E1E9">
<span style="flex: 1; text-align: left">Дополнительно: порт, MTU, DNS, идентификаторы</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#938F99" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
</button>
<div style="flex: 1"></div>
<a href="D_ImportPreview.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Проверить и добавить</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var f = function (label, value, ph, focus) { return { label: label, value: value, ph: ph, border: focus ? '2px solid #6D4AFF' : '1px solid #2E2B35', labelColor: focus ? '#B69DFF' : '#A9A3BF' }; };
return { fields: [f('Название', 'Амстердам', 'Например, Работа'), f('Адрес сервера', 'nl1.[ваш-домен]', 'vpn.example.com', true), f('Тип', 'IKEv2', '')] };
}
}
</script>
</body>
</html>
@@ -0,0 +1,82 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Уведомления</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Settings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Уведомления</h1>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 12px">
<p style="margin: 0 4px; font-size: 14px; line-height: 1.45; color: #CAC4D0">Все события всегда сохраняются в «Событиях». Здесь — что ещё приходит пушем.</p>
<sc-for list="{{groups}}" as="g" hint-placeholder-count="2">
<section style="display: flex; flex-direction: column; gap: 6px">
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">{{g.title}}</h2>
<div style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{g.rows}}" as="r" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 12px; padding: 10px 14px 10px 16px; min-height: 66px; box-sizing: border-box; border-bottom: {{r.divider}}">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="display: flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 700">{{r.title}}<span style="padding: 1px 7px; border-radius: 6px; background: {{r.tagBg}}; color: {{r.tagFg}}; font-size: 10px; font-weight: 800">{{r.tag}}</span></span>
<span style="font-size: 12px; line-height: 1.35; color: #A9A3BF">{{r.sub}}</span>
</span>
<button aria-pressed="{{r.on}}" aria-label="{{r.title}}" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: {{r.track}}; padding: 4px; display: flex; justify-content: {{r.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
</sc-for>
</div>
</section>
</sc-for>
<a href="F_SysNotifs.dc.html" style="display: flex; align-items: center; gap: 10px; height: 52px; padding: 0 16px; border-radius: 18px; background: #2B2930; color: #E0DAF5; text-decoration: none; font-size: 14px; font-weight: 700">
<span style="flex: 1">Звук и вид — в настройках Android</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#A9A3BF" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var T = { 'ВСЕГДА': ['#3B2C88', '#D0C2FF'], 'ВАЖНО': ['#4A3416', '#FFD8A8'], 'ТИХО': ['#2B2930', '#CAC4D0'] };
var row = function (title, sub, tag, on) {
return { title: title, sub: sub, tag: tag, tagBg: T[tag][0], tagFg: T[tag][1], on: on ? 'true' : 'false', track: on ? '#6D4AFF' : '#48454E', align: on ? 'flex-end' : 'flex-start' };
};
var grp = function (title, rows) {
rows.forEach(function (r, i) { r.divider = i < rows.length - 1 ? '1px solid #2B2930' : '0'; });
return { title: title, rows: rows };
};
return {
groups: [
grp('ПОДКЛЮЧЕНИЕ', [
row('Статус VPN', 'Постоянное уведомление: сервер, время, пауза. Требует Android', 'ВСЕГДА', true),
row('Проблемы', 'Белые списки, обрыв, сервер не отвечает', 'ВАЖНО', true)
]),
grp('МАРШРУТЫ', [
row('Новые приложения', 'Предложить пустить напрямую', 'ТИХО', true)
]),
grp('ПРОЧЕЕ', [
row('Обновления приложения', 'Новая версия готова к установке', 'ТИХО', true),
row('Итоги недели', 'Трафик за неделю, по понедельникам', 'ТИХО', false)
])
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,59 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Онбординг</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column; padding: 24px 24px 28px">
<div style="display: flex; justify-content: flex-end">
<a href="D_Home.dc.html" style="height: 44px; display: flex; align-items: center; padding: 0 8px; font-size: 15px; font-weight: 700; text-decoration: none; color: #A9A3BF">Пропустить</a>
</div>
<div aria-hidden="true" style="position: relative; height: 290px; display: flex; align-items: center; justify-content: center; margin-top: 8px">
<span style="position: absolute; width: 260px; height: 260px; border-radius: 42% 58% 50% 50% / 48% 44% 56% 52%; background: #3B2C88"></span>
<span style="position: absolute; width: 180px; height: 180px; border-radius: 55% 45% 48% 52% / 50% 56% 44% 50%; background: #6D4AFF"></span>
<span style="position: absolute; left: 34px; top: 46px; padding: 8px 12px; border-radius: 14px; background: #1F1D24; font-size: 13px; font-weight: 800; color: #D0C2FF; box-shadow: 0 4px 14px rgba(59,44,136,0.15)">Госуслуги → напрямую</span>
<span style="position: absolute; right: 26px; bottom: 50px; padding: 8px 12px; border-radius: 14px; background: #1F1D24; font-size: 13px; font-weight: 800; color: #D0C2FF; box-shadow: 0 4px 14px rgba(59,44,136,0.15)">YouTube → через VPN</span>
<svg width="76" height="76" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position: relative"><path d="M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z"/><path d="M9 12l2 2 4-4"/></svg>
</div>
<div style="display: flex; flex-direction: column; gap: 12px; margin-top: 20px">
<span style="font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.06em">ШАГ 1 ИЗ 3</span>
<h1 style="margin: 0; font-size: 30px; line-height: 1.15; font-weight: 800; letter-spacing: -0.02em">Российское — напрямую, остальное — через VPN</h1>
<p style="margin: 0; font-size: 16px; line-height: 1.5; color: #CAC4D0">Банки и Госуслуги работают как обычно, а заблокированные сервисы открываются без переключений.</p>
</div>
<div style="flex: 1"></div>
<div style="display: flex; justify-content: center; gap: 8px; margin-bottom: 20px" aria-label="Шаг 1 из 3">
<span style="width: 28px; height: 8px; border-radius: 4px; background: #6D4AFF"></span>
<span style="width: 8px; height: 8px; border-radius: 4px; background: #48454E"></span>
<span style="width: 8px; height: 8px; border-radius: 4px; background: #48454E"></span>
</div>
<div style="display: flex; flex-direction: column; gap: 10px">
<a href="D_Permissions.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; font-size: 16px; font-weight: 800; text-decoration: none; display: flex; align-items: center; justify-content: center">Начать</a>
<a href="D_Import.dc.html" style="height: 56px; border-radius: 18px; background: #36334A; color: #E0DAF5; font-size: 16px; font-weight: 700; text-decoration: none; display: flex; align-items: center; justify-content: center; gap: 8px">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="4" width="6" height="6" rx="1"/><rect x="14" y="4" width="6" height="6" rx="1"/><rect x="4" y="14" width="6" height="6" rx="1"/><path d="M14 14h2v2M20 14v6h-6"/></svg>Сканировать QR
</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {};
}
}
</script>
</body>
</html>
@@ -0,0 +1,53 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Пауза VPN</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end">
<section role="dialog" aria-label="Пауза VPN" style="border-radius: 32px 32px 0 0; background: #141318; padding: 12px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 36px; height: 4px; border-radius: 2px; background: #48454E"></span>
<div style="display: flex; flex-direction: column; gap: 4px; padding: 4px 4px 0">
<h1 style="margin: 0; font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Пауза VPN</h1>
<span style="font-size: 14px; line-height: 1.45; color: #A9A3BF">Весь трафик пойдёт напрямую. VPN включится сам.</span>
</div>
<div role="radiogroup" aria-label="На сколько" style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px">
<sc-for list="{{opts}}" as="o" hint-placeholder-count="4">
<button aria-pressed="{{o.on}}" style="height: 64px; border-radius: 20px; border: {{o.border}}; background: {{o.bg}}; color: #E5E1E9; font-family: 'Manrope', sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px">
<span style="font-size: 17px; font-weight: 800">{{o.t}}</span>
<span style="font-size: 12px; color: #A9A3BF">{{o.d}}</span>
</button>
</sc-for>
</div>
<button style="display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 20px; border: 1px solid #2E2B35; background: #1F1D24; text-align: left; font-family: 'Manrope', sans-serif; color: #E5E1E9">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 700">До смены сети</span>
<span style="font-size: 12px; color: #A9A3BF">Включится, когда уйдёте с этого Wi-Fi</span>
</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#938F99" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</button>
<a href="D_Home.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Поставить на паузу 15 мин</a>
<span style="text-align: center; font-size: 12px; line-height: 1.45; color: #A9A3BF">Отменить можно с главной, из шторки или виджета</span>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var o = function (t, d, on) { return { t: t, d: d, on: on ? 'true' : 'false', bg: on ? '#2A2343' : '#1F1D24', border: on ? '2px solid #6D4AFF' : '1px solid #2E2B35' }; };
return { opts: [o('5 мин', 'до 14:27'), o('15 мин', 'до 14:37', true), o('1 час', 'до 15:22'), o('До утра', 'до 07:00')] };
}
}
</script>
</body>
</html>
@@ -0,0 +1,76 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Разрешения</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1100px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column; padding: 24px 16px 28px">
<div style="display: flex; flex-direction: column; gap: 10px; padding: 8px 6px 18px">
<span style="font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.06em">ШАГ 2 ИЗ 3</span>
<h1 style="margin: 0; font-size: 28px; line-height: 1.15; font-weight: 800; letter-spacing: -0.02em">Чтобы VPN работал стабильно</h1>
<p style="margin: 0; font-size: 15px; line-height: 1.5; color: #CAC4D0">Android может выключать VPN в фоне. Разрешите главное — остальное можно позже.</p>
</div>
<div style="display: flex; flex-direction: column; gap: 10px">
<sc-for list="{{items}}" as="p" hint-placeholder-count="5">
<div style="display: flex; align-items: center; gap: 12px; padding: 14px; border-radius: 22px; background: #1F1D24; border: 1px solid {{p.border}}">
<span style="flex: none; width: 40px; height: 40px; border-radius: 14px; background: {{p.iconBg}}; color: {{p.iconFg}}; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{p.icon}}"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="display: flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 800">{{p.title}}<span style="padding: 1px 6px; border-radius: 6px; background: {{p.tagBg}}; color: {{p.tagFg}}; font-size: 10px; font-weight: 800">{{p.tag}}</span></span>
<span style="font-size: 12px; line-height: 1.35; color: #A9A3BF">{{p.why}}</span>
</span>
<sc-if value="{{p.done}}" hint-placeholder-val="{{ false }}">
<span style="flex: none; width: 32px; height: 32px; border-radius: 16px; background: #148A45; color: #FFFFFF; display: flex; align-items: center; justify-content: center" aria-label="Готово">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg>
</span>
</sc-if>
<sc-if value="{{p.todo}}" hint-placeholder-val="{{ true }}">
<a href="{{p.href}}" style="flex: none; height: 36px; padding: 0 12px; border-radius: 12px; background: {{p.btnBg}}; color: {{p.btnFg}}; text-decoration: none; display: flex; align-items: center; font-size: 13px; font-weight: 800">{{p.btn}}</a>
</sc-if>
</div>
</sc-for>
</div>
<div style="flex: 1"></div>
<div style="display: flex; flex-direction: column; gap: 10px">
<a href="D_Import.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 16px; font-weight: 800">Продолжить</a>
<span style="text-align: center; font-size: 12px; color: #A9A3BF">Всё это можно изменить в Настройки → Стабильная работа</span>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1100}}'>
class Component extends DCLogic {
renderVals() {
var T = { 'НУЖНО': ['#6D4AFF', '#FFFFFF'], 'ВАЖНО': ['#4A3416', '#FFD8A8'], 'ПО ЖЕЛАНИЮ': ['#2B2930', '#CAC4D0'] };
var p = function (icon, title, tag, why, done, btn, href) {
return { icon: icon, title: title, tag: tag, tagBg: T[tag][0], tagFg: T[tag][1], why: why, done: !!done, todo: !done, btn: btn || '', href: href || 'D_Permissions.dc.html',
border: done ? '#2E2B35' : (tag === 'ПО ЖЕЛАНИЮ' ? '#2E2B35' : '#4B3D99'),
iconBg: done ? '#12321F' : '#2B2930', iconFg: done ? '#7CE3B0' : '#D0C2FF',
btnBg: tag === 'ПО ЖЕЛАНИЮ' ? '#2B2930' : '#6D4AFF', btnFg: tag === 'ПО ЖЕЛАНИЮ' ? '#D0C2FF' : '#FFFFFF' };
};
return {
items: [
p('M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z', 'VPN-подключение', 'НУЖНО', 'Системное разрешение — без него VPN не включится', true),
p('M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0', 'Уведомления', 'НУЖНО', 'Статус VPN и предупреждения о блокировках', true),
p('M7 4h10v17H7zM10 2h4M10 9h4M10 13h4', 'Без экономии батареи', 'ВАЖНО', 'Иначе Android отключает VPN через 5–30 минут в фоне', false, 'Разрешить', 'D_Battery.dc.html'),
p('M3 20h18M6 16v-5M11 16V7M16 16v-8M21 16v-3', 'Статистика использования', 'ПО ЖЕЛАНИЮ', 'Для «Недавних приложений» и сценариев по приложению', false, 'Разрешить'),
p('M12 21s-7-6.1-7-11a7 7 0 0 1 14 0c0 4.9-7 11-7 11zM12 12.5a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5', 'Геолокация', 'ПО ЖЕЛАНИЮ', 'Только чтобы видеть имя Wi-Fi для сценариев. Место не храним', false, 'Разрешить')
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,139 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Сервер</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1100px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Servers.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<span style="flex: 1"></span>
<a href="D_Share.dc.html" style="height: 40px; padding: 0 14px; border-radius: 20px; background: #3B2C88; color: #D0C2FF; text-decoration: none; display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 800">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="4" width="6" height="6" rx="1"/><rect x="14" y="4" width="6" height="6" rx="1"/><rect x="4" y="14" width="6" height="6" rx="1"/><path d="M14 14h2v2M20 14v6h-6"/></svg>Поделиться
</a>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; align-items: center; gap: 14px; padding: 0 4px 6px">
<span style="width: 56px; height: 56px; border-radius: 28px; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: 800">NL</span>
<span style="display: flex; flex-direction: column; gap: 3px">
<h1 style="margin: 0; font-size: 26px; font-weight: 800; letter-spacing: -0.02em">Амстердам</h1>
<span style="display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 700; color: #7CE3B0"><span style="width: 8px; height: 8px; border-radius: 4px; background: #148A45"></span>Подключён · 38 мс</span>
</span>
</div>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ИСТОЧНИК ПРОФИЛЯ</h2>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<div style="display: flex; align-items: center; gap: 12px; padding: 12px 14px 12px 16px; border-bottom: 1px solid #2B2930">
<span style="flex: none; width: 36px; height: 36px; border-radius: 12px; background: #2B2930; color: #D0C2FF; display: flex; align-items: center; justify-content: center">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{src.icon}}"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 13px; font-weight: 700; color: #A9A3BF">{{src.label}}</span>
<span style="font-size: 14px; font-weight: 700; font-family: {{src.font}}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">{{src.value}}</span>
</span>
<sc-if value="{{src.editable}}" hint-placeholder-val="{{ true }}">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#938F99" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</sc-if>
</div>
<sc-if value="{{src.isLink}}" hint-placeholder-val="{{ true }}">
<div style="display: flex; align-items: center; gap: 10px; padding: 12px 14px 12px 16px; border-bottom: 1px solid #2B2930">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 700">Обновлять автоматически</span>
<span style="font-size: 12px; line-height: 1.35; color: #A9A3BF">Раз в сутки · проверено 2 ч назад · изменений нет</span>
</span>
<button aria-pressed="true" aria-label="Обновлять автоматически" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: #6D4AFF; padding: 4px; display: flex; justify-content: flex-end"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
</sc-if>
<sc-if value="{{src.hasNote}}" hint-placeholder-val="{{ false }}">
<div style="padding: 10px 16px; font-size: 12px; line-height: 1.4; color: #A9A3BF; border-bottom: 1px solid #2B2930">{{src.note}}</div>
</sc-if>
<div style="display: flex; gap: 8px; padding: 12px 14px">
<sc-if value="{{src.hasPrimary}}" hint-placeholder-val="{{ true }}">
<a href="D_ProfileUpdate.dc.html" style="flex: 1; height: 44px; border-radius: 14px; background: #36334A; color: #E0DAF5; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">{{src.primary}}</a>
</sc-if>
<sc-if value="{{src.hasSecondary}}" hint-placeholder-val="{{ false }}">
<a href="D_Import.dc.html" style="flex: 1; height: 44px; border-radius: 14px; border: 1px solid #48454E; color: #E5E1E9; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700; box-sizing: border-box">{{src.secondary}}</a>
</sc-if>
</div>
</section>
<sc-for list="{{groups}}" as="g" hint-placeholder-count="3">
<section style="display: flex; flex-direction: column; gap: 6px">
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">{{g.title}}</h2>
<div style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{g.rows}}" as="r" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 10px; padding: 8px 14px 8px 16px; min-height: 58px; box-sizing: border-box; border-bottom: {{r.divider}}">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 15px; font-weight: 700">{{r.title}}</span>
<sc-if value="{{r.hasSub}}" hint-placeholder-val="{{ false }}"><span style="font-size: 12px; line-height: 1.35; color: #A9A3BF">{{r.sub}}</span></sc-if>
</span>
<sc-if value="{{r.isToggle}}" hint-placeholder-val="{{ false }}">
<button aria-pressed="{{r.on}}" aria-label="{{r.title}}" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: {{r.track}}; padding: 4px; display: flex; justify-content: {{r.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</sc-if>
<sc-if value="{{r.isValue}}" hint-placeholder-val="{{ true }}">
<span style="flex: none; font-size: 14px; font-weight: 600; color: #A9A3BF">{{r.value}}</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#938F99" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</sc-if>
</div>
</sc-for>
</div>
</section>
</sc-for>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; padding-top: 4px">
<a href="D_Share.dc.html" style="height: 52px; border-radius: 18px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font-size: 14px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Экспорт .sswan</a>
<a href="D_ServerDelete.dc.html" style="height: 52px; border-radius: 18px; border: 1px solid #6B2A2A; background: transparent; color: #FFB4AB; font-size: 14px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Удалить</a>
</div>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"source":{"editor":"enum","options":["link","file","qr","manual"],"default":"link"},"$preview":{"width":390,"height":1100}}'>
class Component extends DCLogic {
renderVals() {
var mono = "ui-monospace, 'Cascadia Mono', Menlo, monospace";
var S = {
link: { label: 'Ссылка', value: 'vpn.[ваш-домен]/nl1.sswan', icon: 'M10 14a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1 1M14 10a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1-1', font: mono, editable: true, isLink: true, hasNote: false, note: '', hasPrimary: true, primary: 'Проверить сейчас', hasSecondary: false, secondary: '' },
file: { label: 'Файл', value: 'nl1.sswan · добавлен 12 окт.', icon: 'M6 3h8l4 4v14H6zM14 3v4h4', font: "'Manrope', sans-serif", editable: false, isLink: false, hasNote: true, note: 'Обновлять автоматически нечего: у файла нет ссылки. Новый файл от администратора — «Заменить из файла», настройки ниже сохранятся.', hasPrimary: true, primary: 'Заменить из файла…', hasSecondary: true, secondary: 'Указать ссылку' },
qr: { label: 'QR-код', value: 'отсканирован 12 окт.', icon: 'M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h2v2M20 14v6h-6', font: "'Manrope', sans-serif", editable: false, isLink: false, hasNote: true, note: 'Обновить можно, отсканировав новый QR — настройки ниже сохранятся.', hasPrimary: true, primary: 'Заменить по QR…', hasSecondary: false, secondary: '' },
manual: { label: 'Вручную', value: 'создан 12 окт.', icon: 'M4 20h4l10-10-4-4L4 16zM13 7l4 4', font: "'Manrope', sans-serif", editable: false, isLink: false, hasNote: true, note: 'Адрес, вход и сертификат правятся прямо в группе «Сервер» ниже.', hasPrimary: false, primary: '', hasSecondary: false, secondary: '' }
};
var src = S[this.props.source || 'link'] || S.link;
var v = function (title, value, sub) { return { title: title, value: value, sub: sub || '', hasSub: !!sub, isValue: true, isToggle: false }; };
var t = function (title, on, sub) {
return { title: title, sub: sub || '', hasSub: !!sub, isValue: false, isToggle: true,
on: on ? 'true' : 'false', track: on ? '#6D4AFF' : '#48454E', align: on ? 'flex-end' : 'flex-start' };
};
var grp = function (title, rows) {
rows.forEach(function (r, i) { r.divider = i < rows.length - 1 ? '1px solid #2B2930' : '0'; });
return { title: title, rows: rows };
};
return {
src: src,
groups: [
grp('СЕРВЕР', [v('Адрес', 'nl1.[ваш-домен]'), v('Вход', 'Сертификат')]),
grp('УСТОЙЧИВОСТЬ', [
v('Запасные порты', '443, 53', 'По очереди, если основной не отвечает'),
v('Резервный сервер', 'Хельсинки', 'Если не подключился за 15 с'),
t('Мост при белых списках', true, 'Переключаться на «Москва (мост)»')
]),
grp('СЕТЬ', [v('DNS', 'Как в настройках'), v('MTU', 'Авто'), t('Фрагментация IKE', true)])
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,139 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Сервер — из файла</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1100px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Servers.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<span style="flex: 1"></span>
<a href="D_Share.dc.html" style="height: 40px; padding: 0 14px; border-radius: 20px; background: #3B2C88; color: #D0C2FF; text-decoration: none; display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 800">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="4" width="6" height="6" rx="1"/><rect x="14" y="4" width="6" height="6" rx="1"/><rect x="4" y="14" width="6" height="6" rx="1"/><path d="M14 14h2v2M20 14v6h-6"/></svg>Поделиться
</a>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; align-items: center; gap: 14px; padding: 0 4px 6px">
<span style="width: 56px; height: 56px; border-radius: 28px; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: 800">NL</span>
<span style="display: flex; flex-direction: column; gap: 3px">
<h1 style="margin: 0; font-size: 26px; font-weight: 800; letter-spacing: -0.02em">Амстердам</h1>
<span style="display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 700; color: #7CE3B0"><span style="width: 8px; height: 8px; border-radius: 4px; background: #148A45"></span>Подключён · 38 мс</span>
</span>
</div>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ИСТОЧНИК ПРОФИЛЯ</h2>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<div style="display: flex; align-items: center; gap: 12px; padding: 12px 14px 12px 16px; border-bottom: 1px solid #2B2930">
<span style="flex: none; width: 36px; height: 36px; border-radius: 12px; background: #2B2930; color: #D0C2FF; display: flex; align-items: center; justify-content: center">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{src.icon}}"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 13px; font-weight: 700; color: #A9A3BF">{{src.label}}</span>
<span style="font-size: 14px; font-weight: 700; font-family: {{src.font}}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">{{src.value}}</span>
</span>
<sc-if value="{{src.editable}}" hint-placeholder-val="{{ true }}">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#938F99" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</sc-if>
</div>
<sc-if value="{{src.isLink}}" hint-placeholder-val="{{ true }}">
<div style="display: flex; align-items: center; gap: 10px; padding: 12px 14px 12px 16px; border-bottom: 1px solid #2B2930">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 700">Обновлять автоматически</span>
<span style="font-size: 12px; line-height: 1.35; color: #A9A3BF">Раз в сутки · проверено 2 ч назад · изменений нет</span>
</span>
<button aria-pressed="true" aria-label="Обновлять автоматически" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: #6D4AFF; padding: 4px; display: flex; justify-content: flex-end"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
</sc-if>
<sc-if value="{{src.hasNote}}" hint-placeholder-val="{{ false }}">
<div style="padding: 10px 16px; font-size: 12px; line-height: 1.4; color: #A9A3BF; border-bottom: 1px solid #2B2930">{{src.note}}</div>
</sc-if>
<div style="display: flex; gap: 8px; padding: 12px 14px">
<sc-if value="{{src.hasPrimary}}" hint-placeholder-val="{{ true }}">
<a href="D_ProfileUpdate.dc.html" style="flex: 1; height: 44px; border-radius: 14px; background: #36334A; color: #E0DAF5; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">{{src.primary}}</a>
</sc-if>
<sc-if value="{{src.hasSecondary}}" hint-placeholder-val="{{ false }}">
<a href="D_Import.dc.html" style="flex: 1; height: 44px; border-radius: 14px; border: 1px solid #48454E; color: #E5E1E9; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700; box-sizing: border-box">{{src.secondary}}</a>
</sc-if>
</div>
</section>
<sc-for list="{{groups}}" as="g" hint-placeholder-count="3">
<section style="display: flex; flex-direction: column; gap: 6px">
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">{{g.title}}</h2>
<div style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{g.rows}}" as="r" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 10px; padding: 8px 14px 8px 16px; min-height: 58px; box-sizing: border-box; border-bottom: {{r.divider}}">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 15px; font-weight: 700">{{r.title}}</span>
<sc-if value="{{r.hasSub}}" hint-placeholder-val="{{ false }}"><span style="font-size: 12px; line-height: 1.35; color: #A9A3BF">{{r.sub}}</span></sc-if>
</span>
<sc-if value="{{r.isToggle}}" hint-placeholder-val="{{ false }}">
<button aria-pressed="{{r.on}}" aria-label="{{r.title}}" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: {{r.track}}; padding: 4px; display: flex; justify-content: {{r.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</sc-if>
<sc-if value="{{r.isValue}}" hint-placeholder-val="{{ true }}">
<span style="flex: none; font-size: 14px; font-weight: 600; color: #A9A3BF">{{r.value}}</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#938F99" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</sc-if>
</div>
</sc-for>
</div>
</section>
</sc-for>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; padding-top: 4px">
<a href="D_Share.dc.html" style="height: 52px; border-radius: 18px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font-size: 14px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Экспорт .sswan</a>
<a href="D_ServerDelete.dc.html" style="height: 52px; border-radius: 18px; border: 1px solid #6B2A2A; background: transparent; color: #FFB4AB; font-size: 14px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Удалить</a>
</div>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"source":{"editor":"enum","options":["link","file","qr","manual"],"default":"file"},"$preview":{"width":390,"height":1100}}'>
class Component extends DCLogic {
renderVals() {
var mono = "ui-monospace, 'Cascadia Mono', Menlo, monospace";
var S = {
link: { label: 'Ссылка', value: 'vpn.[ваш-домен]/nl1.sswan', icon: 'M10 14a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1 1M14 10a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1-1', font: mono, editable: true, isLink: true, hasNote: false, note: '', hasPrimary: true, primary: 'Проверить сейчас', hasSecondary: false, secondary: '' },
file: { label: 'Файл', value: 'nl1.sswan · добавлен 12 окт.', icon: 'M6 3h8l4 4v14H6zM14 3v4h4', font: "'Manrope', sans-serif", editable: false, isLink: false, hasNote: true, note: 'Обновлять автоматически нечего: у файла нет ссылки. Новый файл от администратора — «Заменить из файла», настройки ниже сохранятся.', hasPrimary: true, primary: 'Заменить из файла…', hasSecondary: true, secondary: 'Указать ссылку' },
qr: { label: 'QR-код', value: 'отсканирован 12 окт.', icon: 'M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h2v2M20 14v6h-6', font: "'Manrope', sans-serif", editable: false, isLink: false, hasNote: true, note: 'Обновить можно, отсканировав новый QR — настройки ниже сохранятся.', hasPrimary: true, primary: 'Заменить по QR…', hasSecondary: false, secondary: '' },
manual: { label: 'Вручную', value: 'создан 12 окт.', icon: 'M4 20h4l10-10-4-4L4 16zM13 7l4 4', font: "'Manrope', sans-serif", editable: false, isLink: false, hasNote: true, note: 'Адрес, вход и сертификат правятся прямо в группе «Сервер» ниже.', hasPrimary: false, primary: '', hasSecondary: false, secondary: '' }
};
var src = S[this.props.source || 'file'] || S.file;
var v = function (title, value, sub) { return { title: title, value: value, sub: sub || '', hasSub: !!sub, isValue: true, isToggle: false }; };
var t = function (title, on, sub) {
return { title: title, sub: sub || '', hasSub: !!sub, isValue: false, isToggle: true,
on: on ? 'true' : 'false', track: on ? '#6D4AFF' : '#48454E', align: on ? 'flex-end' : 'flex-start' };
};
var grp = function (title, rows) {
rows.forEach(function (r, i) { r.divider = i < rows.length - 1 ? '1px solid #2B2930' : '0'; });
return { title: title, rows: rows };
};
return {
src: src,
groups: [
grp('СЕРВЕР', [v('Адрес', 'nl1.[ваш-домен]'), v('Вход', 'Сертификат')]),
grp('УСТОЙЧИВОСТЬ', [
v('Запасные порты', '443, 53', 'По очереди, если основной не отвечает'),
v('Резервный сервер', 'Хельсинки', 'Если не подключился за 15 с'),
t('Мост при белых списках', true, 'Переключаться на «Москва (мост)»')
]),
grp('СЕТЬ', [v('DNS', 'Как в настройках'), v('MTU', 'Авто'), t('Фрагментация IKE', true)])
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,59 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Обновление профиля</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end">
<section role="dialog" aria-label="Обновление профиля" style="border-radius: 32px 32px 0 0; background: #141318; padding: 12px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 36px; height: 4px; border-radius: 2px; background: #48454E"></span>
<div style="display: flex; flex-direction: column; gap: 4px; padding: 4px 4px 0">
<h1 style="margin: 0; font-size: 24px; font-weight: 800; letter-spacing: -0.02em">В профиле есть изменения</h1>
<span style="font-size: 14px; color: #A9A3BF">Амстердам · проверено только что по ссылке</span>
</div>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{diff}}" as="d" hint-placeholder-count="3">
<div style="display: flex; flex-direction: column; gap: 4px; padding: 12px 16px; border-bottom: {{d.divider}}">
<span style="font-size: 13px; font-weight: 700; color: #A9A3BF">{{d.k}}</span>
<span style="display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 700; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace">
<span style="color: #938F99; text-decoration: line-through">{{d.old}}</span>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
<span style="color: #E5E1E9">{{d.new}}</span>
</span>
</div>
</sc-for>
</section>
<div style="display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px; border-radius: 18px; background: #12321F; color: #A8F0C8; font-size: 13px; line-height: 1.45">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#7CE3B0" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex: none; margin-top: 1px"><path d="M5 12l5 5 9-10"/></svg>
<span>Останутся без изменений: запасные порты, резервный сервер, мост, DNS, правила и приложения.</span>
</div>
<div style="display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 10px">
<a href="D_Profile.dc.html" style="height: 56px; border-radius: 18px; border: 1px solid #48454E; color: #E5E1E9; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700; box-sizing: border-box">Позже</a>
<a href="D_Profile.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Применить и переподключить</a>
</div>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var d = [['Адрес сервера', 'nl1.[домен]', 'nl2.[домен]'], ['Сертификат CA', 'до 01.2027', 'до 01.2028'], ['Порт', '4500', '443']];
return { diff: d.map(function (x, i) { return { k: x[0], old: x[1], new: x[2], divider: i < d.length - 1 ? '1px solid #2B2930' : '0' }; }) };
}
}
</script>
</body>
</html>
@@ -0,0 +1,75 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · DNS и реклама</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Settings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">DNS и реклама</h1>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<section style="padding: 18px; border-radius: 24px; background: #12321F; display: flex; flex-direction: column; gap: 4px">
<span style="font-size: 13px; font-weight: 700; color: #7CE3B0">Блокировка включена</span>
<span style="font-size: 30px; font-weight: 800; letter-spacing: -0.02em; color: #A8F0C8">AdGuard DNS</span>
<span style="font-size: 13px; font-weight: 600; color: #7CE3B0">Блокируются: реклама · трекеры · фишинг</span>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">БЛОКИРОВАТЬ</h2>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{toggles}}" as="t" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 12px; padding: 0 14px 0 16px; height: 64px; border-bottom: {{t.divider}}">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 700">{{t.title}}</span>
<span style="font-size: 12px; color: #A9A3BF">{{t.sub}}</span>
</span>
<button aria-pressed="{{t.on}}" aria-label="{{t.title}}" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: {{t.track}}; padding: 4px; display: flex; justify-content: {{t.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
</sc-for>
</section>
<p style="margin: 0 6px; font-size: 12px; line-height: 1.45; color: #A9A3BF">Реклама и трекеры блокируются вместе — через AdGuard DNS; только фишинг — через Cloudflare 1.1.1.2.</p>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">DNS-СЕРВЕР</h2>
<section role="radiogroup" aria-label="DNS-сервер" style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{dns}}" as="d" hint-placeholder-count="4">
<label style="display: flex; align-items: center; gap: 12px; padding: 0 16px; height: 62px; border-bottom: {{d.divider}}; cursor: pointer">
<input type="radio" name="fdns" checked="{{d.checked}}" style="width: 20px; height: 20px; accent-color: #6D4AFF; margin: 0">
<span style="flex: 1; display: flex; flex-direction: column; gap: 1px">
<span style="font-size: 15px; font-weight: 700">{{d.title}}</span>
<span style="font-size: 12px; color: #A9A3BF">{{d.sub}}</span>
</span>
</label>
</sc-for>
</section>
<p style="margin: 0 6px; font-size: 12px; line-height: 1.45; color: #A9A3BF">Запросы к этому DNS идут через туннель — провайдер не сможет подменить ответ. Приложения, которые идут мимо VPN, используют DNS сети.</p>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var t = [['Рекламу', 'Баннеры в браузере и приложениях', true], ['Трекеры', 'Аналитика и сбор данных', true], ['Фишинг', 'Поддельные сайты банков и сервисов', true]];
var d = [['Из профиля сервера', 'Как настроил администратор', false], ['Cloudflare', '1.1.1.1 · через туннель', false], ['AdGuard DNS', 'Со встроенной фильтрацией', true], ['Свой адрес', 'IPv4 или IPv6 через запятую', false]];
return {
toggles: t.map(function (x, i) { return { title: x[0], sub: x[1], on: x[2] ? 'true' : 'false', track: x[2] ? '#6D4AFF' : '#48454E', align: x[2] ? 'flex-end' : 'flex-start', divider: i < t.length - 1 ? '1px solid #2B2930' : '0' }; }),
dns: d.map(function (x, i) { return { title: x[0], sub: x[1], checked: x[2], divider: i < d.length - 1 ? '1px solid #2B2930' : '0' }; })
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,47 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Плитка в быстрых настройках</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 900px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<div style="padding: 20px 16px 0; display: flex; flex-direction: column; gap: 10px">
<span style="display: flex; justify-content: space-between; font-size: 13px; font-weight: 700; color: #CAC4D0; padding: 0 6px"><span>14:22</span><span>LTE · 78%</span></span>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px"><div style="height: 72px; border-radius: 36px; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; gap: 12px; padding: 0 18px; box-sizing: border-box"><span style="flex: none; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">SHX VPN</span><span style="font-size: 12px; font-weight: 600; color: #E7DFFF; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Амстердам</span></span></div><div style="height: 72px; border-radius: 36px; background: #2B2930; color: #E5E1E9; display: flex; align-items: center; gap: 12px; padding: 0 18px; box-sizing: border-box"><span style="flex: none; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 8.8a15 15 0 0 1 20 0M5 12.9a10 10 0 0 1 14 0M8.5 16.4a5 5 0 0 1 7 0M12 20h.01"/></svg></span><span style="min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Интернет</span><span style="font-size: 12px; font-weight: 600; color: #A9A3BF; white-space: nowrap; overflow: hidden; text-overflow: ellipsis"></span></span></div><div style="height: 72px; border-radius: 36px; background: #2B2930; color: #E5E1E9; display: flex; align-items: center; gap: 12px; padding: 0 18px; box-sizing: border-box"><span style="flex: none; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 7l10 10-5 5V2l5 5L7 17"/></svg></span><span style="min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Bluetooth</span><span style="font-size: 12px; font-weight: 600; color: #A9A3BF; white-space: nowrap; overflow: hidden; text-overflow: ellipsis"></span></span></div><div style="height: 72px; border-radius: 36px; background: #2B2930; color: #E5E1E9; display: flex; align-items: center; gap: 12px; padding: 0 18px; box-sizing: border-box"><span style="flex: none; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 2h8v5l-2 3v12h-4V10L8 7z"/></svg></span><span style="min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Фонарик</span><span style="font-size: 12px; font-weight: 600; color: #A9A3BF; white-space: nowrap; overflow: hidden; text-overflow: ellipsis"></span></span></div></div>
<div style="height: 1px; background: #2E2B35; margin: 8px 0"></div>
<span style="font-size: 15px; font-weight: 800">Состояния плитки SHX VPN</span>
<div style="display: flex; flex-direction: column; gap: 6px"><span style="font-size: 12px; font-weight: 700; color: #A9A3BF">Защищено — тап выключает</span><div style="height: 72px; border-radius: 36px; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; gap: 12px; padding: 0 18px; box-sizing: border-box"><span style="flex: none; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">SHX VPN</span><span style="font-size: 12px; font-weight: 600; color: #E7DFFF; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Амстердам</span></span></div></div><div style="display: flex; flex-direction: column; gap: 6px"><span style="font-size: 12px; font-weight: 700; color: #A9A3BF">Выключен — тап подключает последний сервер</span><div style="height: 72px; border-radius: 36px; background: #2B2930; color: #E5E1E9; display: flex; align-items: center; gap: 12px; padding: 0 18px; box-sizing: border-box"><span style="flex: none; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#CAC4D0"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#2B2930" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">SHX VPN</span><span style="font-size: 12px; font-weight: 600; color: #A9A3BF; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Выключен</span></span></div></div><div style="display: flex; flex-direction: column; gap: 6px"><span style="font-size: 12px; font-weight: 700; color: #A9A3BF">Подключаемся — тап отменяет</span><div style="height: 72px; border-radius: 36px; background: #3B2C88; color: #D0C2FF; display: flex; align-items: center; gap: 12px; padding: 0 18px; box-sizing: border-box"><span style="flex: none; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#6D4AFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#3B2C88" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">SHX VPN</span><span style="font-size: 12px; font-weight: 600; color: #A9A3BF; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Подключаемся…</span></span></div></div><div style="display: flex; flex-direction: column; gap: 6px"><span style="font-size: 12px; font-weight: 700; color: #A9A3BF">Проблема — тап открывает приложение</span><div style="height: 72px; border-radius: 36px; background: #4A3416; color: #F5C892; display: flex; align-items: center; gap: 12px; padding: 0 18px; box-sizing: border-box"><span style="flex: none; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 8v5M12 16.5v.5M10.3 3.9L2.4 18a2 2 0 0 0 1.7 3h15.8a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg></span><span style="min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">SHX VPN</span><span style="font-size: 12px; font-weight: 600; color: #FFD8A8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Сервер не отвечает</span></span></div></div>
<section role="status" style="padding: 16px; border-radius: 24px; background: #2A2343; border: 1px solid #4B3D99; display: flex; flex-direction: column; gap: 10px"><span style="font-size: 15px; font-weight: 800; color: #D0C2FF">Долгое нажатие — экран «Серверы»</span><span style="font-size: 13px; line-height: 1.45; color: #D0C2FF">Если серверов ещё нет, тап открывает «Добавить сервер». Плитку предлагаем добавить после первого подключения.</span></section>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":900}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
return {
tabs: tabs.map(function (t, i) {
var on = i === 0;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
})
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,103 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Недавние приложения</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1160px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Routing.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<span style="flex: 1; display: flex; flex-direction: column">
<h1 style="margin: 0; font-size: 22px; font-weight: 800">Недавние приложения</h1>
<span style="display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: #A9A3BF"><span style="width: 7px; height: 7px; border-radius: 4px; background: #148A45"></span>за последний час · обновляется вживую</span>
</span>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; gap: 8px; flex-wrap: wrap">
<button aria-pressed="true" style="height: 36px; padding: 0 14px; border-radius: 12px; border: 0; background: #3B2C88; color: #FFFFFF; font: 700 13px 'Manrope', sans-serif">Все · 9</button>
<button style="height: 36px; padding: 0 12px; border-radius: 12px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 600 13px 'Manrope', sans-serif">Через VPN</button>
<button style="height: 36px; padding: 0 12px; border-radius: 12px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 600 13px 'Manrope', sans-serif">Напрямую</button>
<button style="height: 36px; padding: 0 12px; border-radius: 12px; border: 0; background: #4A3416; color: #FFD8A8; font: 700 13px 'Manrope', sans-serif">С ошибками · 2</button>
</div>
<section role="status" style="padding: 14px; border-radius: 24px; background: #3A2A12; border: 1px solid #5A4220; display: flex; flex-direction: column; gap: 10px">
<div style="display: flex; align-items: center; gap: 12px">
<span style="flex: none; width: 40px; height: 40px; border-radius: 12px; background: #1F5FBF; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 16px; font-weight: 800">Г</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 800; color: #FFD8A8">Госуслуги не открываются</span>
<span style="font-size: 12px; line-height: 1.35; color: #F5C892">7 неудачных соединений через VPN за 5 мин. Скорее всего, сервис не пускает зарубежные адреса.</span>
</span>
</div>
<div style="display: flex; gap: 8px">
<button style="flex: 1; height: 42px; border: 0; border-radius: 12px; background: #B45309; color: #FFFFFF; font: 800 13px 'Manrope', sans-serif">Пустить напрямую</button>
<a href="D_Check.dc.html" style="flex: none; height: 42px; padding: 0 14px; border-radius: 12px; border: 1px solid #7A5A30; color: #FFD8A8; text-decoration: none; display: flex; align-items: center; font-size: 13px; font-weight: 700">Подробнее</a>
</div>
</section>
<sc-for list="{{groups}}" as="g" hint-placeholder-count="2">
<section style="display: flex; flex-direction: column; gap: 6px">
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">{{g.title}}</h2>
<div style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{g.apps}}" as="a" hint-placeholder-count="4">
<div style="display: flex; align-items: center; gap: 12px; padding: 0 14px; height: 70px; border-bottom: {{a.divider}}">
<span style="flex: none; width: 40px; height: 40px; border-radius: 12px; background: {{a.color}}; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 16px; font-weight: 800">{{a.letter}}</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 4px; min-width: 0">
<span style="display: flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 700">{{a.name}}<sc-if value="{{a.isNew}}" hint-placeholder-val="{{ false }}"><span style="padding: 1px 6px; border-radius: 6px; background: #6D4AFF; color: #FFFFFF; font-size: 10px; font-weight: 800">НОВОЕ</span></sc-if></span>
<span style="display: flex; align-items: center; gap: 6px; font-size: 12px; color: #A9A3BF"><span style="padding: 1px 7px; border-radius: 999px; background: {{a.routeBg}}; color: {{a.routeFg}}; font-weight: 800">{{a.route}}</span>{{a.meta}}</span>
</span>
<button aria-pressed="{{a.on}}" aria-label="{{a.name}}: напрямую" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: {{a.track}}; padding: 4px; display: flex; justify-content: {{a.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
</sc-for>
</div>
</section>
</sc-for>
<p style="margin: 0 6px; font-size: 12px; line-height: 1.45; color: #A9A3BF">Переключатель — «напрямую, без VPN». Трафик приложений считается по системной статистике: нужен доступ «Статистика использования».</p>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1160}}'>
class Component extends DCLogic {
renderVals() {
var a = function (name, letter, color, direct, meta, isNew) {
return { name: name, letter: letter, color: color, meta: meta, isNew: !!isNew,
route: direct ? 'напрямую' : 'VPN', routeBg: direct ? '#12321F' : '#3B2C88', routeFg: direct ? '#7CE3B0' : '#D0C2FF',
on: direct ? 'true' : 'false', track: direct ? '#6D4AFF' : '#48454E', align: direct ? 'flex-end' : 'flex-start' };
};
var grp = function (title, apps) {
apps.forEach(function (x, i) { x.divider = i < apps.length - 1 ? '1px solid #2B2930' : '0'; });
return { title: title, apps: apps };
};
return {
groups: [
grp('СЕЙЧАС АКТИВНЫ', [
a('YouTube', 'Y', '#C62828', false, '312 МБ · сейчас'),
a('Telegram', 'T', '#1E88C8', false, '18 МБ · сейчас'),
a('СберБанк', 'С', '#21A038', true, '2 МБ · 1 мин назад')
]),
grp('НЕДАВНО', [
a('ВкусВилл', 'В', '#2E7D32', false, '4 МБ · 12 мин · установлено сегодня', true),
a('Wildberries', 'W', '#7B2CBF', true, '36 МБ · 20 мин'),
a('Chrome', 'C', '#2E7D32', false, '88 МБ · 34 мин'),
a('Яндекс Карты', 'Я', '#D84315', true, '9 МБ · 51 мин')
])
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,48 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Недавние приложения — нет доступа</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Routing.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Недавние приложения</h1>
</header>
<div style="flex: 1; padding: 0 24px 28px; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 16px">
<div aria-hidden="true" style="margin-top: 48px; display: grid; grid-template-columns: repeat(3, 56px); gap: 10px; opacity: 0.9">
<sc-for list="{{ghost}}" as="g" hint-placeholder-count="6">
<span style="width: 56px; height: 56px; border-radius: 18px; background: {{g}}"></span>
</sc-for>
</div>
<h2 style="margin: 16px 0 0; font-size: 22px; font-weight: 800; letter-spacing: -0.02em">Покажем, какие приложения выходят в сеть</h2>
<p style="margin: 0; font-size: 15px; line-height: 1.5; color: #CAC4D0">И каким путём — через VPN или напрямую. Так проще найти приложение, которое не работает. Для этого нужен доступ «Статистика использования».</p>
<div style="width: 100%; padding: 12px 14px; border-radius: 18px; background: #2A2343; font-size: 13px; line-height: 1.45; color: #E0DAF5; text-align: left">Мы видим только объём трафика по приложениям. Содержимое и сайты остаются на телефоне.</div>
<div style="flex: 1"></div>
<a href="D_Permissions.dc.html" style="width: 100%; height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 16px; font-weight: 800">Разрешить доступ</a>
<a href="D_Routing.dc.html" style="font-size: 14px; font-weight: 700; text-decoration: none">Не сейчас</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return { ghost: ['#3B2C88', '#2B2930', '#12321F', '#2B2930', '#3B2C88', '#2B2930'] };
}
}
</script>
</body>
</html>
@@ -0,0 +1,140 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Маршруты</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1340px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="padding: 18px 20px 8px">
<h1 style="margin: 0; font-size: 26px; font-weight: 800; letter-spacing: -0.02em">Маршруты</h1>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<section style="border-radius: 26px; background: #3B2C88; color: #EADDFF; padding: 16px; display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; align-items: center; gap: 14px">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 17px; font-weight: 800">Раздельный туннель</span>
<span style="font-size: 13px; color: #D0C2FF">Мимо VPN: сайты РФ · 24 приложения · 2 правила</span>
</span>
<button aria-pressed="true" aria-label="Раздельный туннель" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: #6D4AFF; padding: 4px; display: flex; justify-content: flex-end"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
<div style="display: flex; height: 8px; border-radius: 4px; overflow: hidden; gap: 2px"><span style="width: 72%; background: #6D4AFF; border-radius: 4px"></span><span style="flex: 1; background: #3FBF7F; border-radius: 4px"></span></div>
<div style="display: flex; justify-content: space-between; font-size: 12px; font-weight: 700; color: #D0C2FF"><span>Через VPN 72%</span><span>Напрямую 28%</span></div>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">САЙТЫ И СЕРВИСЫ РФ</h2>
<section style="padding: 16px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; align-items: center; gap: 12px">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Сайты РФ напрямую</span>
<span style="font-size: 12px; color: #A9A3BF">База: 12 480 сетей · сегодня</span>
</span>
<button aria-label="Обновить базу адресов" style="flex: none; width: 40px; height: 40px; border: 0; border-radius: 20px; background: #2B2930; color: #D0C2FF; display: flex; align-items: center; justify-content: center">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 12a8 8 0 1 1-2.3-5.7"/><path d="M20 4v5h-5"/></svg>
</button>
<button aria-pressed="true" aria-label="Сайты РФ напрямую" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: #6D4AFF; padding: 4px; display: flex; justify-content: flex-end"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
<div role="radiogroup" aria-label="Способ" style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px">
<button aria-pressed="true" style="padding: 12px; border-radius: 18px; border: 2px solid #6D4AFF; background: #2A2343; text-align: left; font-family: 'Manrope', sans-serif; color: #E5E1E9; display: flex; flex-direction: column; gap: 4px">
<span style="font-size: 14px; font-weight: 800">Стабильный</span>
<span style="font-size: 12px; line-height: 1.35; color: #CAC4D0">Новые адреса — после переподключения</span>
</button>
<button style="padding: 12px; border-radius: 18px; border: 1px solid #48454E; background: #1F1D24; text-align: left; font-family: 'Manrope', sans-serif; color: #E5E1E9; display: flex; flex-direction: column; gap: 4px">
<span style="display: flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 800; white-space: nowrap">Гибкий<span style="padding: 1px 6px; border-radius: 6px; background: #4A3416; color: #FFD8A8; font-size: 10px; font-weight: 800">БЕТА</span></span>
<span style="font-size: 12px; line-height: 1.35; color: #CAC4D0">На лету, без переподключения</span>
</button>
</div>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ИСКЛЮЧЕНИЯ</h2>
<section style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<a href="D_Apps.dc.html" style="display: flex; align-items: center; gap: 14px; padding: 0 14px 0 16px; height: 76px; border-bottom: 1px solid #2B2930; text-decoration: none; color: #E5E1E9">
<span style="width: 40px; height: 40px; border-radius: 14px; background: #3B2C88; color: #D0C2FF; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="4" y="4" width="6" height="6" rx="2"/><rect x="14" y="4" width="6" height="6" rx="2"/><rect x="4" y="14" width="6" height="6" rx="2"/><rect x="14" y="14" width="6" height="6" rx="2"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Приложения напрямую</span>
<span style="font-size: 13px; color: #A9A3BF">24 работают без VPN</span>
</span>
<span style="display: flex; align-items: center">
<span style="width: 26px; height: 26px; border-radius: 13px; border: 2px solid #1F1D24; background: #21A038; box-sizing: border-box"></span>
<span style="margin-left: -8px; width: 26px; height: 26px; border-radius: 13px; border: 2px solid #1F1D24; background: #1F5FBF; box-sizing: border-box"></span>
<span style="margin-left: -8px; height: 26px; padding: 0 6px; border-radius: 13px; border: 2px solid #1F1D24; background: #36333D; color: #CAC4D0; font-size: 11px; font-weight: 800; display: flex; align-items: center; box-sizing: border-box">+22</span>
</span>
</a>
<a href="D_Rules.dc.html" style="display: flex; align-items: center; gap: 14px; padding: 0 14px 0 16px; height: 76px; text-decoration: none; color: #E5E1E9">
<span style="width: 40px; height: 40px; border-radius: 14px; background: #2B2930; color: #D0C2FF; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M5 7h14M5 12h14M5 17h9"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Правила</span>
<span style="font-size: 13px; color: #A9A3BF">Домены, адреса и шаблоны пакетов</span>
</span>
<span style="font-size: 14px; font-weight: 700; color: #A9A3BF">5</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#A9A3BF" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</a>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ПРОВЕРКА</h2>
<a href="D_Check.dc.html" style="display: flex; align-items: center; gap: 10px; height: 52px; padding: 0 16px; border-radius: 18px; background: #2B2930; color: #A9A3BF; text-decoration: none">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
<span style="flex: 1; font-size: 15px; font-weight: 600">Как ходит сайт, IP или приложение</span>
</a>
<a href="D_Recent.dc.html" style="display: flex; flex-direction: column; gap: 12px; padding: 14px 16px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9">
<span style="display: flex; align-items: center; gap: 8px">
<span style="flex: 1; font-size: 16px; font-weight: 700">Недавние приложения</span>
<span style="padding: 2px 8px; border-radius: 999px; background: #4A3416; color: #FFD8A8; font-size: 11px; font-weight: 800">2 с ошибками</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#A9A3BF" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</span>
<span style="display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px">
<sc-for list="{{recent}}" as="r" hint-placeholder-count="4">
<span style="display: flex; flex-direction: column; align-items: center; gap: 5px">
<span style="position: relative; width: 44px; height: 44px; border-radius: 14px; background: {{r.c}}; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 16px; font-weight: 800">{{r.l}}<span style="position: absolute; right: -3px; bottom: -3px; width: 14px; height: 14px; border-radius: 7px; border: 2px solid #1F1D24; background: {{r.dot}}"></span></span>
<span style="font-size: 11px; font-weight: 600; color: #CAC4D0; max-width: 72px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap">{{r.n}}</span>
</span>
</sc-for>
</span>
</a>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1340}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var r = function (n, l, c, dot) { return { n: n, l: l, c: c, dot: dot }; };
return {
recent: [r('YouTube', 'Y', '#C62828', '#6D4AFF'), r('Госуслуги', 'Г', '#1F5FBF', '#B45309'), r('СберБанк', 'С', '#21A038', '#3FBF7F'), r('ВкусВилл', 'В', '#2E7D32', '#6D4AFF')],
tabs: tabs.map(function (t, i) {
var on = i === 2;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
})
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,65 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Новое правило</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end">
<section role="dialog" aria-label="Новое правило" style="border-radius: 32px 32px 0 0; background: #141318; padding: 12px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 36px; height: 4px; border-radius: 2px; background: #48454E"></span>
<h1 style="margin: 4px 4px 0; font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Новое правило</h1>
<div role="tablist" aria-label="Тип" style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 4px; border-radius: 16px; background: #2B2930">
<button role="tab" aria-selected="true" style="height: 40px; border: 0; border-radius: 12px; background: #1F1D24; color: #E5E1E9; font: 800 14px 'Manrope', sans-serif; box-shadow: 0 1px 3px rgba(28,27,32,0.12)">Сайт</button>
<button role="tab" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #CAC4D0; font: 600 14px 'Manrope', sans-serif">Адрес / сеть</button>
<button role="tab" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #CAC4D0; font: 600 14px 'Manrope', sans-serif">Пакет</button>
</div>
<label style="display: flex; flex-direction: column; gap: 4px; padding: 10px 14px; border-radius: 14px; border: 2px solid #6D4AFF; background: #1F1D24">
<span style="font-size: 12px; font-weight: 700; color: #B69DFF">Домен, например chatgpt.com или *.mos.ru</span>
<input type="text" value="kinopoisk.ru" style="border: 0; background: transparent; padding: 0; font: 600 16px ui-monospace, Menlo, monospace; color: #E5E1E9; outline: none; min-width: 0; width: 100%">
</label>
<label style="display: flex; align-items: center; gap: 10px; padding: 0 4px; font-size: 14px; font-weight: 600; color: #E0DAF5">
<input type="checkbox" checked style="width: 20px; height: 20px; accent-color: #6D4AFF; margin: 0">Вместе с поддоменами
</label>
<span style="padding: 0 4px; font-size: 13px; font-weight: 700; color: #CAC4D0">Куда направлять</span>
<div role="radiogroup" aria-label="Куда" style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px">
<button aria-pressed="true" style="padding: 14px; border-radius: 18px; border: 2px solid #148A45; background: #12321F; text-align: left; font-family: 'Manrope', sans-serif; color: #A8F0C8; display: flex; flex-direction: column; gap: 4px">
<span style="font-size: 15px; font-weight: 800">Напрямую</span>
<span style="font-size: 12px; line-height: 1.35; color: #7CE3B0">Мимо VPN</span>
</button>
<button style="padding: 14px; border-radius: 18px; border: 1px solid #48454E; background: #1F1D24; text-align: left; font-family: 'Manrope', sans-serif; color: #E5E1E9; display: flex; flex-direction: column; gap: 4px">
<span style="font-size: 15px; font-weight: 800">Через VPN</span>
<span style="font-size: 12px; line-height: 1.35; color: #CAC4D0">Даже если сайт в базе РФ</span>
</button>
</div>
<div style="padding: 12px 14px; border-radius: 18px; background: #2A2343; font-size: 13px; line-height: 1.45; color: #E0DAF5">Сейчас kinopoisk.ru и так идёт напрямую — по базе РФ. Правило закрепит это, даже если база изменится.</div>
<div style="display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 10px">
<a href="D_Rules.dc.html" style="height: 56px; border-radius: 18px; border: 1px solid #48454E; color: #E5E1E9; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700; box-sizing: border-box">Отмена</a>
<a href="D_Rules.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Добавить правило</a>
</div>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {};
}
}
</script>
</body>
</html>
@@ -0,0 +1,88 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Правила</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 900px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Routing.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Правила</h1>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 12px">
<p style="margin: 0 4px; font-size: 14px; line-height: 1.45; color: #CAC4D0">Куда идут сайты, адреса и приложения. Правило важнее базы РФ.</p>
<div style="display: flex; gap: 8px">
<button aria-pressed="true" style="height: 36px; padding: 0 14px; border-radius: 12px; border: 0; background: #3B2C88; color: #FFFFFF; font: 700 13px 'Manrope', sans-serif">Все · 6</button>
<button style="height: 36px; padding: 0 14px; border-radius: 12px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 600 13px 'Manrope', sans-serif">Сайты</button>
<button style="height: 36px; padding: 0 14px; border-radius: 12px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 600 13px 'Manrope', sans-serif">Адреса</button>
<button style="height: 36px; padding: 0 14px; border-radius: 12px; border: 1px solid #48454E; background: transparent; color: #E5E1E9; font: 600 13px 'Manrope', sans-serif">Пакеты</button>
</div>
<sc-for list="{{groups}}" as="g" hint-placeholder-count="2">
<section style="display: flex; flex-direction: column; gap: 6px">
<h2 style="margin: 6px 6px 0; display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em"><span style="width: 8px; height: 8px; border-radius: 4px; background: {{g.dot}}"></span>{{g.title}}</h2>
<div style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{g.rows}}" as="r" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 12px; padding: 0 14px; height: 64px; border-bottom: {{r.divider}}">
<span style="flex: none; padding: 3px 7px; border-radius: 8px; background: {{r.tagBg}}; color: {{r.tagFg}}; font-size: 10px; font-weight: 800">{{r.kind}}</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 15px; font-weight: 700; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">{{r.value}}</span>
<span style="font-size: 12px; color: #A9A3BF">{{r.sub}}</span>
</span>
<button aria-pressed="{{r.on}}" aria-label="Включить правило" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: {{r.track}}; padding: 4px; display: flex; justify-content: {{r.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #1F1D24"></span></button>
</div>
</sc-for>
</div>
</section>
</sc-for>
</div>
<a href="D_RuleAdd.dc.html" style="position: absolute; right: 16px; bottom: 24px; height: 60px; padding: 0 22px; border: 0; border-radius: 20px; background: #6D4AFF; color: #FFFFFF; font-size: 16px; font-weight: 800; text-decoration: none; display: flex; align-items: center; gap: 10px; box-shadow: 0 6px 18px rgba(109,74,255,0.35)">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>Правило
</a>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":900}}'>
class Component extends DCLogic {
renderVals() {
var tag = { 'САЙТ': ['#1E2A44', '#A8C7FF'], 'АДРЕС': ['#2B2930', '#CAC4D0'], 'ПАКЕТ': ['#12321F', '#7CE3B0'] };
var grp = function (title, dot, rows) {
return { title: title, dot: dot, rows: rows.map(function (r, i) {
return { kind: r[0], tagBg: tag[r[0]][0], tagFg: tag[r[0]][1], value: r[1], sub: r[2],
on: r[3] ? 'true' : 'false', track: r[3] ? '#6D4AFF' : '#48454E', align: r[3] ? 'flex-end' : 'flex-start',
divider: i < rows.length - 1 ? '1px solid #2B2930' : '0' };
}) };
};
return {
groups: [
grp('ВСЕГДА ЧЕРЕЗ VPN', '#6D4AFF', [
['САЙТ', 'chatgpt.com', 'и поддомены', true],
['АДРЕС', '130.49.213.176', 'один адрес', true],
['АДРЕС', '10.8.0.0/24', 'подсеть', false]
]),
grp('ВСЕГДА НАПРЯМУЮ', '#3FBF7F', [
['ПАКЕТ', 'ru.*', '14 приложений', true],
['ПАКЕТ', '*yandex*', '6 приложений · 1 исключение', true],
['САЙТ', '*.mos.ru', 'и поддомены', true]
])
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,62 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Правила — пусто</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Routing.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Правила</h1>
</header>
<div style="flex: 1; padding: 0 16px 28px; display: flex; flex-direction: column; gap: 14px">
<div style="padding: 28px 20px; border-radius: 28px; background: #1F1D24; border: 1px dashed #4B3D99; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 10px; margin-top: 12px">
<span style="width: 56px; height: 56px; border-radius: 18px; background: #3B2C88; color: #D0C2FF; display: flex; align-items: center; justify-content: center">
<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M5 7h14M5 12h14M5 17h9"/></svg>
</span>
<span style="font-size: 18px; font-weight: 800">Правил пока нет — и это нормально</span>
<span style="font-size: 14px; line-height: 1.5; color: #CAC4D0">Сайты РФ и выбранные приложения уже идут напрямую. Правило нужно, только если какой-то сайт идёт не тем путём.</span>
</div>
<span style="padding: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ЧАСТО ДОБАВЛЯЮТ</span>
<div style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{ideas}}" as="i" hint-placeholder-count="3">
<a href="D_RuleAdd.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 0 14px 0 16px; height: 64px; border-bottom: {{i.divider}}; text-decoration: none; color: #E5E1E9">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 700; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace">{{i.v}}</span>
<span style="font-size: 12px; color: #A9A3BF">{{i.d}}</span>
</span>
<span style="padding: 4px 10px; border-radius: 999px; background: {{i.bg}}; color: {{i.fg}}; font-size: 12px; font-weight: 800">{{i.to}}</span>
</a>
</sc-for>
</div>
<div style="flex: 1"></div>
<a href="D_RuleAdd.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 16px; font-weight: 800">+ Своё правило</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var V = ['#3B2C88', '#D0C2FF', 'через VPN'], D = ['#12321F', '#7CE3B0', 'напрямую'];
var I = [['chatgpt.com', 'не пускает с российских адресов', V], ['*.mos.ru', 'работает только из России', D], ['ru.*', 'все пакеты, начинающиеся с ru.', D]];
return { ideas: I.map(function (x, i) { return { v: x[0], d: x[1], bg: x[2][0], fg: x[2][1], to: x[2][2], divider: i < I.length - 1 ? '1px solid #2B2930' : '0' }; }) };
}
}
</script>
</body>
</html>
@@ -0,0 +1,79 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Новый сценарий</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end">
<section role="dialog" aria-label="Новый сценарий" style="border-radius: 32px 32px 0 0; background: #141318; padding: 12px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 36px; height: 4px; border-radius: 2px; background: #48454E"></span>
<h1 style="margin: 4px 4px 0; font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Новый сценарий</h1>
<span style="padding: 0 4px; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">1 · КОГДА</span>
<div role="radiogroup" aria-label="Когда" style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px">
<sc-for list="{{whens}}" as="w" hint-placeholder-count="6">
<button aria-pressed="{{w.on}}" style="height: 76px; border-radius: 18px; border: {{w.border}}; background: {{w.bg}}; color: {{w.fg}}; font-family: 'Manrope', sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; padding: 0 4px">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{w.icon}}"/></svg>
<span style="font-size: 12px; font-weight: 700; text-align: center; line-height: 1.2">{{w.t}}</span>
</button>
</sc-for>
</div>
<div style="display: flex; gap: 8px; flex-wrap: wrap; padding: 2px 2px 0">
<span style="display: flex; align-items: center; gap: 8px; height: 36px; padding: 0 12px 0 6px; border-radius: 18px; background: #3B2C88; color: #EADDFF; font-size: 13px; font-weight: 700"><span style="width: 24px; height: 24px; border-radius: 8px; background: #1E88C8; color: #FFFFFF; font-size: 11px; font-weight: 800; display: flex; align-items: center; justify-content: center">T</span>Telegram</span>
<span style="display: flex; align-items: center; gap: 8px; height: 36px; padding: 0 12px 0 6px; border-radius: 18px; background: #3B2C88; color: #EADDFF; font-size: 13px; font-weight: 700"><span style="width: 24px; height: 24px; border-radius: 8px; background: #C62828; color: #FFFFFF; font-size: 11px; font-weight: 800; display: flex; align-items: center; justify-content: center">Y</span>YouTube</span>
<a href="D_AppPicker.dc.html" style="height: 36px; padding: 0 12px; border-radius: 18px; border: 1px dashed #5A5663; background: transparent; color: #B69DFF; font-size: 13px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">+ Выбрать</a>
</div>
<span style="padding: 6px 4px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">2 · ЧТО СДЕЛАТЬ</span>
<div role="radiogroup" aria-label="Что сделать" style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px">
<sc-for list="{{thens}}" as="a" hint-placeholder-count="4">
<button aria-pressed="{{a.on}}" style="height: 52px; border-radius: 16px; border: {{a.border}}; background: {{a.bg}}; color: {{a.fg}}; font: 700 14px 'Manrope', sans-serif">{{a.t}}</button>
</sc-for>
</div>
<div style="display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: 18px; background: #1F1D24; border: 1px solid #2E2B35">
<span style="flex: 1; font-size: 14px; font-weight: 700">Сервер</span>
<span style="font-size: 14px; font-weight: 600; color: #A9A3BF">Автоматически</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#938F99" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</div>
<div style="padding: 12px 14px; border-radius: 18px; background: #2A2343; font-size: 14px; line-height: 1.45; color: #EADDFF"><b>Итог:</b> когда открыт Telegram или YouTube → включить VPN. После закрытия — вернуть как было.</div>
<div style="display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 10px">
<a href="D_Automation.dc.html" style="height: 56px; border-radius: 18px; border: 1px solid #48454E; color: #E5E1E9; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700; box-sizing: border-box">Отмена</a>
<a href="D_Automation.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Сохранить</a>
</div>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var pick = function (t, icon, on) {
return { t: t, icon: icon, on: on ? 'true' : 'false', bg: on ? '#2A2343' : '#1F1D24', fg: on ? '#EADDFF' : '#E5E1E9', border: on ? '2px solid #6D4AFF' : '1px solid #2E2B35' };
};
return {
whens: [
pick('Wi-Fi сеть', 'M2 9a15 15 0 0 1 20 0M5 13a10 10 0 0 1 14 0M9 17a4 4 0 0 1 6 0'),
pick('Мобильная сеть', 'M7 3h10v18H7zM11 18h2'),
pick('Открыто приложение', 'M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z', true),
pick('Время', 'M12 7v5l3 2M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18'),
pick('Роуминг', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18'),
pick('Белые списки', 'M12 4l9 16H3zM12 10v4M12 17.5v.5')
],
thens: [pick('Включить VPN', '', true), pick('Выключить VPN', ''), pick('Пауза', ''), pick('Сменить сервер', '')]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,108 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Главная — предложение сценария</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #B69DFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="D_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #141318; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="D_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #2B2930; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Включить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #36333D; color: #CAC4D0; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #2B2930, 0 0 0 28px #211F26; margin: 28px 0 22px; cursor: pointer">
<svg width="68" height="68" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M12 3v9"/><path d="M6.3 6.3a8 8 0 1 0 11.4 0"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em">VPN выключен</span>
<span style="display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; color: #A9A3BF"><span style="width: 8px; height: 8px; border-radius: 4px; background: #79767F"></span>Выключен вручную · Home_5G</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="D_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; text-decoration: none; color: #E5E1E9">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #3B2C88; color: #D0C2FF; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #A9A3BF">последний сервер</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #B69DFF">Сменить</span>
</a>
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px">
<sc-for list="{{actions}}" as="q" hint-placeholder-count="3">
<a href="{{q.href}}" style="height: 72px; border-radius: 20px; background: #2B2930; color: #E0DAF5; text-decoration: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; font-size: 12px; font-weight: 700; text-align: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{q.icon}}"/></svg>{{q.label}}
</a>
</sc-for>
</div>
<section role="status" style="padding: 16px; border-radius: 24px; background: #2A2343; border: 1px solid #4B3D99; display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; gap: 12px; align-items: flex-start">
<span style="flex: none; width: 40px; height: 40px; border-radius: 14px; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 2L4 14h7l-1 8 9-12h-7z"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 3px">
<span style="font-size: 15px; font-weight: 800; color: #EADDFF">Выключать VPN здесь автоматически?</span>
<span style="font-size: 13px; line-height: 1.4; color: #D0C2FF">Вы уже 3-й раз выключаете его в сети Home_5G. Вне этой сети VPN будет включаться сам.</span>
</span>
</div>
<div style="display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 8px">
<a href="D_ScenarioAdd.dc.html" style="height: 44px; border-radius: 14px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">Да, создать сценарий</a>
<a href="D_Home.dc.html" style="height: 44px; border-radius: 14px; border: 1px solid #48454E; color: #E5E1E9; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700; box-sizing: border-box">Не надо</a>
</div>
</section>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
}),
actions: [
{ label: 'Включить', href: 'D_Home.dc.html', icon: 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0' },
{ label: 'Быстрейший', href: 'D_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'D_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,40 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Удалить сервер</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; align-items: center; justify-content: center; padding: 24px">
<section role="alertdialog" aria-label="Удалить сервер" style="width: 100%; border-radius: 28px; background: #141318; padding: 24px; display: flex; flex-direction: column; gap: 14px">
<span style="width: 48px; height: 48px; border-radius: 24px; background: #4A1C1C; color: #FFB4AB; display: flex; align-items: center; justify-content: center">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 7h14M10 7V4h4v3M7 7l1 13h8l1-13"/></svg>
</span>
<h1 style="margin: 0; font-size: 22px; font-weight: 800">Удалить «Амстердам»?</h1>
<p style="margin: 0; font-size: 14px; line-height: 1.5; color: #CAC4D0">Это текущий сервер — VPN отключится.</p>
<p style="margin: 0; font-size: 14px; line-height: 1.5; color: #CAC4D0">Вернуть можно, снова добавив профиль по ссылке, файлу или QR.</p>
<div style="display: flex; justify-content: flex-end; gap: 8px; padding-top: 4px">
<a href="D_Profile.dc.html" style="height: 44px; padding: 0 16px; border-radius: 22px; color: #B69DFF; text-decoration: none; display: flex; align-items: center; font-size: 15px; font-weight: 700">Отмена</a>
<a href="D_Servers.dc.html" style="height: 44px; padding: 0 20px; border-radius: 22px; background: #B3261E; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; font-size: 15px; font-weight: 800">Удалить</a>
</div>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {};
}
}
</script>
</body>
</html>
@@ -0,0 +1,95 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Серверы</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 8px">
<h1 style="margin: 0; font-size: 26px; font-weight: 800; letter-spacing: -0.02em">Серверы</h1>
<a href="D_Import.dc.html" aria-label="Добавить сервер" style="width: 44px; height: 44px; border-radius: 22px; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; justify-content: center">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>
</a>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<button style="display: flex; align-items: center; gap: 14px; padding: 14px 16px; border-radius: 24px; border: 2px solid #6D4AFF; background: #2A2343; text-align: left; font-family: 'Manrope', sans-serif; color: #E5E1E9">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 2L4 14h7l-1 8 9-12h-7z"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 800">Автоматически</span>
<span style="font-size: 13px; color: #D0C2FF; font-weight: 600">Самый быстрый, что подключается</span>
</span>
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg>
</button>
<h2 style="margin: 8px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">МОИ СЕРВЕРЫ · 4</h2>
<div style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{servers}}" as="s" hint-placeholder-count="4">
<div style="display: flex; align-items: center; gap: 12px; padding: 0 8px 0 14px; height: 68px; border-bottom: {{s.divider}}">
<span style="width: 40px; height: 40px; border-radius: 20px; background: {{s.bg}}; color: {{s.fg}}; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 13px">{{s.code}}</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 3px; min-width: 0">
<span style="display: flex; align-items: center; gap: 6px; font-size: 16px; font-weight: 700">{{s.name}}<sc-if value="{{s.hasTag}}" hint-placeholder-val="{{ false }}"><span style="padding: 1px 7px; border-radius: 6px; background: {{s.tagBg}}; color: {{s.tagFg}}; font-size: 10px; font-weight: 800">{{s.tag}}</span></sc-if></span>
<span style="display: flex; align-items: center; gap: 6px; font-size: 12px; color: #A9A3BF"><span style="width: 7px; height: 7px; border-radius: 4px; background: {{s.dot}}"></span>{{s.meta}}</span>
</span>
<a href="D_Profile.dc.html" aria-label="Настройки сервера" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #A9A3BF">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="12" cy="5.5" r="1.8"/><circle cx="12" cy="12" r="1.8"/><circle cx="12" cy="18.5" r="1.8"/></svg>
</a>
</div>
</sc-for>
</div>
<p style="margin: 0 6px; font-size: 12px; line-height: 1.45; color: #A9A3BF">Один сервер — один профиль .sswan. Резерв и мост включаются сами, когда основной недоступен.</p>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var s = function (code, name, meta, dot, active, tag, tagBg, tagFg) {
return { code: code, name: name, meta: meta, dot: dot, bg: active ? '#6D4AFF' : '#2B2930', fg: active ? '#FFFFFF' : '#D0C2FF',
hasTag: !!tag, tag: tag || '', tagBg: tagBg || '', tagFg: tagFg || '' };
};
var list = [
s('NL', 'Амстердам', 'подключён · 38 мс', '#148A45', true),
s('FI', 'Хельсинки', 'доступен · 29 мс', '#148A45', false, 'РЕЗЕРВ', '#3B2C88', '#D0C2FF'),
s('DE', 'Франкфурт', 'доступен · 44 мс', '#148A45', false),
s('RU', 'Москва', 'для белых списков', '#B45309', false, 'МОСТ', '#4A3416', '#FFD8A8')
];
list.forEach(function (x, i) { x.divider = i < list.length - 1 ? '1px solid #2B2930' : '0'; });
return {
servers: list,
tabs: tabs.map(function (t, i) {
var on = i === 1;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
})
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,102 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Настройки</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1200px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden">
<header style="padding: 18px 20px 8px">
<h1 style="margin: 0; font-size: 26px; font-weight: 800; letter-spacing: -0.02em">Настройки</h1>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<label style="display: flex; align-items: center; gap: 10px; height: 48px; padding: 0 16px; border-radius: 24px; background: #2B2930; color: #A9A3BF">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
<input type="text" placeholder="Поиск по настройкам" aria-label="Поиск по настройкам" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 500 15px 'Manrope', sans-serif; color: #E5E1E9; outline: none">
</label>
<sc-for list="{{groups}}" as="g" hint-placeholder-count="3">
<section style="display: flex; flex-direction: column; gap: 6px">
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">{{g.title}}</h2>
<div style="border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; overflow: hidden">
<sc-for list="{{g.rows}}" as="r" hint-placeholder-count="2">
<a href="{{r.href}}" style="display: flex; align-items: center; gap: 12px; padding: 0 14px; height: 62px; border-bottom: {{r.divider}}; text-decoration: none; color: #E5E1E9">
<span style="flex: none; width: 36px; height: 36px; border-radius: 12px; background: #2B2930; color: #D0C2FF; display: flex; align-items: center; justify-content: center"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{r.icon}}"/></svg></span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 1px; min-width: 0">
<span style="font-size: 15px; font-weight: 700">{{r.title}}</span>
<span style="font-size: 12px; color: {{r.subColor}}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">{{r.sub}}</span>
</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#938F99" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</a>
</sc-for>
</div>
</section>
</sc-for>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #2B2930; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1200}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var grp = function (title, rows) {
return { title: title, rows: rows.map(function (r, i) {
return { title: r[0], sub: r[1], href: r[2], icon: r[3], subColor: r[4] ? '#FFB869' : '#A9A3BF', divider: i < rows.length - 1 ? '1px solid #2B2930' : '0' };
}) };
};
return {
tabs: tabs.map(function (t, i) {
var on = i === 3;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
}),
groups: [
grp('АВТОМАТИЗАЦИЯ', [
['Сценарии', '3 активных · сеть, приложения, время', 'D_Automation.dc.html', 'M5 4l14 8-14 8z'],
['Доверенные сети', 'Дом, Офис', 'D_Automation.dc.html', 'M2 9a15 15 0 0 1 20 0M5 13a10 10 0 0 1 14 0M9 17a4 4 0 0 1 6 0'],
['Проверка связи', 'Каждые 30 с · переподключать', 'D_Diag.dc.html', 'M3 12h4l3-8 4 16 3-8h4']
]),
grp('ЗАЩИТА', [
['DNS и реклама', 'Cloudflare DoH · блокировка включена', 'D_Protection.dc.html', 'M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z'],
['Без VPN — без сети', 'Выключено — нажмите, чтобы включить', 'D_KillSwitch.dc.html', 'M6 11V8a6 6 0 0 1 12 0v3M5 11h14v10H5z', true]
]),
grp('ПРИЛОЖЕНИЕ', [
['Стабильная работа', 'Батарея, уведомления, разрешения', 'D_Permissions.dc.html', 'M7 4h10v17H7zM10 2h4M10 9h4M10 13h4'],
['Уведомления', 'Проблемы — важные, подсказки — тихо', 'D_NotifSettings.dc.html', 'M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0'],
['Обновления', 'Версия 2.17.0 · ставятся сами', 'D_Update.dc.html', 'M20 12a8 8 0 1 1-2.3-5.7M20 4v5h-5'],
['Оформление', 'Как в системе', 'D_Appearance.dc.html', 'M12 3a9 9 0 1 0 9 9a7 7 0 0 1-9-9']
]),
grp('ПОДДЕРЖКА', [
['Помощь', 'Частые вопросы, о приложении', 'D_Help.dc.html', 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18'],
['Журнал', 'Для поддержки', 'D_Log.dc.html', 'M6 3h9l4 4v14H6zM9 12h6M9 16h6'],
['Сертификаты', '2 из профилей · 1 скоро истекает', 'D_Certs.dc.html', 'M4 5h16v10H4zM8 19l4-2 4 2v-4H8z']
])
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,85 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Поделиться по QR</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Profile.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Поделиться сервером</h1>
</header>
<div style="flex: 1; padding: 8px 24px 28px; display: flex; flex-direction: column; align-items: center; gap: 20px">
<p style="margin: 0; text-align: center; font-size: 15px; line-height: 1.45; color: #CAC4D0">Пусть друг откроет SHX → «Серверы» → «+» → «Сканировать QR». Интернет не нужен.</p>
<div role="img" aria-label="QR-код профиля Амстердам" style="padding: 22px; border-radius: 32px; background: #1F1D24; border: 1px solid #2E2B35; box-shadow: 0 8px 28px rgba(59,44,136,0.10)">
<div style="position: relative; width: 252px; height: 252px; display: grid; grid-template-columns: repeat(21, minmax(0, 1fr)); gap: 0">
<sc-for list="{{cells}}" as="c" hint-placeholder-count="441">
<span style="aspect-ratio: 1 / 1; background: {{c}}; border-radius: 2px"></span>
</sc-for>
<span style="position: absolute; left: 50%; top: 50%; width: 52px; height: 52px; margin: -26px 0 0 -26px; border-radius: 14px; background: #6D4AFF; border: 4px solid #1F1D24; box-sizing: border-box; display: flex; align-items: center; justify-content: center">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg>
</span>
</div>
</div>
<div style="display: flex; align-items: center; gap: 10px">
<span style="width: 36px; height: 36px; border-radius: 18px; background: #3B2C88; color: #D0C2FF; display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 800">NL</span>
<span style="display: flex; flex-direction: column; gap: 1px">
<span style="font-size: 16px; font-weight: 800">Амстердам</span>
<span style="font-size: 12px; color: #A9A3BF">профиль .sswan · без пароля и ключа</span>
</span>
</div>
<div style="flex: 1"></div>
<div style="width: 100%; padding: 12px 14px; border-radius: 18px; background: #3A2A12; font-size: 13px; line-height: 1.45; color: #F5C892">Если профиль входит по сертификату, другу понадобится свой — в QR его нет.</div>
<div style="width: 100%; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px">
<button style="height: 52px; border: 0; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; font: 800 14px 'Manrope', sans-serif">Отправить файлом</button>
<button style="height: 52px; border: 0; border-radius: 18px; background: #36334A; color: #E0DAF5; font: 700 14px 'Manrope', sans-serif">Скопировать ссылку</button>
</div>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var N = 21, cells = [], seed = 7;
var rnd = function () { seed = (seed * 9301 + 49297) % 233280; return seed / 233280; };
var finder = function (r, c) {
var f = [[0, 0], [0, N - 7], [N - 7, 0]];
for (var i = 0; i < 3; i++) {
var y = r - f[i][0], x = c - f[i][1];
if (y >= 0 && y < 7 && x >= 0 && x < 7) {
return (y === 0 || y === 6 || x === 0 || x === 6 || (y >= 2 && y <= 4 && x >= 2 && x <= 4)) ? 1 : 0;
}
if (y >= -1 && y <= 7 && x >= -1 && x <= 7) return 0;
}
return -1;
};
for (var r = 0; r < N; r++) {
for (var c = 0; c < N; c++) {
var f = finder(r, c);
var on = f === -1 ? rnd() > 0.52 : f === 1;
cells.push(on ? '#E5E1E9' : 'transparent');
}
}
return { cells: cells };
}
}
</script>
</body>
</html>
@@ -0,0 +1,96 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Статистика трафика</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Home.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Статистика</h1>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 14px">
<div role="group" aria-label="Период" style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 4px; border-radius: 16px; background: #2B2930">
<button style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #CAC4D0; font: 600 14px 'Manrope', sans-serif">День</button>
<button aria-pressed="true" style="height: 40px; border: 0; border-radius: 12px; background: #1F1D24; color: #E5E1E9; font: 800 14px 'Manrope', sans-serif; box-shadow: 0 1px 3px rgba(28,27,32,0.12)">Неделя</button>
<button style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #CAC4D0; font: 600 14px 'Manrope', sans-serif">Месяц</button>
</div>
<section style="padding: 18px; border-radius: 22px; background: #1F1D24; border: 1px solid #2E2B35; display: flex; flex-direction: column; gap: 14px">
<div style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 13px; font-weight: 600; color: #A9A3BF">4 – 10 октября</span>
<span style="font-size: 32px; font-weight: 800; letter-spacing: -0.02em">18,4 ГБ</span>
</div>
<div role="img" aria-label="Трафик по дням: через VPN и напрямую" style="display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 10px; align-items: end; height: 170px">
<sc-for list="{{days}}" as="d" hint-placeholder-count="7">
<div style="display: flex; flex-direction: column; align-items: center; gap: 6px">
<div style="width: 100%; display: flex; flex-direction: column; gap: 2px">
<div style="height: {{d.direct}}; border-radius: 6px 6px 2px 2px; background: #48454E"></div>
<div style="height: {{d.vpn}}; border-radius: 2px 2px 6px 6px; background: #6D4AFF"></div>
</div>
<span style="font-size: 12px; font-weight: 600; color: #A9A3BF">{{d.label}}</span>
</div>
</sc-for>
</div>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px">
<div style="padding: 12px; border-radius: 16px; background: #3B2C88; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 12px; font-weight: 700; color: #D0C2FF">Через VPN</span>
<span style="font-size: 20px; font-weight: 800">13,1 ГБ</span>
</div>
<div style="padding: 12px; border-radius: 16px; background: #2B2930; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 12px; font-weight: 700; color: #CAC4D0">Напрямую (РФ)</span>
<span style="font-size: 20px; font-weight: 800">5,3 ГБ</span>
</div>
</div>
</section>
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 0; padding: 0 4px; font-size: 15px; font-weight: 800">Приложения</h2>
<div style="display: flex; flex-direction: column; padding: 4px 14px; border-radius: 22px; background: #1F1D24; border: 1px solid #2E2B35">
<sc-for list="{{apps}}" as="a" hint-placeholder-count="4">
<div style="display: flex; align-items: center; gap: 12px; padding: 10px 0">
<span style="width: 36px; height: 36px; border-radius: 10px; background: {{a.bg}}; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">{{a.letter}}</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 6px">
<span style="display: flex; justify-content: space-between; font-size: 14px; font-weight: 700"><span>{{a.name}}</span><span>{{a.size}}</span></span>
<span style="height: 6px; border-radius: 3px; background: #2B2930; display: flex; overflow: hidden"><span style="height: 6px; border-radius: 3px; background: {{a.bar}}; width: {{a.pct}}"></span></span>
</span>
</div>
</sc-for>
</div>
</section>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var d = [['Пн', 1.6, 0.6], ['Вт', 1.9, 0.9], ['Ср', 1.2, 0.5], ['Чт', 2.4, 0.8], ['Пт', 2.1, 1.1], ['Сб', 2.6, 0.7], ['Вс', 1.3, 0.7]];
var k = 40;
var apps = [
['YouTube', 'Y', '#C62828', '6,2 ГБ', 100, '#6D4AFF'],
['Telegram', 'T', '#1E88C8', '3,4 ГБ', 55, '#6D4AFF'],
['Госуслуги', 'Г', '#1F5FBF', '1,1 ГБ', 18, '#938F99'],
['Chrome', 'C', '#2E7D32', '0,9 ГБ', 15, '#6D4AFF']
];
return {
days: d.map(function (x) { return { label: x[0], vpn: Math.round(x[1] * k) + 'px', direct: Math.round(x[2] * k) + 'px' }; }),
apps: apps.map(function (a) { return { name: a[0], letter: a[1], bg: a[2], size: a[3], pct: a[4] + '%', bar: a[5] }; })
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,66 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Статистика — первый день</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="D_Home.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #E5E1E9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Статистика</h1>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 14px">
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 4px; border-radius: 16px; background: #2B2930">
<button aria-pressed="true" style="height: 40px; border: 0; border-radius: 12px; background: #1F1D24; color: #E5E1E9; font: 800 14px 'Manrope', sans-serif; box-shadow: 0 1px 3px rgba(28,27,32,0.12)">День</button>
<button aria-pressed="false" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #938F99; font: 600 14px 'Manrope', sans-serif">Неделя</button>
<button aria-pressed="false" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #938F99; font: 600 14px 'Manrope', sans-serif">Месяц</button>
</div>
<section style="padding: 18px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; display: flex; flex-direction: column; gap: 14px">
<span style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 13px; font-weight: 600; color: #A9A3BF">Сегодня</span>
<span style="font-size: 32px; font-weight: 800; letter-spacing: -0.02em">86 МБ</span>
</span>
<div aria-hidden="true" style="display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 10px; align-items: end; height: 140px">
<sc-for list="{{bars}}" as="b" hint-placeholder-count="7">
<div style="display: flex; flex-direction: column; align-items: center; gap: 6px">
<div style="width: 100%; height: {{b.h}}; border-radius: 6px; background: {{b.c}}; border: {{b.border}}; box-sizing: border-box"></div>
<span style="font-size: 12px; font-weight: 600; color: #938F99">{{b.d}}</span>
</div>
</sc-for>
</div>
</section>
<div style="display: flex; gap: 12px; align-items: flex-start; padding: 16px; border-radius: 22px; background: #2A2343">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#6D4AFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex: none"><path d="M12 7v5l3 2M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18"/></svg>
<span style="display: flex; flex-direction: column; gap: 4px">
<span style="font-size: 15px; font-weight: 800; color: #EADDFF">История копится с сегодняшнего дня</span>
<span style="font-size: 13px; line-height: 1.45; color: #D0C2FF">Через неделю здесь будет видно, сколько трафика идёт через VPN и сколько напрямую, и какие приложения тратят больше всего.</span>
</span>
</div>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var d = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];
return { bars: d.map(function (x, i) { var today = i === 5; return { d: x, h: today ? '34px' : '100%', c: today ? '#B69DFF' : 'transparent', border: today ? '0' : '1.5px dashed #3A3740' }; }) };
}
}
</script>
</body>
</html>
@@ -0,0 +1,55 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Обновление приложения</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end">
<section role="dialog" aria-label="Доступна новая версия" style="border-radius: 32px 32px 0 0; background: #141318; padding: 12px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 36px; height: 4px; border-radius: 2px; background: #48454E"></span>
<div style="display: flex; align-items: center; gap: 14px; padding: 4px 4px 0">
<span style="flex: none; width: 56px; height: 56px; border-radius: 16px; background: #6D4AFF; display: flex; align-items: center; justify-content: center">
<svg width="38" height="38" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.3" stroke-linecap="round"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<h1 style="margin: 0; font-size: 22px; font-weight: 800; letter-spacing: -0.02em">SHX VPN 2.17.0</h1>
<span style="font-size: 13px; color: #A9A3BF">У вас 2.16.0 · 18,4 МБ · подпись проверена</span>
</span>
</div>
<section style="padding: 16px; border-radius: 24px; background: #1F1D24; border: 1px solid #2E2B35; display: flex; flex-direction: column; gap: 10px">
<span style="font-size: 13px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ЧТО НОВОГО</span>
<sc-for list="{{notes}}" as="n" hint-placeholder-count="4">
<span style="display: flex; gap: 10px; font-size: 14px; line-height: 1.45"><span style="flex: none; width: 6px; height: 6px; margin-top: 8px; border-radius: 3px; background: #6D4AFF"></span>{{n}}</span>
</sc-for>
</section>
<div style="display: flex; flex-direction: column; gap: 8px">
<span style="display: flex; justify-content: space-between; font-size: 13px; font-weight: 700; color: #CAC4D0"><span>Скачивание</span><span>Скачано · 18,4 МБ</span></span>
<span style="height: 8px; border-radius: 4px; background: #2E2B35; display: flex; overflow: hidden"><span style="width: 100%; background: #6D4AFF; border-radius: 4px"></span></span>
</div>
<div style="display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 10px">
<a href="D_Inbox.dc.html" style="height: 56px; border-radius: 18px; border: 1px solid #48454E; color: #E5E1E9; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700; box-sizing: border-box">Позже</a>
<a href="D_UpdateInstall.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Установить</a>
</div>
<span style="text-align: center; font-size: 12px; color: #A9A3BF">Текст «Что нового» берётся из заметок релиза</span>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return { notes: ['Вкладка «Серверы»: выбор и автоматический сервер', 'История трафика за день, неделю, месяц', 'Правила по доменам: «всегда через VPN» и «напрямую»', 'Центр событий и новые уведомления'] };
}
}
</script>
</body>
</html>
@@ -0,0 +1,57 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Установка обновления</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end">
<section role="dialog" aria-label="Разрешить установку обновлений" style="border-radius: 32px 32px 0 0; background: #141318; padding: 12px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 36px; height: 4px; border-radius: 2px; background: #48454E"></span>
<div style="display: flex; flex-direction: column; gap: 6px; padding: 4px 4px 0">
<h1 style="margin: 0; font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Разрешите установку обновлений</h1>
<span style="font-size: 14px; line-height: 1.5; color: #CAC4D0">SHX VPN обновляется сам, без Google Play. Android один раз спросит, можно ли приложению устанавливать обновления.</span>
</div>
<section style="padding: 14px 16px; border-radius: 22px; background: #1F1D24; border: 1px solid #2E2B35; display: flex; flex-direction: column; gap: 10px">
<span style="font-size: 12px; font-weight: 800; color: #B69DFF; letter-spacing: 0.04em">ВЫ УВИДИТЕ ТАКОЙ ЭКРАН</span>
<div style="display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 16px; background: #2B2930">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 14px; font-weight: 700">Разрешить установку из этого источника</span>
<span style="font-size: 12px; color: #A9A3BF">SHX VPN</span>
</span>
<span style="width: 44px; height: 26px; border-radius: 13px; background: #6D4AFF; padding: 3px; box-sizing: border-box; display: flex; justify-content: flex-end"><span style="width: 20px; height: 20px; border-radius: 10px; background: #1F1D24"></span></span>
</div>
<span style="font-size: 13px; line-height: 1.45; color: #CAC4D0">Включите переключатель и нажмите «Назад» — установка продолжится.</span>
</section>
<div style="display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px; border-radius: 18px; background: #12321F; color: #A8F0C8; font-size: 13px; line-height: 1.45">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#7CE3B0" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex: none; margin-top: 1px"><path d="M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z"/></svg>
<span>Безопасно: приложение ставит только файлы с подписью SHX и проверенной контрольной суммой.</span>
</div>
<div style="display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 10px">
<a href="D_Update.dc.html" style="height: 56px; border-radius: 18px; border: 1px solid #48454E; color: #E5E1E9; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700; box-sizing: border-box">Не сейчас</a>
<button style="height: 56px; border: 0; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; font: 800 15px 'Manrope', sans-serif">Открыть разрешение</button>
</div>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {};
}
}
</script>
</body>
</html>
@@ -0,0 +1,50 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Системный запрос VPN</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: rgba(28,27,32,0.55); font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; display: flex; flex-direction: column; justify-content: space-between; padding: 24px 20px 32px">
<section style="padding: 16px; border-radius: 22px; background: #141318; display: flex; gap: 12px; align-items: flex-start">
<span style="flex: none; width: 36px; height: 36px; border-radius: 12px; background: #6D4AFF; display: flex; align-items: center; justify-content: center">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 3px">
<span style="font-size: 15px; font-weight: 800">Сейчас Android спросит разрешение</span>
<span style="font-size: 13px; line-height: 1.45; color: #CAC4D0">Это стандартное окно для любого VPN. Нажмите «ОК» — без этого подключиться нельзя.</span>
</span>
</section>
<section role="dialog" aria-label="Запрос на подключение" style="border-radius: 28px; background: #2B2930; padding: 24px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 40px; height: 40px; border-radius: 20px; background: #36333D; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#CAC4D0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 11V8a6 6 0 0 1 12 0v3M5 11h14v10H5z"/></svg>
</span>
<h1 style="margin: 0; text-align: center; font-size: 22px; font-weight: 500">Запрос на подключение</h1>
<p style="margin: 0; font-size: 14px; line-height: 1.5; color: #CAC4D0">Приложение «SHX VPN» пытается подключиться к сети VPN, что позволит ему отслеживать сетевой трафик. Продолжайте, только если доверяете источнику.</p>
<div style="display: flex; justify-content: flex-end; gap: 8px">
<button style="height: 40px; padding: 0 16px; border: 0; border-radius: 20px; background: transparent; color: #B69DFF; font: 600 14px 'Manrope', sans-serif">Отмена</button>
<a href="D_HomeConnecting.dc.html" style="height: 40px; padding: 0 20px; border-radius: 20px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; font-size: 14px; font-weight: 700">ОК</a>
</div>
</section>
<span style="text-align: center; font-size: 12px; color: #E5E1E9">Окно рисует Android — его текст и вид изменить нельзя</span>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {};
}
}
</script>
</body>
</html>
@@ -0,0 +1,47 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тёмная · Виджеты на рабочем столе</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#B69DFF}a:hover{color:#D0C2FF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #141318; font-family: 'Manrope', system-ui, sans-serif; color: #E5E1E9; overflow: hidden; font-variant-numeric: tabular-nums">
<div style="position: absolute; inset: 0; background: linear-gradient(160deg, #B9A6F2 0%, #D9C9F5 45%, #F4D9C4 100%)"></div>
<div style="position: relative; padding: 48px 16px 0; display: flex; flex-direction: column; gap: 22px">
<div style="display: flex; flex-direction: column; gap: 8px"><span style="font-size: 12px; font-weight: 700; color: #FFFFFF; text-shadow: 0 1px 2px rgba(0,0,0,.35)">4×2 · подробный</span><div style="width: 358px; height: 176px; border-radius: 28px; background: #141318; box-sizing: border-box; padding: 14px; display: flex; flex-direction: column; justify-content: space-between; box-shadow: 0 2px 8px rgba(40,20,90,.12)"><span style="display: flex; align-items: center; gap: 10px"><span style="width: 32px; height: 32px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; color: #E5E1E9; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Защищено · 01:24</span><span style="font-size: 12px; font-weight: 600; color: #A9A3BF; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Амстердам · 1,24 ГБ сегодня</span></span><span style="flex: none; width: 44px; height: 44px; border-radius: 22px; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0"/></svg></span></span><span style="display: flex; height: 6px; border-radius: 3px; overflow: hidden; gap: 2px"><span style="width: 72%; background: #6D4AFF; border-radius: 3px"></span><span style="flex: 1; background: #3FBF7F; border-radius: 3px"></span></span><span style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px"><span style="height: 44px; border-radius: 14px; background: #2B2930; color: #E0DAF5; display: flex; align-items: center; justify-content: center; gap: 6px; font-size: 13px; font-weight: 700"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 5v14M15 5v14"/></svg>Пауза</span><span style="height: 44px; border-radius: 14px; background: #2B2930; color: #E0DAF5; display: flex; align-items: center; justify-content: center; gap: 6px; font-size: 13px; font-weight: 700"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 2L4 14h7l-1 8 9-12h-7z"/></svg>Быстрейший</span><span style="height: 44px; border-radius: 14px; background: #2B2930; color: #E0DAF5; display: flex; align-items: center; justify-content: center; gap: 6px; font-size: 13px; font-weight: 700"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 7h13l-3-3M17 17H4l3 3"/></svg>Сменить</span></span></div></div>
<div style="display: flex; flex-direction: column; gap: 8px"><span style="font-size: 12px; font-weight: 700; color: #FFFFFF; text-shadow: 0 1px 2px rgba(0,0,0,.35)">2×1 · защищено и выключен</span><div style="display: flex; gap: 16px"><div style="width: 171px; height: 80px; border-radius: 28px; background: #141318; box-sizing: border-box; padding: 14px; display: flex; align-items: center; gap: 8px; box-shadow: 0 2px 8px rgba(40,20,90,.12)"><span style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; color: #E5E1E9; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Защищено</span><span style="font-size: 12px; font-weight: 600; color: #A9A3BF; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">NL · 01:24</span></span><span style="flex: none; width: 44px; height: 44px; border-radius: 22px; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0"/></svg></span></div><div style="width: 171px; height: 80px; border-radius: 28px; background: #141318; box-sizing: border-box; padding: 14px; display: flex; align-items: center; gap: 8px; box-shadow: 0 2px 8px rgba(40,20,90,.12)"><span style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; color: #E5E1E9; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Выключен</span><span style="font-size: 12px; font-weight: 600; color: #A9A3BF; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">тап — Амстердам</span></span><span style="flex: none; width: 44px; height: 44px; border-radius: 22px; background: #2B2930; color: #CAC4D0; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0"/></svg></span></div></div></div>
<div style="display: flex; flex-direction: column; gap: 8px"><span style="font-size: 12px; font-weight: 700; color: #FFFFFF; text-shadow: 0 1px 2px rgba(0,0,0,.35)">2×1 · подключаемся и проблема</span><div style="display: flex; gap: 16px"><div style="width: 171px; height: 80px; border-radius: 28px; background: #141318; box-sizing: border-box; padding: 14px; display: flex; align-items: center; gap: 8px; box-shadow: 0 2px 8px rgba(40,20,90,.12)"><span style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; color: #E5E1E9; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Подключаемся</span><span style="font-size: 12px; font-weight: 600; color: #A9A3BF; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Амстердам</span></span><span style="flex: none; width: 44px; height: 44px; border-radius: 22px; background: #3B2C88; color: #B69DFF; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0"/></svg></span></div><div style="width: 171px; height: 80px; border-radius: 28px; background: #3A2A12; box-sizing: border-box; padding: 14px; display: flex; align-items: center; gap: 8px; box-shadow: 0 2px 8px rgba(40,20,90,.12)"><span style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 800; color: #F5C892; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Нет ответа</span><span style="font-size: 12px; font-weight: 600; color: #FFD8A8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Амстердам</span></span><span style="flex: none; width: 44px; height: 44px; border-radius: 16px; background: #4A3416; color: #FFD8A8; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 8v5M12 16.5v.5M10.3 3.9L2.4 18a2 2 0 0 0 1.7 3h15.8a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg></span></div></div></div>
<div style="display: flex; flex-direction: column; gap: 8px"><span style="font-size: 12px; font-weight: 700; color: #FFFFFF; text-shadow: 0 1px 2px rgba(0,0,0,.35)">1×1 · значок со статусом</span><div style="display: flex; gap: 24px"><div style="position: relative; width: 64px; height: 64px; border-radius: 32px; background: #6D4AFF; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 8px rgba(40,20,90,.12)"><svg width="34" height="34" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg><span style="position: absolute; right: 2px; bottom: 2px; width: 16px; height: 16px; border-radius: 8px; background: #148A45; border: 3px solid #141318"></span></div><div style="position: relative; width: 64px; height: 64px; border-radius: 32px; background: #79767F; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 8px rgba(40,20,90,.12)"><svg width="34" height="34" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#938F99" stroke-width="2.4" stroke-linecap="round"/></svg><span style="position: absolute; right: 2px; bottom: 2px; width: 16px; height: 16px; border-radius: 8px; background: #5A5663; border: 3px solid #141318"></span></div><div style="position: relative; width: 64px; height: 64px; border-radius: 32px; background: #B45309; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 8px rgba(40,20,90,.12)"><svg width="34" height="34" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#FFB869" stroke-width="2.4" stroke-linecap="round"/></svg><span style="position: absolute; right: 2px; bottom: 2px; width: 16px; height: 16px; border-radius: 8px; background: #B45309; border: 3px solid #141318"></span></div></div></div>
<section style="padding: 16px 16px 10px; border-radius: 24px; background: #141318; box-shadow: 0 2px 8px rgba(40,20,90,.12)"><span style="font-size: 15px; font-weight: 800">Как работает</span><ul style="margin: 10px 0 0; padding-left: 18px; font-size: 13px; line-height: 1.45; color: #A9A3BF"><li style="margin: 0 0 6px">Тап по кнопке — вкл/выкл, по тексту — открыть приложение.</li><li style="margin: 0 0 6px">Цвета берутся из Material You, как у приложения; в тёмной теме — тёмный фон.</li><li style="margin: 0 0 6px">Состояния те же, что на главной: защищено, выключен, подключаемся, проблема.</li><li style="margin: 0 0 6px">Размеры 1×1, 2×1 и 4×2; растягиваются по сетке лаунчера.</li></ul></section>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'D_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'D_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'D_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'D_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
return {
tabs: tabs.map(function (t, i) {
var on = i === 0;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#E5E1E9' : '#CAC4D0', weight: on ? '800' : '600', pill: on ? '#3B2C88' : 'transparent' };
})
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,91 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Диагностика</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="Main.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Почему не работает?</h1>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 14px">
<section style="padding: 18px; border-radius: 22px; background: #FFF4E0; display: flex; flex-direction: column; gap: 10px">
<div style="display: flex; align-items: center; gap: 10px">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #B45309; color: #FFFFFF; display: flex; align-items: center; justify-content: center">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 4l9 16H3z"/><path d="M12 10v4M12 17.5v.5"/></svg>
</span>
<span style="font-size: 17px; font-weight: 800; color: #5C2A04">Оператор включил белые списки</span>
</div>
<p style="margin: 0; font-size: 14px; line-height: 1.45; color: #5C2A04">Мобильная сеть пропускает только российские сайты. VPN-сервер недоступен, а РФ-сервисы работают напрямую.</p>
<div style="display: flex; flex-direction: column; gap: 8px; padding-top: 4px">
<button style="height: 48px; border: 0; border-radius: 16px; background: #6D4AFF; color: #FFFFFF; font: 700 15px 'Manrope', sans-serif">Подключиться через Wi-Fi</button>
<button style="height: 48px; border-radius: 16px; border: 1px solid #C7A27A; background: transparent; color: #5C2A04; font: 700 15px 'Manrope', sans-serif">Ждать и переподключиться само</button>
</div>
</section>
<section style="border-radius: 22px; background: #FFFFFF; border: 1px solid #EAE6EE; padding: 6px 16px">
<sc-for list="{{steps}}" as="s" hint-placeholder-count="5">
<div style="display: flex; align-items: center; gap: 12px; padding: 11px 0; border-bottom: 1px solid #F0ECF4">
<span style="width: 28px; height: 28px; border-radius: 14px; background: {{s.bg}}; color: {{s.fg}}; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">{{s.mark}}</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 1px">
<span style="font-size: 15px; font-weight: 700">{{s.title}}</span>
<span style="font-size: 12px; color: #5E5A7D">{{s.detail}}</span>
</span>
</div>
</sc-for>
</section>
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 0; padding: 0 4px; font-size: 15px; font-weight: 800">Проверить сайт</h2>
<div style="display: flex; gap: 8px">
<label style="flex: 1; min-width: 0; display: flex; align-items: center; height: 48px; padding: 0 14px; border-radius: 16px; background: #F0ECF4">
<input type="text" value="youtube.com" aria-label="Домен" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 600 15px 'Manrope', sans-serif; color: #1C1B20; outline: none">
</label>
<button style="flex: none; white-space: nowrap; height: 48px; padding: 0 18px; border: 0; border-radius: 16px; background: #E4E0F9; color: #2A2640; font: 700 14px 'Manrope', sans-serif">Проверить</button>
</div>
<div style="display: flex; align-items: center; gap: 8px; font-size: 13px; color: #49454F; padding: 0 4px">
<span style="padding: 4px 10px; border-radius: 999px; background: #E7DFFF; color: #3B2C88; font-weight: 700">через VPN</span>DNS туннеля · 142.250.•••.••
</div>
</section>
<button style="height: 44px; border: 0; background: transparent; color: #6D4AFF; font: 700 14px 'Manrope', sans-serif; display: flex; align-items: center; justify-content: center; gap: 8px">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 4h16v12H8l-4 4z"/></svg>Отправить отчёт с логом
</button>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var ok = { bg: '#C8F2DA', fg: '#0E6B35', mark: '✓' };
var warn = { bg: '#FFE2B8', fg: '#7A3A06', mark: '!' };
var bad = { bg: '#FFDAD8', fg: '#8C1D24', mark: '×' };
var rows = [
[ok, 'Интернет', 'Мобильная сеть · LTE'],
[ok, 'Российские сайты', 'gosuslugi.ru · 21 мс'],
[bad, 'Зарубежные сайты', 'Нет ответа от 3 из 3 проверок'],
[bad, 'VPN-сервер', 'Амстердам · таймаут IKE'],
[warn, 'Режим ожидания', 'Повтор через 2 мин, экономим батарею']
];
return {
steps: rows.map(function (r) { return { bg: r[0].bg, fg: r[0].fg, mark: r[0].mark, title: r[1], detail: r[2] }; })
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,55 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Выбор приложений</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="F_ScenarioAdd.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Приложения</h1>
<span style="font-size: 14px; font-weight: 700; color: #6D4AFF; padding-right: 8px">Выбрано 2</span>
</header>
<div style="flex: 1; padding: 0 16px 24px; display: flex; flex-direction: column; gap: 12px">
<label style="display: flex; align-items: center; gap: 10px; height: 52px; padding: 0 16px; border-radius: 26px; background: #F0ECF4; color: #5E5A7D">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
<input type="text" placeholder="Поиск приложений" aria-label="Поиск приложений" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 500 16px 'Manrope', sans-serif; color: #1C1B20; outline: none">
</label>
<span style="padding: 0 6px; font-size: 13px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.04em">ЧАСТО ОТКРЫВАЕТЕ</span>
<div style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; overflow: hidden">
<sc-for list="{{apps}}" as="a" hint-placeholder-count="7">
<label style="display: flex; align-items: center; gap: 12px; padding: 0 16px; height: 60px; border-bottom: {{a.divider}}; cursor: pointer">
<span style="flex: none; width: 36px; height: 36px; border-radius: 10px; background: {{a.c}}; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">{{a.l}}</span>
<span style="flex: 1; font-size: 15px; font-weight: 700">{{a.n}}</span>
<input type="checkbox" checked="{{a.on}}" aria-label="{{a.n}}" style="width: 22px; height: 22px; accent-color: #6D4AFF; margin: 0">
</label>
</sc-for>
</div>
<div style="flex: 1"></div>
<a href="F_ScenarioAdd.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Готово</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var A = [['Telegram', 'T', '#1E88C8', true], ['YouTube', 'Y', '#C62828', true], ['Chrome', 'C', '#2E7D32'], ['WhatsApp', 'W', '#25A244'], ['Instagram', 'I', '#C13584'], ['Discord', 'D', '#5865F2'], ['Spotify', 'S', '#1DB954']];
return { apps: A.map(function (x, i) { return { n: x[0], l: x[1], c: x[2], on: !!x[3], divider: i < A.length - 1 ? '1px solid #F0ECF4' : '0' }; }) };
}
}
</script>
</body>
</html>
@@ -0,0 +1,66 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Оформление</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="F_Settings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Оформление</h1>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<span style="padding: 0 6px; font-size: 13px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.04em">ТЕМА</span>
<div role="radiogroup" aria-label="Тема" style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px">
<sc-for list="{{themes}}" as="t" hint-placeholder-count="3">
<button aria-pressed="{{t.on}}" style="display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 10px; border-radius: 20px; border: {{t.border}}; background: #FFFFFF; font-family: 'Manrope', sans-serif; color: #1C1B20">
<span style="width: 100%; height: 120px; border-radius: 14px; background: {{t.bg}}; border: 1px solid #E5E1E9; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; box-sizing: border-box">
<span style="width: 34px; height: 34px; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: {{t.accent}}"></span>
<span style="width: 56px; height: 8px; border-radius: 4px; background: {{t.line}}"></span>
<span style="width: 40px; height: 8px; border-radius: 4px; background: {{t.line}}"></span>
</span>
<span style="font-size: 13px; font-weight: 700">{{t.name}}</span>
</button>
</sc-for>
</div>
<section style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; overflow: hidden; margin-top: 4px">
<div style="display: flex; align-items: center; gap: 12px; padding: 12px 14px 12px 16px; border-bottom: 1px solid #F0ECF4">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 700">Цвета обоев (Material You)</span>
<span style="font-size: 12px; color: #5E5A7D">Вместо фиолетового — цвета вашего телефона. Статусы остаются прежними.</span>
</span>
<button aria-pressed="false" aria-label="Цвета обоев" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: #C9C5D0; padding: 4px; display: flex; justify-content: flex-start"><span style="width: 24px; height: 24px; border-radius: 12px; background: #FFFFFF"></span></button>
</div>
<div style="display: flex; align-items: center; gap: 12px; padding: 0 14px 0 16px; height: 60px">
<span style="flex: 1; font-size: 15px; font-weight: 700">Язык</span>
<span style="font-size: 14px; font-weight: 600; color: #5E5A7D">Как в системе</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#79767F" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</div>
</section>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var t = function (name, bg, accent, line, on) { return { name: name, bg: bg, accent: accent, line: line, on: on ? 'true' : 'false', border: on ? '2px solid #6D4AFF' : '1px solid #EDE8F2' }; };
return { themes: [t('Как в системе', 'linear-gradient(90deg, #FCF8FF 50%, #141318 50%)', '#6D4AFF', '#C9C5D0', true), t('Светлая', '#FCF8FF', '#6D4AFF', '#E5E1E9'), t('Тёмная', '#141318', '#9C7CFF', '#36333D')] };
}
}
</script>
</body>
</html>
@@ -0,0 +1,126 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Приложения напрямую</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1380px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="F_Routing.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Приложения напрямую</h1>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 12px">
<p style="margin: 0 4px; font-size: 14px; line-height: 1.45; color: #49454F">Включённые приложения ходят в сеть напрямую, мимо VPN. Банки и сервисы РФ часто не работают через VPN.</p>
<label style="display: flex; align-items: center; gap: 10px; height: 52px; padding: 0 16px; border-radius: 26px; background: #F0ECF4; color: #5E5A7D">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
<input type="text" placeholder="Поиск приложений" aria-label="Поиск приложений" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 500 16px 'Manrope', sans-serif; color: #1C1B20; outline: none">
</label>
<div style="display: flex; gap: 8px">
<button aria-pressed="true" style="height: 36px; padding: 0 12px; border-radius: 10px; border: 0; background: #E4E0F9; color: #2A2640; font: 700 13px 'Manrope', sans-serif; display: flex; align-items: center; gap: 6px">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg>Напрямую · 24
</button>
<button style="height: 36px; padding: 0 12px; border-radius: 10px; border: 1px solid #C9C5D0; background: transparent; color: #1C1B20; font: 600 13px 'Manrope', sans-serif">Через VPN · 87</button>
<button style="height: 36px; padding: 0 12px; border-radius: 10px; border: 1px solid #C9C5D0; background: transparent; color: #1C1B20; font: 600 13px 'Manrope', sans-serif">Все</button>
</div>
<div style="display: flex; flex-direction: column; gap: 8px">
<span style="padding: 0 4px; font-size: 13px; font-weight: 700; color: #49454F">Быстро добавить</span>
<div style="display: flex; flex-wrap: wrap; gap: 8px">
<sc-for list="{{quick}}" as="q" hint-placeholder-count="7">
<button style="height: 34px; padding: 0 12px; border-radius: 10px; border: {{q.border}}; background: {{q.bg}}; color: {{q.fg}}; font: 700 13px 'Manrope', sans-serif">{{q.label}}</button>
</sc-for>
</div>
</div>
<sc-for list="{{groups}}" as="g" hint-placeholder-count="3">
<section style="display: flex; flex-direction: column; gap: 6px">
<h2 style="margin: 4px 6px 0; font-size: 12px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.06em">{{g.title}}</h2>
<div style="border-radius: 22px; background: #FFFFFF; border: 1px solid #EAE6EE; overflow: hidden">
<sc-for list="{{g.apps}}" as="a" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 12px; padding: 10px 14px; min-height: 60px; box-sizing: border-box; border-bottom: 1px solid #F0ECF4">
<span style="width: 36px; height: 36px; border-radius: 10px; background: {{a.color}}; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">{{a.letter}}</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 15px; font-weight: 700">{{a.name}}</span>
<span style="font-size: 12px; color: {{a.reasonColor}}">{{a.reason}}</span>
</span>
<button aria-pressed="{{a.on}}" aria-label="{{a.name}}: напрямую, без VPN" style="width: 52px; height: 32px; border: 0; border-radius: 16px; background: {{a.track}}; padding: 4px; display: flex; justify-content: {{a.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #FFFFFF"></span></button>
</div>
</sc-for>
</div>
</section>
</sc-for>
<label style="display: flex; align-items: center; gap: 12px; padding: 8px 6px; font-size: 14px; font-weight: 600; color: #2A2640">
<input type="checkbox" style="width: 20px; height: 20px; accent-color: #6D4AFF; margin: 0">Показывать системные приложения
</label>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1380}}'>
class Component extends DCLogic {
renderVals() {
var chip = function (label, done) {
return {
label: done ? '✓ ' + label : label,
bg: done ? '#E7DFFF' : '#FFFFFF',
fg: done ? '#3B2C88' : '#1C1B20',
border: done ? '0' : '1px solid #C9C5D0'
};
};
var app = function (name, letter, color, kind, tpl) {
var reasons = {
added: ['Напрямую · добавлено вами', '#0E6B35'],
tpl: ['Напрямую · по шаблону «' + tpl + '»', '#0E6B35'],
vpn: ['Через VPN', '#5E5A7D'],
over: ['Исключение: через VPN (шаблон «' + tpl + '» не действует)', '#7A3A06']
};
var on = kind === 'added' || kind === 'tpl';
return {
name: name, letter: letter, color: color,
reason: reasons[kind][0], reasonColor: reasons[kind][1],
on: on ? 'true' : 'false', track: on ? '#6D4AFF' : '#C9C5D0', align: on ? 'flex-end' : 'flex-start'
};
};
return {
quick: [chip('Банки', true), chip('Госуслуги', true), chip('Маркетплейсы', true), chip('Связь', false), chip('Транспорт', false), chip('Сервисы', false), chip('Все приложения РФ', false)],
groups: [
{ title: 'БАНКИ', apps: [
app('СберБанк Онлайн', 'С', '#21A038', 'tpl', 'ru.*'),
app('Т-Банк', 'Т', '#3A3A3A', 'added'),
app('Альфа-Банк', 'А', '#C62828', 'tpl', 'ru.*')
] },
{ title: 'ГОСУСЛУГИ И СЕРВИСЫ', apps: [
app('Госуслуги', 'Г', '#1F5FBF', 'tpl', 'ru.*'),
app('Яндекс Карты', 'Я', '#D84315', 'tpl', '*yandex*'),
app('Яндекс Браузер', 'Я', '#5E35B1', 'over', '*yandex*')
] },
{ title: 'МАРКЕТПЛЕЙСЫ', apps: [
app('Wildberries', 'W', '#7B2CBF', 'added'),
app('Ozon', 'O', '#1565C0', 'added')
] },
{ title: 'ДРУГИЕ', apps: [
app('Telegram', 'T', '#1E88C8', 'vpn'),
app('YouTube', 'Y', '#C62828', 'vpn')
] }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,80 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Сценарии</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="F_Settings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Сценарии</h1>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 10px">
<p style="margin: 0 4px 4px; font-size: 14px; line-height: 1.45; color: #49454F">VPN сам включается, выключается или встаёт на паузу. Верхние сценарии важнее нижних.</p>
<sc-for list="{{rules}}" as="r" hint-placeholder-count="4">
<div style="display: flex; align-items: center; gap: 12px; padding: 14px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2">
<span style="flex: none; width: 44px; height: 44px; border-radius: 14px; background: {{r.bg}}; color: {{r.fg}}; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{r.icon}}"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 4px; min-width: 0">
<span style="font-size: 13px; color: #5E5A7D; font-weight: 600">{{r.when}}</span>
<span style="display: flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 800"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6D4AFF" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>{{r.then}}</span>
</span>
<button aria-pressed="{{r.on}}" aria-label="{{r.when}}" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: {{r.track}}; padding: 4px; display: flex; justify-content: {{r.align}}"><span style="width: 24px; height: 24px; border-radius: 12px; background: #FFFFFF"></span></button>
</div>
</sc-for>
<a href="F_Servers.dc.html" style="display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: 18px; background: #FFFFFF; border: 1px solid #EDE8F2; text-decoration: none; color: #1C1B20">
<span style="flex: 1; font-size: 14px; font-weight: 700">Сервер для этих правил</span>
<span style="font-size: 14px; font-weight: 600; color: #5E5A7D">Амстердам</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#5E5A7D" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</a>
<h2 style="margin: 10px 6px 0; font-size: 13px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.04em">ДОВЕРЕННЫЕ СЕТИ</h2>
<div style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; overflow: hidden">
<sc-for list="{{nets}}" as="n" hint-placeholder-count="2">
<div style="display: flex; align-items: center; gap: 12px; padding: 0 16px; height: 56px; border-bottom: 1px solid #F0ECF4">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#3B2C88" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M2 9a15 15 0 0 1 20 0M5 13a10 10 0 0 1 14 0M9 17a4 4 0 0 1 6 0"/></svg>
<span style="flex: 1; font-size: 15px; font-weight: 700">{{n}}</span>
<button aria-label="Удалить сеть" style="width: 40px; height: 40px; border: 0; border-radius: 20px; background: transparent; color: #79767F; font: 700 18px 'Manrope', sans-serif">×</button>
</div>
</sc-for>
<button style="width: 100%; height: 56px; border: 0; background: transparent; color: #6D4AFF; font: 700 15px 'Manrope', sans-serif">+ Добавить текущую сеть</button>
</div>
</div>
<a href="F_ScenarioAdd.dc.html" style="position: absolute; right: 16px; bottom: 24px; height: 60px; padding: 0 22px; border-radius: 20px; background: #6D4AFF; color: #FFFFFF; font-size: 16px; font-weight: 800; text-decoration: none; display: flex; align-items: center; box-shadow: 0 6px 18px rgba(109,74,255,0.35)">+ Сценарий</a>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var r = function (icon, bg, fg, when, then, on) {
return { icon: icon, bg: bg, fg: fg, when: when, then: then, on: on ? 'true' : 'false', track: on ? '#6D4AFF' : '#C9C5D0', align: on ? 'flex-end' : 'flex-start' };
};
return {
rules: [
r('M2 9a15 15 0 0 1 20 0M5 13a10 10 0 0 1 14 0M9 17a4 4 0 0 1 6 0', '#E7DFFF', '#3B2C88', 'В доверенной Wi-Fi сети', 'Выключить VPN', true),
r('M7 3h10v18H7zM11 18h2', '#E7DFFF', '#3B2C88', 'Мобильная сеть или чужой Wi-Fi', 'Включить VPN', true),
r('M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z', '#FFE2B8', '#7A3A06', 'Открыт Telegram или YouTube', 'Включить VPN', true),
r('M12 7v5l3 2M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18', '#F0ECF4', '#49454F', 'Каждую ночь 01:00–07:00', 'Пауза', false)
],
nets: ['Home_5G', 'Office']
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,75 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Экономия батареи</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="F_Permissions.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Без экономии батареи</h1>
</header>
<div style="flex: 1; padding: 0 16px 28px; display: flex; flex-direction: column; gap: 12px">
<p style="margin: 0 4px; font-size: 15px; line-height: 1.5; color: #2A2640">VPN почти не тратит заряд, но Android этого не знает и усыпляет его в фоне. Два шага:</p>
<section style="padding: 16px; border-radius: 24px; background: #FFFFFF; border: 1px solid #CFC3FF; display: flex; flex-direction: column; gap: 10px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 28px; height: 28px; border-radius: 14px; background: #6D4AFF; color: #FFFFFF; font-size: 13px; font-weight: 800; display: flex; align-items: center; justify-content: center">1</span><span style="font-size: 16px; font-weight: 800">Системное разрешение</span></span>
<span style="font-size: 13px; line-height: 1.45; color: #49454F">Появится окно «Разрешить работу в фоне?» — нажмите «Разрешить».</span>
<button style="height: 48px; border: 0; border-radius: 14px; background: #6D4AFF; color: #FFFFFF; font: 800 14px 'Manrope', sans-serif">Разрешить</button>
</section>
<section style="padding: 16px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; display: flex; flex-direction: column; gap: 12px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 28px; height: 28px; border-radius: 14px; background: #6D4AFF; color: #FFFFFF; font-size: 13px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span><span style="font-size: 16px; font-weight: 800">Настройка телефона</span></span>
<div style="display: flex; gap: 6px; flex-wrap: wrap">
<sc-for list="{{brands}}" as="b" hint-placeholder-count="5">
<button aria-pressed="{{b.on}}" style="height: 32px; padding: 0 12px; border-radius: 10px; border: {{b.border}}; background: {{b.bg}}; color: {{b.fg}}; font: 700 12px 'Manrope', sans-serif">{{b.name}}</button>
</sc-for>
</div>
<span style="font-size: 12px; font-weight: 700; color: #6D4AFF">Определили: Xiaomi · HyperOS</span>
<ol style="margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px">
<sc-for list="{{steps}}" as="s" hint-placeholder-count="3">
<li style="display: flex; gap: 10px; font-size: 14px; line-height: 1.45"><span style="flex: none; width: 22px; height: 22px; border-radius: 11px; background: #F0ECF4; color: #3B2C88; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center">{{s.n}}</span><span>{{s.t}}</span></li>
</sc-for>
</ol>
<button style="height: 48px; border-radius: 14px; border: 1px solid #C9C5D0; background: transparent; color: #1C1B20; font: 700 14px 'Manrope', sans-serif">Открыть настройки приложения</button>
</section>
<div style="flex: 1"></div>
<div style="display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: 18px; background: #FFF4E0; color: #6B3A10; font-size: 13px; line-height: 1.45">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#B45309" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex: none"><path d="M12 4l9 16H3zM12 10v4M12 17.5v.5"/></svg>
<span>Шаг 1 ещё не сделан — VPN может отключаться в фоне</span>
</div>
<a href="F_Permissions.dc.html" style="height: 56px; border-radius: 18px; background: #E4E0F9; color: #2A2640; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Проверить снова</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var b = function (name, on) { return { name: name, on: on ? 'true' : 'false', bg: on ? '#3B2C88' : '#FFFFFF', fg: on ? '#FFFFFF' : '#1C1B20', border: on ? '0' : '1px solid #C9C5D0' }; };
return {
brands: [b('Xiaomi', true), b('Samsung'), b('Honor / Huawei'), b('Realme / OPPO'), b('Другой')],
steps: [
{ n: 1, t: 'Откройте настройки приложения кнопкой ниже' },
{ n: 2, t: 'Экономия заряда → «Нет ограничений»' },
{ n: 3, t: 'Включите «Автозапуск»' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,98 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Главная — сертификат истекает</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #6D4AFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="F_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #FCF8FF; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="F_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Отключить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #E7DFFF, 0 0 0 28px #F3EEFF; margin: 28px 0 22px; cursor: pointer">
<svg width="68" height="68" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M12 3v9"/><path d="M6.3 6.3a8 8 0 1 0 11.4 0"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Защищено</span>
<span style="display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; color: #5E5A7D"><span style="width: 8px; height: 8px; border-radius: 4px; background: #148A45"></span>01:24:37 · РФ-сайты напрямую</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="F_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; text-decoration: none; color: #1C1B20">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #E7DFFF; color: #3B2C88; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #5E5A7D">IP 185.•••.•••.12 · 38 мс</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #6D4AFF">Сменить</span>
</a>
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px">
<sc-for list="{{actions}}" as="q" hint-placeholder-count="3">
<a href="{{q.href}}" style="height: 72px; border-radius: 20px; background: #F0ECF4; color: #2A2640; text-decoration: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; font-size: 12px; font-weight: 700; text-align: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{q.icon}}"/></svg>{{q.label}}
</a>
</sc-for>
</div>
<section role="status" style="padding: 16px; border-radius: 24px; background: #FFF4E0; border: 1px solid #F3D3A6; display: flex; flex-direction: column; gap: 10px">
<span style="font-size: 15px; font-weight: 800; color: #5C2A04">Сертификат истекает через 7 дней</span>
<span style="font-size: 13px; line-height: 1.45; color: #6B3A10">«Амстердам» перестанет подключаться 18 октября. Попросите у администратора новый профиль и добавьте его.</span>
<div style="display: flex; gap: 8px"><a href="F_ProfileUpdate.dc.html" style="height: 44px; padding: 0 14px; border-radius: 14px; background: #B45309; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; box-sizing: border-box; flex: 2">Обновить сейчас</a><a href="F_Home.dc.html" style="height: 44px; padding: 0 14px; border-radius: 14px; border: 1px solid #C7A27A; color: #5C2A04; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; box-sizing: border-box; flex: 1">Позже</a></div>
</section>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #F0ECF4; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'F_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'F_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'F_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'F_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#1C1B20' : '#49454F', weight: on ? '800' : '600', pill: on ? '#E7DFFF' : 'transparent' };
}),
actions: [
{ label: 'Пауза 15 мин', href: 'F_Pause.dc.html', icon: 'M9 5v14M15 5v14' },
{ label: 'Быстрейший', href: 'F_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'F_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,68 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Сертификаты</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="F_Settings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Сертификаты</h1>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 12px">
<p style="margin: 0 4px; font-size: 14px; line-height: 1.45; color: #49454F">Нужны, чтобы убедиться, что вы подключаетесь к настоящему серверу. Обычно приходят вместе с профилем — трогать ничего не нужно.</p>
<div role="tablist" aria-label="Источник" style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 4px; border-radius: 16px; background: #F0ECF4">
<button role="tab" aria-selected="true" style="height: 40px; border: 0; border-radius: 12px; background: #FFFFFF; color: #1C1B20; font: 800 13px 'Manrope', sans-serif; box-shadow: 0 1px 3px rgba(28,27,32,0.12)">Из профилей · 2</button>
<button role="tab" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #49454F; font: 600 13px 'Manrope', sans-serif">Добавленные</button>
<button role="tab" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #49454F; font: 600 13px 'Manrope', sans-serif">Системные</button>
</div>
<section style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; overflow: hidden">
<sc-for list="{{certs}}" as="c" hint-placeholder-count="2">
<div style="display: flex; align-items: center; gap: 12px; padding: 12px 14px 12px 16px; border-bottom: {{c.divider}}">
<span style="flex: none; width: 40px; height: 40px; border-radius: 14px; background: {{c.bg}}; color: {{c.fg}}; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5h16v10H4zM8 19l4-2 4 2v-4H8z"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 15px; font-weight: 700">{{c.name}}</span>
<span style="font-size: 12px; color: #5E5A7D">{{c.used}}</span>
<span style="font-size: 12px; font-weight: 700; color: {{c.expColor}}">{{c.exp}}</span>
</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#79767F" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</div>
</sc-for>
</section>
<button style="display: flex; align-items: center; justify-content: center; gap: 8px; height: 52px; border-radius: 18px; border: 1px solid #C9C5D0; background: transparent; color: #1C1B20; font: 700 14px 'Manrope', sans-serif">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>Добавить сертификат (.crt, .pem)
</button>
<p style="margin: 0 6px; font-size: 12px; line-height: 1.45; color: #5E5A7D">Системные — те, которым доверяет Android.</p>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var C = [
['SHX Root CA', 'Амстердам, Хельсинки, Франкфурт', 'действует до 01.2028', '#0E6B35', '#DDF3E6', '#0E6B35'],
['SHX Bridge CA', 'Москва (мост)', 'истекает через 7 дней — 18.10.2026', '#B45309', '#FFE2B8', '#7A3A06']
];
return { certs: C.map(function (x, i) { return { name: x[0], used: 'используют: ' + x[1], exp: x[2], expColor: x[3], bg: x[4], fg: x[5], divider: i < C.length - 1 ? '1px solid #F0ECF4' : '0' }; }) };
}
}
</script>
</body>
</html>
@@ -0,0 +1,123 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Как ходит трафик</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1420px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="F_Routing.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Как ходит трафик</h1>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<div role="tablist" aria-label="Что проверить" style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 4px; border-radius: 16px; background: #F0ECF4">
<button role="tab" aria-selected="true" style="height: 40px; border: 0; border-radius: 12px; background: #FFFFFF; color: #1C1B20; font: 800 14px 'Manrope', sans-serif; box-shadow: 0 1px 3px rgba(28,27,32,0.12)">Сайт</button>
<button role="tab" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #49454F; font: 600 14px 'Manrope', sans-serif">IP / сеть</button>
<button role="tab" style="height: 40px; border: 0; border-radius: 12px; background: transparent; color: #49454F; font: 600 14px 'Manrope', sans-serif">Приложение</button>
</div>
<div style="display: flex; gap: 8px">
<label style="flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; height: 52px; padding: 0 14px; border-radius: 16px; background: #FFFFFF; border: 2px solid #6D4AFF; box-sizing: border-box">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#5E5A7D" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18"/></svg>
<input type="text" value="youtube.com" aria-label="Сайт" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 700 16px 'Manrope', sans-serif; color: #1C1B20; outline: none">
</label>
<button style="flex: none; white-space: nowrap; height: 52px; padding: 0 16px; border: 0; border-radius: 16px; background: #6D4AFF; color: #FFFFFF; font: 700 14px 'Manrope', sans-serif">Проверить</button>
</div>
<div style="display: flex; gap: 6px; flex-wrap: wrap">
<sc-for list="{{recent}}" as="r" hint-placeholder-count="4">
<button style="height: 32px; padding: 0 12px; border-radius: 10px; border: 1px solid #DCD7E3; background: transparent; color: #49454F; font: 600 12px 'Manrope', sans-serif">{{r}}</button>
</sc-for>
</div>
<section style="padding: 16px; border-radius: 24px; background: #E7DFFF; display: flex; flex-direction: column; gap: 14px">
<div style="display: flex; align-items: center; justify-content: space-between">
<span style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 12px; font-weight: 800; color: #3B2C88; letter-spacing: 0.04em">ИТОГ</span>
<span style="font-size: 22px; font-weight: 800; color: #21005D">Через VPN</span>
</span>
<span style="padding: 6px 12px; border-radius: 999px; background: #FFFFFF; color: #3B2C88; font-size: 13px; font-weight: 800">открывается · 41 мс</span>
</div>
<div style="display: flex; align-items: center; gap: 6px">
<span style="flex: none; padding: 8px 10px; border-radius: 12px; background: #FFFFFF; font-size: 12px; font-weight: 800">Телефон</span>
<span style="flex: 1; height: 3px; border-radius: 2px; background: #6D4AFF"></span>
<span style="flex: none; padding: 8px 10px; border-radius: 12px; background: #6D4AFF; color: #FFFFFF; font-size: 12px; font-weight: 800">VPN · NL</span>
<span style="flex: 1; height: 3px; border-radius: 2px; background: #6D4AFF"></span>
<span style="flex: none; padding: 8px 10px; border-radius: 12px; background: #FFFFFF; font-size: 12px; font-weight: 800">youtube.com</span>
</div>
<span style="font-size: 13px; line-height: 1.45; color: #3B2C88">Почему: адресов нет в базе РФ, своих правил для сайта нет — значит, по умолчанию через VPN.</span>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.04em">ПРЯМОЙ ПУТЬ ДЛЯ СРАВНЕНИЯ</h2>
<section style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; padding: 4px 16px">
<sc-for list="{{compare}}" as="c" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 10px; height: 52px; border-bottom: {{c.divider}}">
<span style="flex: 1; font-size: 14px; font-weight: 600">{{c.t}}</span>
<span style="font-size: 13px; font-weight: 800; color: {{c.color}}">{{c.v}}</span>
</div>
</sc-for>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.04em">DNS</h2>
<section style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; padding: 12px 16px; display: flex; flex-direction: column; gap: 10px">
<div style="display: flex; flex-direction: column; gap: 3px">
<span style="font-size: 13px; font-weight: 700; color: #49454F">Через туннель</span>
<span style="font-size: 14px; font-weight: 600; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace">142.250.•••.14 · 142.250.•••.46</span>
</div>
<div style="display: flex; flex-direction: column; gap: 3px">
<span style="font-size: 13px; font-weight: 700; color: #49454F">Через провайдера</span>
<span style="font-size: 14px; font-weight: 600; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace">195.208.•••.3</span>
</div>
<span style="padding: 8px 12px; border-radius: 12px; background: #FFF4E0; color: #6B3A10; font-size: 13px; line-height: 1.4"><b>Ответы различаются.</b> Похоже, провайдер подменяет DNS — поэтому используем DNS туннеля.</span>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.04em">АДРЕСА · 2</h2>
<section style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; overflow: hidden">
<sc-for list="{{ips}}" as="i" hint-placeholder-count="2">
<div style="display: flex; align-items: center; gap: 10px; padding: 10px 14px 10px 16px; border-bottom: {{i.divider}}">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 14px; font-weight: 700; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace">{{i.ip}}</span>
<span style="font-size: 12px; color: #5E5A7D">{{i.why}}</span>
</span>
<span style="flex: none; padding: 4px 10px; border-radius: 999px; background: #E7DFFF; color: #3B2C88; font-size: 12px; font-weight: 800">через VPN</span>
</div>
</sc-for>
</section>
<section style="display: flex; flex-direction: column; gap: 8px; padding-top: 4px">
<span style="padding: 0 6px; font-size: 13px; font-weight: 700; color: #49454F">Изменить для youtube.com</span>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px">
<a href="F_Rules.dc.html" style="height: 52px; border-radius: 16px; background: #DDF3E6; color: #0E6B35; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">Всегда напрямую</a>
<a href="F_Rules.dc.html" style="height: 52px; border-radius: 16px; background: #E4E0F9; color: #2A2640; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">Всегда через VPN</a>
</div>
</section>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1420}}'>
class Component extends DCLogic {
renderVals() {
var cmp = [['Напрямую', 'не открывается', '#B3261E'], ['Через VPN', '41 мс', '#0E6B35'], ['Скорость напрямую', 'замедлено ~90%', '#B45309']];
var ips = [['142.250.•••.14', 'не в базе РФ · по умолчанию'], ['142.250.•••.46', 'не в базе РФ · по умолчанию']];
return {
recent: ['gosuslugi.ru', '95.163.•••.12', 'Telegram', 'chatgpt.com'],
compare: cmp.map(function (c, i) { return { t: c[0], v: c[1], color: c[2], divider: i < cmp.length - 1 ? '1px solid #F0ECF4' : '0' }; }),
ips: ips.map(function (x, i) { return { ip: x[0], why: x[1], divider: i < ips.length - 1 ? '1px solid #F0ECF4' : '0' }; })
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,106 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Диагностика</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1240px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="F_Home.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Диагностика</h1>
<a href="F_Log.dc.html" style="flex: none; height: 40px; padding: 0 14px; border-radius: 20px; background: #F0ECF4; color: #3B2C88; font-size: 13px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Журнал</a>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 14px">
<section style="padding: 16px; border-radius: 24px; background: #C8F2DA; display: flex; gap: 12px; align-items: center">
<span style="flex: none; width: 40px; height: 40px; border-radius: 20px; background: #148A45; color: #FFFFFF; display: flex; align-items: center; justify-content: center">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 17px; font-weight: 800; color: #08381C">VPN работает нормально</span>
<span style="font-size: 13px; color: #0E6B35">Проверено 10 с назад</span>
</span>
</section>
<section style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; padding: 4px 16px">
<sc-for list="{{steps}}" as="s" hint-placeholder-count="5">
<div style="display: flex; align-items: center; gap: 12px; height: 50px; border-bottom: {{s.divider}}">
<span style="width: 22px; height: 22px; border-radius: 11px; background: {{s.bg}}; color: {{s.fg}}; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 800">{{s.mark}}</span>
<span style="flex: 1; font-size: 15px; font-weight: 600">{{s.title}}</span>
<span style="font-size: 13px; color: #5E5A7D">{{s.value}}</span>
</div>
</sc-for>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.04em">ЧТО-ТО НЕ ОТКРЫВАЕТСЯ?</h2>
<section style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; padding: 14px; display: flex; flex-direction: column; gap: 14px">
<div style="display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px">
<sc-for list="{{apps}}" as="a" hint-placeholder-count="5">
<button style="display: flex; flex-direction: column; align-items: center; gap: 5px; border: 0; background: transparent; padding: 0; font-family: 'Manrope', sans-serif; color: #1C1B20">
<span style="width: 48px; height: 48px; border-radius: 15px; background: {{a.c}}; color: #FFFFFF; display: flex; align-items: center; justify-content: center; font-size: 17px; font-weight: 800; box-shadow: {{a.ring}}">{{a.l}}</span>
<span style="font-size: 11px; font-weight: 600; max-width: 62px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap">{{a.n}}</span>
</button>
</sc-for>
</div>
<div style="display: flex; gap: 8px">
<label style="flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; height: 48px; padding: 0 12px; border-radius: 16px; background: #F0ECF4; color: #5E5A7D">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
<input type="text" placeholder="или сайт" aria-label="Сайт" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 600 15px 'Manrope', sans-serif; color: #1C1B20; outline: none">
</label>
<a href="F_Check.dc.html" style="flex: none; white-space: nowrap; height: 48px; padding: 0 16px; border-radius: 16px; background: #6D4AFF; color: #FFFFFF; font-size: 14px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Проверить</a>
</div>
<div role="status" style="padding: 12px; border-radius: 18px; background: #F3EEFF; display: flex; align-items: center; gap: 10px">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 14px; font-weight: 800">СберБанк пущен напрямую</span>
<span style="font-size: 12px; color: #49454F">Банк не пускал через VPN</span>
</span>
<button style="flex: none; height: 36px; padding: 0 12px; border: 0; border-radius: 12px; background: #FFFFFF; color: #3B2C88; font: 700 13px 'Manrope', sans-serif">Отменить</button>
</div>
</section>
<h2 style="margin: 6px 6px 0; display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.04em">НЕДОСТУПНЫЕ ХОСТЫ<span style="padding: 1px 7px; border-radius: 6px; background: #FFE2B8; color: #7A3A06; font-size: 11px; letter-spacing: 0">3</span></h2>
<section style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; overflow: hidden">
<sc-for list="{{hosts}}" as="h" hint-placeholder-count="3">
<div style="display: flex; align-items: center; gap: 10px; padding: 0 12px 0 16px; height: 60px; border-bottom: {{h.divider}}">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0">
<span style="font-size: 14px; font-weight: 700; font-family: ui-monospace, 'Cascadia Mono', Menlo, monospace">{{h.host}}</span>
<span style="font-size: 12px; color: #5E5A7D">{{h.meta}}</span>
</span>
<button style="flex: none; height: 36px; padding: 0 12px; border: 0; border-radius: 12px; background: #FFE2B8; color: #5C2A04; font: 700 13px 'Manrope', sans-serif">Через VPN</button>
</div>
</sc-for>
</section>
<a href="F_Log.dc.html" style="height: 52px; border-radius: 18px; border: 1px solid #C9C5D0; background: transparent; color: #1C1B20; font-size: 15px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Отправить отчёт</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1240}}'>
class Component extends DCLogic {
renderVals() {
var ok = { bg: '#C8F2DA', fg: '#0E6B35', mark: '✓' };
var steps = [['Интернет', 'Wi-Fi'], ['Российские сайты', '21 мс'], ['Зарубежные сайты', 'через VPN'], ['Сервер VPN', '38 мс · порт 4500'], ['DNS', 'туннель']];
var a = function (n, l, c, sel) { return { n: n, l: l, c: c, ring: sel ? '0 0 0 2px #FFFFFF, 0 0 0 4px #6D4AFF' : 'none' }; };
var hs = [['95.163.•••.12:443', 'отказов 14 · пауза 4 мин'], ['178.248.•••.70:443', 'отказов 9 · пауза 2 мин'], ['212.193.•••.5:5222', 'отказов 6 · пауза 40 с']];
return {
steps: steps.map(function (s, i) { return { bg: ok.bg, fg: ok.fg, mark: ok.mark, title: s[0], value: s[1], divider: i < steps.length - 1 ? '1px solid #F0ECF4' : '0' }; }),
apps: [a('СберБанк', 'С', '#21A038', true), a('Госуслуги', 'Г', '#1F5FBF'), a('YouTube', 'Y', '#C62828'), a('Telegram', 'T', '#1E88C8'), a('Ещё', '+', '#79767F')],
hosts: hs.map(function (h, i) { return { host: h[0], meta: h[1], divider: i < hs.length - 1 ? '1px solid #F0ECF4' : '0' }; })
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,93 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Главная — вход отклонён</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #6D4AFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="F_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #FCF8FF; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="F_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Повторить подключение" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #FFDAD8; color: #B3261E; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #FFE9E7, 0 0 0 28px #FFF4F3; margin: 28px 0 22px; cursor: pointer">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 4l9 16H3zM12 10v4M12 17.5v.5"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em; color: #8C1D24">Вход отклонён</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: #8C1D24">Амстердам · ошибка аутентификации</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="F_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; text-decoration: none; color: #1C1B20">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #E7DFFF; color: #3B2C88; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #5E5A7D">IP 185.•••.•••.12 · 38 мс</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #6D4AFF">Сменить</span>
</a>
<section role="status" style="padding: 16px; border-radius: 24px; background: #FFF1F0; border: 1px solid #F5C2BE; display: flex; flex-direction: column; gap: 10px">
<span style="font-size: 15px; font-weight: 800; color: #8C1D24">Сервер не принял сертификат</span>
<span style="font-size: 13px; line-height: 1.45; color: #6B1A1F">Скорее всего, у профиля закончился срок действия или администратор выпустил новый. Обновите профиль или выберите другой сервер.</span>
<div style="display: flex; gap: 8px"><a href="F_ProfileUpdate.dc.html" style="height: 44px; padding: 0 14px; border-radius: 14px; background: #B3261E; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; box-sizing: border-box; flex: 2">Обновить профиль</a><a href="F_Log.dc.html" style="height: 44px; padding: 0 14px; border-radius: 14px; border: 1px solid #E0A8A3; color: #6B1A1F; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; box-sizing: border-box; flex: 1">Журнал</a></div>
</section>
<a href="F_Servers.dc.html" style="height: 52px; border-radius: 18px; background: #F0ECF4; color: #2A2640; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700">Подключиться к другому серверу</a>
<a href="F_Home.dc.html" style="height: 44px; border-radius: 14px; color: #6D4AFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700">Отключить VPN</a>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #F0ECF4; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'F_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'F_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'F_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'F_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#1C1B20' : '#49454F', weight: on ? '800' : '600', pill: on ? '#E7DFFF' : 'transparent' };
}),
actions: [
{ label: 'Пауза 15 мин', href: 'F_Pause.dc.html', icon: 'M9 5v14M15 5v14' },
{ label: 'Быстрейший', href: 'F_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'F_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,61 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Профиль не добавлен</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end">
<section role="alertdialog" aria-label="Профиль не добавлен" style="border-radius: 32px 32px 0 0; background: #FCF8FF; padding: 12px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 36px; height: 4px; border-radius: 2px; background: #C9C5D0"></span>
<div style="display: flex; align-items: center; gap: 14px; padding: 4px 4px 0">
<span style="flex: none; width: 52px; height: 52px; border-radius: 26px; background: #FFDAD8; color: #B3261E; display: flex; align-items: center; justify-content: center">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 14a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1 1M14 10a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1-1M4 4l16 16"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<h1 style="margin: 0; font-size: 22px; font-weight: 800; letter-spacing: -0.02em">Не удалось скачать профиль</h1>
<span style="font-size: 13px; color: #5E5A7D; font-family: ui-monospace, Menlo, monospace">vpn.[ваш-домен]/nl1.sswan</span>
</span>
</div>
<section style="padding: 14px 16px; border-radius: 22px; background: #FFFFFF; border: 1px solid #EDE8F2; display: flex; flex-direction: column; gap: 8px">
<span style="font-size: 12px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.04em">ВОЗМОЖНЫЕ ПРИЧИНЫ</span>
<sc-for list="{{reasons}}" as="r" hint-placeholder-count="3">
<span style="display: flex; gap: 10px; font-size: 14px; line-height: 1.45"><span style="flex: none; width: 6px; height: 6px; margin-top: 8px; border-radius: 3px; background: #B3261E"></span><span><b>{{r.t}}</b> — <span style="color: #49454F">{{r.d}}</span></span></span>
</sc-for>
</section>
<div style="padding: 12px 14px; border-radius: 18px; background: #F3EEFF; font-size: 13px; line-height: 1.45; color: #2A2640">Попросите у администратора файл .sswan или QR — их можно добавить без интернета.</div>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px">
<a href="F_Import.dc.html" style="height: 52px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">Повторить</a>
<a href="F_ImportQR.dc.html" style="height: 52px; border-radius: 18px; background: #E4E0F9; color: #2A2640; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700">Сканировать QR</a>
</div>
<a href="F_Log.dc.html" style="align-self: center; font-size: 13px; font-weight: 700; text-decoration: none">Подробности для поддержки</a>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {
reasons: [
{ t: 'Сайт заблокирован', d: 'ссылка не открывается без VPN' },
{ t: 'Нет интернета', d: 'проверьте мобильную сеть или Wi-Fi' },
{ t: 'Ошибка сертификата сайта', d: 'HTTPS-соединение не прошло проверку' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,92 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Помощь</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1240px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="F_Settings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Помощь</h1>
</header>
<div style="padding: 0 16px; display: flex; flex-direction: column; gap: 12px">
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px">
<a href="F_Diag.dc.html" style="height: 84px; padding: 14px; box-sizing: border-box; border-radius: 22px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; flex-direction: column; justify-content: space-between">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
<span style="font-size: 14px; font-weight: 800">Проверить подключение</span>
</a>
<a href="F_Log.dc.html" style="height: 84px; padding: 14px; box-sizing: border-box; border-radius: 22px; background: #E7DFFF; color: #21005D; text-decoration: none; display: flex; flex-direction: column; justify-content: space-between">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 4h16v12H8l-4 4z"/></svg>
<span style="font-size: 14px; font-weight: 800">Написать в поддержку</span>
</a>
</div>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.04em">ЧАСТЫЕ ВОПРОСЫ</h2>
<section style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; overflow: hidden">
<sc-for list="{{faq}}" as="q" hint-placeholder-count="6">
<div style="border-bottom: {{q.divider}}">
<button aria-expanded="{{q.openStr}}" style="width: 100%; display: flex; align-items: center; gap: 10px; padding: 0 16px; min-height: 58px; border: 0; background: transparent; text-align: left; font: 700 15px 'Manrope', sans-serif; color: #1C1B20">
<span style="flex: 1">{{q.q}}</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#79767F" stroke-width="2.4" stroke-linecap="round" aria-hidden="true" style="transform: {{q.rot}}"><path d="M6 9l6 6 6-6"/></svg>
</button>
<sc-if value="{{q.open}}" hint-placeholder-val="{{ false }}">
<p style="margin: 0; padding: 0 16px 16px; font-size: 14px; line-height: 1.5; color: #49454F">{{q.a}}</p>
</sc-if>
</div>
</sc-for>
</section>
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.04em">О ПРИЛОЖЕНИИ</h2>
<section style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; overflow: hidden">
<div style="display: flex; align-items: center; gap: 14px; padding: 16px">
<span style="flex: none; width: 52px; height: 52px; border-radius: 15px; background: #6D4AFF; display: flex; align-items: center; justify-content: center">
<svg width="36" height="36" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.3" stroke-linecap="round"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 17px; font-weight: 800">SHX VPN 2.17.0</span>
<span style="font-size: 12px; color: #5E5A7D">сборка 172 · на основе strongSwan · GPLv2</span>
</span>
</div>
<sc-for list="{{links}}" as="l" hint-placeholder-count="3">
<a href="{{l.href}}" style="display: flex; align-items: center; gap: 10px; padding: 0 16px; height: 52px; border-top: 1px solid #F0ECF4; text-decoration: none; color: #1C1B20; font-size: 15px; font-weight: 600">
<span style="flex: 1">{{l.t}}</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#79767F" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</a>
</sc-for>
</section>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1240}}'>
class Component extends DCLogic {
renderVals() {
var Q = [
['Банк или Госуслуги не открываются', 'Многие российские сервисы не пускают зарубежные адреса. Откройте «Не открывается?» на главной и выберите приложение — мы пустим его напрямую, мимо VPN.', true],
['Где взять профиль .sswan?', 'Его выдаёт администратор вашего VPN: файлом, ссылкой или QR-кодом. Можно отсканировать QR с экрана друга.'],
['Что такое мост?', 'Сервер с российским адресом. Когда оператор включает белые списки, обычные серверы недоступны, а мост — работает. Включите «Мост при белых списках» на странице сервера.'],
['VPN сам отключается', 'Скорее всего, Android экономит батарею. Откройте Настройки → Стабильная работа и снимите ограничения.'],
['Стабильный или Гибкий режим?', 'Стабильный надёжнее: новые адреса применяются после переподключения. Гибкий обновляет маршруты на лету, но пока в бете.'],
['Видит ли SHX мои сайты?', 'Нет. С доступом к статистике приложение считает только объём трафика по приложениям; сайты и содержимое не сохраняются и никуда не отправляются.']
];
return {
faq: Q.map(function (x, i) { return { q: x[0], a: x[1], open: !!x[2], openStr: x[2] ? 'true' : 'false', rot: x[2] ? 'rotate(180deg)' : 'none', divider: i < Q.length - 1 ? '1px solid #F0ECF4' : '0' }; }),
links: [{ t: 'Проверить обновления', href: 'F_Update.dc.html' }, { t: 'Лицензии открытого ПО', href: 'F_Help.dc.html' }, { t: 'Исходный код strongSwan', href: 'F_Help.dc.html' }]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,101 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Главная</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #6D4AFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="F_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #FCF8FF; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="F_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Отключить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #6D4AFF; color: #FFFFFF; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #E7DFFF, 0 0 0 28px #F3EEFF; margin: 28px 0 22px; cursor: pointer">
<svg width="68" height="68" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M12 3v9"/><path d="M6.3 6.3a8 8 0 1 0 11.4 0"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Защищено</span>
<span style="display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; color: #5E5A7D"><span style="width: 8px; height: 8px; border-radius: 4px; background: #148A45"></span>01:24:37 · РФ-сайты напрямую</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="F_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; text-decoration: none; color: #1C1B20">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #E7DFFF; color: #3B2C88; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #5E5A7D">IP 185.•••.•••.12 · 38 мс</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #6D4AFF">Сменить</span>
</a>
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px">
<sc-for list="{{actions}}" as="q" hint-placeholder-count="3">
<a href="{{q.href}}" style="height: 72px; border-radius: 20px; background: #F0ECF4; color: #2A2640; text-decoration: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; font-size: 12px; font-weight: 700; text-align: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{q.icon}}"/></svg>{{q.label}}
</a>
</sc-for>
</div>
<a href="F_Stats.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 14px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; text-decoration: none; color: #1C1B20">
<span style="flex: 1; display: flex; flex-direction: column; gap: 8px">
<span style="display: flex; align-items: baseline; gap: 8px"><span style="font-size: 20px; font-weight: 800">1,24 ГБ</span><span style="font-size: 13px; color: #5E5A7D">сегодня</span></span>
<span style="display: flex; height: 6px; border-radius: 3px; overflow: hidden; gap: 2px"><span style="width: 72%; background: #6D4AFF; border-radius: 3px"></span><span style="flex: 1; background: #3FBF7F; border-radius: 3px"></span></span>
<span style="font-size: 12px; font-weight: 600; color: #5E5A7D">72% через VPN · 342 трекера заблокировано</span>
</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#5E5A7D" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</a>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #F0ECF4; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'F_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'F_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'F_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'F_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#1C1B20' : '#49454F', weight: on ? '800' : '600', pill: on ? '#E7DFFF' : 'transparent' };
}),
actions: [
{ label: 'Пауза 15 мин', href: 'F_Pause.dc.html', icon: 'M9 5v14M15 5v14' },
{ label: 'Быстрейший', href: 'F_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'F_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,81 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Главная — проблема</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #6D4AFF">vpn</span></span></span>
<a href="F_Diag.dc.html" aria-label="Диагностика: есть проблема" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
<span style="position: absolute; top: 8px; right: 8px; width: 10px; height: 10px; border-radius: 5px; background: #B45309; border: 2px solid #F0ECF4"></span>
</a>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Подключить сейчас" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #FFE2B8; color: #B45309; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #FFEFD6, 0 0 0 28px #FFF7EC; margin: 28px 0 22px; cursor: pointer">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
</button>
<span style="font-size: 22px; font-weight: 800; letter-spacing: -0.02em; color: #5C2A04">Оператор включил белые списки</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; line-height: 1.45; color: #6B3A10">Работают только российские сайты — банки и Госуслуги открываются. VPN подключится сам.</span>
</section>
<div style="padding: 20px 16px 0; display: flex; flex-direction: column; gap: 10px">
<div role="status" style="display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 24px; background: #FFFFFF; border: 1px solid #F3D3A6">
<span style="width: 10px; height: 10px; border-radius: 5px; background: #B45309"></span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 700; color: #5C2A04">Пробуем резервный сервер</span>
<span style="font-size: 12px; color: #6B3A10">Хельсинки · попытка 2 из 3</span>
</span>
<button style="flex: none; height: 40px; padding: 0 14px; border-radius: 12px; border: 1px solid #C7A27A; background: transparent; color: #5C2A04; font: 700 13px 'Manrope', sans-serif">Стоп</button>
</div>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px">
<a href="F_Diag.dc.html" style="height: 52px; border-radius: 18px; background: #B45309; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800">Что делать</a>
<button style="height: 52px; border: 0; border-radius: 18px; background: #F0ECF4; color: #2A2640; font: 700 14px 'Manrope', sans-serif">Через Wi-Fi</button>
</div>
<div role="status" style="display: flex; align-items: center; gap: 10px; padding: 10px 12px 10px 14px; border-radius: 18px; background: #F6F2FA">
<span style="flex: 1; font-size: 13px; font-weight: 600; color: #2A2640">Постоянный VPN выключен</span>
<a href="F_KillSwitch.dc.html" style="flex: none; height: 36px; padding: 0 12px; border-radius: 12px; background: #E7DFFF; color: #3B2C88; font-size: 13px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Включить</a>
</div>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #F0ECF4; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'F_HomeAlert.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'F_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'F_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'F_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
return {
tabs: tabs.map(function (t, i) {
var on = i === 0;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#1C1B20' : '#49454F', weight: on ? '800' : '600', pill: on ? '#FFE2B8' : 'transparent' };
})
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,88 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Главная — подключаемся</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #6D4AFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="F_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #FCF8FF; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="F_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Отменить подключение" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #E7DFFF; color: #6D4AFF; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #F3EEFF, 0 0 0 28px #F8F5FF; margin: 28px 0 22px; cursor: pointer">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em; color: #1C1B20">Подключаемся…</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: #5E5A7D">Амстердам · шаг 3 из 4</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="F_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; text-decoration: none; color: #1C1B20">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #E7DFFF; color: #3B2C88; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #5E5A7D">IP 185.•••.•••.12 · 38 мс</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #6D4AFF">Сменить</span>
</a>
<section style="padding: 8px 16px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2"><div style="display: flex; align-items: center; gap: 12px; height: 40px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #DDF3E6; color: #0E6B35; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center">✓</span><span style="flex: 1; font-size: 14px; font-weight: 600; color: #1C1B20">Сеть</span><span style="font-size: 13px; color: #5E5A7D">LTE</span></div><div style="display: flex; align-items: center; gap: 12px; height: 40px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #DDF3E6; color: #0E6B35; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center">✓</span><span style="flex: 1; font-size: 14px; font-weight: 600; color: #1C1B20">Сервер ответил</span><span style="font-size: 13px; color: #5E5A7D">38 мс</span></div><div style="display: flex; align-items: center; gap: 12px; height: 40px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #6D4AFF; color: #FFFFFF; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center">…</span><span style="flex: 1; font-size: 14px; font-weight: 800; color: #1C1B20">Проверка входа</span><span style="font-size: 13px; color: #5E5A7D"></span></div><div style="display: flex; align-items: center; gap: 12px; height: 40px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #F0ECF4; color: #79767F; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center"></span><span style="flex: 1; font-size: 14px; font-weight: 600; color: #79767F">Туннель и маршруты</span><span style="font-size: 13px; color: #5E5A7D"></span></div></section>
<a href="F_Home.dc.html" style="height: 48px; border-radius: 16px; background: #F0ECF4; color: #2A2640; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700">Отменить</a>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #F0ECF4; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'F_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'F_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'F_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'F_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#1C1B20' : '#49454F', weight: on ? '800' : '600', pill: on ? '#E7DFFF' : 'transparent' };
}),
actions: [
{ label: 'Пауза 15 мин', href: 'F_Pause.dc.html', icon: 'M9 5v14M15 5v14' },
{ label: 'Быстрейший', href: 'F_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'F_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,79 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Главная — нет серверов</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #6D4AFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="F_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #FCF8FF; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="F_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Добавить сервер" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #F0ECF4; color: #79767F; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #F6F2FA, 0 0 0 28px #FAF7FC; margin: 28px 0 22px; cursor: pointer">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em; color: #1C1B20">Добавьте сервер</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: #5E5A7D">Чтобы подключиться, нужен профиль .sswan</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="F_ImportQR.dc.html" style="height: 60px; border-radius: 20px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; gap: 10px; font-size: 16px; font-weight: 800"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 8V5a1 1 0 0 1 1-1h3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3M4 12h16"/></svg>Сканировать QR</a>
<a href="F_Import.dc.html" style="height: 56px; border-radius: 18px; background: #E4E0F9; color: #2A2640; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700">Ссылка, файл или вручную</a>
<div style="padding: 14px 16px; border-radius: 20px; background: #FFFFFF; border: 1px solid #EDE8F2; display: flex; flex-direction: column; gap: 4px"><span style="font-size: 14px; font-weight: 800">Где взять профиль?</span><span style="font-size: 13px; line-height: 1.45; color: #5E5A7D">Его присылает администратор вашего VPN — файлом .sswan, ссылкой или QR-кодом. Можно отсканировать с экрана друга.</span></div>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #F0ECF4; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'F_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'F_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'F_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'F_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#1C1B20' : '#49454F', weight: on ? '800' : '600', pill: on ? '#E7DFFF' : 'transparent' };
}),
actions: [
{ label: 'Пауза 15 мин', href: 'F_Pause.dc.html', icon: 'M9 5v14M15 5v14' },
{ label: 'Быстрейший', href: 'F_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'F_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,70 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Главная — нет интернета</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #6D4AFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="F_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #FCF8FF; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="F_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Отключить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #F0ECF4; color: #49454F; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #F6F2FA, 0 0 0 28px #FAF7FC; margin: 28px 0 22px; cursor: pointer"><svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 8.8a15 15 0 0 1 4.4-2.7M10 5.1A15 15 0 0 1 22 8.8M5 12.9a10 10 0 0 1 4.6-2.6M14.6 10.5A10 10 0 0 1 19 12.9M8.5 16.4a5 5 0 0 1 7 0M12 20h.01M3 3l18 18"/></svg></button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Нет интернета</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: #5E5A7D">Проблема не в VPN. Подключимся сами, как только появится сеть</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<section style="padding: 6px 16px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2"><div style="display: flex; align-items: center; gap: 12px; height: 38px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #FFDAD8; color: #8C1D24; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center">×</span><span style="flex: 1; font-size: 14px; font-weight: 600">Wi-Fi</span><span style="font-size: 13px; color: #5E5A7D">выключен</span></div><div style="display: flex; align-items: center; gap: 12px; height: 38px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #FFDAD8; color: #8C1D24; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center">×</span><span style="flex: 1; font-size: 14px; font-weight: 600">Мобильные данные</span><span style="font-size: 13px; color: #5E5A7D">нет сигнала</span></div><div style="display: flex; align-items: center; gap: 12px; height: 38px"><span style="width: 22px; height: 22px; border-radius: 11px; background: #F0ECF4; color: #79767F; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center"></span><span style="flex: 1; font-size: 14px; font-weight: 600">Сервер Амстердам</span><span style="font-size: 13px; color: #5E5A7D">ждёт сеть</span></div></section>
<section role="status" style="padding: 16px; border-radius: 24px; background: #EFEAFF; border: 1px solid #CFC3FF; display: flex; flex-direction: column; gap: 10px"><span style="font-size: 15px; font-weight: 800; color: #3B2C88">Приложения без сети — так и задумано</span><span style="font-size: 13px; line-height: 1.45; color: #3B2C88">Включено «Без VPN — без сети»: пока туннеля нет, трафик не уйдёт напрямую.</span><div style="display: flex; gap: 8px"><a href="F_Settings.dc.html" style="flex: 1; min-width: 0; height: 48px; padding: 0 14px; border-radius: 16px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; white-space: nowrap; box-sizing: border-box">Настройки сети</a><a href="F_KillSwitch.dc.html" style="flex: none; min-width: 0; height: 48px; padding: 0 14px; border-radius: 16px; background: #F0ECF4; color: #2A2640; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; white-space: nowrap; box-sizing: border-box">Подробнее</a></div></section>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #F0ECF4; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'F_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'F_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'F_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'F_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
return {
tabs: tabs.map(function (t, i) {
var on = i === 0;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#1C1B20' : '#49454F', weight: on ? '800' : '600', pill: on ? '#E7DFFF' : 'transparent' };
})
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,88 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Главная — пауза</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #6D4AFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="F_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #FCF8FF; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="F_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Включить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #F0ECF4; color: #49454F; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #F6F2FA, 0 0 0 28px #FAF7FC; margin: 28px 0 22px; cursor: pointer">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 5v14M15 5v14"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em; color: #1C1B20">Пауза · 12:40</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: #5E5A7D">VPN включится сам в 14:37</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="F_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; text-decoration: none; color: #1C1B20">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #E7DFFF; color: #3B2C88; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #5E5A7D">IP 185.•••.•••.12 · 38 мс</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #6D4AFF">Сменить</span>
</a>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px"><a href="F_Home.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Включить сейчас</a><a href="F_Pause.dc.html" style="height: 56px; border-radius: 18px; background: #F0ECF4; color: #2A2640; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700">+15 минут</a></div>
<div style="padding: 12px 14px; border-radius: 18px; background: #FFF4E0; color: #6B3A10; font-size: 13px; line-height: 1.45">Весь трафик сейчас идёт напрямую, без защиты. Банки и РФ-сервисы работают как обычно.</div>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #F0ECF4; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'F_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'F_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'F_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'F_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#1C1B20' : '#49454F', weight: on ? '800' : '600', pill: on ? '#E7DFFF' : 'transparent' };
}),
actions: [
{ label: 'Пауза 15 мин', href: 'F_Pause.dc.html', icon: 'M9 5v14M15 5v14' },
{ label: 'Быстрейший', href: 'F_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'F_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,106 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Главная — сценарий</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #6D4AFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="F_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #FCF8FF; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="F_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Включить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #E5E1E9; color: #49454F; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #F0ECF4, 0 0 0 28px #F6F2FA; margin: 28px 0 22px; cursor: pointer">
<svg width="68" height="68" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M12 3v9"/><path d="M6.3 6.3a8 8 0 1 0 11.4 0"/></svg>
</button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em">VPN выключен</span>
<a href="F_Automation.dc.html" style="display: flex; align-items: center; gap: 8px; height: 40px; padding: 0 8px 0 14px; border-radius: 20px; background: #E7DFFF; color: #21005D; text-decoration: none; font-size: 14px; font-weight: 700">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 9a15 15 0 0 1 20 0M5 13a10 10 0 0 1 14 0M9 17a4 4 0 0 1 6 0"/></svg>
Сценарий · Home_5G
<span style="width: 24px; height: 24px; border-radius: 12px; background: #FFFFFF; display: flex; align-items: center; justify-content: center"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6D4AFF" stroke-width="2.6" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg></span>
</a>
<span style="font-size: 13px; color: #5E5A7D">Включится сам, когда уйдёте из этой сети</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<a href="F_Servers.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; text-decoration: none; color: #1C1B20">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #E7DFFF; color: #3B2C88; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px">NL</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 16px; font-weight: 700">Амстердам</span>
<span style="font-size: 13px; color: #5E5A7D">подключится при выходе из Home_5G</span>
</span>
<span style="font-size: 13px; font-weight: 700; color: #6D4AFF">Сменить</span>
</a>
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px">
<sc-for list="{{actions}}" as="q" hint-placeholder-count="3">
<a href="{{q.href}}" style="height: 72px; border-radius: 20px; background: #F0ECF4; color: #2A2640; text-decoration: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; font-size: 12px; font-weight: 700; text-align: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{q.icon}}"/></svg>{{q.label}}
</a>
</sc-for>
</div>
<a href="F_Stats.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 14px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; text-decoration: none; color: #1C1B20">
<span style="flex: 1; display: flex; flex-direction: column; gap: 8px">
<span style="display: flex; align-items: baseline; gap: 8px"><span style="font-size: 20px; font-weight: 800">1,24 ГБ</span><span style="font-size: 13px; color: #5E5A7D">сегодня</span></span>
<span style="display: flex; height: 6px; border-radius: 3px; overflow: hidden; gap: 2px"><span style="width: 72%; background: #6D4AFF; border-radius: 3px"></span><span style="flex: 1; background: #3FBF7F; border-radius: 3px"></span></span>
<span style="font-size: 12px; font-weight: 600; color: #5E5A7D">72% через VPN · 28% напрямую</span>
</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#5E5A7D" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
</a>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #F0ECF4; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'F_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'F_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'F_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'F_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
var active = 0;
return {
tabs: tabs.map(function (t, i) {
var on = i === active;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#1C1B20' : '#49454F', weight: on ? '800' : '600', pill: on ? '#E7DFFF' : 'transparent' };
}),
actions: [
{ label: 'Включить сейчас', href: 'F_Home.dc.html', icon: 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0' },
{ label: 'Быстрейший', href: 'F_Servers.dc.html', icon: 'M13 2L4 14h7l-1 8 9-12h-7z' },
{ label: 'Не открывается?', href: 'F_Diag.dc.html', icon: 'M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6M12 17v.5' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,71 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Главная — сервер не отвечает</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 4px">
<span style="display: flex; align-items: center; gap: 10px"><span style="width: 34px; height: 34px; border-radius: 10px; background: #6D4AFF; display: flex; align-items: center; justify-content: center"><svg width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 2.6l7.6 2.8v6c0 5-3.3 8.4-7.6 10-4.3-1.6-7.6-5-7.6-10v-6z" fill="#FFFFFF"/><path d="M14.6 8.8c-.6-.95-1.6-1.45-2.7-1.45-1.5 0-2.6.85-2.6 2.05 0 2.8 5.5 1.6 5.5 4.5 0 1.3-1.2 2.25-2.8 2.25-1.2 0-2.2-.55-2.8-1.5" stroke="#6D4AFF" stroke-width="2.4" stroke-linecap="round"/></svg></span><span style="font-size: 22px; font-weight: 800; letter-spacing: -0.04em">shx<span style="font-weight: 500; color: #6D4AFF">vpn</span></span></span>
<span style="display: flex; gap: 8px">
<a href="F_Inbox.dc.html" aria-label="События: 2 ждут решения" style="position: relative; width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15zM10 20a2 2 0 0 0 4 0"/></svg>
<span style="position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box; border-radius: 9px; background: #6D4AFF; border: 2px solid #FCF8FF; color: #FFFFFF; font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center">2</span>
</a>
<a href="F_Diag.dc.html" aria-label="Диагностика" style="width: 44px; height: 44px; border-radius: 22px; background: #F0ECF4; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>
</a>
</span>
</header>
<section style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px">
<button aria-label="Отключить VPN" style="width: 188px; height: 188px; border: 0; border-radius: 40% 60% 55% 45% / 50% 45% 55% 50%; background: #FFE2B8; color: #7A3A06; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 14px #FFEFD6, 0 0 0 28px #FFF7EC; margin: 28px 0 22px; cursor: pointer"><svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 8v5M12 16.5v.5M10.3 3.9L2.4 18a2 2 0 0 0 1.7 3h15.8a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg></button>
<span style="font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Сервер не отвечает</span>
<span style="max-width: 320px; text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: #5E5A7D">Амстердам молчит 40 с · снова пробуем через 12 с</span>
</section>
<div style="padding: 22px 16px 0; display: flex; flex-direction: column; gap: 10px">
<section role="status" style="padding: 16px; border-radius: 24px; background: #FFF4E0; border: 1px solid #F3D3A6; display: flex; flex-direction: column; gap: 10px"><span style="font-size: 15px; font-weight: 800; color: #6B3A10">Интернет есть — не отвечает сам сервер</span><span style="font-size: 13px; line-height: 1.45; color: #6B3A10">Возможно, он перегружен или недоступен из вашей сети. Франкфурт сейчас отвечает за 41 мс.</span><div style="display: flex; gap: 8px"><a href="F_Home.dc.html" style="flex: 1; min-width: 0; height: 48px; padding: 0 14px; border-radius: 16px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; white-space: nowrap; box-sizing: border-box">Перейти на Франкфурт</a><a href="F_HomeConnecting.dc.html" style="flex: none; min-width: 0; height: 48px; padding: 0 14px; border-radius: 16px; background: #F0ECF4; color: #2A2640; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; white-space: nowrap; box-sizing: border-box">Повторить</a></div></section>
<a href="F_Settings.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 20px; background: #FFFFFF; border: 1px solid #EDE8F2; text-decoration: none; color: #1C1B20"><span style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 700">Переключаться автоматически</span><span style="font-size: 13px; color: #5E5A7D; line-height: 1.4">Если сервер молчит дольше минуты — на ближайший рабочий</span></span><span style="flex: none; width: 52px; height: 32px; border-radius: 16px; background: #E5E1E9; display: flex; align-items: center; padding: 0 4px; box-sizing: border-box; justify-content: flex-start"><span style="width: 24px; height: 24px; border-radius: 12px; background: #79767F"></span></span></a>
<a href="F_Diag.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 20px; background: #FFFFFF; border: 1px solid #EDE8F2; text-decoration: none; color: #1C1B20"><span style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px"><span style="font-size: 15px; font-weight: 700">Проверить, в чём дело</span><span style="font-size: 13px; color: #5E5A7D; line-height: 1.4">Сеть, сервер, DNS и белые списки за 10 секунд</span></span><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#5E5A7D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg></a>
</div>
<nav aria-label="Основная навигация" style="position: absolute; left: 0; right: 0; bottom: 0; height: 80px; background: #F0ECF4; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center">
<sc-for list="{{tabs}}" as="t" hint-placeholder-count="4">
<a href="{{t.href}}" style="display: flex; flex-direction: column; align-items: center; gap: 4px; text-decoration: none; color: {{t.fg}}; font-size: 12px; font-weight: {{t.weight}}">
<span style="width: 60px; height: 32px; border-radius: 16px; background: {{t.pill}}; display: flex; align-items: center; justify-content: center"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{t.icon}}"/></svg></span>{{t.label}}
</a>
</sc-for>
</nav>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
var tabs = [
['Главная', 'F_Home.dc.html', 'M12 3v9M6.3 6.3a8 8 0 1 0 11.4 0'],
['Серверы', 'F_Servers.dc.html', 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18'],
['Маршруты', 'F_Routing.dc.html', 'M4 12h6l4-6h6M10 12l4 6h6'],
['Настройки', 'F_Settings.dc.html', 'M4 7h10M18 7h2M4 17h4M12 17h8M14 5v4M8 15v4']
];
return {
tabs: tabs.map(function (t, i) {
var on = i === 0;
return { label: t[0], href: t[1], icon: t[2], fg: on ? '#1C1B20' : '#49454F', weight: on ? '800' : '600', pill: on ? '#E7DFFF' : 'transparent' };
})
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,63 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Добавить сервер</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end">
<section role="dialog" aria-label="Добавить сервер" style="border-radius: 32px 32px 0 0; background: #FCF8FF; padding: 12px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 36px; height: 4px; border-radius: 2px; background: #C9C5D0"></span>
<div style="display: flex; align-items: center; justify-content: space-between; padding: 0 4px">
<h1 style="margin: 0; font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Добавить сервер</h1>
<a href="F_Servers.dc.html" aria-label="Закрыть" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #49454F">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg>
</a>
</div>
<a href="F_ImportQR.dc.html" style="display: flex; align-items: center; gap: 14px; padding: 18px; border-radius: 24px; background: #6D4AFF; color: #FFFFFF; text-decoration: none">
<span style="width: 48px; height: 48px; border-radius: 16px; background: rgba(255,255,255,0.18); display: flex; align-items: center; justify-content: center">
<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 8V5a1 1 0 0 1 1-1h3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3M4 12h16"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 17px; font-weight: 800">Сканировать QR</span>
<span style="font-size: 13px; color: #E7DFFF">С экрана друга или с сайта</span>
</span>
</a>
<div style="display: flex; flex-direction: column; gap: 8px; padding: 14px; border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2">
<label for="fi-url" style="font-size: 15px; font-weight: 800">Ссылка на профиль</label>
<div style="display: flex; gap: 8px">
<span style="flex: 1; min-width: 0; display: flex; align-items: center; height: 48px; padding: 0 12px; border-radius: 14px; background: #F0ECF4">
<input id="fi-url" type="url" placeholder="https://…/profile.sswan" style="flex: 1; min-width: 0; width: 100%; border: 0; background: transparent; font: 500 15px 'Manrope', sans-serif; color: #1C1B20; outline: none">
</span>
<a href="F_ImportPreview.dc.html" style="flex: none; white-space: nowrap; height: 48px; padding: 0 16px; border-radius: 14px; background: #E4E0F9; color: #2A2640; text-decoration: none; display: flex; align-items: center; font-size: 14px; font-weight: 700">Вставить</a>
</div>
<span style="font-size: 12px; line-height: 1.4; color: #5E5A7D">Ссылку запомним и будем подтягивать изменения профиля</span>
</div>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px">
<a href="F_ImportPreview.dc.html" style="height: 56px; border-radius: 18px; border: 1px solid #C9C5D0; color: #1C1B20; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700; box-sizing: border-box">Файл .sswan</a>
<a href="F_ManualAdd.dc.html" style="height: 56px; border-radius: 18px; border: 1px solid #C9C5D0; background: transparent; color: #1C1B20; font-size: 14px; font-weight: 700; display: flex; align-items: center; justify-content: center; text-decoration: none; box-sizing: border-box">Вручную</a>
</div>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {};
}
}
</script>
</body>
</html>
@@ -0,0 +1,73 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Проверка профиля</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: rgba(28,27,32,0.5); font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end">
<section role="dialog" aria-label="Добавить сервер" style="border-radius: 32px 32px 0 0; background: #FCF8FF; padding: 12px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<span style="align-self: center; width: 36px; height: 4px; border-radius: 2px; background: #C9C5D0"></span>
<div style="display: flex; align-items: center; gap: 14px; padding: 4px 4px 0">
<span style="width: 56px; height: 56px; border-radius: 28px; background: #E7DFFF; color: #3B2C88; display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: 800">NL</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<h1 style="margin: 0; font-size: 24px; font-weight: 800; letter-spacing: -0.02em">Добавить сервер?</h1>
<span style="font-size: 13px; color: #5E5A7D">Профиль прочитан, всё в порядке</span>
</span>
</div>
<section style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; overflow: hidden">
<label style="display: flex; flex-direction: column; gap: 4px; padding: 12px 16px; border-bottom: 1px solid #F0ECF4">
<span style="font-size: 12px; font-weight: 700; color: #5E5A7D">Название</span>
<input type="text" value="Амстердам" style="border: 0; background: transparent; padding: 0; font: 700 16px 'Manrope', sans-serif; color: #1C1B20; outline: none; min-width: 0; width: 100%">
</label>
<sc-for list="{{rows}}" as="r" hint-placeholder-count="4">
<div style="display: flex; align-items: center; gap: 10px; padding: 0 16px; height: 52px; border-bottom: {{r.divider}}">
<span style="flex: 1; font-size: 14px; font-weight: 600; color: #49454F">{{r.k}}</span>
<span style="font-size: 14px; font-weight: 700; color: {{r.color}}">{{r.v}}</span>
</div>
</sc-for>
</section>
<section style="border-radius: 24px; background: #FFFFFF; border: 1px solid #EDE8F2; overflow: hidden">
<div style="display: flex; align-items: center; gap: 10px; padding: 12px 14px 12px 16px; border-bottom: 1px solid #F0ECF4">
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 700">Обновлять по ссылке</span>
<span style="font-size: 12px; color: #5E5A7D">Есть только у профилей, добавленных по ссылке</span>
</span>
<button aria-pressed="true" aria-label="Обновлять по ссылке" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: #6D4AFF; padding: 4px; display: flex; justify-content: flex-end"><span style="width: 24px; height: 24px; border-radius: 12px; background: #FFFFFF"></span></button>
</div>
<div style="display: flex; align-items: center; gap: 10px; padding: 12px 14px 12px 16px">
<span style="flex: 1; font-size: 15px; font-weight: 700">Подключиться сразу</span>
<button aria-pressed="true" aria-label="Подключиться сразу" style="flex: none; width: 52px; height: 32px; border: 0; border-radius: 16px; background: #6D4AFF; padding: 4px; display: flex; justify-content: flex-end"><span style="width: 24px; height: 24px; border-radius: 12px; background: #FFFFFF"></span></button>
</div>
</section>
<div style="padding: 12px 14px; border-radius: 18px; background: #F3EEFF; font-size: 13px; line-height: 1.45; color: #2A2640"><b>Такой сервер уже есть</b> («Амстердам», добавлен 12 окт.). Новый профиль заменит его, ваши настройки останутся.</div>
<div style="display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 10px">
<a href="F_Import.dc.html" style="height: 56px; border-radius: 18px; border: 1px solid #C9C5D0; color: #1C1B20; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700; box-sizing: border-box">Отмена</a>
<a href="F_Servers.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Обновить сервер</a>
</div>
</section>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var r = [['Сервер', 'nl1.[ваш-домен]', '#1C1B20'], ['Тип', 'IKEv2', '#1C1B20'], ['Вход', 'Сертификат в профиле', '#1C1B20'], ['Источник', 'ссылка', '#1C1B20'], ['Сертификат CA', 'входит в профиль', '#0E6B35']];
return { rows: r.map(function (x, i) { return { k: x[0], v: x[1], color: x[2], divider: i < r.length - 1 ? '1px solid #F0ECF4' : '0' }; }) };
}
}
</script>
</body>
</html>
@@ -0,0 +1,60 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Сканер QR</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#C4B2FF}a:hover{color:#FFFFFF}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #0F0E13; font-family: 'Manrope', system-ui, sans-serif; color: #FFFFFF; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; justify-content: space-between; padding: 16px 12px">
<a href="F_Import.dc.html" aria-label="Закрыть" style="width: 44px; height: 44px; border-radius: 22px; background: rgba(255,255,255,0.12); display: flex; align-items: center; justify-content: center; color: #FFFFFF">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg>
</a>
<button aria-label="Фонарик" style="width: 44px; height: 44px; border: 0; border-radius: 22px; background: rgba(255,255,255,0.12); color: #FFFFFF; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3h8l-2 6v11h-4V9z"/></svg>
</button>
</header>
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 28px">
<div style="position: relative; width: 260px; height: 260px">
<span style="position: absolute; left: 0; top: 0; width: 56px; height: 56px; border-left: 5px solid #9C7CFF; border-top: 5px solid #9C7CFF; border-radius: 22px 0 0 0"></span>
<span style="position: absolute; right: 0; top: 0; width: 56px; height: 56px; border-right: 5px solid #9C7CFF; border-top: 5px solid #9C7CFF; border-radius: 0 22px 0 0"></span>
<span style="position: absolute; left: 0; bottom: 0; width: 56px; height: 56px; border-left: 5px solid #9C7CFF; border-bottom: 5px solid #9C7CFF; border-radius: 0 0 0 22px"></span>
<span style="position: absolute; right: 0; bottom: 0; width: 56px; height: 56px; border-right: 5px solid #9C7CFF; border-bottom: 5px solid #9C7CFF; border-radius: 0 0 22px 0"></span>
<span style="position: absolute; left: 24px; right: 24px; top: 118px; height: 3px; border-radius: 2px; background: #9C7CFF; box-shadow: 0 0 18px #9C7CFF"></span>
</div>
<span style="max-width: 280px; text-align: center; font-size: 16px; font-weight: 700; line-height: 1.4">Наведите на QR с профилем .sswan или ссылкой на него</span>
</div>
<div style="padding: 0 16px 28px; display: flex; flex-direction: column; gap: 10px">
<a href="F_ImportPreview.dc.html" style="display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 22px; background: #FFFFFF; color: #1C1B20; text-decoration: none">
<span style="width: 40px; height: 40px; border-radius: 20px; background: #148A45; color: #FFFFFF; display: flex; align-items: center; justify-content: center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 15px; font-weight: 800">Найден профиль «Амстердам»</span>
<span style="font-size: 12px; color: #5E5A7D">Нажмите, чтобы проверить и добавить</span>
</span>
</a>
<button style="height: 48px; border: 0; border-radius: 16px; background: rgba(255,255,255,0.12); color: #FFFFFF; font: 700 14px 'Manrope', sans-serif">Выбрать картинку из галереи</button>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {};
}
}
</script>
</body>
</html>
@@ -0,0 +1,108 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>События</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1300px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; font-variant-numeric: tabular-nums">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="F_Home.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">События</h1>
<button style="flex: none; height: 40px; padding: 0 12px; border: 0; border-radius: 20px; background: transparent; color: #6D4AFF; font: 700 13px 'Manrope', sans-serif">Прочитать все</button>
</header>
<div style="padding: 4px 16px 0; display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; gap: 8px; flex-wrap: wrap">
<button aria-pressed="true" style="height: 34px; padding: 0 12px; border-radius: 12px; border: 0; background: #3B2C88; color: #FFFFFF; font: 700 13px 'Manrope', sans-serif">Все</button>
<button style="height: 34px; padding: 0 12px; border-radius: 12px; border: 0; background: #FFE2B8; color: #7A3A06; font: 700 13px 'Manrope', sans-serif">Ждут решения · 2</button>
<button style="height: 34px; padding: 0 12px; border-radius: 12px; border: 1px solid #C9C5D0; background: transparent; color: #1C1B20; font: 600 13px 'Manrope', sans-serif">Подключение</button>
<button style="height: 34px; padding: 0 12px; border-radius: 12px; border: 1px solid #C9C5D0; background: transparent; color: #1C1B20; font: 600 13px 'Manrope', sans-serif">Маршруты</button>
</div>
<sc-for list="{{days}}" as="d" hint-placeholder-count="2">
<section style="display: flex; flex-direction: column; gap: 8px">
<h2 style="margin: 6px 6px 0; font-size: 13px; font-weight: 800; color: #6D4AFF; letter-spacing: 0.04em">{{d.title}}</h2>
<sc-for list="{{d.items}}" as="e" hint-placeholder-count="3">
<article style="display: flex; gap: 12px; padding: 14px; border-radius: 22px; background: {{e.bg}}; border: 1px solid {{e.border}}">
<span style="flex: none; width: 36px; height: 36px; border-radius: 12px; background: {{e.iconBg}}; color: {{e.iconFg}}; display: flex; align-items: center; justify-content: center">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="{{e.icon}}"/></svg>
</span>
<span style="flex: 1; display: flex; flex-direction: column; gap: 4px; min-width: 0">
<span style="display: flex; align-items: baseline; gap: 8px">
<span style="flex: 1; font-size: 15px; font-weight: 800">{{e.title}}</span>
<span style="flex: none; font-size: 12px; color: #5E5A7D">{{e.time}}</span>
</span>
<span style="font-size: 13px; line-height: 1.4; color: #49454F">{{e.text}}</span>
<sc-if value="{{e.hasActions}}" hint-placeholder-val="{{ false }}">
<span style="display: flex; gap: 8px; padding-top: 6px">
<a href="{{e.href1}}" style="height: 36px; padding: 0 14px; border-radius: 12px; background: {{e.primaryBg}}; color: #FFFFFF; font-size: 13px; font-weight: 800; text-decoration: none; display: flex; align-items: center">{{e.primary}}</a>
<sc-if value="{{e.hasSecondary}}" hint-placeholder-val="{{ false }}">
<a href="{{e.href2}}" style="height: 36px; padding: 0 12px; border-radius: 12px; border: 1px solid #C9C5D0; color: #1C1B20; font-size: 13px; font-weight: 700; text-decoration: none; display: flex; align-items: center; box-sizing: border-box">{{e.secondary}}</a>
</sc-if>
</span>
</sc-if>
</span>
</article>
</sc-for>
</section>
</sc-for>
<p style="margin: 4px 6px 0; font-size: 12px; line-height: 1.45; color: #5E5A7D">Храним 30 дней на устройстве. Что приходит пушем, а что только сюда — в Настройки → Уведомления.</p>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1300}}'>
class Component extends DCLogic {
renderVals() {
var K = {
warn: { bg: '#FFF4E0', border: '#F3D3A6', iconBg: '#B45309', iconFg: '#FFFFFF', primaryBg: '#B45309' },
ask: { bg: '#FFFFFF', border: '#CFC3FF', iconBg: '#6D4AFF', iconFg: '#FFFFFF', primaryBg: '#6D4AFF' },
info: { bg: '#FFFFFF', border: '#EDE8F2', iconBg: '#F0ECF4', iconFg: '#3B2C88', primaryBg: '#6D4AFF' },
ok: { bg: '#FFFFFF', border: '#EDE8F2', iconBg: '#DDF3E6', iconFg: '#0E6B35', primaryBg: '#6D4AFF' }
};
var I = {
alert: 'M12 4l9 16H3zM12 10v4M12 17.5v.5',
swap: 'M4 8h13l-3-3M20 16H7l3 3',
app: 'M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z',
route: 'M4 12h6l4-6h6M10 12l4 6h6',
db: 'M4 6c0-1.7 3.6-3 8-3s8 1.3 8 3-3.6 3-8 3-8-1.3-8-3zM4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6',
shield: 'M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z',
down: 'M12 4v12M7 11l5 5 5-5M5 20h14'
};
var e = function (kind, icon, title, time, text, primary, secondary, href1, href2) {
var k = K[kind];
return { bg: k.bg, border: k.border, iconBg: k.iconBg, iconFg: k.iconFg, primaryBg: k.primaryBg, icon: I[icon],
title: title, time: time, text: text, hasActions: !!primary, primary: primary || '', hasSecondary: !!secondary, secondary: secondary || '', href1: href1 || 'F_Inbox.dc.html', href2: href2 || 'F_Inbox.dc.html' };
};
return {
days: [
{ title: 'СЕГОДНЯ', items: [
e('warn', 'alert', 'Белые списки у оператора', '14:02', 'Включили мост «Москва» — банки и Госуслуги работают, остальное через VPN.', 'Подробнее', null, 'F_Diag.dc.html'),
e('ask', 'app', 'Новое приложение: ВкусВилл', '13:40', 'Похоже на российский сервис. Пустить напрямую, мимо VPN?', 'Да, напрямую', 'Нет', 'F_Recent.dc.html', 'F_Inbox.dc.html'),
e('ask', 'route', 'Госуслуги не открываются через VPN', '12:15', '7 неудачных соединений за 5 минут.', 'Пустить напрямую', 'Проверить', 'F_Recent.dc.html', 'F_Check.dc.html'),
e('info', 'swap', 'Переключились на резервный сервер', '09:31', 'Амстердам не ответил за 15 с → Хельсинки. Через 10 минут вернулись обратно.')
] },
{ title: 'ВЧЕРА', items: [
e('ok', 'db', 'База адресов РФ обновлена', '22:00', '+214 сетей, всего 12 480.'),
e('info', 'down', 'Доступна версия 2.17.0', '18:44', 'Серверы, история трафика, новые правила.', 'Обновить', null, 'F_Update.dc.html'),
e('ok', 'shield', 'Итоги недели', '10:00', '18,4 ГБ трафика · 1 284 трекера заблокировано · 0 утечек без VPN.')
] }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,68 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Без VPN — без сети</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 844px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="F_Settings.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Без VPN — без сети</h1>
</header>
<div style="flex: 1; padding: 4px 16px 28px; display: flex; flex-direction: column; gap: 14px">
<section style="display: flex; align-items: center; gap: 12px; padding: 16px; border-radius: 24px; background: #FFF4E0; border: 1px solid #F3D3A6">
<span style="flex: none; width: 44px; height: 44px; border-radius: 14px; background: #B45309; color: #FFFFFF; display: flex; align-items: center; justify-content: center">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 11V8a6 6 0 0 1 12 0v3M5 11h14v10H5z"/></svg>
</span>
<span style="display: flex; flex-direction: column; gap: 2px">
<span style="font-size: 17px; font-weight: 800; color: #5C2A04">Сейчас выключено</span>
<span style="font-size: 13px; line-height: 1.4; color: #6B3A10">При обрыве VPN приложения на секунды выйдут в сеть напрямую</span>
</span>
</section>
<p style="margin: 0 4px; font-size: 15px; line-height: 1.5; color: #2A2640">Android может блокировать интернет, пока VPN не подключён. Включается в системных настройках — это займёт 20 секунд.</p>
<ol style="margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 10px">
<sc-for list="{{steps}}" as="s" hint-placeholder-count="3">
<li style="display: flex; align-items: flex-start; gap: 12px; padding: 14px; border-radius: 20px; background: #FFFFFF; border: 1px solid #EDE8F2">
<span style="flex: none; width: 28px; height: 28px; border-radius: 14px; background: #6D4AFF; color: #FFFFFF; font-size: 13px; font-weight: 800; display: flex; align-items: center; justify-content: center">{{s.n}}</span>
<span style="font-size: 14px; line-height: 1.45; color: #1C1B20">{{s.t}}</span>
</li>
</sc-for>
</ol>
<div style="padding: 12px 14px; border-radius: 18px; background: #F3EEFF; font-size: 13px; line-height: 1.45; color: #2A2640">Приложения из списка «напрямую» продолжат работать через обычную сеть. Всё остальное, включая сайты РФ, будет ждать VPN.</div>
<div style="flex: 1"></div>
<button style="height: 56px; border: 0; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; font: 800 15px 'Manrope', sans-serif">Открыть настройки Android</button>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":844}}'>
class Component extends DCLogic {
renderVals() {
return {
steps: [
{ n: 1, t: 'Нажмите кнопку ниже — откроется раздел VPN в настройках Android.' },
{ n: 2, t: 'Нажмите на шестерёнку рядом с «SHX VPN».' },
{ n: 3, t: 'Включите «Постоянный VPN» и «Блокировать подключения без VPN».' }
]
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,65 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Журнал</title>
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap">
<style>
body{margin:0}
a{color:#6D4AFF}a:hover{color:#4B2FD1}
</style>
</helmet>
<div style="position: relative; width: 390px; height: 1000px; box-sizing: border-box; background: #FCF8FF; font-family: 'Manrope', system-ui, sans-serif; color: #1C1B20; overflow: hidden; display: flex; flex-direction: column">
<header style="display: flex; align-items: center; gap: 8px; padding: 16px 12px 8px">
<a href="F_Diag.dc.html" aria-label="Назад" style="width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; color: #1C1B20">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 6l-6 6 6 6"/></svg>
</a>
<h1 style="margin: 0; flex: 1; font-size: 22px; font-weight: 800">Журнал</h1>
<button aria-label="Скопировать журнал" style="width: 44px; height: 44px; border: 0; border-radius: 22px; background: #F0ECF4; color: #3B2C88; display: flex; align-items: center; justify-content: center">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2"/><path d="M16 8V5a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h3"/></svg>
</button>
</header>
<div style="flex: 1; padding: 0 16px 24px; display: flex; flex-direction: column; gap: 12px; min-height: 0">
<div style="display: flex; gap: 8px">
<button aria-pressed="true" style="height: 34px; padding: 0 12px; border-radius: 12px; border: 0; background: #3B2C88; color: #FFFFFF; font: 700 13px 'Manrope', sans-serif">Важное</button>
<button aria-pressed="false" style="height: 34px; padding: 0 12px; border-radius: 12px; border: 1px solid #C9C5D0; background: transparent; color: #1C1B20; font: 600 13px 'Manrope', sans-serif">Всё</button>
<button aria-pressed="false" style="height: 34px; padding: 0 12px; border-radius: 12px; border: 1px solid #C9C5D0; background: transparent; color: #1C1B20; font: 600 13px 'Manrope', sans-serif">Ошибки</button>
</div>
<section style="flex: 1; min-height: 0; border-radius: 22px; background: #1C1B20; padding: 14px; display: flex; flex-direction: column; gap: 6px; overflow: hidden">
<sc-for list="{{lines}}" as="l" hint-placeholder-count="14">
<div style="display: flex; gap: 10px; font: 500 12px/1.45 ui-monospace, 'Cascadia Mono', Menlo, monospace">
<span style="flex: none; color: #79767F">{{l.t}}</span>
<span style="color: {{l.c}}">{{l.m}}</span>
</div>
</sc-for>
</section>
<div style="padding: 12px 14px; border-radius: 18px; background: #F3EEFF; font-size: 13px; line-height: 1.45; color: #2A2640">В отчёт попадут журнал подключения и версия приложения.</div>
<a href="F_Share.dc.html" style="height: 56px; border-radius: 18px; background: #6D4AFF; color: #FFFFFF; text-decoration: none; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800">Отправить отчёт</a>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":390,"height":1000}}'>
class Component extends DCLogic {
renderVals() {
var W = '#E5E1E9', G = '#7CE3B0', A = '#FFB869', P = '#C4B2FF';
var L = [
['14:02:11', 'Сеть: мобильная (LTE)', W], ['14:02:12', 'IKE_SA_INIT → nl1 :4500', W], ['14:02:27', 'Нет ответа 15 с — таймаут', A],
['14:02:27', 'Проверка: только сайты РФ отвечают', A], ['14:02:28', 'Белые списки обнаружены', A], ['14:02:28', 'Переключение на «Москва (мост)»', P],
['14:02:29', 'IKE_SA_INIT → msk-bridge :4500', W], ['14:02:29', 'IKE_AUTH: сертификат принят', G], ['14:02:30', 'CHILD_SA установлен', G],
['14:02:30', 'Маршруты: РФ напрямую, 12 480 сетей', W], ['14:02:30', 'Приложений напрямую: 24', W], ['14:02:31', 'Туннель работает · 52 мс', G],
['14:05:40', 'Госуслуги: 7 отказов через VPN', A], ['14:05:41', 'Подсказка: пустить напрямую', P]
];
return { lines: L.map(function (x) { return { t: x[0], m: x[1], c: x[2] }; }) };
}
}
</script>
</body>
</html>
Loaded 100 of 157 files, more files were not shown because too many files have changed in this diff. Show more