v6.8.8: added a section to support the project
@@ -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
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
No accounts. No servers storing your messages. No installation required.
|
||||
|
||||
[](LICENSE)
|
||||
[](CHANGELOG.md)
|
||||
[](CHANGELOG.md)
|
||||
[](https://snapcraft.io/securebit-chat)
|
||||
[](#install-as-an-app)
|
||||
[](#security-model)
|
||||
|
||||
@@ -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>
|
||||
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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>
|
||||
@@ -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.
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 रिपॉज़िटरी",
|
||||
|
||||
@@ -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 저장소",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 مخزن",
|
||||
|
||||
@@ -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 仓库",
|
||||
|
||||
@@ -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,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": {
|
||||
|
||||
@@ -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>
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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;
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 रिपॉज़िटरी",
|
||||
|
||||
@@ -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 저장소",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 مخزن",
|
||||
|
||||
@@ -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 仓库",
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||