v6.8.8: added a section to support the project
CodeQL Analysis / Analyze CodeQL (push) Canceled after 0s
Deploy Application / deploy (push) Canceled after 0s
Mirror to Codeberg / mirror (push) Canceled after 0s
Mirror to PrivacyGuides / mirror (push) Canceled after 0s

This commit is contained in:
lockbitchat
2026-09-24 00:52:14 -04:00
parent eac3009339
commit cd9d78d398
60 changed files with 943 additions and 292 deletions
+4
View File
@@ -1,5 +1,9 @@
# Changelog
## v6.8.8 — Project support section
Added a section to support the project.
## v6.8.6 — Desktop 1.0.4 downloads, and a simpler roadmap
The download buttons now give you desktop version 1.0.4, which fetches its relay
+1 -1
View File
@@ -9,7 +9,7 @@
No accounts. No servers storing your messages. No installation required.
[![License: MIT](https://img.shields.io/badge/License-MIT-f0892a.svg)](LICENSE)
[![Version](https://img.shields.io/badge/version-6.8.6-3ecf8e.svg)](CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-6.8.8-3ecf8e.svg)](CHANGELOG.md)
[![Get it from the Snap Store](https://snapcraft.io/securebit-chat/badge.svg)](https://snapcraft.io/securebit-chat)
[![PWA](https://img.shields.io/badge/PWA-installable-3ecf8e.svg)](#install-as-an-app)
[![Encryption](https://img.shields.io/badge/crypto-ECDH%20P--384%20%C2%B7%20AES--256--GCM-blue.svg)](#security-model)
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/ar/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/ar.js?v=1790219928897"></script>
<script type="module" src="/src/i18n/dict/ar.js?v=1790225533889"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><g fill="none" fill-rule="evenodd"><circle cx="16" cy="16" r="16" fill="#F7931A"/><path fill="#FFF" fill-rule="nonzero" d="M23.189 14.02c.314-2.096-1.283-3.223-3.465-3.975l.708-2.84-1.728-.43-.69 2.765c-.454-.114-.92-.22-1.385-.326l.695-2.783L15.596 6l-.708 2.839c-.376-.086-.746-.17-1.104-.26l.002-.009-2.384-.595-.46 1.846s1.283.294 1.256.312c.7.175.826.638.805 1.006l-.806 3.235c.048.012.11.03.18.057l-.183-.045-1.13 4.532c-.086.212-.303.531-.793.41.018.025-1.256-.313-1.256-.313l-.858 1.978 2.25.561c.418.105.828.215 1.231.318l-.715 2.872 1.727.43.708-2.84c.472.127.93.245 1.378.357l-.706 2.828 1.728.43.715-2.866c2.948.558 5.164.333 6.097-2.333.752-2.146-.037-3.385-1.588-4.192 1.13-.26 1.98-1.003 2.207-2.538zm-3.95 5.538c-.533 2.147-4.148.986-5.32.695l.95-3.805c1.172.293 4.929.872 4.37 3.11zm.535-5.569c-.487 1.953-3.495.96-4.47.717l.86-3.45c.975.243 4.118.696 3.61 2.733z"/></g></svg>

After

Width:  |  Height:  |  Size: 953 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><g fill="none" fill-rule="evenodd"><circle cx="16" cy="16" r="16" fill="#627EEA"/><g fill="#FFF" fill-rule="nonzero"><path fill-opacity=".602" d="M16.498 4v8.87l7.497 3.35z"/><path d="M16.498 4L9 16.22l7.498-3.35z"/><path fill-opacity=".602" d="M16.498 21.968v6.027L24 17.616z"/><path d="M16.498 27.995v-6.028L9 17.616z"/><path fill-opacity=".2" d="M16.498 20.573l7.497-4.353-7.497-3.348z"/><path fill-opacity=".602" d="M9 16.22l7.498 4.353v-7.701z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 525 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 37 37" shape-rendering="crispEdges"><path fill="#111114" d="M0 0h7v1h-7zM8 0h2v1h-2zM11 0h2v1h-2zM14 0h1v1h-1zM16 0h1v1h-1zM18 0h1v1h-1zM20 0h6v1h-6zM28 0h1v1h-1zM30 0h7v1h-7zM0 1h1v1h-1zM6 1h1v1h-1zM8 1h1v1h-1zM11 1h1v1h-1zM14 1h2v1h-2zM18 1h2v1h-2zM25 1h3v1h-3zM30 1h1v1h-1zM36 1h1v1h-1zM0 2h1v1h-1zM2 2h3v1h-3zM6 2h1v1h-1zM8 2h1v1h-1zM10 2h2v1h-2zM13 2h1v1h-1zM15 2h1v1h-1zM20 2h1v1h-1zM22 2h1v1h-1zM28 2h1v1h-1zM30 2h1v1h-1zM32 2h3v1h-3zM36 2h1v1h-1zM0 3h1v1h-1zM2 3h3v1h-3zM6 3h1v1h-1zM14 3h1v1h-1zM16 3h8v1h-8zM25 3h4v1h-4zM30 3h1v1h-1zM32 3h3v1h-3zM36 3h1v1h-1zM0 4h1v1h-1zM2 4h3v1h-3zM6 4h1v1h-1zM10 4h2v1h-2zM18 4h7v1h-7zM26 4h1v1h-1zM30 4h1v1h-1zM32 4h3v1h-3zM36 4h1v1h-1zM0 5h1v1h-1zM6 5h1v1h-1zM8 5h3v1h-3zM12 5h1v1h-1zM15 5h4v1h-4zM20 5h1v1h-1zM23 5h1v1h-1zM27 5h2v1h-2zM30 5h1v1h-1zM36 5h1v1h-1zM0 6h7v1h-7zM8 6h1v1h-1zM10 6h1v1h-1zM12 6h1v1h-1zM14 6h1v1h-1zM16 6h1v1h-1zM18 6h1v1h-1zM20 6h1v1h-1zM22 6h1v1h-1zM24 6h1v1h-1zM26 6h1v1h-1zM28 6h1v1h-1zM30 6h7v1h-7zM8 7h1v1h-1zM11 7h3v1h-3zM15 7h2v1h-2zM18 7h1v1h-1zM22 7h1v1h-1zM24 7h1v1h-1zM2 8h3v1h-3zM6 8h1v1h-1zM8 8h3v1h-3zM12 8h1v1h-1zM17 8h1v1h-1zM22 8h1v1h-1zM25 8h7v1h-7zM34 8h3v1h-3zM0 9h1v1h-1zM2 9h2v1h-2zM5 9h1v1h-1zM7 9h3v1h-3zM11 9h3v1h-3zM15 9h3v1h-3zM20 9h2v1h-2zM24 9h1v1h-1zM26 9h1v1h-1zM28 9h2v1h-2zM33 9h3v1h-3zM0 10h4v1h-4zM6 10h2v1h-2zM11 10h2v1h-2zM15 10h3v1h-3zM21 10h1v1h-1zM24 10h2v1h-2zM27 10h1v1h-1zM30 10h2v1h-2zM34 10h3v1h-3zM1 11h3v1h-3zM5 11h1v1h-1zM7 11h1v1h-1zM9 11h2v1h-2zM12 11h2v1h-2zM15 11h4v1h-4zM20 11h2v1h-2zM27 11h1v1h-1zM29 11h2v1h-2zM3 12h2v1h-2zM6 12h1v1h-1zM8 12h1v1h-1zM11 12h1v1h-1zM13 12h2v1h-2zM16 12h1v1h-1zM20 12h2v1h-2zM25 12h2v1h-2zM29 12h6v1h-6zM36 12h1v1h-1zM1 13h2v1h-2zM4 13h2v1h-2zM8 13h1v1h-1zM11 13h9v1h-9zM21 13h1v1h-1zM23 13h4v1h-4zM28 13h1v1h-1zM33 13h1v1h-1zM35 13h1v1h-1zM0 14h3v1h-3zM6 14h4v1h-4zM11 14h3v1h-3zM17 14h2v1h-2zM26 14h3v1h-3zM32 14h5v1h-5zM1 15h2v1h-2zM4 15h1v1h-1zM7 15h1v1h-1zM13 15h4v1h-4zM19 15h1v1h-1zM21 15h3v1h-3zM28 15h1v1h-1zM30 15h2v1h-2zM35 15h1v1h-1zM0 16h7v1h-7zM9 16h2v1h-2zM12 16h2v1h-2zM17 16h3v1h-3zM21 16h1v1h-1zM23 16h1v1h-1zM25 16h12v1h-12zM0 17h1v1h-1zM3 17h3v1h-3zM7 17h1v1h-1zM11 17h2v1h-2zM14 17h1v1h-1zM20 17h1v1h-1zM23 17h1v1h-1zM26 17h1v1h-1zM31 17h1v1h-1zM33 17h1v1h-1zM0 18h1v1h-1zM2 18h1v1h-1zM4 18h1v1h-1zM6 18h1v1h-1zM8 18h2v1h-2zM11 18h1v1h-1zM13 18h1v1h-1zM20 18h2v1h-2zM23 18h3v1h-3zM27 18h4v1h-4zM33 18h1v1h-1zM35 18h2v1h-2zM0 19h4v1h-4zM5 19h1v1h-1zM7 19h1v1h-1zM11 19h4v1h-4zM16 19h2v1h-2zM20 19h2v1h-2zM26 19h2v1h-2zM29 19h2v1h-2zM33 19h1v1h-1zM2 20h2v1h-2zM5 20h3v1h-3zM11 20h2v1h-2zM16 20h3v1h-3zM20 20h2v1h-2zM23 20h4v1h-4zM30 20h3v1h-3zM34 20h1v1h-1zM2 21h2v1h-2zM5 21h1v1h-1zM7 21h3v1h-3zM11 21h3v1h-3zM16 21h1v1h-1zM18 21h2v1h-2zM22 21h2v1h-2zM28 21h2v1h-2zM31 21h1v1h-1zM2 22h1v1h-1zM4 22h1v1h-1zM6 22h2v1h-2zM9 22h2v1h-2zM14 22h3v1h-3zM19 22h7v1h-7zM27 22h2v1h-2zM31 22h1v1h-1zM33 22h1v1h-1zM35 22h2v1h-2zM3 23h1v1h-1zM5 23h1v1h-1zM7 23h1v1h-1zM10 23h2v1h-2zM13 23h2v1h-2zM16 23h1v1h-1zM19 23h1v1h-1zM23 23h1v1h-1zM27 23h4v1h-4zM1 24h2v1h-2zM4 24h4v1h-4zM9 24h1v1h-1zM11 24h2v1h-2zM15 24h3v1h-3zM20 24h2v1h-2zM28 24h5v1h-5zM34 24h1v1h-1zM0 25h1v1h-1zM2 25h1v1h-1zM9 25h1v1h-1zM11 25h2v1h-2zM14 25h1v1h-1zM16 25h1v1h-1zM19 25h2v1h-2zM24 25h2v1h-2zM28 25h1v1h-1zM31 25h1v1h-1zM35 25h1v1h-1zM0 26h1v1h-1zM3 26h4v1h-4zM8 26h1v1h-1zM10 26h1v1h-1zM13 26h3v1h-3zM18 26h1v1h-1zM21 26h1v1h-1zM27 26h3v1h-3zM31 26h1v1h-1zM34 26h1v1h-1zM36 26h1v1h-1zM0 27h1v1h-1zM2 27h1v1h-1zM4 27h1v1h-1zM9 27h1v1h-1zM12 27h4v1h-4zM19 27h1v1h-1zM21 27h2v1h-2zM24 27h1v1h-1zM0 28h1v1h-1zM4 28h4v1h-4zM10 28h4v1h-4zM15 28h4v1h-4zM20 28h1v1h-1zM25 28h2v1h-2zM28 28h9v1h-9zM8 29h2v1h-2zM12 29h1v1h-1zM14 29h6v1h-6zM23 29h1v1h-1zM25 29h1v1h-1zM28 29h1v1h-1zM32 29h2v1h-2zM35 29h1v1h-1zM0 30h7v1h-7zM9 30h2v1h-2zM12 30h1v1h-1zM14 30h1v1h-1zM17 30h4v1h-4zM25 30h1v1h-1zM28 30h1v1h-1zM30 30h1v1h-1zM32 30h1v1h-1zM34 30h1v1h-1zM36 30h1v1h-1zM0 31h1v1h-1zM6 31h1v1h-1zM12 31h6v1h-6zM19 31h2v1h-2zM22 31h2v1h-2zM28 31h1v1h-1zM32 31h2v1h-2zM36 31h1v1h-1zM0 32h1v1h-1zM2 32h3v1h-3zM6 32h1v1h-1zM8 32h1v1h-1zM10 32h3v1h-3zM15 32h3v1h-3zM20 32h2v1h-2zM24 32h9v1h-9zM34 32h2v1h-2zM0 33h1v1h-1zM2 33h3v1h-3zM6 33h1v1h-1zM8 33h7v1h-7zM18 33h1v1h-1zM25 33h1v1h-1zM27 33h4v1h-4zM32 33h2v1h-2zM0 34h1v1h-1zM2 34h3v1h-3zM6 34h1v1h-1zM8 34h2v1h-2zM12 34h1v1h-1zM16 34h1v1h-1zM21 34h4v1h-4zM26 34h2v1h-2zM31 34h1v1h-1zM33 34h1v1h-1zM36 34h1v1h-1zM0 35h1v1h-1zM6 35h1v1h-1zM9 35h2v1h-2zM12 35h3v1h-3zM16 35h1v1h-1zM19 35h2v1h-2zM22 35h2v1h-2zM28 35h1v1h-1zM30 35h2v1h-2zM36 35h1v1h-1zM0 36h7v1h-7zM12 36h1v1h-1zM14 36h1v1h-1zM19 36h1v1h-1zM22 36h5v1h-5zM29 36h1v1h-1zM32 36h1v1h-1zM34 36h3v1h-3z"/></svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 37 37" shape-rendering="crispEdges"><path fill="#111114" d="M0 0h7v1h-7zM8 0h3v1h-3zM16 0h4v1h-4zM22 0h3v1h-3zM27 0h2v1h-2zM30 0h7v1h-7zM0 1h1v1h-1zM6 1h1v1h-1zM8 1h1v1h-1zM11 1h1v1h-1zM15 1h1v1h-1zM17 1h1v1h-1zM19 1h1v1h-1zM22 1h1v1h-1zM25 1h1v1h-1zM27 1h2v1h-2zM30 1h1v1h-1zM36 1h1v1h-1zM0 2h1v1h-1zM2 2h3v1h-3zM6 2h1v1h-1zM8 2h1v1h-1zM11 2h1v1h-1zM13 2h2v1h-2zM16 2h1v1h-1zM18 2h2v1h-2zM21 2h3v1h-3zM26 2h1v1h-1zM28 2h1v1h-1zM30 2h1v1h-1zM32 2h3v1h-3zM36 2h1v1h-1zM0 3h1v1h-1zM2 3h3v1h-3zM6 3h1v1h-1zM9 3h1v1h-1zM13 3h1v1h-1zM15 3h2v1h-2zM21 3h2v1h-2zM25 3h1v1h-1zM27 3h1v1h-1zM30 3h1v1h-1zM32 3h3v1h-3zM36 3h1v1h-1zM0 4h1v1h-1zM2 4h3v1h-3zM6 4h1v1h-1zM17 4h1v1h-1zM19 4h1v1h-1zM23 4h2v1h-2zM26 4h1v1h-1zM28 4h1v1h-1zM30 4h1v1h-1zM32 4h3v1h-3zM36 4h1v1h-1zM0 5h1v1h-1zM6 5h1v1h-1zM8 5h2v1h-2zM11 5h3v1h-3zM16 5h4v1h-4zM21 5h3v1h-3zM25 5h3v1h-3zM30 5h1v1h-1zM36 5h1v1h-1zM0 6h7v1h-7zM8 6h1v1h-1zM10 6h1v1h-1zM12 6h1v1h-1zM14 6h1v1h-1zM16 6h1v1h-1zM18 6h1v1h-1zM20 6h1v1h-1zM22 6h1v1h-1zM24 6h1v1h-1zM26 6h1v1h-1zM28 6h1v1h-1zM30 6h7v1h-7zM8 7h2v1h-2zM11 7h2v1h-2zM15 7h2v1h-2zM19 7h3v1h-3zM28 7h1v1h-1zM2 8h3v1h-3zM6 8h1v1h-1zM8 8h1v1h-1zM12 8h1v1h-1zM14 8h2v1h-2zM17 8h2v1h-2zM24 8h2v1h-2zM27 8h1v1h-1zM29 8h3v1h-3zM34 8h3v1h-3zM0 9h2v1h-2zM3 9h3v1h-3zM7 9h2v1h-2zM14 9h1v1h-1zM18 9h2v1h-2zM22 9h2v1h-2zM26 9h1v1h-1zM28 9h2v1h-2zM36 9h1v1h-1zM1 10h2v1h-2zM5 10h2v1h-2zM8 10h3v1h-3zM13 10h1v1h-1zM17 10h2v1h-2zM20 10h2v1h-2zM23 10h2v1h-2zM27 10h4v1h-4zM32 10h1v1h-1zM35 10h2v1h-2zM4 11h2v1h-2zM7 11h2v1h-2zM11 11h1v1h-1zM13 11h2v1h-2zM20 11h2v1h-2zM24 11h1v1h-1zM26 11h2v1h-2zM30 11h2v1h-2zM33 11h1v1h-1zM0 12h4v1h-4zM5 12h2v1h-2zM8 12h2v1h-2zM11 12h1v1h-1zM15 12h2v1h-2zM18 12h1v1h-1zM23 12h2v1h-2zM26 12h2v1h-2zM29 12h2v1h-2zM34 12h1v1h-1zM36 12h1v1h-1zM1 13h1v1h-1zM3 13h3v1h-3zM10 13h4v1h-4zM19 13h2v1h-2zM22 13h1v1h-1zM28 13h1v1h-1zM31 13h1v1h-1zM33 13h1v1h-1zM36 13h1v1h-1zM0 14h1v1h-1zM6 14h1v1h-1zM10 14h4v1h-4zM15 14h4v1h-4zM20 14h2v1h-2zM23 14h3v1h-3zM27 14h1v1h-1zM30 14h2v1h-2zM33 14h1v1h-1zM35 14h2v1h-2zM0 15h2v1h-2zM5 15h1v1h-1zM8 15h5v1h-5zM17 15h1v1h-1zM19 15h2v1h-2zM22 15h1v1h-1zM26 15h1v1h-1zM29 15h3v1h-3zM35 15h2v1h-2zM1 16h2v1h-2zM5 16h3v1h-3zM9 16h4v1h-4zM16 16h4v1h-4zM22 16h1v1h-1zM25 16h1v1h-1zM27 16h2v1h-2zM30 16h1v1h-1zM32 16h1v1h-1zM34 16h3v1h-3zM0 17h2v1h-2zM5 17h1v1h-1zM7 17h3v1h-3zM13 17h2v1h-2zM16 17h4v1h-4zM26 17h1v1h-1zM29 17h1v1h-1zM31 17h1v1h-1zM33 17h1v1h-1zM35 17h1v1h-1zM1 18h2v1h-2zM4 18h1v1h-1zM6 18h4v1h-4zM11 18h2v1h-2zM16 18h1v1h-1zM18 18h4v1h-4zM23 18h1v1h-1zM27 18h4v1h-4zM32 18h1v1h-1zM34 18h1v1h-1zM36 18h1v1h-1zM0 19h1v1h-1zM3 19h3v1h-3zM7 19h1v1h-1zM11 19h4v1h-4zM17 19h1v1h-1zM21 19h4v1h-4zM26 19h3v1h-3zM31 19h1v1h-1zM33 19h1v1h-1zM0 20h2v1h-2zM3 20h4v1h-4zM8 20h1v1h-1zM11 20h1v1h-1zM18 20h10v1h-10zM29 20h2v1h-2zM34 20h1v1h-1zM0 21h1v1h-1zM2 21h2v1h-2zM9 21h1v1h-1zM13 21h2v1h-2zM17 21h2v1h-2zM23 21h1v1h-1zM28 21h1v1h-1zM31 21h1v1h-1zM33 21h1v1h-1zM35 21h1v1h-1zM1 22h1v1h-1zM3 22h4v1h-4zM8 22h2v1h-2zM11 22h3v1h-3zM15 22h1v1h-1zM18 22h2v1h-2zM23 22h5v1h-5zM30 22h3v1h-3zM36 22h1v1h-1zM1 23h1v1h-1zM4 23h1v1h-1zM8 23h2v1h-2zM11 23h2v1h-2zM14 23h4v1h-4zM20 23h1v1h-1zM24 23h1v1h-1zM26 23h5v1h-5zM33 23h1v1h-1zM35 23h1v1h-1zM1 24h1v1h-1zM3 24h4v1h-4zM8 24h1v1h-1zM10 24h2v1h-2zM13 24h3v1h-3zM18 24h2v1h-2zM23 24h1v1h-1zM27 24h1v1h-1zM29 24h2v1h-2zM32 24h1v1h-1zM34 24h3v1h-3zM0 25h2v1h-2zM5 25h1v1h-1zM7 25h3v1h-3zM11 25h3v1h-3zM16 25h1v1h-1zM21 25h2v1h-2zM24 25h1v1h-1zM27 25h2v1h-2zM31 25h1v1h-1zM33 25h1v1h-1zM35 25h1v1h-1zM0 26h1v1h-1zM2 26h1v1h-1zM6 26h1v1h-1zM8 26h1v1h-1zM10 26h1v1h-1zM12 26h1v1h-1zM15 26h6v1h-6zM22 26h1v1h-1zM26 26h2v1h-2zM29 26h2v1h-2zM32 26h1v1h-1zM36 26h1v1h-1zM0 27h1v1h-1zM2 27h3v1h-3zM9 27h1v1h-1zM12 27h3v1h-3zM16 27h1v1h-1zM18 27h1v1h-1zM24 27h1v1h-1zM27 27h2v1h-2zM36 27h1v1h-1zM0 28h1v1h-1zM2 28h1v1h-1zM4 28h1v1h-1zM6 28h1v1h-1zM13 28h2v1h-2zM16 28h1v1h-1zM19 28h1v1h-1zM21 28h2v1h-2zM25 28h1v1h-1zM27 28h10v1h-10zM8 29h1v1h-1zM14 29h2v1h-2zM17 29h1v1h-1zM19 29h1v1h-1zM22 29h3v1h-3zM26 29h3v1h-3zM32 29h3v1h-3zM36 29h1v1h-1zM0 30h7v1h-7zM9 30h1v1h-1zM14 30h6v1h-6zM24 30h2v1h-2zM28 30h1v1h-1zM30 30h1v1h-1zM32 30h2v1h-2zM35 30h2v1h-2zM0 31h1v1h-1zM6 31h1v1h-1zM13 31h1v1h-1zM16 31h1v1h-1zM19 31h1v1h-1zM21 31h4v1h-4zM26 31h1v1h-1zM28 31h1v1h-1zM32 31h1v1h-1zM36 31h1v1h-1zM0 32h1v1h-1zM2 32h3v1h-3zM6 32h1v1h-1zM8 32h4v1h-4zM14 32h3v1h-3zM19 32h1v1h-1zM21 32h1v1h-1zM24 32h10v1h-10zM35 32h2v1h-2zM0 33h1v1h-1zM2 33h3v1h-3zM6 33h1v1h-1zM8 33h3v1h-3zM12 33h1v1h-1zM14 33h1v1h-1zM18 33h3v1h-3zM29 33h2v1h-2zM33 33h1v1h-1zM0 34h1v1h-1zM2 34h3v1h-3zM6 34h1v1h-1zM8 34h1v1h-1zM12 34h1v1h-1zM15 34h1v1h-1zM18 34h1v1h-1zM20 34h1v1h-1zM22 34h4v1h-4zM27 34h1v1h-1zM30 34h2v1h-2zM36 34h1v1h-1zM0 35h1v1h-1zM6 35h1v1h-1zM12 35h1v1h-1zM15 35h2v1h-2zM18 35h1v1h-1zM20 35h4v1h-4zM26 35h1v1h-1zM28 35h5v1h-5zM36 35h1v1h-1zM0 36h7v1h-7zM10 36h5v1h-5zM16 36h1v1h-1zM19 36h1v1h-1zM22 36h6v1h-6zM31 36h1v1h-1zM33 36h4v1h-4z"/></svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 33" shape-rendering="crispEdges"><path fill="#111114" d="M0 0h7v1h-7zM9 0h1v1h-1zM11 0h1v1h-1zM14 0h2v1h-2zM17 0h1v1h-1zM21 0h2v1h-2zM26 0h7v1h-7zM0 1h1v1h-1zM6 1h1v1h-1zM8 1h1v1h-1zM10 1h1v1h-1zM12 1h2v1h-2zM15 1h1v1h-1zM17 1h1v1h-1zM19 1h2v1h-2zM24 1h1v1h-1zM26 1h1v1h-1zM32 1h1v1h-1zM0 2h1v1h-1zM2 2h3v1h-3zM6 2h1v1h-1zM8 2h1v1h-1zM10 2h3v1h-3zM14 2h1v1h-1zM17 2h2v1h-2zM21 2h1v1h-1zM26 2h1v1h-1zM28 2h3v1h-3zM32 2h1v1h-1zM0 3h1v1h-1zM2 3h3v1h-3zM6 3h1v1h-1zM8 3h2v1h-2zM12 3h1v1h-1zM14 3h2v1h-2zM18 3h2v1h-2zM21 3h4v1h-4zM26 3h1v1h-1zM28 3h3v1h-3zM32 3h1v1h-1zM0 4h1v1h-1zM2 4h3v1h-3zM6 4h1v1h-1zM8 4h1v1h-1zM10 4h1v1h-1zM12 4h1v1h-1zM14 4h3v1h-3zM19 4h2v1h-2zM23 4h1v1h-1zM26 4h1v1h-1zM28 4h3v1h-3zM32 4h1v1h-1zM0 5h1v1h-1zM6 5h1v1h-1zM8 5h2v1h-2zM11 5h4v1h-4zM17 5h2v1h-2zM20 5h2v1h-2zM24 5h1v1h-1zM26 5h1v1h-1zM32 5h1v1h-1zM0 6h7v1h-7zM8 6h1v1h-1zM10 6h1v1h-1zM12 6h1v1h-1zM14 6h1v1h-1zM16 6h1v1h-1zM18 6h1v1h-1zM20 6h1v1h-1zM22 6h1v1h-1zM24 6h1v1h-1zM26 6h7v1h-7zM9 7h6v1h-6zM17 7h1v1h-1zM20 7h1v1h-1zM2 8h1v1h-1zM5 8h5v1h-5zM11 8h1v1h-1zM16 8h1v1h-1zM18 8h1v1h-1zM23 8h3v1h-3zM27 8h5v1h-5zM1 9h1v1h-1zM3 9h1v1h-1zM5 9h1v1h-1zM7 9h1v1h-1zM9 9h2v1h-2zM14 9h2v1h-2zM17 9h1v1h-1zM19 9h1v1h-1zM21 9h1v1h-1zM24 9h4v1h-4zM30 9h1v1h-1zM0 10h3v1h-3zM4 10h3v1h-3zM8 10h4v1h-4zM14 10h2v1h-2zM18 10h6v1h-6zM25 10h1v1h-1zM30 10h1v1h-1zM32 10h1v1h-1zM2 11h4v1h-4zM7 11h1v1h-1zM9 11h1v1h-1zM11 11h2v1h-2zM14 11h2v1h-2zM17 11h4v1h-4zM22 11h1v1h-1zM24 11h1v1h-1zM26 11h4v1h-4zM31 11h1v1h-1zM0 12h3v1h-3zM5 12h3v1h-3zM12 12h2v1h-2zM15 12h1v1h-1zM19 12h2v1h-2zM23 12h1v1h-1zM26 12h1v1h-1zM28 12h1v1h-1zM32 12h1v1h-1zM0 13h1v1h-1zM2 13h1v1h-1zM11 13h1v1h-1zM13 13h1v1h-1zM17 13h1v1h-1zM19 13h2v1h-2zM22 13h1v1h-1zM24 13h1v1h-1zM27 13h1v1h-1zM29 13h1v1h-1zM31 13h1v1h-1zM1 14h2v1h-2zM4 14h1v1h-1zM6 14h1v1h-1zM10 14h2v1h-2zM14 14h3v1h-3zM18 14h1v1h-1zM20 14h1v1h-1zM22 14h2v1h-2zM25 14h1v1h-1zM27 14h3v1h-3zM32 14h1v1h-1zM0 15h2v1h-2zM3 15h2v1h-2zM7 15h3v1h-3zM11 15h1v1h-1zM13 15h1v1h-1zM16 15h1v1h-1zM22 15h1v1h-1zM29 15h1v1h-1zM32 15h1v1h-1zM0 16h1v1h-1zM3 16h1v1h-1zM6 16h3v1h-3zM10 16h1v1h-1zM14 16h2v1h-2zM17 16h2v1h-2zM23 16h2v1h-2zM26 16h2v1h-2zM31 16h2v1h-2zM0 17h1v1h-1zM2 17h2v1h-2zM9 17h2v1h-2zM12 17h4v1h-4zM17 17h3v1h-3zM23 17h2v1h-2zM26 17h2v1h-2zM29 17h1v1h-1zM31 17h2v1h-2zM0 18h3v1h-3zM4 18h4v1h-4zM9 18h1v1h-1zM12 18h3v1h-3zM17 18h4v1h-4zM23 18h3v1h-3zM28 18h3v1h-3zM32 18h1v1h-1zM1 19h2v1h-2zM5 19h1v1h-1zM8 19h2v1h-2zM11 19h1v1h-1zM14 19h3v1h-3zM20 19h1v1h-1zM24 19h1v1h-1zM27 19h1v1h-1zM29 19h1v1h-1zM31 19h1v1h-1zM1 20h1v1h-1zM3 20h1v1h-1zM5 20h2v1h-2zM8 20h2v1h-2zM13 20h2v1h-2zM16 20h2v1h-2zM21 20h1v1h-1zM23 20h1v1h-1zM26 20h5v1h-5zM2 21h2v1h-2zM5 21h1v1h-1zM7 21h9v1h-9zM17 21h4v1h-4zM22 21h1v1h-1zM24 21h1v1h-1zM27 21h1v1h-1zM29 21h1v1h-1zM31 21h1v1h-1zM0 22h2v1h-2zM3 22h1v1h-1zM6 22h5v1h-5zM15 22h3v1h-3zM19 22h1v1h-1zM21 22h1v1h-1zM23 22h4v1h-4zM30 22h1v1h-1zM32 22h1v1h-1zM5 23h1v1h-1zM7 23h5v1h-5zM15 23h2v1h-2zM18 23h1v1h-1zM20 23h1v1h-1zM23 23h2v1h-2zM27 23h1v1h-1zM29 23h1v1h-1zM31 23h1v1h-1zM0 24h2v1h-2zM4 24h5v1h-5zM10 24h1v1h-1zM16 24h1v1h-1zM18 24h2v1h-2zM21 24h1v1h-1zM24 24h5v1h-5zM31 24h2v1h-2zM8 25h1v1h-1zM10 25h1v1h-1zM17 25h2v1h-2zM20 25h1v1h-1zM23 25h2v1h-2zM28 25h1v1h-1zM31 25h2v1h-2zM0 26h7v1h-7zM8 26h1v1h-1zM10 26h12v1h-12zM23 26h2v1h-2zM26 26h1v1h-1zM28 26h1v1h-1zM31 26h2v1h-2zM0 27h1v1h-1zM6 27h1v1h-1zM8 27h2v1h-2zM14 27h2v1h-2zM18 27h3v1h-3zM22 27h3v1h-3zM28 27h2v1h-2zM31 27h2v1h-2zM0 28h1v1h-1zM2 28h3v1h-3zM6 28h1v1h-1zM9 28h1v1h-1zM14 28h3v1h-3zM18 28h1v1h-1zM20 28h9v1h-9zM0 29h1v1h-1zM2 29h3v1h-3zM6 29h1v1h-1zM10 29h2v1h-2zM13 29h1v1h-1zM15 29h3v1h-3zM20 29h1v1h-1zM24 29h2v1h-2zM28 29h1v1h-1zM30 29h1v1h-1zM32 29h1v1h-1zM0 30h1v1h-1zM2 30h3v1h-3zM6 30h1v1h-1zM8 30h1v1h-1zM10 30h4v1h-4zM15 30h1v1h-1zM19 30h5v1h-5zM25 30h2v1h-2zM28 30h2v1h-2zM31 30h2v1h-2zM0 31h1v1h-1zM6 31h1v1h-1zM10 31h2v1h-2zM13 31h1v1h-1zM15 31h1v1h-1zM19 31h2v1h-2zM23 31h2v1h-2zM27 31h1v1h-1zM29 31h1v1h-1zM0 32h7v1h-7zM18 32h1v1h-1zM23 32h3v1h-3zM30 32h1v1h-1zM32 32h1v1h-1z"/></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

+1
View File
@@ -0,0 +1 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><g fill="none"><circle fill="#EF0027" cx="16" cy="16" r="16"/><path d="M21.932 9.913L7.5 7.257l7.595 19.112 10.583-12.894-3.746-3.562zm-.232 1.17l2.208 2.099-6.038 1.093 3.83-3.192zm-5.142 2.973l-6.364-5.278 10.402 1.914-4.038 3.364zm-.453.934l-1.038 8.58L9.472 9.487l6.633 5.502zm.96.455l6.687-1.21-7.67 9.343.983-8.133z" fill="#FFF"/></g></svg>

After

Width:  |  Height:  |  Size: 429 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><g fill="none" fill-rule="evenodd"><circle cx="16" cy="16" r="16" fill="#26A17B"/><path fill="#FFF" d="M17.922 17.383v-.002c-.11.008-.677.042-1.942.042-1.01 0-1.721-.03-1.971-.042v.003c-3.888-.171-6.79-.848-6.79-1.658 0-.809 2.902-1.486 6.79-1.66v2.644c.254.018.982.061 1.988.061 1.207 0 1.812-.05 1.925-.06v-2.643c3.88.173 6.775.85 6.775 1.658 0 .81-2.895 1.485-6.775 1.657m0-3.59v-2.366h5.414V7.819H8.595v3.608h5.414v2.365c-4.4.202-7.709 1.074-7.709 2.118 0 1.044 3.309 1.915 7.709 2.118v7.582h3.913v-7.584c4.393-.202 7.694-1.073 7.694-2.116 0-1.043-3.301-1.914-7.694-2.117"/></g></svg>

After

Width:  |  Height:  |  Size: 648 B

+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/de/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/de.js?v=1790219928897"></script>
<script type="module" src="/src/i18n/dict/de.js?v=1790225533889"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>
+20 -20
View File
File diff suppressed because one or more lines are too long
+4 -4
View File
File diff suppressed because one or more lines are too long
Vendored
+4 -4
View File
File diff suppressed because one or more lines are too long
+3 -3
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -7,7 +7,7 @@ this document describes.
| | |
| --- | --- |
| Release | v6.8.6 |
| Release | v6.8.8 |
| Protocol version | 4.1 |
| Ratchet wire version | 1 |
@@ -347,5 +347,5 @@ no leg may stop a capture it borrowed.
## Scope
This describes the browser implementation as it stands in v6.8.6. It is not a
This describes the browser implementation as it stands in v6.8.8. It is not a
substitute for independent cryptographic review.
+2 -2
View File
@@ -153,7 +153,7 @@
</thead>
<tbody><tr>
<td>Release</td>
<td>v6.8.6</td>
<td>v6.8.8</td>
</tr>
<tr>
<td>Protocol version</td>
@@ -486,7 +486,7 @@
shared across every leg, and stopped when the call, the group or the tab ends;
no leg may stop a capture it borrowed.</p>
<h2 id="scope">Scope</h2>
<p>This describes the browser implementation as it stands in v6.8.6. It is not a
<p>This describes the browser implementation as it stands in v6.8.8. It is not a
substitute for independent cryptographic review.</p>
<nav class="more">
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/es/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/es.js?v=1790219928897"></script>
<script type="module" src="/src/i18n/dict/es.js?v=1790225533889"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/fa/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/fa.js?v=1790219928897"></script>
<script type="module" src="/src/i18n/dict/fa.js?v=1790225533889"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/fr/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/fr.js?v=1790219928897"></script>
<script type="module" src="/src/i18n/dict/fr.js?v=1790225533889"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/he/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/he.js?v=1790219928897"></script>
<script type="module" src="/src/i18n/dict/he.js?v=1790225533889"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/hi/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/hi.js?v=1790219928897"></script>
<script type="module" src="/src/i18n/dict/hi.js?v=1790225533889"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>
+18 -18
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,18 +287,18 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -486,12 +486,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/ko/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/ko.js?v=1790219928897"></script>
<script type="module" src="/src/i18n/dict/ko.js?v=1790225533889"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>
+12
View File
@@ -42,6 +42,18 @@
"theme.system": "النظام",
"theme.light": "فاتح",
"theme.dark": "داكن",
"donate.eyebrow": "تبرّع بالعملات المشفّرة",
"donate.title": "ساعدنا في إبقاء SecureBit مستقلًا",
"donate.description": "يذهب كل تبرّع إلى التطوير وعمليات التدقيق الأمني.",
"donate.copy": "نسخ",
"donate.copied": "تم النسخ",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "شبكة Bitcoin",
"donate.net.eth": "الشبكة الرئيسية لـ Ethereum",
"donate.warn.usdt": "أرسل USDT على شبكة Tron (TRC-20) فقط.",
"donate.warn.btc": "أرسل BTC على شبكة Bitcoin فقط.",
"donate.warn.eth": "أرسل ETH على الشبكة الرئيسية لـ Ethereum فقط.",
"donate.qrAlt": "رمز QR لعنوان التبرّع بـ {coin}",
"community.title": "انضمّ إلى مستقبل الخصوصية",
"community.description": "ينمو SecureBit بفضل مجتمعه. أفكاركم وملاحظاتكم هي ما يصوغ مستقبل التواصل الآمن - مبنيّ في العلن، مع تحقّق ASN.1 كامل من طرف إلى طرف.",
"community.github": "مستودع GitHub",
+12
View File
@@ -42,6 +42,18 @@
"theme.system": "System",
"theme.light": "Hell",
"theme.dark": "Dunkel",
"donate.eyebrow": "Mit Krypto spenden",
"donate.title": "Halte SecureBit unabhängig",
"donate.description": "Jede Spende fließt in Entwicklung und Audits.",
"donate.copy": "Kopieren",
"donate.copied": "Kopiert",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Bitcoin-Netzwerk",
"donate.net.eth": "Ethereum-Mainnet",
"donate.warn.usdt": "Sende nur USDT über Tron (TRC-20).",
"donate.warn.btc": "Sende nur BTC über das Bitcoin-Netzwerk.",
"donate.warn.eth": "Sende nur ETH über das Ethereum-Mainnet.",
"donate.qrAlt": "QR-Code der {coin}-Spendenadresse",
"community.title": "Gestalten Sie die Zukunft der Privatsphäre mit",
"community.description": "SecureBit wächst durch seine Community. Ihre Ideen und Ihr Feedback prägen die Zukunft sicherer Kommunikation - offen entwickelt, mit vollständiger ASN.1-Validierung von Ende zu Ende.",
"community.github": "GitHub-Repository",
+12
View File
@@ -37,6 +37,18 @@
"theme.system": "System",
"theme.light": "Light",
"theme.dark": "Dark",
"donate.eyebrow": "Donate in crypto",
"donate.title": "Keep SecureBit independent",
"donate.description": "Every donation goes to development and audits.",
"donate.copy": "Copy",
"donate.copied": "Copied",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Bitcoin network",
"donate.net.eth": "Ethereum mainnet",
"donate.warn.usdt": "Send only USDT on Tron (TRC-20).",
"donate.warn.btc": "Send only BTC on the Bitcoin network.",
"donate.warn.eth": "Send only ETH on Ethereum mainnet.",
"donate.qrAlt": "QR code of the {coin} donation address",
"community.title": "Join the future of privacy",
"community.description": "SecureBit grows thanks to its community. Your ideas and feedback shape the future of secure communication - built in the open, with complete ASN.1 validation end-to-end.",
"community.github": "GitHub Repository",
+12
View File
@@ -42,6 +42,18 @@
"theme.system": "Sistema",
"theme.light": "Claro",
"theme.dark": "Oscuro",
"donate.eyebrow": "Dona en cripto",
"donate.title": "Mantén SecureBit independiente",
"donate.description": "Cada donación se destina al desarrollo y a las auditorías.",
"donate.copy": "Copiar",
"donate.copied": "Copiado",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Red Bitcoin",
"donate.net.eth": "Red principal de Ethereum",
"donate.warn.usdt": "Envía solo USDT en Tron (TRC-20).",
"donate.warn.btc": "Envía solo BTC en la red Bitcoin.",
"donate.warn.eth": "Envía solo ETH en la red principal de Ethereum.",
"donate.qrAlt": "Código QR de la dirección de donación en {coin}",
"community.title": "Construye el futuro de la privacidad",
"community.description": "SecureBit crece gracias a su comunidad. Tus ideas y comentarios dan forma al futuro de la comunicación segura, desarrollada de forma abierta y con validación ASN.1 completa de extremo a extremo.",
"community.github": "Repositorio en GitHub",
+12
View File
@@ -42,6 +42,18 @@
"theme.system": "سیستم",
"theme.light": "روشن",
"theme.dark": "تیره",
"donate.eyebrow": "اهدای کمک با رمزارز",
"donate.title": "به مستقل ماندن SecureBit کمک کنید",
"donate.description": "هر کمک صرف توسعه و ممیزی‌های امنیتی می‌شود.",
"donate.copy": "کپی",
"donate.copied": "کپی شد",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "شبکه Bitcoin",
"donate.net.eth": "شبکه اصلی Ethereum",
"donate.warn.usdt": "فقط USDT را روی شبکه Tron (TRC-20) بفرستید.",
"donate.warn.btc": "فقط BTC را روی شبکه Bitcoin بفرستید.",
"donate.warn.eth": "فقط ETH را روی شبکه اصلی Ethereum بفرستید.",
"donate.qrAlt": "کد QR نشانی کمک با {coin}",
"community.title": "به آیندهٔ حریم خصوصی بپیوندید",
"community.description": "‏SecureBit به‌لطف جامعه‌اش رشد می‌کند. ایده‌ها و بازخوردهای شما آیندهٔ ارتباط امن را شکل می‌دهد - ساخته‌شده در فضای باز، با اعتبارسنجی کامل ASN.1 از یک سر تا سر دیگر.",
"community.github": "مخزن GitHub",
+12
View File
@@ -37,6 +37,18 @@
"theme.system": "Système",
"theme.light": "Clair",
"theme.dark": "Sombre",
"donate.eyebrow": "Faire un don en crypto",
"donate.title": "Gardons SecureBit indépendant",
"donate.description": "Chaque don finance le développement et les audits.",
"donate.copy": "Copier",
"donate.copied": "Copié",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Réseau Bitcoin",
"donate.net.eth": "Réseau principal Ethereum",
"donate.warn.usdt": "Envoyez uniquement de l'USDT sur Tron (TRC-20).",
"donate.warn.btc": "Envoyez uniquement du BTC sur le réseau Bitcoin.",
"donate.warn.eth": "Envoyez uniquement de l'ETH sur le réseau principal Ethereum.",
"donate.qrAlt": "QR code de l'adresse de don {coin}",
"community.title": "Construisez l'avenir de la vie privée",
"community.description": "SecureBit grandit grâce à sa communauté. Vos idées et vos retours façonnent l'avenir des communications sécurisées, développées à ciel ouvert, avec une validation ASN.1 complète de bout en bout.",
"community.github": "Dépôt GitHub",
+12
View File
@@ -42,6 +42,18 @@
"theme.system": "מערכת",
"theme.light": "בהיר",
"theme.dark": "כהה",
"donate.eyebrow": "תרומה בקריפטו",
"donate.title": "עזרו לשמור על SecureBit עצמאית",
"donate.description": "כל תרומה מופנית לפיתוח ולביקורות אבטחה.",
"donate.copy": "העתקה",
"donate.copied": "הועתק",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "רשת Bitcoin",
"donate.net.eth": "הרשת הראשית של Ethereum",
"donate.warn.usdt": "שלחו USDT ברשת Tron (TRC-20) בלבד.",
"donate.warn.btc": "שלחו BTC ברשת Bitcoin בלבד.",
"donate.warn.eth": "שלחו ETH ברשת הראשית של Ethereum בלבד.",
"donate.qrAlt": "קוד QR של כתובת התרומה ב-{coin}",
"community.title": "הצטרפו לעתיד של הפרטיות",
"community.description": "SecureBit גדל בזכות הקהילה שלו. הרעיונות והמשוב שלכם מעצבים את עתיד התקשורת המאובטחת - נבנה בגלוי, עם אימות ASN.1 מלא מקצה לקצה.",
"community.github": "מאגר GitHub",
+12
View File
@@ -37,6 +37,18 @@
"theme.system": "सिस्टम",
"theme.light": "हल्की",
"theme.dark": "गहरी",
"donate.eyebrow": "क्रिप्टो में दान करें",
"donate.title": "SecureBit को स्वतंत्र बनाए रखें",
"donate.description": "हर दान विकास और सुरक्षा ऑडिट पर खर्च होता है।",
"donate.copy": "कॉपी करें",
"donate.copied": "कॉपी हो गया",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Bitcoin नेटवर्क",
"donate.net.eth": "Ethereum मेननेट",
"donate.warn.usdt": "केवल Tron (TRC-20) पर USDT भेजें।",
"donate.warn.btc": "केवल Bitcoin नेटवर्क पर BTC भेजें।",
"donate.warn.eth": "केवल Ethereum मेननेट पर ETH भेजें।",
"donate.qrAlt": "{coin} दान पते का QR कोड",
"community.title": "निजता के भविष्य में शामिल हों",
"community.description": "SecureBit अपने समुदाय से बढ़ता है। आपके विचार और सुझाव सुरक्षित संवाद का भविष्य गढ़ते हैं - खुले में बना, और पूरे रास्ते पूरी ASN.1 जाँच के साथ।",
"community.github": "GitHub रिपॉज़िटरी",
+12
View File
@@ -37,6 +37,18 @@
"theme.system": "시스템",
"theme.light": "밝게",
"theme.dark": "어둡게",
"donate.eyebrow": "암호화폐로 후원하기",
"donate.title": "SecureBit의 독립을 지켜 주세요",
"donate.description": "모든 후원금은 개발과 보안 감사에 쓰입니다.",
"donate.copy": "복사",
"donate.copied": "복사됨",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "비트코인 네트워크",
"donate.net.eth": "이더리움 메인넷",
"donate.warn.usdt": "USDT는 Tron(TRC-20) 네트워크로만 보내세요.",
"donate.warn.btc": "BTC는 비트코인 네트워크로만 보내세요.",
"donate.warn.eth": "ETH는 이더리움 메인넷으로만 보내세요.",
"donate.qrAlt": "{coin} 후원 주소 QR 코드",
"community.title": "프라이버시의 미래를 함께 만듭니다",
"community.description": "SecureBit은 커뮤니티 덕분에 자랍니다. 여러분의 아이디어와 의견이 안전한 소통의 미래를 만듭니다 - 모든 과정이 공개되어 있고, 전 구간에서 ASN.1 검증을 수행합니다.",
"community.github": "GitHub 저장소",
+12
View File
@@ -42,6 +42,18 @@
"theme.system": "Системная",
"theme.light": "Светлая",
"theme.dark": "Тёмная",
"donate.eyebrow": "Пожертвование в криптовалюте",
"donate.title": "Сохраним SecureBit независимым",
"donate.description": "Каждое пожертвование идёт на разработку и аудиты.",
"donate.copy": "Копировать",
"donate.copied": "Скопировано",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Сеть Bitcoin",
"donate.net.eth": "Основная сеть Ethereum",
"donate.warn.usdt": "Отправляйте только USDT в сети Tron (TRC-20).",
"donate.warn.btc": "Отправляйте только BTC в сети Bitcoin.",
"donate.warn.eth": "Отправляйте только ETH в основной сети Ethereum.",
"donate.qrAlt": "QR-код адреса для пожертвований в {coin}",
"community.title": "Присоединяйтесь к будущему приватности",
"community.description": "SecureBit растёт благодаря сообществу. Ваши идеи и отзывы формируют будущее защищённого общения - разработка ведётся открыто, с полной проверкой ASN.1 на всём пути.",
"community.github": "Репозиторий на GitHub",
+12
View File
@@ -42,6 +42,18 @@
"theme.system": "Системна",
"theme.light": "Світла",
"theme.dark": "Темна",
"donate.eyebrow": "Пожертва в криптовалюті",
"donate.title": "Збережімо SecureBit незалежним",
"donate.description": "Кожна пожертва йде на розробку та аудити.",
"donate.copy": "Копіювати",
"donate.copied": "Скопійовано",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Мережа Bitcoin",
"donate.net.eth": "Основна мережа Ethereum",
"donate.warn.usdt": "Надсилайте лише USDT у мережі Tron (TRC-20).",
"donate.warn.btc": "Надсилайте лише BTC у мережі Bitcoin.",
"donate.warn.eth": "Надсилайте лише ETH в основній мережі Ethereum.",
"donate.qrAlt": "QR-код адреси для пожертв у {coin}",
"community.title": "Долучайтеся до майбутнього приватності",
"community.description": "SecureBit росте завдяки своїй спільноті. Ваші ідеї та відгуки формують майбутнє захищеного спілкування - розробка ведеться відкрито, з повною валідацією ASN.1 на всьому шляху.",
"community.github": "Репозиторій на GitHub",
+12
View File
@@ -42,6 +42,18 @@
"theme.system": "سسٹم",
"theme.light": "روشن",
"theme.dark": "گہرا",
"donate.eyebrow": "کرپٹو میں عطیہ دیں",
"donate.title": "SecureBit کو خودمختار رکھیں",
"donate.description": "ہر عطیہ ڈیولپمنٹ اور سیکیورٹی آڈٹ پر خرچ ہوتا ہے۔",
"donate.copy": "کاپی کریں",
"donate.copied": "کاپی ہو گیا",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Bitcoin نیٹ ورک",
"donate.net.eth": "Ethereum مین نیٹ",
"donate.warn.usdt": "صرف Tron (TRC-20) پر USDT بھیجیں۔",
"donate.warn.btc": "صرف Bitcoin نیٹ ورک پر BTC بھیجیں۔",
"donate.warn.eth": "صرف Ethereum مین نیٹ پر ETH بھیجیں۔",
"donate.qrAlt": "{coin} عطیہ ایڈریس کا QR کوڈ",
"community.title": "نجیت کے مستقبل میں شامل ہوں",
"community.description": "‏SecureBit اپنی برادری کی بدولت بڑھتا ہے۔ آپ کے خیالات اور آراء محفوظ رابطے کا مستقبل تشکیل دیتے ہیں - کھلے عام بنایا گیا، سرے سے سرے تک مکمل ASN.1 توثیق کے ساتھ۔",
"community.github": "‏GitHub مخزن",
+12
View File
@@ -37,6 +37,18 @@
"theme.system": "跟随系统",
"theme.light": "浅色",
"theme.dark": "深色",
"donate.eyebrow": "加密货币捐赠",
"donate.title": "让 SecureBit 保持独立",
"donate.description": "每一笔捐赠都用于开发和安全审计。",
"donate.copy": "复制",
"donate.copied": "已复制",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "比特币网络",
"donate.net.eth": "以太坊主网",
"donate.warn.usdt": "仅通过 Tron (TRC-20) 发送 USDT。",
"donate.warn.btc": "仅通过比特币网络发送 BTC。",
"donate.warn.eth": "仅通过以太坊主网发送 ETH。",
"donate.qrAlt": "{coin} 捐赠地址二维码",
"community.title": "一起构筑隐私的未来",
"community.description": "SecureBit 因社区而成长。你的想法与反馈塑造着安全通讯的未来 —— 开放开发,全程完整的 ASN.1 校验。",
"community.github": "GitHub 仓库",
+7 -7
View File
@@ -1,10 +1,10 @@
{
"version": "1790219928897",
"buildVersion": "1790219928897",
"appVersion": "6.8.6",
"buildTime": "2026-09-24T03:18:48.935Z",
"buildId": "1790219928897-02380a7",
"gitHash": "02380a7",
"version": "1790225533889",
"buildVersion": "1790225533889",
"appVersion": "6.8.8",
"buildTime": "2026-09-24T04:52:13.935Z",
"buildId": "1790225533889-eac3009",
"gitHash": "eac3009",
"generated": true,
"generatedAt": "2026-09-24T03:18:48.936Z"
"generatedAt": "2026-09-24T04:52:13.936Z"
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "securebit-chat",
"version": "6.8.6",
"version": "6.8.8",
"description": "Secure P2P Communication Application with End-to-End Encryption",
"main": "index.html",
"scripts": {
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/ru/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/ru.js?v=1790219928897"></script>
<script type="module" src="/src/i18n/dict/ru.js?v=1790225533889"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>
+22 -1
View File
@@ -38,6 +38,14 @@ const DIR = direction();
// someone who asked for less motion does not want. The jump still happens and
// still lands in the same place — it just stops travelling to get there.
const scrollBehavior = () => (prefersReducedMotion() ? 'auto' : 'smooth');
// After a chat ends, the start page scrolls to the donation card. The flag covers the
// usual case where the card only mounts once the chat is gone; the event covers a card
// that is already on screen. See src/components/ui/DonateCrypto.jsx.
const requestDonateScroll = () => {
window.__sbScrollToDonate = Date.now();
document.dispatchEvent(new CustomEvent('securebit:scroll-to-donate'));
};
import { GroupChatView, GroupSasModal, CreateGroupModal, GroupInviteModal, GroupErrorModal, AddMembersModal } from './components/ui/GroupChat.jsx';
import { GroupCallUI } from './components/ui/GroupCallUI.jsx';
import { GroupCallMedia, mediaErrorCode } from './group/groupCallMedia.js';
@@ -1825,6 +1833,7 @@ import { GroupCallMedia, mediaErrorCode } from './group/groupCallMedia.js';
const uniqueSection = atIntro && h(UniqueFeatureSlider, { key: 'unique-features-slider' });
const partnersSection = atIntro && h(BecomePartner, { key: 'become-partner' });
const roadmapSection = atIntro && h(Roadmap, { key: 'roadmap' });
const donateSection = atIntro && h(DonateCrypto, { key: 'donate-crypto' });
const communitySection = atIntro && h(CommunityCTA, { key: 'community-cta' });
// Ship the keyframes inside app.js so the animations can never go
@@ -1870,7 +1879,7 @@ import { GroupCallMedia, mediaErrorCode } from './group/groupCallMedia.js';
return h('div', { className: 'sb-start', style: { flex: 1, minHeight: 0, width: '100%', display: 'flex', flexDirection: 'column', background: 'var(--sb-bg)', color: 'var(--sb-text-2)' } }, [keyframeStyle, rightPanel, qrModal]);
}
return h('div', { className: 'sb-start', style: { width: '100%' } }, [keyframeStyle, hero, uniqueSection, partnersSection, roadmapSection, communitySection, qrModal]);
return h('div', { className: 'sb-start', style: { width: '100%' } }, [keyframeStyle, hero, uniqueSection, partnersSection, roadmapSection, donateSection, communitySection, qrModal]);
};
// Global scroll function - defined outside components to ensure availability
@@ -6880,6 +6889,7 @@ import { GroupCallMedia, mediaErrorCode } from './group/groupCallMedia.js';
const handleDisconnect = () => {
try {
const id = activeIdRef.current;
requestDonateScroll();
setSessionTimeLeft(0);
// Global lifecycle events (consumed by any remaining listeners).
document.dispatchEvent(new CustomEvent('peer-disconnect'));
@@ -6942,6 +6952,17 @@ import { GroupCallMedia, mediaErrorCode } from './group/groupCallMedia.js';
const isConnectedAndVerified = (connectionStatus === 'connected' || connectionStatus === 'verified' || connectionStatus === 'reconnecting') && isVerified;
// A chat that ends — the peer leaves, the link drops for good — lands
// back on the start page; bring the donation card into view there. Only
// for the SAME session going from chatting to not: switching to another
// tab's blank session is not an ending.
const prevChatRef = React.useRef({ id: activeSessionId, live: isConnectedAndVerified });
React.useEffect(() => {
const prev = prevChatRef.current;
prevChatRef.current = { id: activeSessionId, live: isConnectedAndVerified };
if (prev.live && !isConnectedAndVerified && prev.id === activeSessionId) requestDonateScroll();
}, [isConnectedAndVerified, activeSessionId]);
// The PWA "Install app" pill is a landing-page affordance — hide it once
// we're inside the chat (CSS: body.sb-in-chat #pwa-install-button).
React.useEffect(() => {
+306
View File
@@ -0,0 +1,306 @@
import { t, isRTL } from '../../i18n/index.js';
// "Keep SecureBit independent" — crypto donation card.
// Translated from the Claude Design component (Crypto Donate v3.dc.html): coin switcher,
// address with copy, and a QR on the right.
//
// Everything is served from this origin. The design pulled the coin icons from jsDelivr
// and built the QR with a CDN script; the site's CSP (`img-src 'self' data:`) would block
// the first, and both would hand a third party the address of every visitor. The
// addresses are fixed, so the QRs are pre-rendered SVGs in /assets/crypto/.
const WALLETS = [
{ id: 'usdt', tab: 'USDT', coin: 'Tether USDT', badge: 'trx', address: 'TMopDoco5EwJB1QvQYsuhjUJdMvzPXNQYu' },
{ id: 'btc', tab: 'BTC', coin: 'Bitcoin', badge: null, address: 'bc1qnmc2xl7p0pxcy6lzf2tyf52wnslgzkgaq9kxpr' },
{ id: 'eth', tab: 'ETH', coin: 'Ethereum', badge: null, address: '0xCDfDfaD4EC1fa657C3d2A7EFabc1cb751bf1dAf7' }
];
const icon = (id) => `/assets/crypto/${id}.svg`;
// A disconnect asks for the page to be brought here (see handleDisconnect in app.jsx).
// The request is a timestamped flag rather than just an event, because the landing — and
// this card with it — usually mounts only after the chat has been torn down. It expires
// so that a request made while no landing was shown cannot fire minutes later.
const SCROLL_FLAG = '__sbScrollToDonate';
const SCROLL_EVENT = 'securebit:scroll-to-donate';
const SCROLL_TTL_MS = 5000;
const DonateCrypto = () => {
const [isMobile, setIsMobile] = React.useState(
typeof window !== 'undefined' && window.matchMedia('(max-width:767px)').matches
);
const [sel, setSel] = React.useState(0);
const [copied, setCopied] = React.useState(false);
// +1 when the new coin comes in from the end side, -1 from the start side; the QR
// slides in accordingly so a swipe feels like moving along the row of tabs.
const [slide, setSlide] = React.useState(0);
const touchStart = React.useRef(null);
const sectionRef = React.useRef(null);
const copyTimer = React.useRef(null);
React.useEffect(() => {
const mq = window.matchMedia('(max-width:767px)');
const onChange = () => setIsMobile(mq.matches);
mq.addEventListener ? mq.addEventListener('change', onChange) : mq.addListener(onChange);
return () => {
mq.removeEventListener ? mq.removeEventListener('change', onChange) : mq.removeListener(onChange);
clearTimeout(copyTimer.current);
};
}, []);
React.useEffect(() => {
let timer = null;
const scrollHere = () => {
const at = window[SCROLL_FLAG];
window[SCROLL_FLAG] = 0;
if (!at || Date.now() - at > SCROLL_TTL_MS) return;
clearTimeout(timer);
// Let the landing finish laying out first, or the target moves under the scroll.
timer = setTimeout(() => {
const el = sectionRef.current;
if (!el) return;
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
el.scrollIntoView({ behavior: reduce ? 'auto' : 'smooth', block: 'center' });
}, 350);
};
scrollHere();
document.addEventListener(SCROLL_EVENT, scrollHere);
return () => {
document.removeEventListener(SCROLL_EVENT, scrollHere);
clearTimeout(timer);
};
}, []);
const cur = WALLETS[sel];
const pick = (i) => {
const next = (i + WALLETS.length) % WALLETS.length;
if (next === sel) return;
setSlide(i > sel ? 1 : -1);
setSel(next);
setCopied(false);
};
// Swipe across the QR to change coin on a phone. Horizontal only, and only past a
// clear threshold, so a vertical scroll that starts on the QR still scrolls the page
// (touch-action: pan-y hands vertical pans to the browser). In a right-to-left locale
// the tab row runs the other way, and so does the swipe.
const onTouchStart = (e) => {
const p = e.touches[0];
touchStart.current = { x: p.clientX, y: p.clientY };
};
const onTouchEnd = (e) => {
const start = touchStart.current;
touchStart.current = null;
if (!start) return;
const p = e.changedTouches[0];
const dx = p.clientX - start.x;
const dy = p.clientY - start.y;
if (Math.abs(dx) < 40 || Math.abs(dx) < Math.abs(dy) * 1.5) return;
const forward = isRTL() ? dx > 0 : dx < 0;
pick(sel + (forward ? 1 : -1));
};
const copy = async () => {
try {
await navigator.clipboard.writeText(cur.address);
} catch (e) {
const ta = document.createElement('textarea');
ta.value = cur.address;
document.body.appendChild(ta);
ta.select();
try { document.execCommand('copy'); } catch (_) {}
ta.remove();
}
setCopied(true);
clearTimeout(copyTimer.current);
copyTimer.current = setTimeout(() => setCopied(false), 1800);
};
const SANS = "'Manrope', system-ui, -apple-system, sans-serif";
const MONO = "'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace";
const FIELD = {
borderRadius: '14px', background: 'var(--sb-bg)', border: '1px solid rgba(var(--sb-ink), 0.07)'
};
const tabs = React.createElement('div', {
key: 'tabs', role: 'tablist',
style: { ...FIELD, display: 'flex', gap: '6px', padding: '5px', marginBottom: '14px' }
}, WALLETS.map((w, i) => {
const on = i === sel;
return React.createElement('button', {
key: w.id, type: 'button', role: 'tab', 'aria-selected': on,
onClick: () => pick(i),
style: {
flex: '1 1 0', minWidth: 0, display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
gap: '9px', padding: '11px 10px', borderRadius: '10px', border: 'none', cursor: 'pointer',
fontFamily: SANS, fontSize: '14px', fontWeight: 700, transition: 'all .18s',
background: on ? 'var(--sb-surface-2)' : 'transparent',
color: on ? 'var(--sb-text-1)' : 'var(--sb-text-7)',
boxShadow: on ? 'inset 0 0 0 1px rgba(var(--sb-orange-rgb), 0.45)' : 'none'
}
}, [
React.createElement('span', { key: 'ic', style: { position: 'relative', flex: 'none', width: '22px', height: '22px' } }, [
React.createElement('img', { key: 'logo', src: icon(w.id), alt: '', width: 22, height: 22, style: { display: 'block', width: '22px', height: '22px' } }),
w.badge && React.createElement('img', {
key: 'badge', src: icon(w.badge), alt: '', width: 11, height: 11,
style: {
position: 'absolute', right: '-3px', bottom: '-3px', width: '11px', height: '11px', borderRadius: '50%',
border: '1.5px solid var(--sb-surface-2)', background: 'var(--sb-surface-2)'
}
})
]),
w.tab
]);
}));
const copyBtn = React.createElement('button', {
key: 'copy', type: 'button', onClick: copy,
style: {
flex: 'none', display: 'inline-flex', alignItems: 'center', gap: '8px', padding: '12px 16px',
borderRadius: '10px', fontFamily: SANS, fontSize: '13.5px', fontWeight: 700, cursor: 'pointer',
background: 'rgba(var(--sb-ink), 0.05)', color: 'var(--sb-text-2)',
border: '1px solid rgba(var(--sb-ink), 0.1)', transition: 'all .18s'
},
onMouseEnter: (e) => { e.currentTarget.style.background = 'rgba(var(--sb-ink), 0.09)'; },
onMouseLeave: (e) => { e.currentTarget.style.background = 'rgba(var(--sb-ink), 0.05)'; }
}, [
copied
? React.createElement('svg', {
key: 'ok', width: 15, height: 15, viewBox: '0 0 24 24', fill: 'none', stroke: 'var(--sb-green-solid)',
strokeWidth: 2.4, strokeLinecap: 'round', strokeLinejoin: 'round',
dangerouslySetInnerHTML: { __html: '<path d="M5 12.5l4.2 4.2L19 6.5"/>' }
})
: React.createElement('svg', {
key: 'cp', width: 15, height: 15, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor',
strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round',
dangerouslySetInnerHTML: { __html: '<rect x="9" y="9" width="12" height="12" rx="2.5"/><path d="M5 15V5a2 2 0 0 1 2-2h8"/>' }
}),
React.createElement('span', { key: 'l', 'aria-live': 'polite' }, copied ? t('donate.copied') : t('donate.copy'))
]);
const addressField = React.createElement('div', {
key: 'addr',
style: { ...FIELD, display: 'flex', alignItems: 'center', gap: '12px', padding: '8px 8px 8px 18px' }
}, [
React.createElement('div', { key: 'tx', style: { flex: 1, minWidth: 0 } }, [
React.createElement('div', { key: 'net', style: { fontSize: '11.5px', fontWeight: 600, color: 'var(--sb-text-9)', marginBottom: '2px' } }, t(`donate.net.${cur.id}`)),
React.createElement('div', {
key: 'a', title: cur.address, dir: 'ltr',
style: { fontFamily: MONO, fontSize: '14px', color: 'var(--sb-text-2)', letterSpacing: '0.3px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }
}, cur.address.slice(0, 8) + '…' + cur.address.slice(-8))
]),
copyBtn
]);
const warn = React.createElement('div', {
key: 'warn',
style: { display: 'flex', alignItems: 'center', gap: '7px', marginTop: '14px', fontSize: '12px', color: 'var(--sb-text-9)' }
}, [
React.createElement('svg', {
key: 'i', width: 13, height: 13, viewBox: '0 0 24 24', fill: 'none', stroke: 'var(--sb-orange-solid)',
strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round', style: { flex: 'none' },
dangerouslySetInnerHTML: { __html: '<path d="M12 3l9.5 17h-19z"/><path d="M12 10v4M12 17.5v.01"/>' }
}),
t(`donate.warn.${cur.id}`)
]);
const left = React.createElement('div', {
key: 'left',
style: { flex: '1 1 440px', minWidth: 0, padding: isMobile ? '32px 22px 8px' : '44px', display: 'flex', flexDirection: 'column' }
}, [
React.createElement('div', {
key: 'eyebrow',
style: { fontFamily: MONO, fontSize: '11px', fontWeight: 600, color: 'var(--sb-text-9)', textTransform: 'uppercase', letterSpacing: '1.8px', marginBottom: '14px' }
}, t('donate.eyebrow')),
React.createElement('h2', {
key: 'title',
style: { margin: '0 0 10px', fontSize: isMobile ? '28px' : '34px', fontWeight: 800, letterSpacing: '-1px', lineHeight: 1.08, color: 'var(--sb-text-1)' }
}, t('donate.title')),
React.createElement('p', {
key: 'desc',
style: { margin: '0 0 30px', fontSize: '15px', lineHeight: 1.6, color: 'var(--sb-text-7)' }
}, t('donate.description')),
tabs,
addressField,
warn
]);
// The QR plate is white in both themes: scanners want dark modules on a light ground.
const dirSign = isRTL() ? -1 : 1;
const slideAnim = slide === 0 ? 'none'
: `${slide * dirSign > 0 ? 'cdInEnd' : 'cdInStart'} .28s cubic-bezier(.2,.7,.3,1)`;
const plate = React.createElement('div', {
key: 'plate',
onTouchStart, onTouchEnd,
style: {
position: 'relative', width: '232px', height: '232px', padding: '14px', borderRadius: '20px', background: '#fff',
boxShadow: '0 24px 60px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))',
border: '1px solid rgba(var(--sb-ink), 0.07)', overflow: 'hidden', touchAction: 'pan-y', userSelect: 'none'
}
}, React.createElement('div', {
key: cur.id,
style: { position: 'relative', width: '100%', height: '100%', animation: slideAnim }
}, [
React.createElement('img', {
key: 'qr', src: `/assets/crypto/qr-${cur.id}.svg`, alt: t('donate.qrAlt', { coin: cur.coin }),
width: 204, height: 204, draggable: false,
style: { display: 'block', width: '100%', height: '100%', imageRendering: 'pixelated' }
}),
React.createElement('div', {
key: 'logo',
style: { position: 'absolute', left: '50%', top: '50%', transform: 'translate(-50%,-50%)', width: '48px', height: '48px', borderRadius: '12px', background: '#fff', display: 'grid', placeItems: 'center' }
}, React.createElement('img', { src: icon(cur.id), alt: '', width: 34, height: 34, draggable: false, style: { display: 'block', width: '34px', height: '34px' } }))
]));
// Page dots under the QR on a phone — the hint that it can be swiped.
const dots = isMobile && React.createElement('div', {
key: 'dots', 'aria-hidden': true,
style: { display: 'flex', justifyContent: 'center', gap: '7px', marginTop: '18px' }
}, WALLETS.map((w, i) => React.createElement('span', {
key: w.id,
style: {
width: i === sel ? '18px' : '7px', height: '7px', borderRadius: '4px', transition: 'all .25s',
background: i === sel ? 'var(--sb-orange-solid)' : 'rgba(var(--sb-ink), 0.16)'
}
})));
const right = React.createElement('div', {
key: 'right',
style: { flex: '0 0 auto', minWidth: isMobile ? 0 : '300px', margin: '0 auto', padding: isMobile ? '24px 22px 32px' : '44px', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }
}, [plate, dots]);
const card = React.createElement('div', {
key: 'card',
style: {
width: '100%', maxWidth: '1000px', position: 'relative', overflow: 'hidden', borderRadius: '24px',
background: 'radial-gradient(520px 420px at 100% 50%, rgba(var(--sb-orange-rgb), 0.09), transparent 70%), var(--sb-surface)',
border: '1px solid rgba(var(--sb-ink), 0.07)', display: 'flex', flexWrap: 'wrap', alignItems: 'stretch',
animation: 'cdUp .45s cubic-bezier(.2,.7,.3,1)'
}
}, [
left,
right
]);
return React.createElement('section', {
id: 'donate', ref: sectionRef,
style: {
width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center',
background: 'var(--sb-bg)', color: 'var(--sb-text-2)', fontFamily: SANS,
padding: isMobile ? '48px 18px' : '64px 32px'
}
}, [
React.createElement('style', { key: 'kf', dangerouslySetInnerHTML: { __html: '@keyframes cdUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}' +
'@keyframes cdInEnd{from{opacity:0;transform:translateX(36px)}to{opacity:1;transform:none}}' +
'@keyframes cdInStart{from{opacity:0;transform:translateX(-36px)}to{opacity:1;transform:none}}' +
'@media (prefers-reduced-motion: reduce){#donate [style*="cdIn"]{animation:none!important}}' } }),
card
]);
};
DonateCrypto.SCROLL_FLAG = SCROLL_FLAG;
DonateCrypto.SCROLL_EVENT = SCROLL_EVENT;
window.DonateCrypto = DonateCrypto;
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "النظام",
"theme.light": "فاتح",
"theme.dark": "داكن",
"donate.eyebrow": "تبرّع بالعملات المشفّرة",
"donate.title": "ساعدنا في إبقاء SecureBit مستقلًا",
"donate.description": "يذهب كل تبرّع إلى التطوير وعمليات التدقيق الأمني.",
"donate.copy": "نسخ",
"donate.copied": "تم النسخ",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "شبكة Bitcoin",
"donate.net.eth": "الشبكة الرئيسية لـ Ethereum",
"donate.warn.usdt": "أرسل USDT على شبكة Tron (TRC-20) فقط.",
"donate.warn.btc": "أرسل BTC على شبكة Bitcoin فقط.",
"donate.warn.eth": "أرسل ETH على الشبكة الرئيسية لـ Ethereum فقط.",
"donate.qrAlt": "رمز QR لعنوان التبرّع بـ {coin}",
"community.title": "انضمّ إلى مستقبل الخصوصية",
"community.description": "ينمو SecureBit بفضل مجتمعه. أفكاركم وملاحظاتكم هي ما يصوغ مستقبل التواصل الآمن - مبنيّ في العلن، مع تحقّق ASN.1 كامل من طرف إلى طرف.",
"community.github": "مستودع GitHub",
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "System",
"theme.light": "Hell",
"theme.dark": "Dunkel",
"donate.eyebrow": "Mit Krypto spenden",
"donate.title": "Halte SecureBit unabhängig",
"donate.description": "Jede Spende fließt in Entwicklung und Audits.",
"donate.copy": "Kopieren",
"donate.copied": "Kopiert",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Bitcoin-Netzwerk",
"donate.net.eth": "Ethereum-Mainnet",
"donate.warn.usdt": "Sende nur USDT über Tron (TRC-20).",
"donate.warn.btc": "Sende nur BTC über das Bitcoin-Netzwerk.",
"donate.warn.eth": "Sende nur ETH über das Ethereum-Mainnet.",
"donate.qrAlt": "QR-Code der {coin}-Spendenadresse",
"community.title": "Gestalten Sie die Zukunft der Privatsphäre mit",
"community.description": "SecureBit wächst durch seine Community. Ihre Ideen und Ihr Feedback prägen die Zukunft sicherer Kommunikation - offen entwickelt, mit vollständiger ASN.1-Validierung von Ende zu Ende.",
"community.github": "GitHub-Repository",
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "System",
"theme.light": "Light",
"theme.dark": "Dark",
"donate.eyebrow": "Donate in crypto",
"donate.title": "Keep SecureBit independent",
"donate.description": "Every donation goes to development and audits.",
"donate.copy": "Copy",
"donate.copied": "Copied",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Bitcoin network",
"donate.net.eth": "Ethereum mainnet",
"donate.warn.usdt": "Send only USDT on Tron (TRC-20).",
"donate.warn.btc": "Send only BTC on the Bitcoin network.",
"donate.warn.eth": "Send only ETH on Ethereum mainnet.",
"donate.qrAlt": "QR code of the {coin} donation address",
"community.title": "Join the future of privacy",
"community.description": "SecureBit grows thanks to its community. Your ideas and feedback shape the future of secure communication - built in the open, with complete ASN.1 validation end-to-end.",
"community.github": "GitHub Repository",
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "Sistema",
"theme.light": "Claro",
"theme.dark": "Oscuro",
"donate.eyebrow": "Dona en cripto",
"donate.title": "Mantén SecureBit independiente",
"donate.description": "Cada donación se destina al desarrollo y a las auditorías.",
"donate.copy": "Copiar",
"donate.copied": "Copiado",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Red Bitcoin",
"donate.net.eth": "Red principal de Ethereum",
"donate.warn.usdt": "Envía solo USDT en Tron (TRC-20).",
"donate.warn.btc": "Envía solo BTC en la red Bitcoin.",
"donate.warn.eth": "Envía solo ETH en la red principal de Ethereum.",
"donate.qrAlt": "Código QR de la dirección de donación en {coin}",
"community.title": "Construye el futuro de la privacidad",
"community.description": "SecureBit crece gracias a su comunidad. Tus ideas y comentarios dan forma al futuro de la comunicación segura, desarrollada de forma abierta y con validación ASN.1 completa de extremo a extremo.",
"community.github": "Repositorio en GitHub",
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "سیستم",
"theme.light": "روشن",
"theme.dark": "تیره",
"donate.eyebrow": "اهدای کمک با رمزارز",
"donate.title": "به مستقل ماندن SecureBit کمک کنید",
"donate.description": "هر کمک صرف توسعه و ممیزی‌های امنیتی می‌شود.",
"donate.copy": "کپی",
"donate.copied": "کپی شد",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "شبکه Bitcoin",
"donate.net.eth": "شبکه اصلی Ethereum",
"donate.warn.usdt": "فقط USDT را روی شبکه Tron (TRC-20) بفرستید.",
"donate.warn.btc": "فقط BTC را روی شبکه Bitcoin بفرستید.",
"donate.warn.eth": "فقط ETH را روی شبکه اصلی Ethereum بفرستید.",
"donate.qrAlt": "کد QR نشانی کمک با {coin}",
"community.title": "به آیندهٔ حریم خصوصی بپیوندید",
"community.description": "‏SecureBit به‌لطف جامعه‌اش رشد می‌کند. ایده‌ها و بازخوردهای شما آیندهٔ ارتباط امن را شکل می‌دهد - ساخته‌شده در فضای باز، با اعتبارسنجی کامل ASN.1 از یک سر تا سر دیگر.",
"community.github": "مخزن GitHub",
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "Système",
"theme.light": "Clair",
"theme.dark": "Sombre",
"donate.eyebrow": "Faire un don en crypto",
"donate.title": "Gardons SecureBit indépendant",
"donate.description": "Chaque don finance le développement et les audits.",
"donate.copy": "Copier",
"donate.copied": "Copié",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Réseau Bitcoin",
"donate.net.eth": "Réseau principal Ethereum",
"donate.warn.usdt": "Envoyez uniquement de l'USDT sur Tron (TRC-20).",
"donate.warn.btc": "Envoyez uniquement du BTC sur le réseau Bitcoin.",
"donate.warn.eth": "Envoyez uniquement de l'ETH sur le réseau principal Ethereum.",
"donate.qrAlt": "QR code de l'adresse de don {coin}",
"community.title": "Construisez l'avenir de la vie privée",
"community.description": "SecureBit grandit grâce à sa communauté. Vos idées et vos retours façonnent l'avenir des communications sécurisées, développées à ciel ouvert, avec une validation ASN.1 complète de bout en bout.",
"community.github": "Dépôt GitHub",
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "מערכת",
"theme.light": "בהיר",
"theme.dark": "כהה",
"donate.eyebrow": "תרומה בקריפטו",
"donate.title": "עזרו לשמור על SecureBit עצמאית",
"donate.description": "כל תרומה מופנית לפיתוח ולביקורות אבטחה.",
"donate.copy": "העתקה",
"donate.copied": "הועתק",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "רשת Bitcoin",
"donate.net.eth": "הרשת הראשית של Ethereum",
"donate.warn.usdt": "שלחו USDT ברשת Tron (TRC-20) בלבד.",
"donate.warn.btc": "שלחו BTC ברשת Bitcoin בלבד.",
"donate.warn.eth": "שלחו ETH ברשת הראשית של Ethereum בלבד.",
"donate.qrAlt": "קוד QR של כתובת התרומה ב-{coin}",
"community.title": "הצטרפו לעתיד של הפרטיות",
"community.description": "SecureBit גדל בזכות הקהילה שלו. הרעיונות והמשוב שלכם מעצבים את עתיד התקשורת המאובטחת - נבנה בגלוי, עם אימות ASN.1 מלא מקצה לקצה.",
"community.github": "מאגר GitHub",
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "सिस्टम",
"theme.light": "हल्की",
"theme.dark": "गहरी",
"donate.eyebrow": "क्रिप्टो में दान करें",
"donate.title": "SecureBit को स्वतंत्र बनाए रखें",
"donate.description": "हर दान विकास और सुरक्षा ऑडिट पर खर्च होता है।",
"donate.copy": "कॉपी करें",
"donate.copied": "कॉपी हो गया",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Bitcoin नेटवर्क",
"donate.net.eth": "Ethereum मेननेट",
"donate.warn.usdt": "केवल Tron (TRC-20) पर USDT भेजें।",
"donate.warn.btc": "केवल Bitcoin नेटवर्क पर BTC भेजें।",
"donate.warn.eth": "केवल Ethereum मेननेट पर ETH भेजें।",
"donate.qrAlt": "{coin} दान पते का QR कोड",
"community.title": "निजता के भविष्य में शामिल हों",
"community.description": "SecureBit अपने समुदाय से बढ़ता है। आपके विचार और सुझाव सुरक्षित संवाद का भविष्य गढ़ते हैं - खुले में बना, और पूरे रास्ते पूरी ASN.1 जाँच के साथ।",
"community.github": "GitHub रिपॉज़िटरी",
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "시스템",
"theme.light": "밝게",
"theme.dark": "어둡게",
"donate.eyebrow": "암호화폐로 후원하기",
"donate.title": "SecureBit의 독립을 지켜 주세요",
"donate.description": "모든 후원금은 개발과 보안 감사에 쓰입니다.",
"donate.copy": "복사",
"donate.copied": "복사됨",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "비트코인 네트워크",
"donate.net.eth": "이더리움 메인넷",
"donate.warn.usdt": "USDT는 Tron(TRC-20) 네트워크로만 보내세요.",
"donate.warn.btc": "BTC는 비트코인 네트워크로만 보내세요.",
"donate.warn.eth": "ETH는 이더리움 메인넷으로만 보내세요.",
"donate.qrAlt": "{coin} 후원 주소 QR 코드",
"community.title": "프라이버시의 미래를 함께 만듭니다",
"community.description": "SecureBit은 커뮤니티 덕분에 자랍니다. 여러분의 아이디어와 의견이 안전한 소통의 미래를 만듭니다 - 모든 과정이 공개되어 있고, 전 구간에서 ASN.1 검증을 수행합니다.",
"community.github": "GitHub 저장소",
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "Системная",
"theme.light": "Светлая",
"theme.dark": "Тёмная",
"donate.eyebrow": "Пожертвование в криптовалюте",
"donate.title": "Сохраним SecureBit независимым",
"donate.description": "Каждое пожертвование идёт на разработку и аудиты.",
"donate.copy": "Копировать",
"donate.copied": "Скопировано",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Сеть Bitcoin",
"donate.net.eth": "Основная сеть Ethereum",
"donate.warn.usdt": "Отправляйте только USDT в сети Tron (TRC-20).",
"donate.warn.btc": "Отправляйте только BTC в сети Bitcoin.",
"donate.warn.eth": "Отправляйте только ETH в основной сети Ethereum.",
"donate.qrAlt": "QR-код адреса для пожертвований в {coin}",
"community.title": "Присоединяйтесь к будущему приватности",
"community.description": "SecureBit растёт благодаря сообществу. Ваши идеи и отзывы формируют будущее защищённого общения - разработка ведётся открыто, с полной проверкой ASN.1 на всём пути.",
"community.github": "Репозиторий на GitHub",
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "Системна",
"theme.light": "Світла",
"theme.dark": "Темна",
"donate.eyebrow": "Пожертва в криптовалюті",
"donate.title": "Збережімо SecureBit незалежним",
"donate.description": "Кожна пожертва йде на розробку та аудити.",
"donate.copy": "Копіювати",
"donate.copied": "Скопійовано",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Мережа Bitcoin",
"donate.net.eth": "Основна мережа Ethereum",
"donate.warn.usdt": "Надсилайте лише USDT у мережі Tron (TRC-20).",
"donate.warn.btc": "Надсилайте лише BTC у мережі Bitcoin.",
"donate.warn.eth": "Надсилайте лише ETH в основній мережі Ethereum.",
"donate.qrAlt": "QR-код адреси для пожертв у {coin}",
"community.title": "Долучайтеся до майбутнього приватності",
"community.description": "SecureBit росте завдяки своїй спільноті. Ваші ідеї та відгуки формують майбутнє захищеного спілкування - розробка ведеться відкрито, з повною валідацією ASN.1 на всьому шляху.",
"community.github": "Репозиторій на GitHub",
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "سسٹم",
"theme.light": "روشن",
"theme.dark": "گہرا",
"donate.eyebrow": "کرپٹو میں عطیہ دیں",
"donate.title": "SecureBit کو خودمختار رکھیں",
"donate.description": "ہر عطیہ ڈیولپمنٹ اور سیکیورٹی آڈٹ پر خرچ ہوتا ہے۔",
"donate.copy": "کاپی کریں",
"donate.copied": "کاپی ہو گیا",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "Bitcoin نیٹ ورک",
"donate.net.eth": "Ethereum مین نیٹ",
"donate.warn.usdt": "صرف Tron (TRC-20) پر USDT بھیجیں۔",
"donate.warn.btc": "صرف Bitcoin نیٹ ورک پر BTC بھیجیں۔",
"donate.warn.eth": "صرف Ethereum مین نیٹ پر ETH بھیجیں۔",
"donate.qrAlt": "{coin} عطیہ ایڈریس کا QR کوڈ",
"community.title": "نجیت کے مستقبل میں شامل ہوں",
"community.description": "‏SecureBit اپنی برادری کی بدولت بڑھتا ہے۔ آپ کے خیالات اور آراء محفوظ رابطے کا مستقبل تشکیل دیتے ہیں - کھلے عام بنایا گیا، سرے سے سرے تک مکمل ASN.1 توثیق کے ساتھ۔",
"community.github": "‏GitHub مخزن",
+12
View File
@@ -10,6 +10,18 @@ export const DICTIONARY = {
"theme.system": "跟随系统",
"theme.light": "浅色",
"theme.dark": "深色",
"donate.eyebrow": "加密货币捐赠",
"donate.title": "让 SecureBit 保持独立",
"donate.description": "每一笔捐赠都用于开发和安全审计。",
"donate.copy": "复制",
"donate.copied": "已复制",
"donate.net.usdt": "USDT · Tron (TRC-20)",
"donate.net.btc": "比特币网络",
"donate.net.eth": "以太坊主网",
"donate.warn.usdt": "仅通过 Tron (TRC-20) 发送 USDT。",
"donate.warn.btc": "仅通过比特币网络发送 BTC。",
"donate.warn.eth": "仅通过以太坊主网发送 ETH。",
"donate.qrAlt": "{coin} 捐赠地址二维码",
"community.title": "一起构筑隐私的未来",
"community.description": "SecureBit 因社区而成长。你的想法与反馈塑造着安全通讯的未来 —— 开放开发,全程完整的 ASN.1 校验。",
"community.github": "GitHub 仓库",
+1
View File
@@ -10,6 +10,7 @@ import '../components/ui/DownloadApps.jsx';
import '../components/ui/BecomePartner.jsx';
import '../components/ui/UniqueFeatureSlider.jsx';
import '../components/ui/Roadmap.jsx';
import '../components/ui/DonateCrypto.jsx';
import '../components/ui/CommunityCTA.jsx';
import '../components/ui/FileTransfer.jsx';
import '../components/ui/IceServerSettings.jsx';
+1 -1
View File
@@ -11,7 +11,7 @@ let DYNAMIC_CACHE = 'securebit-pwa-dynamic-v4.7.56';
// Build stamp — rewritten by scripts/post-build.js on every release so this file's
// bytes change each deploy. That is what makes the browser detect a new Service Worker,
// reinstall it, drop stale caches and (via controllerchange) prompt the page to update.
const SW_BUILD_VERSION = '1790219928897';
const SW_BUILD_VERSION = '1790225533889';
// Locale subdirectories, rewritten by scripts/build-i18n.js. Each localized page is a
// separate document at its own URL, so the shell has to be cached and served per
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/uk/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/uk.js?v=1790219928897"></script>
<script type="module" src="/src/i18n/dict/uk.js?v=1790225533889"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/ur/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/ur.js?v=1790219928897"></script>
<script type="module" src="/src/i18n/dict/ur.js?v=1790225533889"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>
+19 -19
View File
@@ -30,18 +30,18 @@
<!-- PWA Manifest -->
<link rel="manifest" href="/zh/manifest.json">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
from localStorage while the parser is still in <head>, so the page paints in the
chosen theme on the first frame instead of flashing dark and correcting itself.
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
<script src="/src/scripts/theme-boot.js?v=1790219928897"></script>
<script src="/src/scripts/theme-boot.js?v=1790225533889"></script>
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
not replayed, so the listener has to exist before Chrome decides the page
is installable. Deferred/module scripts are already too late. -->
<script src="/src/scripts/pwa-install-capture.js?v=1790219928897"></script>
<script src="/src/scripts/pwa-install-capture.js?v=1790225533889"></script>
<!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes">
@@ -116,7 +116,7 @@
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1790225533889">
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
@@ -125,7 +125,7 @@
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790219928897">
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1790225533889">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#ff6b35">
@@ -264,7 +264,7 @@
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
both execute in document order after parsing, so React still runs before the
app modules below, but the parser / first paint is no longer blocked. -->
<script defer src="/config/ice-servers.js?v=1790219928897"></script>
<script defer src="/config/ice-servers.js?v=1790225533889"></script>
<script defer src="/libs/react/react.production.min.js"></script>
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
@@ -278,8 +278,8 @@
the end of <body>: 21 KB of CSS in total, but eight round trips before the
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
connection. Bytes were never the problem; requests were. -->
<link rel="stylesheet" href="/assets/app.css?v=1790219928897">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790219928897">
<link rel="stylesheet" href="/assets/app.css?v=1790225533889">
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1790225533889">
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
answers for every weight, so there is one to preload rather than the two of five
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
@@ -287,19 +287,19 @@
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
<script defer src="/src/scripts/load-async-css.js?v=1790219928897"></script>
<script defer src="/src/scripts/load-async-css.js?v=1790225533889"></script>
<noscript>
<link rel="stylesheet" href="/libs/prism/prism.css">
</noscript>
<script defer src="/src/scripts/fa-check.js?v=1790219928897"></script>
<script defer src="/src/scripts/fa-check.js?v=1790225533889"></script>
<!-- This locale's dictionary, registered before anything can ask for a string.
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
falls back to it); every other page loads its own here instead of all thirteen
riding along inside dist/app.js. Absent on the default locale's own page. -->
<script type="module" src="/src/i18n/dict/zh.js?v=1790219928897"></script>
<script type="module" src="/src/i18n/dict/zh.js?v=1790225533889"></script>
<!-- Update Manager - система принудительного обновления -->
<script defer src="/src/utils/updateManager.js?v=1790219928897"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790219928897"></script>
<script defer src="/src/utils/updateManager.js?v=1790225533889"></script>
<script type="module" src="/src/components/UpdateChecker.jsx?v=1790225533889"></script>
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
app has mounted and the browser is idle, so the 142 KB it weighs is off the
first load. src/components/QRScanner.js used to be here too and registered
@@ -487,12 +487,12 @@
</div>
</div>
</div>
<script type="module" src="/dist/app-boot.js?v=1790219928897"></script>
<script type="module" src="/dist/app.js?v=1790219928897"></script>
<script type="module" src="/dist/app-boot.js?v=1790225533889"></script>
<script type="module" src="/dist/app.js?v=1790225533889"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790219928897"></script>
<script src="/src/pwa/install-prompt.js?v=1790219928897" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790219928897" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790219928897"></script>
<script defer src="/src/scripts/pwa-register.js?v=1790225533889"></script>
<script src="/src/pwa/install-prompt.js?v=1790225533889" type="module"></script>
<script src="/src/pwa/pwa-manager.js?v=1790225533889" type="module"></script>
<script defer src="/src/scripts/pwa-offline-test.js?v=1790225533889"></script>
</body>
</html>