mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-22 13:11:55 +00:00
Merge branch 'master' into chat-relays
This commit is contained in:
commit
27938db582
174 files changed
+14050
-855
No files matched your search
@@ -54,6 +54,7 @@ website/translations.json
|
||||
website/src/img/images/
|
||||
website/src/images/
|
||||
website/src/js/lottie.min.js
|
||||
website/src/js/ethers*
|
||||
website/src/privacy.md
|
||||
# Generated files
|
||||
website/package/generated*
|
||||
|
||||
@@ -24,15 +24,15 @@
|
||||
|
||||
## Install the app
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/apple_store.svg" alt="iOS app" height="42">](https://apps.apple.com/us/app/simplex-chat/id1605771084)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/apple_store.svg" alt="iOS app" height="42">](https://apps.apple.com/us/app/simplex-chat/id1605771084)
|
||||
|
||||
[](https://play.google.com/store/apps/details?id=chat.simplex.app)
|
||||
[](https://play.google.com/store/apps/details?id=chat.simplex.app)
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/f_droid.svg" alt="F-Droid" height="41">](https://app.simplex.chat)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/f_droid.svg" alt="F-Droid" height="41">](https://app.simplex.chat)
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/testflight.png" alt="iOS TestFlight" height="41">](https://testflight.apple.com/join/DWuT2LQu)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/testflight.png" alt="iOS TestFlight" height="41">](https://testflight.apple.com/join/DWuT2LQu)
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/apk_icon.png" alt="APK" height="41">](https://github.com/simplex-chat/simplex-chat/releases/latest/download/simplex.apk)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/apk_icon.png" alt="APK" height="41">](https://github.com/simplex-chat/simplex-chat/releases/latest/download/simplex.apk)
|
||||
|
||||
- 🖲 Protects your messages and metadata - who you talk to and when.
|
||||
- 🔐 Double ratchet end-to-end encryption, with additional encryption layer.
|
||||
@@ -84,7 +84,7 @@ You need to share a link with your friend or scan a QR code from their phone, in
|
||||
|
||||
The channel through which you share the link does not have to be secure - it is enough that you can confirm who sent you the message and that your SimpleX connection is established.
|
||||
|
||||
<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/app1.png" alt="Make a private connection" height="360"> <img src="https://github.com/simplex-chat/.github/blob/master/profile/images/arrow.png" height="360"> <img src="https://github.com/simplex-chat/.github/blob/master/profile/images/app2.png" alt="Conversation" height="360"> <img src="https://github.com/simplex-chat/.github/blob/master/profile/images/arrow.png" height="360"> <img src="https://github.com/simplex-chat/.github/blob/master/profile/images/app3.png" alt="Video call" height="360">
|
||||
<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/app1.png" alt="Make a private connection" height="360"> <img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/arrow.png" height="360"> <img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/app2.png" alt="Conversation" height="360"> <img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/arrow.png" height="360"> <img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/app3.png" alt="Video call" height="360">
|
||||
|
||||
After you connect, you can [verify connection security code](./blog/20230103-simplex-chat-v4.4-disappearing-messages.md#connection-security-verification).
|
||||
|
||||
@@ -425,12 +425,14 @@ Please do NOT report security vulnerabilities via GitHub issues.
|
||||
|
||||
This software is licensed under the GNU Affero General Public License version 3 (AGPLv3). See the [LICENSE](./LICENSE) file for details. The SimpleX and SimpleX Chat name, logo, and associated branding materials are not covered by this license and are subject to the terms outlined in the [TRADEMARK](./docs/TRADEMARK.md) file.
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/apple_store.svg" alt="iOS app" height="42">](https://apps.apple.com/us/app/simplex-chat/id1605771084)
|
||||
Graphic designs, artworks and layouts are not licensed for re-use. If you want to use them in your publications, please ask for permission. Texts can be used as direct quotes, referencing the source.
|
||||
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/apple_store.svg" alt="iOS app" height="42">](https://apps.apple.com/us/app/simplex-chat/id1605771084)
|
||||
|
||||
[](https://play.google.com/store/apps/details?id=chat.simplex.app)
|
||||
[](https://play.google.com/store/apps/details?id=chat.simplex.app)
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/f_droid.svg" alt="F-Droid" height="41">](https://app.simplex.chat)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/f_droid.svg" alt="F-Droid" height="41">](https://app.simplex.chat)
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/testflight.png" alt="iOS TestFlight" height="41">](https://testflight.apple.com/join/DWuT2LQu)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/testflight.png" alt="iOS TestFlight" height="41">](https://testflight.apple.com/join/DWuT2LQu)
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/apk_icon.png" alt="APK" height="41">](https://github.com/simplex-chat/simplex-chat/releases/latest/download/simplex.apk)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/apk_icon.png" alt="APK" height="41">](https://github.com/simplex-chat/simplex-chat/releases/latest/download/simplex.apk)
|
||||
@@ -42,12 +42,14 @@ class AppTheme: ObservableObject, Equatable {
|
||||
}
|
||||
|
||||
func updateFromCurrentColors() {
|
||||
objectWillChange.send()
|
||||
name = CurrentColors.name
|
||||
base = CurrentColors.base
|
||||
colors.updateColorsFrom(CurrentColors.colors)
|
||||
appColors.updateColorsFrom(CurrentColors.appColors)
|
||||
wallpaper.updateWallpaperFrom(CurrentColors.wallpaper)
|
||||
DispatchQueue.main.async {
|
||||
self.objectWillChange.send()
|
||||
self.name = CurrentColors.name
|
||||
self.base = CurrentColors.base
|
||||
self.colors.updateColorsFrom(CurrentColors.colors)
|
||||
self.appColors.updateColorsFrom(CurrentColors.appColors)
|
||||
self.wallpaper.updateWallpaperFrom(CurrentColors.wallpaper)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -272,7 +272,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="%lldd" xml:space="preserve">
|
||||
<source>%lldd</source>
|
||||
<target>%lldn</target>
|
||||
<target>%lldnap</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lldh" xml:space="preserve">
|
||||
@@ -292,7 +292,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="%lldmth" xml:space="preserve">
|
||||
<source>%lldmth</source>
|
||||
<target>%lldh</target>
|
||||
<target>%lldhónap</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%llds" xml:space="preserve">
|
||||
@@ -1199,17 +1199,17 @@ swipe action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Bad desktop address" xml:space="preserve">
|
||||
<source>Bad desktop address</source>
|
||||
<target>Érvénytelen számítógépcím</target>
|
||||
<target>Hibás a számítógép címe</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Bad message ID" xml:space="preserve">
|
||||
<source>Bad message ID</source>
|
||||
<target>Téves üzenet ID</target>
|
||||
<target>Hibás az üzenet azonosítója</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Bad message hash" xml:space="preserve">
|
||||
<source>Bad message hash</source>
|
||||
<target>Érvénytelen az üzenet kivonata</target>
|
||||
<target>Hibás az üzenet kivonata</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Better calls" xml:space="preserve">
|
||||
@@ -1239,7 +1239,7 @@ swipe action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Better networking" xml:space="preserve">
|
||||
<source>Better networking</source>
|
||||
<target>Jobb hálózatkezelés</target>
|
||||
<target>Továbbfejlesztett hálózatkezelés</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Better notifications" xml:space="preserve">
|
||||
@@ -2267,7 +2267,7 @@ Ez a saját egyszer használható meghívója!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Current conditions text couldn't be loaded, you can review conditions via this link:" xml:space="preserve">
|
||||
<source>Current conditions text couldn't be loaded, you can review conditions via this link:</source>
|
||||
<target>A jelenlegi feltételek szövegét nem lehetett betölteni, a feltételeket a következő hivatkozáson keresztül vizsgálhatja felül:</target>
|
||||
<target>A jelenlegi feltételek szövegét nem sikerült betölteni, a feltételeket a következő hivatkozáson keresztül vizsgálhatja felül:</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Current passphrase…" xml:space="preserve">
|
||||
@@ -2771,7 +2771,7 @@ swipe action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Different names, avatars and transport isolation." xml:space="preserve">
|
||||
<source>Different names, avatars and transport isolation.</source>
|
||||
<target>Különböző nevek, profilképek és átvitelizoláció.</target>
|
||||
<target>Különböző nevek, profilképek és átvitelelkülönítés.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Direct messages" xml:space="preserve">
|
||||
@@ -3457,7 +3457,7 @@ chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error opening group" xml:space="preserve">
|
||||
<source>Error opening group</source>
|
||||
<target>Hiba a csoport előkészítésekor</target>
|
||||
<target>Hiba történt a csoport megnyitásakor</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error receiving file" xml:space="preserve">
|
||||
@@ -3843,7 +3843,7 @@ snd error text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media not allowed" xml:space="preserve">
|
||||
<source>Files and media not allowed</source>
|
||||
<target>A fájlok és a médiatartalmak nincsenek engedélyezve</target>
|
||||
<target>A fájlok és a médiatartalmak küldése nincs engedélyezve</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media prohibited!" xml:space="preserve">
|
||||
@@ -4362,7 +4362,7 @@ Hiba: %2$@</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Import failed" xml:space="preserve">
|
||||
<source>Import failed</source>
|
||||
<target>Sikertelen importálás</target>
|
||||
<target>Nem sikerült az importálás</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Import theme" xml:space="preserve">
|
||||
@@ -4389,12 +4389,12 @@ További fejlesztések hamarosan!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Improved privacy and security" xml:space="preserve">
|
||||
<source>Improved privacy and security</source>
|
||||
<target>Fejlesztett adatvédelem és biztonság</target>
|
||||
<target>Továbbfejlesztett adatvédelem és biztonság</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Improved server configuration" xml:space="preserve">
|
||||
<source>Improved server configuration</source>
|
||||
<target>Javított kiszolgáló konfiguráció</target>
|
||||
<target>Továbbfejlesztett kiszolgálókonfiguráció</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In order to continue, chat should be stopped." xml:space="preserve">
|
||||
@@ -4672,7 +4672,7 @@ További fejlesztések hamarosan!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Join as %@" xml:space="preserve">
|
||||
<source>Join as %@</source>
|
||||
<target>csatlakozás mint %@</target>
|
||||
<target>Csatlakozás mint: %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Join group" xml:space="preserve">
|
||||
@@ -5574,7 +5574,7 @@ Ez a saját hivatkozása a(z) %@ nevű csoporthoz!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="No servers to send files." xml:space="preserve">
|
||||
<source>No servers to send files.</source>
|
||||
<target>Nincsenek fájlküldő-kiszolgálók.</target>
|
||||
<target>Nincsenek fájlküldési kiszolgálók.</target>
|
||||
<note>servers error</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No token!" xml:space="preserve">
|
||||
@@ -5784,7 +5784,7 @@ VPN engedélyezése szükséges.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Only your contact can send files and media." xml:space="preserve">
|
||||
<source>Only your contact can send files and media.</source>
|
||||
<target>Csak a partnere küldhet fájlokat és a médiatartalmakat.</target>
|
||||
<target>Csak a partnere küldhet fájlokat és médiatartalmakat.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Only your contact can send voice messages." xml:space="preserve">
|
||||
@@ -7536,7 +7536,7 @@ chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Share old link" xml:space="preserve">
|
||||
<source>Share old link</source>
|
||||
<target>Teljes hivatkozás megosztása</target>
|
||||
<target>Régi (hosszú) hivatkozás megosztása</target>
|
||||
<note>alert button</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Share profile" xml:space="preserve">
|
||||
@@ -8595,7 +8595,7 @@ A kapcsolódáshoz kérje meg a partnerét, hogy hozzon létre egy másik kapcso
|
||||
</trans-unit>
|
||||
<trans-unit id="Unlink" xml:space="preserve">
|
||||
<source>Unlink</source>
|
||||
<target>Szétkapcsolás</target>
|
||||
<target>Leválasztás</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Unlink desktop?" xml:space="preserve">
|
||||
@@ -8755,7 +8755,7 @@ A kapcsolódáshoz kérje meg a partnerét, hogy hozzon létre egy másik kapcso
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<target>A 443-as TCP-port használata kizárólag az előre beállított kiszolgálokhoz.</target>
|
||||
<target>A 443-as TCP-port használata kizárólag az előre beállított kiszolgálókhoz.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
@@ -8815,7 +8815,7 @@ A kapcsolódáshoz kérje meg a partnerét, hogy hozzon létre egy másik kapcso
|
||||
</trans-unit>
|
||||
<trans-unit id="Use private routing with unknown servers." xml:space="preserve">
|
||||
<source>Use private routing with unknown servers.</source>
|
||||
<target>Privát útválasztás használata ismeretlen kiszolgálókkal.</target>
|
||||
<target>Privát útválasztás használata az ismeretlen kiszolgálókhoz.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use server" xml:space="preserve">
|
||||
@@ -9317,7 +9317,7 @@ Megismétli a csatlakozási kérést?</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can't send messages!" xml:space="preserve">
|
||||
<source>You can't send messages!</source>
|
||||
<target>Nem lehet üzeneteket küldeni!</target>
|
||||
<target>Ön nem tud üzeneteket küldeni!</target>
|
||||
<note>alert title</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You could not be verified; please try again." xml:space="preserve">
|
||||
@@ -9529,7 +9529,7 @@ Megismétli a kapcsolódási kérést?</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Your credentials may be sent unencrypted." xml:space="preserve">
|
||||
<source>Your credentials may be sent unencrypted.</source>
|
||||
<target>A hitelesítési adati titkosítatlanul is elküldhetők.</target>
|
||||
<target>A hitelesítési adatai titkosítatlanul is elküldhetők.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Your current chat database will be DELETED and REPLACED with the imported one." xml:space="preserve">
|
||||
@@ -9559,7 +9559,7 @@ Megismétli a kapcsolódási kérést?</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Your profile" xml:space="preserve">
|
||||
<source>Your profile</source>
|
||||
<target>Profil</target>
|
||||
<target>Saját profil</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Your profile **%@** will be shared." xml:space="preserve">
|
||||
@@ -10523,7 +10523,7 @@ utoljára fogadott üzenet: %2$@</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="unknown servers" xml:space="preserve">
|
||||
<source>unknown servers</source>
|
||||
<target>ismeretlen átjátszók</target>
|
||||
<target>ismeretlen kiszolgálók</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="unknown status" xml:space="preserve">
|
||||
|
||||
@@ -56,5 +56,7 @@
|
||||
<string>remote-notification</string>
|
||||
<string>voip</string>
|
||||
</array>
|
||||
<key>UIDesignRequiresCompatibility</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -178,8 +178,8 @@
|
||||
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; };
|
||||
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829982D54AEED006B9E89 /* libgmp.a */; };
|
||||
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829992D54AEEE006B9E89 /* libffi.a */; };
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.3-8ATMbsLjvgc8dH25M4OGyN-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.3-8ATMbsLjvgc8dH25M4OGyN-ghc9.6.3.a */; };
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.3-8ATMbsLjvgc8dH25M4OGyN.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.3-8ATMbsLjvgc8dH25M4OGyN.a */; };
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.4-45BRYFUa7pfAow5e7qNgo6-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.4-45BRYFUa7pfAow5e7qNgo6-ghc9.6.3.a */; };
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.4-45BRYFUa7pfAow5e7qNgo6.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.4-45BRYFUa7pfAow5e7qNgo6.a */; };
|
||||
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */; };
|
||||
64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; };
|
||||
64D0C2C229FA57AB00B38D5F /* UserAddressLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */; };
|
||||
@@ -545,8 +545,8 @@
|
||||
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = "<group>"; };
|
||||
64C829982D54AEED006B9E89 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
64C829992D54AEEE006B9E89 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.3-8ATMbsLjvgc8dH25M4OGyN-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.5.0.3-8ATMbsLjvgc8dH25M4OGyN-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.3-8ATMbsLjvgc8dH25M4OGyN.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.5.0.3-8ATMbsLjvgc8dH25M4OGyN.a"; sourceTree = "<group>"; };
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.4-45BRYFUa7pfAow5e7qNgo6-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.5.0.4-45BRYFUa7pfAow5e7qNgo6-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.4-45BRYFUa7pfAow5e7qNgo6.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.5.0.4-45BRYFUa7pfAow5e7qNgo6.a"; sourceTree = "<group>"; };
|
||||
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = "<group>"; };
|
||||
64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressLearnMore.swift; sourceTree = "<group>"; };
|
||||
@@ -708,8 +708,8 @@
|
||||
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */,
|
||||
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */,
|
||||
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */,
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.3-8ATMbsLjvgc8dH25M4OGyN-ghc9.6.3.a in Frameworks */,
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.3-8ATMbsLjvgc8dH25M4OGyN.a in Frameworks */,
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.4-45BRYFUa7pfAow5e7qNgo6-ghc9.6.3.a in Frameworks */,
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.4-45BRYFUa7pfAow5e7qNgo6.a in Frameworks */,
|
||||
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -795,8 +795,8 @@
|
||||
64C829992D54AEEE006B9E89 /* libffi.a */,
|
||||
64C829982D54AEED006B9E89 /* libgmp.a */,
|
||||
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */,
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.3-8ATMbsLjvgc8dH25M4OGyN-ghc9.6.3.a */,
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.3-8ATMbsLjvgc8dH25M4OGyN.a */,
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.4-45BRYFUa7pfAow5e7qNgo6-ghc9.6.3.a */,
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.4-45BRYFUa7pfAow5e7qNgo6.a */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@@ -2003,7 +2003,7 @@
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 309;
|
||||
CURRENT_PROJECT_VERSION = 312;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -2053,7 +2053,7 @@
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 309;
|
||||
CURRENT_PROJECT_VERSION = 312;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -2095,7 +2095,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 309;
|
||||
CURRENT_PROJECT_VERSION = 312;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
@@ -2115,7 +2115,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 309;
|
||||
CURRENT_PROJECT_VERSION = 312;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
@@ -2140,7 +2140,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 309;
|
||||
CURRENT_PROJECT_VERSION = 312;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
@@ -2177,7 +2177,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 309;
|
||||
CURRENT_PROJECT_VERSION = 312;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_CODE_COVERAGE = NO;
|
||||
@@ -2214,7 +2214,7 @@
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 309;
|
||||
CURRENT_PROJECT_VERSION = 312;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -2265,7 +2265,7 @@
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 309;
|
||||
CURRENT_PROJECT_VERSION = 312;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -2316,7 +2316,7 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 309;
|
||||
CURRENT_PROJECT_VERSION = 312;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
@@ -2350,7 +2350,7 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 309;
|
||||
CURRENT_PROJECT_VERSION = 312;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
"%lld seconds" = "%lld mp";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%lldd" = "%lldn";
|
||||
"%lldd" = "%lldnap";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%lldh" = "%lldó";
|
||||
@@ -239,7 +239,7 @@
|
||||
"%lldm" = "%lldp";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%lldmth" = "%lldh";
|
||||
"%lldmth" = "%lldhónap";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%llds" = "%lldmp";
|
||||
@@ -774,19 +774,19 @@ swipe action */
|
||||
"Background" = "Háttér";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Bad desktop address" = "Érvénytelen számítógépcím";
|
||||
"Bad desktop address" = "Hibás a számítógép címe";
|
||||
|
||||
/* integrity error chat item */
|
||||
"bad message hash" = "hibás az üzenet kivonata";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Bad message hash" = "Érvénytelen az üzenet kivonata";
|
||||
"Bad message hash" = "Hibás az üzenet kivonata";
|
||||
|
||||
/* integrity error chat item */
|
||||
"bad message ID" = "hibás az üzenet azonosítója";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Bad message ID" = "Téves üzenet ID";
|
||||
"Bad message ID" = "Hibás az üzenet azonosítója";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Better calls" = "Továbbfejlesztett hívásélmény";
|
||||
@@ -804,7 +804,7 @@ swipe action */
|
||||
"Better messages" = "Továbbfejlesztett üzenetek";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Better networking" = "Jobb hálózatkezelés";
|
||||
"Better networking" = "Továbbfejlesztett hálózatkezelés";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Better notifications" = "Továbbfejlesztett értesítések";
|
||||
@@ -1522,7 +1522,7 @@ set passcode view */
|
||||
"creator" = "készítő";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Current conditions text couldn't be loaded, you can review conditions via this link:" = "A jelenlegi feltételek szövegét nem lehetett betölteni, a feltételeket a következő hivatkozáson keresztül vizsgálhatja felül:";
|
||||
"Current conditions text couldn't be loaded, you can review conditions via this link:" = "A jelenlegi feltételek szövegét nem sikerült betölteni, a feltételeket a következő hivatkozáson keresztül vizsgálhatja felül:";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Current Passcode" = "Jelenlegi jelkód";
|
||||
@@ -1857,7 +1857,7 @@ swipe action */
|
||||
"different migration in the app/database: %@ / %@" = "különböző átköltöztetés az alkalmazásban/adatbázisban: %@ / %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Different names, avatars and transport isolation." = "Különböző nevek, profilképek és átvitelizoláció.";
|
||||
"Different names, avatars and transport isolation." = "Különböző nevek, profilképek és átvitelelkülönítés.";
|
||||
|
||||
/* connection level description */
|
||||
"direct" = "közvetlen";
|
||||
@@ -2326,7 +2326,7 @@ chat item action */
|
||||
"Error opening chat" = "Hiba történt a csevegés megnyitásakor";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error opening group" = "Hiba a csoport előkészítésekor";
|
||||
"Error opening group" = "Hiba történt a csoport megnyitásakor";
|
||||
|
||||
/* alert title */
|
||||
"Error receiving file" = "Hiba történt a fájl fogadásakor";
|
||||
@@ -2559,7 +2559,7 @@ snd error text */
|
||||
"Files and media are prohibited." = "A fájlok és a médiatartalmak küldése le van tiltva.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Files and media not allowed" = "A fájlok és a médiatartalmak nincsenek engedélyezve";
|
||||
"Files and media not allowed" = "A fájlok és a médiatartalmak küldése nincs engedélyezve";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Files and media prohibited!" = "A fájlok és a médiatartalmak küldése le van tiltva!";
|
||||
@@ -2883,7 +2883,7 @@ snd error text */
|
||||
"Import database" = "Adatbázis importálása";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Import failed" = "Sikertelen importálás";
|
||||
"Import failed" = "Nem sikerült az importálás";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Import theme" = "Téma importálása";
|
||||
@@ -2898,10 +2898,10 @@ snd error text */
|
||||
"Improved message delivery" = "Továbbfejlesztett üzenetkézbesítés";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Improved privacy and security" = "Fejlesztett adatvédelem és biztonság";
|
||||
"Improved privacy and security" = "Továbbfejlesztett adatvédelem és biztonság";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Improved server configuration" = "Javított kiszolgáló konfiguráció";
|
||||
"Improved server configuration" = "Továbbfejlesztett kiszolgálókonfiguráció";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"In order to continue, chat should be stopped." = "A folytatáshoz a csevegést meg kell szakítani.";
|
||||
@@ -3117,7 +3117,7 @@ snd error text */
|
||||
"Join" = "Csatlakozás";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Join as %@" = "csatlakozás mint %@";
|
||||
"Join as %@" = "Csatlakozás mint: %@";
|
||||
|
||||
/* new chat sheet title */
|
||||
"Join group" = "Csatlakozás a csoporthoz";
|
||||
@@ -3711,7 +3711,7 @@ snd error text */
|
||||
"No servers to receive messages." = "Nincsenek üzenetfogadási kiszolgálók.";
|
||||
|
||||
/* servers error */
|
||||
"No servers to send files." = "Nincsenek fájlküldő-kiszolgálók.";
|
||||
"No servers to send files." = "Nincsenek fájlküldési kiszolgálók.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"no subscription" = "nincs előfizetés";
|
||||
@@ -3860,7 +3860,7 @@ new chat action */
|
||||
"Only your contact can send disappearing messages." = "Csak a partnere tud eltűnő üzeneteket küldeni.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Only your contact can send files and media." = "Csak a partnere küldhet fájlokat és a médiatartalmakat.";
|
||||
"Only your contact can send files and media." = "Csak a partnere küldhet fájlokat és médiatartalmakat.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Only your contact can send voice messages." = "Csak a partnere tud hangüzeneteket küldeni.";
|
||||
@@ -5007,7 +5007,7 @@ chat item action */
|
||||
"Share old address" = "Régi cím megosztása";
|
||||
|
||||
/* alert button */
|
||||
"Share old link" = "Teljes hivatkozás megosztása";
|
||||
"Share old link" = "Régi (hosszú) hivatkozás megosztása";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Share profile" = "Profil megosztása";
|
||||
@@ -5656,7 +5656,7 @@ report reason */
|
||||
"Unknown error" = "Ismeretlen hiba";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"unknown servers" = "ismeretlen átjátszók";
|
||||
"unknown servers" = "ismeretlen kiszolgálók";
|
||||
|
||||
/* alert title */
|
||||
"Unknown servers!" = "Ismeretlen kiszolgálók!";
|
||||
@@ -5671,7 +5671,7 @@ report reason */
|
||||
"Unless your contact deleted the connection or this link was already used, it might be a bug - please report it.\nTo connect, please ask your contact to create another connection link and check that you have a stable network connection." = "Hacsak a partnere nem törölte a kapcsolatot, vagy ez a hivatkozás már használatban volt egyszer, lehet hogy ez egy hiba – jelentse a problémát.\nA kapcsolódáshoz kérje meg a partnerét, hogy hozzon létre egy másik kapcsolattartási hivatkozást, és ellenőrizze, hogy a hálózati kapcsolat stabil-e.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unlink" = "Szétkapcsolás";
|
||||
"Unlink" = "Leválasztás";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unlink desktop?" = "Leválasztja a számítógépet?";
|
||||
@@ -5800,7 +5800,7 @@ report reason */
|
||||
"Use private routing with unknown servers when IP address is not protected." = "Privát útválasztás használata az ismeretlen kiszolgálókkal, ha az IP-cím nem védett.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use private routing with unknown servers." = "Privát útválasztás használata ismeretlen kiszolgálókkal.";
|
||||
"Use private routing with unknown servers." = "Privát útválasztás használata az ismeretlen kiszolgálókhoz.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use server" = "Kiszolgáló használata";
|
||||
@@ -5818,7 +5818,7 @@ report reason */
|
||||
"Use TCP port %@ when no port is specified." = "A következő TCP-port használata, amikor nincs port megadva: %@.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use TCP port 443 for preset servers only." = "A 443-as TCP-port használata kizárólag az előre beállított kiszolgálokhoz.";
|
||||
"Use TCP port 443 for preset servers only." = "A 443-as TCP-port használata kizárólag az előre beállított kiszolgálókhoz.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use the app while in the call." = "Alkalmazás használata hívás közben.";
|
||||
@@ -6166,7 +6166,7 @@ report reason */
|
||||
"You can view your reports in Chat with admins." = "A jelentéseket megtekintheti a „Csevegés az adminisztrátorokkal” menüben.";
|
||||
|
||||
/* alert title */
|
||||
"You can't send messages!" = "Nem lehet üzeneteket küldeni!";
|
||||
"You can't send messages!" = "Ön nem tud üzeneteket küldeni!";
|
||||
|
||||
/* chat item text */
|
||||
"you changed address" = "Ön módosította a címet";
|
||||
@@ -6316,7 +6316,7 @@ report reason */
|
||||
"Your contacts will remain connected." = "A partnerei továbbra is kapcsolódva maradnak.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Your credentials may be sent unencrypted." = "A hitelesítési adati titkosítatlanul is elküldhetők.";
|
||||
"Your credentials may be sent unencrypted." = "A hitelesítési adatai titkosítatlanul is elküldhetők.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Your current chat database will be DELETED and REPLACED with the imported one." = "A jelenlegi csevegési adatbázis TÖRÖLVE és CSERÉLVE lesz az importáltra.";
|
||||
@@ -6337,7 +6337,7 @@ report reason */
|
||||
"Your privacy" = "Adatvédelem";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Your profile" = "Profil";
|
||||
"Your profile" = "Saját profil";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Your profile **%@** will be shared." = "A(z) **%@** nevű profilja meg lesz osztva.";
|
||||
|
||||
@@ -15,8 +15,7 @@ android {
|
||||
applicationId = "chat.simplex.app"
|
||||
namespace = "chat.simplex.app"
|
||||
minSdk = 26
|
||||
//noinspection OldTargetApi
|
||||
targetSdk = 34
|
||||
targetSdk = 35
|
||||
// !!!
|
||||
// skip version code after release to F-Droid, as it uses two version codes
|
||||
versionCode = (extra["android.version_code"] as String).toInt()
|
||||
|
||||
@@ -95,7 +95,8 @@ kotlin {
|
||||
|
||||
implementation("com.jakewharton:process-phoenix:3.0.0")
|
||||
|
||||
val cameraXVersion = "1.3.4"
|
||||
// https://issuetracker.google.com/issues/351313880
|
||||
val cameraXVersion = "1.5.1"
|
||||
implementation("androidx.camera:camera-core:${cameraXVersion}")
|
||||
implementation("androidx.camera:camera-camera2:${cameraXVersion}")
|
||||
implementation("androidx.camera:camera-lifecycle:${cameraXVersion}")
|
||||
|
||||
@@ -57,6 +57,9 @@ set_target_properties( support PROPERTIES IMPORTED_LOCATION
|
||||
# can link multiple libraries, such as libraries you define in this
|
||||
# build script, prebuilt third-party libraries, or system libraries.
|
||||
|
||||
# https://developer.android.com/guide/practices/page-sizes#cmake
|
||||
target_link_options(app-lib PRIVATE "-Wl,-z,max-page-size=16384")
|
||||
|
||||
target_link_libraries( # Specifies the target library.
|
||||
app-lib
|
||||
|
||||
|
||||
@@ -1128,7 +1128,7 @@
|
||||
<string name="alert_text_msg_bad_id">معرف الرسالة التالية غير صحيح (أقل أو يساوي السابق).
|
||||
\nيمكن أن يحدث ذلك بسبب بعض العلل أو عندما يُخترق الاتصال.</string>
|
||||
<string name="unfavorite_chat">أزل من المفضلة</string>
|
||||
<string name="trying_to_connect_to_server_to_receive_messages">محاولة الاتصال بالخادم المستخدم لاستلام الرسائل من جهة الاتصال هذه.</string>
|
||||
<string name="trying_to_connect_to_server_to_receive_messages">محاولة الاتصال بالخادم المستخدم لاستلام الرسائل من هذا الاتصال.</string>
|
||||
<string name="choose_file_title">اختيار ملف</string>
|
||||
<string name="icon_descr_sent_msg_status_unauthorized_send">إرسال غير مصرح به</string>
|
||||
<string name="error_connecting_to_server_to_receive_messages">محاولة الاتصال بالخادم المستخدم لاستلام الرسائل من جهة الاتصال هذه (خطأ: %1$s).</string>
|
||||
@@ -1137,7 +1137,7 @@
|
||||
<string name="alert_title_cant_invite_contacts_descr">أنت تستخدم ملف تعريف متخفي لهذه المجموعة - لمنع مشاركة ملفك التعريفي الرئيسي الذي يدعو جهات الاتصال غير مسموح به</string>
|
||||
<string name="snd_group_event_changed_member_role">غيّرتَ دور %s إلى %s</string>
|
||||
<string name="chat_preferences_yes">نعم</string>
|
||||
<string name="connected_to_server_to_receive_messages_from_contact">أنت متصل بالخادم المستخدم لاستلام الرسائل من جهة الاتصال هذه.</string>
|
||||
<string name="connected_to_server_to_receive_messages_from_contact">أنت متصل بالخادم المستخدم لاستلام الرسائل من هذا الاتصال.</string>
|
||||
<string name="sender_you_pronoun">أنت</string>
|
||||
<string name="description_you_shared_one_time_link">لقد شاركت رابط لمرة واحدة</string>
|
||||
<string name="profile_will_be_sent_to_contact_sending_link">سيتم إرسال ملف التعريفك إلى جهة الاتصال التي استلمت منها هذا الرابط.</string>
|
||||
@@ -2520,4 +2520,6 @@
|
||||
<string name="proxy_destination_error_unknown_ca">البصمة في عنوان الخادم الوجهة لا تتطابق مع الشهادة: %1$s.</string>
|
||||
<string name="smp_proxy_error_unknown_ca">البصمة في عنوان خادم التحويل لا تتطابق مع الشهادة: %1$s.</string>
|
||||
<string name="network_error_unknown_ca">البصمة في عنوان الخادم لا تتطابق مع الشهادة: %1$s.</string>
|
||||
<string name="server_no_sub">لا اشتراك</string>
|
||||
<string name="not_connected_to_server_to_receive_messages_no_sub">أنت غير متصل بالخادم المستخدم لاستقبال الرسائل من هذا الاتصال (لا يوجد اشتراك).</string>
|
||||
</resources>
|
||||
@@ -429,7 +429,7 @@
|
||||
<string name="simplex_link_mode_description">Leírás</string>
|
||||
<string name="ttl_hour">%d óra</string>
|
||||
<string name="ttl_m">%dp</string>
|
||||
<string name="disconnect_remote_host">Szétkapcsolás</string>
|
||||
<string name="disconnect_remote_host">Kapcsolat bontása</string>
|
||||
<string name="edit_verb">Szerkesztés</string>
|
||||
<string name="receipts_groups_disable_keep_overrides">Letiltás (csoport egyéni beállításainak megtartása)</string>
|
||||
<string name="rcv_group_events_count">%d csoportesemény</string>
|
||||
@@ -532,7 +532,7 @@
|
||||
<string name="files_and_media">Fájlok és médiatartalmak</string>
|
||||
<string name="section_title_for_console">KONZOLHOZ</string>
|
||||
<string name="alert_text_encryption_renegotiation_failed">Nem sikerült a titkosítást újraegyeztetni.</string>
|
||||
<string name="error_deleting_user">Hiba történt a felhasználóprofil törlésekor</string>
|
||||
<string name="error_deleting_user">Hiba történt a felhasználói profil törlésekor</string>
|
||||
<string name="fix_connection_not_supported_by_group_member">Csoporttag általi javítás nem támogatott</string>
|
||||
<string name="enter_welcome_message">Adja meg az üdvözlőüzenetet…</string>
|
||||
<string name="encrypted_database">Titkosított adatbázis</string>
|
||||
@@ -634,7 +634,7 @@
|
||||
<string name="how_to">Hogyan</string>
|
||||
<string name="hide_verb">Összecsukás</string>
|
||||
<string name="gallery_image_button">Kép</string>
|
||||
<string name="v4_3_improved_privacy_and_security">Fejlesztett adatvédelem és biztonság</string>
|
||||
<string name="v4_3_improved_privacy_and_security">Továbbfejlesztett adatvédelem és biztonság</string>
|
||||
<string name="ignore">Mellőzés</string>
|
||||
<string name="icon_descr_image_snd_complete">Kép elküldve</string>
|
||||
<string name="notification_preview_mode_hidden">Se név, se üzenet</string>
|
||||
@@ -645,7 +645,7 @@
|
||||
<string name="incognito">Inkognitó</string>
|
||||
<string name="how_to_use_simplex_chat">Használati útmutató</string>
|
||||
<string name="v4_3_improved_privacy_and_security_desc">Alkalmazás képernyőjének elrejtése a gyakran használt alkalmazások között.</string>
|
||||
<string name="v4_3_improved_server_configuration">Javított kiszolgáló konfiguráció</string>
|
||||
<string name="v4_3_improved_server_configuration">Továbbfejlesztett kiszolgálókonfiguráció</string>
|
||||
<string name="edit_history">Előzmények</string>
|
||||
<string name="hidden_profile_password">Rejtett profiljelszó</string>
|
||||
<string name="import_database">Adatbázis importálása</string>
|
||||
@@ -751,7 +751,7 @@
|
||||
<string name="chat_preferences_on">bekapcsolva</string>
|
||||
<string name="v5_1_japanese_portuguese_interface">Japán és portugál kezelőfelület</string>
|
||||
<string name="message_deletion_prohibited_in_chat">Az üzenetek végleges törlése le van tiltva.</string>
|
||||
<string name="remote_host_was_disconnected_toast"><![CDATA[Kapcsolat bontva a(z) <b>%s</b> nevű hordozható eszközzel]]></string>
|
||||
<string name="remote_host_was_disconnected_toast"><![CDATA[A(z) <b>%s</b> nevű hordozható eszköz le lett választva]]></string>
|
||||
<string name="custom_time_unit_months">hónap</string>
|
||||
<string name="privacy_message_draft">Üzenetvázlat</string>
|
||||
<string name="v5_2_disappear_one_message">Egy üzenet eltüntetése</string>
|
||||
@@ -817,7 +817,7 @@
|
||||
<string name="invite_friends">Barátok meghívása</string>
|
||||
<string name="color_surface">Menük és figyelmeztetések</string>
|
||||
<string name="icon_descr_add_members">Tagok meghívása</string>
|
||||
<string name="group_preview_join_as">Csatlakozás mint %s</string>
|
||||
<string name="group_preview_join_as">Csatlakozás mint: %s</string>
|
||||
<string name="no_selected_chat">Nincs csevegés kijelölve</string>
|
||||
<string name="users_delete_data_only">Csak helyi profiladatok</string>
|
||||
<string name="description_via_one_time_link_incognito">inkognitó egy egyszer használható meghívón keresztül</string>
|
||||
@@ -1142,7 +1142,7 @@
|
||||
<string name="this_QR_code_is_not_a_link">Ez a QR-kód nem egy hivatkozás!</string>
|
||||
<string name="waiting_for_file">Várakozás a fájlra</string>
|
||||
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
|
||||
<string name="unlink_desktop">Szétkapcsolás</string>
|
||||
<string name="unlink_desktop">Leválasztás</string>
|
||||
<string name="incognito_random_profile">Véletlenszerű profil</string>
|
||||
<string name="wrong_passphrase_title">Érvénytelen jelmondat!</string>
|
||||
<string name="prohibit_message_reactions_group">A reakciók hozzáadása az üzenetekhez le van tiltva.</string>
|
||||
@@ -1269,7 +1269,7 @@
|
||||
<string name="chat_with_the_founder">Ötletek és javaslatok</string>
|
||||
<string name="database_downgrade_warning">Figyelmeztetés: néhány adat elveszhet!</string>
|
||||
<string name="tap_to_start_new_chat">Koppintson ide az új csevegés indításához</string>
|
||||
<string name="waiting_for_desktop">Várakozás a számítógépre…</string>
|
||||
<string name="waiting_for_desktop">Várakozás a számítógép-alkalmazásra…</string>
|
||||
<string name="next_generation_of_private_messaging">Az üzenetváltás jövője</string>
|
||||
<string name="update_network_settings_question">Módosítja a hálózati beállításokat?</string>
|
||||
<string name="waiting_for_mobile_to_connect">Várakozás a hordozható eszköz társítására:</string>
|
||||
@@ -1520,7 +1520,7 @@
|
||||
<string name="remote_ctrl_error_inactive">Számítógép inaktív</string>
|
||||
<string name="restart_chat_button">Csevegés újraindítása</string>
|
||||
<string name="remote_ctrl_error_timeout">Időtúllépés a számítógéphez való csatlakozáskor</string>
|
||||
<string name="remote_ctrl_error_disconnected">Kapcsolat bontva a számítógéppel</string>
|
||||
<string name="remote_ctrl_error_disconnected">A számítógép le lett választva</string>
|
||||
<string name="remote_host_was_disconnected_title">A kapcsolat megszakadt</string>
|
||||
<string name="remote_ctrl_was_disconnected_title">A kapcsolat megszakadt</string>
|
||||
<string name="remote_ctrl_error_bad_state">A kapcsolat a számítógéppel rossz állapotban van</string>
|
||||
@@ -1528,10 +1528,10 @@
|
||||
<string name="agent_internal_error_desc">Jelentse a fejlesztőknek:
|
||||
\n%s</string>
|
||||
<string name="remote_host_error_bad_version"><![CDATA[A(z) <b>%s</b> hordozható eszköz által használt alkalmazás verziója nem támogatott. Győződjön meg arról, hogy mindkét eszközön ugyanazt a verziót használja]]></string>
|
||||
<string name="remote_host_error_disconnected"><![CDATA[Kapcsolat bontva a(z) <b>%s</b> nevű hordozható eszközzel]]></string>
|
||||
<string name="remote_host_error_disconnected"><![CDATA[A(z) <b>%s</b> nevű hordozható eszköz le lett választva]]></string>
|
||||
<string name="failed_to_create_user_invalid_title">Érvénytelen megjelenítendő név!</string>
|
||||
<string name="failed_to_create_user_invalid_desc">Ez a megjelenítendő név érvénytelen. Válasszon egy másik nevet.</string>
|
||||
<string name="remote_host_disconnected_from"><![CDATA[Kapcsolat bontva a(z) <b>%s</b> nevű hordozható eszközzel, a következő okból: %s]]></string>
|
||||
<string name="remote_host_disconnected_from"><![CDATA[A(z) <b>%s</b> nevű hordozható eszköz le lett választva, a következő okból: %s]]></string>
|
||||
<string name="remote_ctrl_disconnected_with_reason">Kapcsolat bontva a következő okból: %s</string>
|
||||
<string name="remote_host_error_missing"><![CDATA[A(z) <b>%s</b> hordozható eszköz nem található]]></string>
|
||||
<string name="remote_host_error_bad_state"><![CDATA[A kapcsolat a(z) <b>%s</b> hordozható eszközzel rossz állapotban van]]></string>
|
||||
@@ -1741,7 +1741,7 @@
|
||||
<string name="network_smp_proxy_fallback_allow">Igen</string>
|
||||
<string name="network_smp_proxy_mode_never_description">NE használjon privát útválasztást.</string>
|
||||
<string name="network_smp_proxy_mode_private_routing">Privát útválasztás</string>
|
||||
<string name="network_smp_proxy_mode_unknown_description">Privát útválasztás használata az ismeretlen kiszolgálókkal.</string>
|
||||
<string name="network_smp_proxy_mode_unknown_description">Privát útválasztás használata az ismeretlen kiszolgálókhoz.</string>
|
||||
<string name="network_smp_proxy_mode_always_description">Mindig használjon privát útválasztást.</string>
|
||||
<string name="update_network_smp_proxy_mode_question">Üzenet-útválasztási mód</string>
|
||||
<string name="network_smp_proxy_fallback_allow_protected_description">Közvetlen üzenetküldés, ha az IP-cím védett és a saját kiszolgálója vagy a célkiszolgáló nem támogatja a privát útválasztást.</string>
|
||||
@@ -1790,7 +1790,7 @@
|
||||
<string name="v5_8_persian_ui">Perzsa kezelőfelület</string>
|
||||
<string name="v5_8_private_routing_descr">Védje az IP-címét a partnerei által kiválasztott üzenetváltási továbbítókiszolgálókkal szemben.\nEngedélyezze a *Hálózat és kiszolgálók* menüben.</string>
|
||||
<string name="v5_8_safe_files_descr">Ismeretlen kiszolgálókról származó fájlok megerősítése.</string>
|
||||
<string name="v5_8_message_delivery">Javított üzenetkézbesítés</string>
|
||||
<string name="v5_8_message_delivery">Továbbfejlesztett üzenetkézbesítés</string>
|
||||
<string name="chat_theme_reset_to_app_theme">Alkalmazás témájának visszaállítása</string>
|
||||
<string name="v5_8_chat_themes_descr">Tegye egyedivé a csevegéseit!</string>
|
||||
<string name="v5_8_chat_themes">Új csevegési témák</string>
|
||||
@@ -2057,7 +2057,7 @@
|
||||
<string name="settings_section_title_message_shape">Üzenetbuborék alakja</string>
|
||||
<string name="settings_message_shape_tail">Farok</string>
|
||||
<string name="network_session_mode_server">Kiszolgáló</string>
|
||||
<string name="network_session_mode_session_description">Minden alkalommal, amikor elindítja az alkalmazást, új SOCKS-hitelesítési adatokat fog használni.</string>
|
||||
<string name="network_session_mode_session_description">Minden alkalommal, amikor elindítja az alkalmazást, új SOCKS-hitelesítési adatok lesznek használva.</string>
|
||||
<string name="network_session_mode_session">Alkalmazás munkamenete</string>
|
||||
<string name="network_session_mode_server_description">Az összes kiszolgálóhoz új, SOCKS-hitelesítési adatok lesznek használva.</string>
|
||||
<string name="call_desktop_permission_denied_chrome">Kattintson a címmező melletti info gombra a mikrofon használatának engedélyezéséhez.</string>
|
||||
@@ -2127,7 +2127,7 @@
|
||||
<string name="operator_info_title">Hálózatüzemeltető</string>
|
||||
<string name="operator_website">Weboldal</string>
|
||||
<string name="operator_conditions_accepted_on">Feltételek elfogadásának ideje: %s.</string>
|
||||
<string name="operator_conditions_will_be_accepted_on">A feltételek el lesznek elfogadva a következő időpontban: %s.</string>
|
||||
<string name="operator_conditions_will_be_accepted_on">A feltételek el lesznek fogadva a következő időpontban: %s.</string>
|
||||
<string name="operator_use_operator_toggle_description">Kiszolgálók használata</string>
|
||||
<string name="use_servers_of_operator_x">%s használata</string>
|
||||
<string name="operator_conditions_failed_to_load">A jelenlegi feltételek szövegét nem sikerült betölteni, a feltételeket a következő hivatkozáson keresztül vizsgálhatja felül:</string>
|
||||
@@ -2162,7 +2162,7 @@
|
||||
<string name="v6_2_network_decentralization_enable_flux">A Flux kiszolgálókat engedélyezheti a beállításokban, a „Hálózat és kiszolgálók” menüben, a metaadatok jobb védelme érdekében.</string>
|
||||
<string name="appearance_app_toolbars">Eszköztárak</string>
|
||||
<string name="v6_2_network_decentralization_enable_flux_reason">a metaadatok jobb védelme érdekében.</string>
|
||||
<string name="v6_2_improved_chat_navigation">Javított csevegési navigáció</string>
|
||||
<string name="v6_2_improved_chat_navigation">Továbbfejlesztett csevegési navigáció</string>
|
||||
<string name="v6_2_improved_chat_navigation_descr">- Csevegés megnyitása az első olvasatlan üzenetnél.\n- Ugrás az idézett üzenetekre.</string>
|
||||
<string name="view_updated_conditions">Frissített feltételek megtekintése</string>
|
||||
<string name="xftp_servers_per_user">A jelenlegi csevegési profiljához tartozó új fájlok kiszolgálói</string>
|
||||
@@ -2352,7 +2352,7 @@
|
||||
<string name="network_smp_web_port_all">Összes kiszolgáló</string>
|
||||
<string name="network_smp_web_port_off">Kikapcsolva</string>
|
||||
<string name="network_smp_web_port_preset">Előre beállított kiszolgálók</string>
|
||||
<string name="network_smp_web_port_preset_footer">A 443-as TCP-port használata kizárólag az előre beállított kiszolgálokhoz.</string>
|
||||
<string name="network_smp_web_port_preset_footer">A 443-as TCP-port használata kizárólag az előre beállított kiszolgálókhoz.</string>
|
||||
<string name="error_accepting_member">Hiba a tag befogadásakor</string>
|
||||
<string name="group_new_support_chats">%d csevegés a tagokkal</string>
|
||||
<string name="group_new_support_messages">%d üzenet</string>
|
||||
@@ -2398,7 +2398,7 @@
|
||||
<string name="cant_send_message_contact_not_ready">a partner nem áll készen</string>
|
||||
<string name="cant_send_message_contact_not_synchronized">nincs szinkronizálva</string>
|
||||
<string name="delete_member_support_chat_alert_title">Törli a taggal való csevegést?</string>
|
||||
<string name="cant_send_message_contact_deleted">a partnere elhagyta a csevegést</string>
|
||||
<string name="cant_send_message_contact_deleted">partner törölve</string>
|
||||
<string name="delete_member_support_chat_button">Csevegés törlése</string>
|
||||
<string name="reject_pending_member_button">Elutasítás</string>
|
||||
<string name="reject_pending_member_alert_title">Elutasítja a tagot?</string>
|
||||
@@ -2408,8 +2408,8 @@
|
||||
<string name="connect_plan_open_new_group">Új csoport megnyitása</string>
|
||||
<string name="e2ee_info_e2ee"><![CDATA[Az üzenetek <b>végpontok közötti titkosítással</b> vannak védve.]]></string>
|
||||
<string name="error_rejecting_contact_request">Hiba történt a partneri kapcsolatkérés elutasításakor</string>
|
||||
<string name="error_preparing_contact">Hiba a csevegés megnyitásakor</string>
|
||||
<string name="error_preparing_group">Hiba a csoport megnyitásakor</string>
|
||||
<string name="error_preparing_contact">Hiba történt a csevegés megnyitásakor</string>
|
||||
<string name="error_preparing_group">Hiba történt a csoport megnyitásakor</string>
|
||||
<string name="error_changing_user">Hiba a profil módosításakor</string>
|
||||
<string name="group_preview_open_to_join">Megnyitás a csatlakozáshoz</string>
|
||||
<string name="open_to_connect">Megnyitás a kapcsolódáshoz</string>
|
||||
@@ -2474,11 +2474,11 @@
|
||||
<string name="v6_4_1_short_address_update">Cím frissítése</string>
|
||||
<string name="v6_4_1_welcome_contacts">Üdvözölje a partnereit 👋</string>
|
||||
<string name="v6_4_1_new_interface_languages">4 új kezelőfelületi nyelv</string>
|
||||
<string name="v6_4_1_new_interface_languages_descr">Katalán, indonéz, román és vietnami – köszönjük felhasználóinknak!</string>
|
||||
<string name="v6_4_1_new_interface_languages_descr">Katalán, indonéz, román és vietnámi – köszönjük a felhasználóinknak!</string>
|
||||
<string name="upgrade_group_link">Csoporthivatkozás frissítése</string>
|
||||
<string name="share_group_profile_via_link_alert_text">A hivatkozás rövid lesz és a csoportprofil meg lesz osztva a hivatkozáson keresztül.</string>
|
||||
<string name="share_old_address_alert_button">Régi cím megosztása</string>
|
||||
<string name="share_old_link_alert_button">Régi hivatkozás megosztása</string>
|
||||
<string name="share_old_link_alert_button">Régi (hosszú) hivatkozás megosztása</string>
|
||||
<string name="settings_section_title_contact_requests_from_groups">PARTNERI KAPCSOLATKÉRÉSEK A CSOPORTOKBÓL</string>
|
||||
<string name="member_is_deleted_cant_accept_request">A tag törölve lett – nem lehet elfogadni a kérést</string>
|
||||
<string name="rcv_direct_event_group_inv_link_received">a(z) %1$s nevű csoportból partneri kapcsolatot kért</string>
|
||||
|
||||
@@ -2014,7 +2014,7 @@
|
||||
<string name="info_view_connect_button">connetti</string>
|
||||
<string name="contact_deleted">Contatto eliminato!</string>
|
||||
<string name="confirm_delete_contact_question">Confermare l\'eliminazione del contatto?</string>
|
||||
<string name="compose_message_placeholder">Messaggio</string>
|
||||
<string name="compose_message_placeholder">Chatta</string>
|
||||
<string name="selected_chat_items_nothing_selected">Nessuna selezione</string>
|
||||
<string name="select_verb">Seleziona</string>
|
||||
<string name="selected_chat_items_selected_n">Selezionato %d</string>
|
||||
|
||||
@@ -2125,4 +2125,7 @@
|
||||
<string name="v5_3_simpler_incognito_mode">簡化的匿名模式</string>
|
||||
<string name="contact_tap_to_connect">點擊以連接</string>
|
||||
<string name="settings_section_title_use_from_desktop">從桌面使用</string>
|
||||
<string name="connect_plan_open_new_chat">開啓新聊天</string>
|
||||
<string name="accept_contact_request">接受聯絡請求</string>
|
||||
<string name="chat_banner_accept_contact_request">接受聯絡請求</string>
|
||||
</resources>
|
||||
@@ -24,13 +24,13 @@ android.nonTransitiveRClass=true
|
||||
kotlin.mpp.androidSourceSetLayoutVersion=2
|
||||
kotlin.jvm.target=11
|
||||
|
||||
android.version_name=6.5-beta.0
|
||||
android.version_code=323
|
||||
android.version_name=6.5-beta.1
|
||||
android.version_code=327
|
||||
|
||||
android.bundle=false
|
||||
|
||||
desktop.version_name=6.5-beta.0
|
||||
desktop.version_code=122
|
||||
desktop.version_name=6.5-beta.1
|
||||
desktop.version_code=124
|
||||
|
||||
kotlin.version=2.1.20
|
||||
gradle.plugin.version=8.7.0
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/simplex-chat/simplexmq.git
|
||||
tag: 1ae3e8d0be957aa5090e88f25e6dc42d4af1a334
|
||||
tag: 3016b929b48d3116f8ee60169c06383ca57f78e0
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
@@ -48,7 +48,7 @@ source-repository-package
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/simplex-chat/zip.git
|
||||
tag: bd421c6b19cc4c465cd7af1f6f26169fb8ee1ebc
|
||||
tag: 2eff156c3aac389e35d38bf10a52733d7061640a
|
||||
|
||||
-- waiting for published warp-tls-3.4.7
|
||||
source-repository-package
|
||||
|
||||
+7
-3
@@ -4,6 +4,10 @@ Choosing a private messenger requires the understanding of many technical terms,
|
||||
|
||||
While this glossary aims to be factual and objective, it is not completely unbiased. We designed SimpleX to be the most private, secure and resilient communication network, and some definitions reflect this view.
|
||||
|
||||
## 2-factor key exchange
|
||||
|
||||
The ability of communication service to ensure the security of the [key agreement protocol](#key-agreement-protocol) against [man-in-the-middle](#man-in-the-middle-attack).
|
||||
|
||||
## Address portability
|
||||
|
||||
Similarly to [phone number portability](https://en.wikipedia.org/wiki/Local_number_portability) (the ability of the customer to transfer the service to another provider without changing the number), the address portability means the ability of a communication service customer to change the service provider without changing the service address. Many [federated networks](#federated-network) support SRV records to provide address portability, but allowing service users to set up their own domains for the addresses is not as commonly supported by the available server and client software as for email.
|
||||
@@ -89,7 +93,7 @@ Also known as perfect forward secrecy, it is a feature of a [key agreement proto
|
||||
|
||||
## Key agreement protocol
|
||||
|
||||
Also known as key exchange, it is a process of agreeing cryptographic keys between the sender and the recipient(s) of the message. It is required for [end-to-end encryption](#end-to-end-encryption) to work.
|
||||
Also known as key exchange, it is a process of agreeing cryptographic keys between the sender and the recipient(s) of the message. It is required for [end-to-end encryption](#end-to-end-encryption) to work. Unless it is possible to secure the key exchange via [some second factor](#2-factor-key-exchange), e.g. security code verification, it can be vulnerable to [man-in-the-middle attack](#man-in-the-middle-attack).
|
||||
|
||||
[Wikipedia](https://en.wikipedia.org/wiki/Key-agreement_protocol)
|
||||
|
||||
@@ -169,11 +173,11 @@ The advantage is that the participants do not depend on any servers. There are [
|
||||
|
||||
## Post-compromise security
|
||||
|
||||
Also known as break-in recovery, it is the quality of the end-to-end encryption scheme allowing to recover security against a passive attacker who observes encrypted messages after compromising one (or both) of the parties. Also known as recovery from compromise or break-in recovery. [Double-ratchet algorithm](#double-ratchet-algorithm) has this quality.
|
||||
The quality of the end-to-end encryption scheme allowing to recover security against a passive attacker who observes encrypted messages after compromising one (or both) of the parties. Also known as recovery from compromise or break-in recovery. [Double-ratchet algorithm](#double-ratchet-algorithm) has this quality.
|
||||
|
||||
## Post-quantum cryptography
|
||||
|
||||
Any of the proposed cryptographic systems or algorithms that are thought to be secure against an attack by a quantum computer. It appears that as of 2023 there is no system or algorithm that is proven to be secure against such attacks, or even to be secure against attacks by massively parallel conventional computers, so a general recommendation is to use post-quantum cryptographic systems in combination with the traditional cryptographic systems.
|
||||
Any of the proposed cryptographic systems or algorithms that are thought to be secure against an attack by a quantum computer. It appears that as of 2025 there is no system or algorithm that is *proven* to be secure against such attacks, or even to be secure against attacks by massively parallel conventional computers, so a general recommendation is to use post-quantum hybrid cryptography - combining post-quantum and traditional algorigthms.
|
||||
|
||||
[Wikipedia](https://en.wikipedia.org/wiki/Post-quantum_cryptography)
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
.deps
|
||||
artifacts/
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.sol",
|
||||
"options": {
|
||||
"printWidth": 80,
|
||||
"tabWidth": 4,
|
||||
"useTabs": false,
|
||||
"singleQuote": false,
|
||||
"bracketSpacing": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.yml",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"files": "*.yaml",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"files": "*.toml",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"files": "*.json",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"files": "*.js",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"files": "*.ts",
|
||||
"options": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
{
|
||||
"language": "Solidity",
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"": ["ast"],
|
||||
"*": ["abi", "metadata", "devdoc", "userdoc", "storageLayout", "evm.legacyAssembly", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "evm.gasEstimates", "evm.assembly"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.27;
|
||||
|
||||
import "@openzeppelin/contracts@5.4.0/token/ERC1155/ERC1155.sol";
|
||||
import "@openzeppelin/contracts@5.4.0/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts@5.4.0/utils/Base64.sol";
|
||||
import "@openzeppelin/contracts@5.4.0/utils/Strings.sol";
|
||||
|
||||
/// @title MultiERC1155
|
||||
/// @notice ERC1155 contract with sequential variants for immutable metadata.
|
||||
/// @dev Non-upgradeable. Admin and minter addresses are settable by owner. Global sequential token IDs.
|
||||
contract MultiERC1155 is ERC1155, Ownable {
|
||||
address public admin; // can manage token IDs
|
||||
address public minter; // can mint tokens for existing IDs
|
||||
bool public mintingEnabled;
|
||||
bool public contractLocked; // no more variants can be added, minting cannot be enabled, cannot be unlocked
|
||||
|
||||
// for name and description avoid or escape double quotes, so it can be used in JSON
|
||||
struct TokenInfo {
|
||||
string tokenUri;
|
||||
uint totalSupply; // 0 for unlimited
|
||||
bool enabled;
|
||||
}
|
||||
|
||||
struct TokenState {
|
||||
TokenInfo tokenInfo;
|
||||
uint currentSupply;
|
||||
bool exists;
|
||||
bool locked;
|
||||
}
|
||||
|
||||
uint private _nextTokenId; // Global sequential token ID (starts at 1)
|
||||
mapping(uint => TokenState) public tokens;
|
||||
uint[] public tokenIds;
|
||||
|
||||
function getTokenIds() view external returns(uint[] memory) {
|
||||
return tokenIds;
|
||||
}
|
||||
|
||||
event AdminUpdated(address indexed newAdmin);
|
||||
event MinterUpdated(address indexed newMinter);
|
||||
event MintingEnabled(bool newEnabled);
|
||||
event ContractLocked();
|
||||
event TokenAdded(uint indexed tokenId);
|
||||
event TokenRemoved(uint indexed tokenId);
|
||||
event TokenUpdated(uint indexed tokenId, bool newEnabled, uint newTotalSupply);
|
||||
event TokenLocked(uint indexed tokenId);
|
||||
|
||||
constructor() ERC1155("") Ownable(msg.sender) {
|
||||
admin = msg.sender;
|
||||
minter = msg.sender;
|
||||
_nextTokenId = 1;
|
||||
mintingEnabled = true;
|
||||
}
|
||||
|
||||
/// @notice Updates the minter address.
|
||||
/// @param newAdmin The new minter.
|
||||
function setAdmin(address newAdmin) external onlyOwner {
|
||||
admin = newAdmin;
|
||||
emit AdminUpdated(newAdmin);
|
||||
}
|
||||
|
||||
/// @notice Updates the minter address.
|
||||
/// @param newMinter The new minter.
|
||||
function setMinter(address newMinter) external onlyOwner {
|
||||
minter = newMinter;
|
||||
emit MinterUpdated(newMinter);
|
||||
}
|
||||
|
||||
/// @notice Enables/disables minting.
|
||||
/// @param enabled True/false to enable/disable minting.
|
||||
function toggleMinting(bool enabled) external onlyOwner {
|
||||
if (mintingEnabled != enabled) {
|
||||
mintingEnabled = enabled;
|
||||
emit MintingEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
/// @notice Permanently locks any token changes and minting, irreversible.
|
||||
function lockContract() external onlyOwner {
|
||||
contractLocked = true;
|
||||
mintingEnabled = false;
|
||||
emit ContractLocked();
|
||||
}
|
||||
|
||||
/// @notice Adds a new variant and optionally sets it as current.
|
||||
/// @param info New token info.
|
||||
function addToken(TokenInfo memory info) external {
|
||||
require(msg.sender == admin || msg.sender == owner(), "Only admin and owner can add tokens");
|
||||
_addToken(info);
|
||||
}
|
||||
|
||||
function _addToken(TokenInfo memory info) internal {
|
||||
require(bytes(info.tokenUri).length > 0, "Token tokenUri required");
|
||||
|
||||
uint id = _nextTokenId++;
|
||||
require(!tokens[id].exists, "Contract error: token ID already exists");
|
||||
|
||||
tokens[id] = TokenState({
|
||||
tokenInfo: info,
|
||||
currentSupply: 0,
|
||||
exists: true,
|
||||
locked: false
|
||||
});
|
||||
tokenIds.push(id);
|
||||
|
||||
emit TokenAdded(id);
|
||||
}
|
||||
|
||||
/// @notice Removes the last variant if unused (currentSupply == 0).
|
||||
function removeToken(uint id) external {
|
||||
require(msg.sender == admin || msg.sender == owner(), "Only admin and owner can remove tokens");
|
||||
TokenState storage token = tokens[id];
|
||||
require(token.exists, "Token ID does not exist");
|
||||
require(token.currentSupply == 0, "Tokens already minted for this ID");
|
||||
require(tokenIds.length > 1, "Cannot remove the last token ID");
|
||||
|
||||
delete tokens[id];
|
||||
for (uint i = 0; i < tokenIds.length; i++) {
|
||||
if (tokenIds[i] == id) {
|
||||
tokenIds[i] = tokenIds[tokenIds.length - 1];
|
||||
tokenIds.pop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit TokenRemoved(id);
|
||||
}
|
||||
|
||||
|
||||
/// @notice Enables/disables minting a specific token.
|
||||
/// @param id Token ID.
|
||||
/// @param newEnabled True/false to enable/disable minting.
|
||||
/// @param newTotalSupply 0 for unlimited
|
||||
function updateToken(uint id, bool newEnabled, uint newTotalSupply) external {
|
||||
require(msg.sender == admin || msg.sender == owner(), "Only admin and owner can remove tokens");
|
||||
TokenState storage token = tokens[id];
|
||||
require(token.exists, "Token ID does not exist");
|
||||
require(!token.locked, "Token ID is locked");
|
||||
require(newTotalSupply == 0 || token.currentSupply <= newTotalSupply, "New total supply must be greater than existing token count for ID");
|
||||
|
||||
if (token.tokenInfo.enabled != newEnabled || token.tokenInfo.totalSupply != newTotalSupply) {
|
||||
token.tokenInfo.enabled = newEnabled;
|
||||
token.tokenInfo.totalSupply = newTotalSupply;
|
||||
emit TokenUpdated(id, newEnabled, newTotalSupply);
|
||||
}
|
||||
}
|
||||
|
||||
/// @notice permanently lock a specific token from any further changes.
|
||||
/// @param id Token ID.
|
||||
function lockToken(uint id) external onlyOwner {
|
||||
TokenState storage token = tokens[id];
|
||||
require(token.exists, "Token ID does not exist");
|
||||
require(!token.locked, "Token ID is already locked");
|
||||
require(token.currentSupply != 0, "No tokens minted for this ID, use removeToken instead");
|
||||
token.locked = true;
|
||||
token.tokenInfo.enabled = false;
|
||||
emit TokenLocked(id);
|
||||
}
|
||||
|
||||
/// @notice Mints a token using the default variant.
|
||||
/// @param to Recipient.
|
||||
/// @param id Token ID.
|
||||
/// @param value Amount to mint.
|
||||
/// @param data Optional data.
|
||||
function mint(address to, uint256 id, uint256 value, bytes calldata data) external {
|
||||
require(!contractLocked, "Contract is permanently locked");
|
||||
require(mintingEnabled, "Minting is disabled");
|
||||
require(msg.sender == minter || msg.sender == admin || msg.sender == owner(), "Only minter, admin or owner can mint");
|
||||
TokenState storage token = tokens[id];
|
||||
require(token.exists, "Token ID does not exist");
|
||||
require(!token.locked, "Token ID is locked");
|
||||
require(token.tokenInfo.enabled, "Token ID is disabled");
|
||||
require(token.tokenInfo.totalSupply == 0 || token.tokenInfo.totalSupply >= token.currentSupply + value, "Token supply exceeded for this ID");
|
||||
require(value > 0, "Amount must be > 0");
|
||||
|
||||
_mint(to, id, value, data);
|
||||
}
|
||||
|
||||
/// @dev Hook to update supplies on transfer/burn.
|
||||
function _update(address from, address to, uint[] memory ids, uint[] memory values) internal virtual override {
|
||||
super._update(from, to, ids, values);
|
||||
|
||||
for (uint i = 0; i < ids.length; i++) {
|
||||
if (from == address(0)) { // mint
|
||||
tokens[ids[i]].currentSupply += values[i];
|
||||
}
|
||||
if (to == address(0)) { // burn
|
||||
tokens[ids[i]].currentSupply -= values[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @notice Returns embedded JSON metadata URI.
|
||||
/// @param id Token ID.
|
||||
function uri(uint id) public view virtual override returns (string memory) {
|
||||
TokenState storage token = tokens[id];
|
||||
require(token.exists, "Invalid token ID");
|
||||
return token.tokenInfo.tokenUri;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.27;
|
||||
|
||||
import "@openzeppelin/contracts@5.4.0/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts@5.4.0/utils/Pausable.sol";
|
||||
import "./NFTNumbered.sol";
|
||||
|
||||
contract NFTMinter is Ownable, Pausable {
|
||||
NFTNumbered public nft;
|
||||
uint public mintStartTime;
|
||||
uint public mintEndTime;
|
||||
uint public mintCount;
|
||||
|
||||
/// @param _mintEndTime Unix timestamp when minting ends, 0 to mint without time limit.
|
||||
constructor(address _nftAddress, uint _mintStartTime, uint _mintEndTime, bool _paused) Ownable(msg.sender) {
|
||||
_setNFT(_nftAddress);
|
||||
require(_mintEndTime == 0 || _mintEndTime > _mintStartTime, "Mint end time is before start time");
|
||||
require(_mintEndTime == 0 || _mintEndTime > block.timestamp, "Mint end time is in the past");
|
||||
mintStartTime = _mintStartTime;
|
||||
mintEndTime = _mintEndTime;
|
||||
if (_paused) _pause();
|
||||
}
|
||||
|
||||
event NFTUpdated(address indexed newNFT);
|
||||
event Minted(address indexed to, uint count);
|
||||
event MintStartUpdated(uint newTime);
|
||||
event MintEndUpdated(uint newTime);
|
||||
event MintCountReset(uint oldCount);
|
||||
|
||||
/// @notice Allows anyone to mint NFT for free (gas only). Any mint restrictions other than not paused or mint time must be in NFT contract
|
||||
function mint() external whenNotPaused {
|
||||
require(mintEndTime == 0 || mintEndTime > block.timestamp, "Minting ended");
|
||||
require(mintStartTime <= block.timestamp, "Minting not started");
|
||||
nft.mint(msg.sender);
|
||||
mintCount++;
|
||||
emit Minted(msg.sender, mintCount);
|
||||
}
|
||||
|
||||
/// @notice Update the target NFT contract.
|
||||
/// @param newNFT The new NFT contract address.
|
||||
function setNFT(address newNFT) external onlyOwner {
|
||||
_setNFT(newNFT);
|
||||
emit NFTUpdated(newNFT);
|
||||
}
|
||||
|
||||
function _setNFT(address _nft) internal {
|
||||
require(_nft != address(0), "NFT contract address is 0");
|
||||
uint codeSize;
|
||||
assembly { codeSize := extcodesize(_nft) }
|
||||
require(codeSize > 0, "Not a contract address");
|
||||
nft = NFTNumbered(_nft);
|
||||
}
|
||||
|
||||
/// @notice Reset mint counter.
|
||||
function resetMintCount() external onlyOwner {
|
||||
uint old = mintCount;
|
||||
mintCount = 0;
|
||||
emit MintCountReset(old);
|
||||
}
|
||||
|
||||
/// @notice Update the mint start timestamp.
|
||||
/// @param newTime The new Unix timestamp when minting ends.
|
||||
function setMintStartTime(uint256 newTime) external onlyOwner {
|
||||
require(mintEndTime == 0 || newTime < mintEndTime, "Mint end time is before start time");
|
||||
mintStartTime = newTime;
|
||||
emit MintStartUpdated(newTime);
|
||||
}
|
||||
|
||||
/// @notice Update the mint end timestamp.
|
||||
/// @param newTime The new Unix timestamp when minting ends, 0 to mint without time limit.
|
||||
function setMintEndTime(uint256 newTime) external onlyOwner {
|
||||
require(newTime == 0 || newTime > mintStartTime, "Mint end time is before start time");
|
||||
require(newTime == 0 || newTime > block.timestamp, "Mint end time is in the past");
|
||||
mintEndTime = newTime;
|
||||
emit MintEndUpdated(newTime);
|
||||
}
|
||||
|
||||
/// @notice Pause minting.
|
||||
function pause() external onlyOwner {
|
||||
_pause();
|
||||
}
|
||||
|
||||
/// @notice Unpause minting.
|
||||
function unpause() external onlyOwner {
|
||||
_unpause();
|
||||
}
|
||||
|
||||
/// @notice Withdraw any accidental ETH.
|
||||
function withdraw() external onlyOwner {
|
||||
payable(owner()).transfer(address(this).balance);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,121 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.27;
|
||||
|
||||
import "@openzeppelin/contracts@5.4.0/token/ERC721/extensions/ERC721Enumerable.sol";
|
||||
import {IERC721} from "@openzeppelin/contracts@5.4.0/token/ERC721/IERC721.sol";
|
||||
import "@openzeppelin/contracts@5.4.0/access/Ownable.sol";
|
||||
|
||||
/// @title NFTNumbered
|
||||
/// @notice ERC721 contract with sequential variants for immutable metadata for minted tokens, allowing to change metadata for future tokens.
|
||||
/// @dev Non-upgradeable. Minter address is settable by owner. Global sequential token ID.
|
||||
contract NFTNumbered is ERC721Enumerable, Ownable {
|
||||
address public minter;
|
||||
bool public mintingLocked;
|
||||
TokenInfo[] private tokenInfos;
|
||||
uint public nextTokenId = 1;
|
||||
|
||||
struct TokenInfo {
|
||||
uint tokenId;
|
||||
string tokenUri;
|
||||
}
|
||||
|
||||
constructor(
|
||||
string memory _name,
|
||||
string memory _symbol,
|
||||
string memory _tokenUri
|
||||
) ERC721(_name, _symbol) Ownable(msg.sender) {
|
||||
minter = msg.sender;
|
||||
mintingLocked = false;
|
||||
setNextTokenURI(_tokenUri);
|
||||
}
|
||||
|
||||
event MinterUpdated(address indexed newMinter);
|
||||
event MintingLocked();
|
||||
event NextTokenURI(uint nextTokenId, string nextTokenUri);
|
||||
|
||||
/// @notice Updates the minter address.
|
||||
function setMinter(address newMinter) external onlyOwner whenNotLocked {
|
||||
minter = newMinter;
|
||||
emit MinterUpdated(newMinter);
|
||||
}
|
||||
|
||||
/// @notice Permanently disable minting and changes.
|
||||
function lockMintingPermanently() external onlyOwner {
|
||||
mintingLocked = true;
|
||||
emit MintingLocked();
|
||||
}
|
||||
|
||||
modifier whenNotLocked() {
|
||||
require(!mintingLocked, "Contract permanently locked for changes and minting");
|
||||
_;
|
||||
}
|
||||
|
||||
/// @notice Sets tokenUri for future mints only.
|
||||
function setNextTokenURI(string memory newTokenUri) public onlyOwner whenNotLocked {
|
||||
uint len = tokenInfos.length;
|
||||
TokenInfo memory newInfo = TokenInfo({tokenId: nextTokenId, tokenUri: newTokenUri});
|
||||
if (len == 0 || tokenInfos[len - 1].tokenId < nextTokenId) { // add
|
||||
tokenInfos.push(newInfo);
|
||||
} else { // replace
|
||||
tokenInfos[len - 1] = newInfo;
|
||||
}
|
||||
emit NextTokenURI(nextTokenId, newTokenUri);
|
||||
}
|
||||
|
||||
/// @notice metadata URI of the token that will be minted next
|
||||
function nextTokenURI() external view returns (string memory) {
|
||||
return tokenInfos[tokenInfos.length - 1].tokenUri;
|
||||
}
|
||||
|
||||
/// @notice Mints a new token.
|
||||
/// @param to The recipient of the token.
|
||||
function mint(address to) external whenNotLocked {
|
||||
require(msg.sender == owner() || msg.sender == minter, "Caller must be the owner or minter");
|
||||
require(to != address(0), "Cannot mint to zero address");
|
||||
uint tokenId = nextTokenId++;
|
||||
_safeMint(to, tokenId);
|
||||
}
|
||||
|
||||
/// @notice Burn owned token.
|
||||
function burn(uint tokenId) external {
|
||||
_burn(tokenId);
|
||||
}
|
||||
|
||||
/// @notice prohibit approvals
|
||||
// address to, uint256 tokenId
|
||||
function approve(address, uint256) public virtual override (ERC721, IERC721) {
|
||||
revert("Soulbound token: approvals prohibited");
|
||||
}
|
||||
|
||||
/// @notice prohibit approvals
|
||||
// address operator, bool approved
|
||||
function setApprovalForAll(address, bool) public virtual override (ERC721, IERC721) {
|
||||
revert("Soulbound token: approvals prohibited");
|
||||
}
|
||||
|
||||
/// @notice Limits ownership to 1 token.
|
||||
function _update(address to, uint tokenId, address auth) internal virtual override returns (address) {
|
||||
require(to == address(0) || balanceOf(to) == 0, "Soulbound token: only 1 per address");
|
||||
require(to == address(0) || _ownerOf(tokenId) == address(0), "Soulbound token: transfers prohibited");
|
||||
return super._update(to, tokenId, auth);
|
||||
}
|
||||
|
||||
/// @notice Returns embedded JSON metadata URI.
|
||||
/// @param id Token ID.
|
||||
function tokenURI(uint id) public view virtual override returns (string memory) {
|
||||
_requireOwned(id);
|
||||
uint len = tokenInfos.length;
|
||||
for (uint i = len; i > 0; ) {
|
||||
unchecked { i--; }
|
||||
if (tokenInfos[i].tokenId > id) continue;
|
||||
return tokenInfos[i].tokenUri;
|
||||
}
|
||||
revert("Unknown token ID");
|
||||
}
|
||||
|
||||
/// @notice Withdraw any accidental ETH.
|
||||
function withdraw() external onlyOwner {
|
||||
(bool success, ) = payable(owner()).call{value: address(this).balance}("");
|
||||
require(success, "Withdraw failed");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,10 @@
|
||||
import { deploy } from './ethers-lib'
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const result = await deploy('MyToken', [])
|
||||
console.log(`address: ${result.address}`)
|
||||
} catch (e) {
|
||||
console.log(e.message)
|
||||
}
|
||||
})()
|
||||
@@ -0,0 +1,336 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.27;
|
||||
|
||||
import "remix_tests.sol";
|
||||
|
||||
import "../contracts/MultiERC1155.sol";
|
||||
|
||||
contract MultiERC1155Test {
|
||||
MultiERC1155 public ct;
|
||||
address public owner = address(this);
|
||||
address public admin = address(0x1);
|
||||
address public minter = address(0x2);
|
||||
address public user = address(0x3);
|
||||
address public recipient = address(0x4);
|
||||
|
||||
MultiERC1155.TokenInfo defaultInfo = MultiERC1155.TokenInfo({
|
||||
tokenUri: "https://example.com/token.json",
|
||||
totalSupply: 0,
|
||||
enabled: true
|
||||
});
|
||||
|
||||
function beforeAll() public {
|
||||
ct = new MultiERC1155();
|
||||
MultiERC1155.TokenInfo memory newInfo = defaultInfo;
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("addToken((string,bool,string,string,string,uint256))", newInfo));
|
||||
Assert.equal(success, true, "addToken success");
|
||||
}
|
||||
|
||||
// Constructor Test
|
||||
function testConstructor() public {
|
||||
Assert.equal(ct.owner(), owner, "Owner should be deployer");
|
||||
Assert.equal(ct.admin(), owner, "Admin should be deployer");
|
||||
Assert.equal(ct.minter(), owner, "Minter should be deployer");
|
||||
Assert.equal(ct.mintingEnabled(), true, "Minting should be enabled");
|
||||
Assert.equal(ct.contractLocked(), false, "Contract should not be locked");
|
||||
uint[] memory ids = ct.getTokenIds();
|
||||
Assert.equal(ids.length, uint(1), "One token ID added");
|
||||
Assert.equal(ids[0], uint(1), "First token ID is 1");
|
||||
(, uint currentSupply, bool exists, bool locked) = ct.tokens(1);
|
||||
Assert.equal(exists, true, "Token 1 exists");
|
||||
Assert.equal(locked, false, "Token 1 not locked");
|
||||
Assert.equal(currentSupply, uint(0), "Token 1 supply 0");
|
||||
}
|
||||
|
||||
// setAdmin Test
|
||||
function testSetAdmin() public {
|
||||
ct.setAdmin(admin);
|
||||
Assert.equal(ct.admin(), admin, "Admin updated");
|
||||
}
|
||||
|
||||
function testSetAdminOnlyOwner() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("setAdmin(address)", admin));
|
||||
Assert.equal(success, true, "Set admin from owner succeeds"); // Since this is owner
|
||||
|
||||
// To test revert, Remix plugin runs as this, so for non-owner, manual simulation not easy; note as TODO or skip
|
||||
}
|
||||
|
||||
// setMinter Test
|
||||
function testSetMinter() public {
|
||||
ct.setMinter(minter);
|
||||
Assert.equal(ct.minter(), minter, "Minter updated");
|
||||
}
|
||||
|
||||
function testSetMinterOnlyOwner() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("setMinter(address)", minter));
|
||||
Assert.equal(success, true, "Set minter from owner succeeds");
|
||||
}
|
||||
|
||||
// toggleMinting Test
|
||||
function testToggleMinting() public {
|
||||
ct.toggleMinting(false);
|
||||
Assert.equal(ct.mintingEnabled(), false, "Minting disabled");
|
||||
|
||||
ct.toggleMinting(true);
|
||||
Assert.equal(ct.mintingEnabled(), true, "Minting enabled");
|
||||
}
|
||||
|
||||
function testToggleMintingNoChange() public {
|
||||
ct.toggleMinting(true); // Already true
|
||||
Assert.equal(ct.mintingEnabled(), true, "No change if same");
|
||||
}
|
||||
|
||||
function testToggleMintingOnlyOwner() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("toggleMinting(bool)", false));
|
||||
Assert.equal(success, true, "Toggle from owner succeeds");
|
||||
}
|
||||
|
||||
// lockContract Test
|
||||
function testLockContract() public {
|
||||
ct.lockContract();
|
||||
Assert.equal(ct.contractLocked(), true, "Contract locked");
|
||||
Assert.equal(ct.mintingEnabled(), false, "Minting disabled");
|
||||
}
|
||||
|
||||
function testLockContractOnlyOwner() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("lockContract()"));
|
||||
Assert.equal(success, true, "Lock from owner succeeds");
|
||||
}
|
||||
|
||||
// addToken Test
|
||||
function testAddToken() public {
|
||||
MultiERC1155.TokenInfo memory newInfo = MultiERC1155.TokenInfo({
|
||||
tokenUri: "https://example.com/new_token.json",
|
||||
totalSupply: 100,
|
||||
enabled: true
|
||||
});
|
||||
|
||||
ct.addToken(newInfo);
|
||||
uint[] memory ids = ct.getTokenIds();
|
||||
Assert.equal(ids.length, uint(2), "Two token IDs");
|
||||
Assert.equal(ids[1], uint(2), "Second token ID 2");
|
||||
(MultiERC1155.TokenInfo memory tokenInfo, uint currentSupply, bool exists, bool locked) = ct.tokens(2);
|
||||
Assert.equal(exists, true, "Token 2 exists");
|
||||
Assert.equal(locked, false, "Token 2 not locked");
|
||||
Assert.equal(currentSupply, uint(0), "Token 2 supply 0");
|
||||
Assert.equal(tokenInfo.totalSupply, uint(100), "Token 2 totalSupply 100");
|
||||
// Validate info fields as needed
|
||||
}
|
||||
|
||||
function testAddTokenByAdmin() public {
|
||||
ct.setAdmin(admin);
|
||||
MultiERC1155.TokenInfo memory newInfo = defaultInfo;
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("addToken((string,bool,string,string,string,uint256))", newInfo));
|
||||
Assert.equal(success, true, "Add by admin succeeds");
|
||||
uint[] memory ids = ct.getTokenIds();
|
||||
Assert.equal(ids.length, uint(2), "Two token IDs");
|
||||
}
|
||||
|
||||
function testAddTokenRevertInvalidInfo() public {
|
||||
MultiERC1155.TokenInfo memory invalidInfo = MultiERC1155.TokenInfo({
|
||||
tokenUri: "",
|
||||
totalSupply: 0,
|
||||
enabled: true
|
||||
});
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("addToken((string,bool,string,string,string,uint256))", invalidInfo));
|
||||
Assert.equal(success, false, "Invalid info reverts");
|
||||
}
|
||||
|
||||
function testAddTokenOnlyAdminOrOwner() public {
|
||||
MultiERC1155.TokenInfo memory info = defaultInfo;
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("addToken((string,bool,string,string,string,uint256))", info));
|
||||
Assert.equal(success, true, "Add from owner succeeds");
|
||||
}
|
||||
|
||||
// removeToken Test
|
||||
function testRemoveToken() public {
|
||||
MultiERC1155.TokenInfo memory newInfo = defaultInfo;
|
||||
ct.addToken(newInfo);
|
||||
uint[] memory ids = ct.getTokenIds();
|
||||
Assert.equal(ids.length, uint(2), "Two token IDs");
|
||||
|
||||
ct.removeToken(2);
|
||||
ids = ct.getTokenIds();
|
||||
Assert.equal(ids.length, uint(1), "One token ID after removal");
|
||||
(,,bool exists,) = ct.tokens(2);
|
||||
Assert.equal(exists, false, "Token 2 removed");
|
||||
}
|
||||
|
||||
function testRemoveTokenRevertNonExist() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("removeToken(uint256)", 99));
|
||||
Assert.equal(success, false, "Remove non-exist reverts");
|
||||
}
|
||||
|
||||
function testRemoveTokenRevertHasSupply() public {
|
||||
ct.mint(user, 1, 10, "");
|
||||
(bool success,) = address(ct).call(abi.encodeWithSignature("removeToken(uint256)", 1));
|
||||
Assert.equal(success, false, "Remove with supply reverts");
|
||||
}
|
||||
|
||||
function testRemoveTokenRevertLast() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("removeToken(uint256)", 1));
|
||||
Assert.equal(success, false, "Remove last reverts");
|
||||
}
|
||||
|
||||
function testRemoveTokenOnlyAdminOrOwner() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("removeToken(uint256)", 1));
|
||||
Assert.equal(success, false, "Remove last fails"); // But for non-owner, need simulation
|
||||
}
|
||||
|
||||
// updateToken Test
|
||||
function testUpdateToken() public {
|
||||
ct.updateToken(1, false, 100);
|
||||
(MultiERC1155.TokenInfo memory tokenInfo,,,) = ct.tokens(1);
|
||||
Assert.equal(tokenInfo.enabled, false, "Enabled updated");
|
||||
Assert.equal(tokenInfo.totalSupply, uint(100), "Total supply updated");
|
||||
}
|
||||
|
||||
function testUpdateTokenNoChange() public {
|
||||
(MultiERC1155.TokenInfo memory tokenInfo,,,) = ct.tokens(1);
|
||||
ct.updateToken(1, tokenInfo.enabled, tokenInfo.totalSupply);
|
||||
// No assert, as no change
|
||||
}
|
||||
|
||||
function testUpdateTokenRevertNonExist() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("updateToken(uint256,bool,uint256)", 99, true, 0));
|
||||
Assert.equal(success, false, "Update non-exist reverts");
|
||||
}
|
||||
|
||||
function testUpdateTokenRevertLocked() public {
|
||||
ct.mint(user, 1, 10, "");
|
||||
ct.lockToken(1);
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("updateToken(uint256,bool,uint256)", 1, true, 0));
|
||||
Assert.equal(success, false, "Update locked reverts");
|
||||
}
|
||||
|
||||
function testUpdateTokenRevertInvalidSupply() public {
|
||||
ct.mint(user, 1, 10, "");
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("updateToken(uint256,bool,uint256)", 1, true, 5));
|
||||
Assert.equal(success, false, "Invalid supply reverts");
|
||||
}
|
||||
|
||||
function testUpdateTokenOnlyAdminOrOwner() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("updateToken(uint256,bool,uint256)", 1, true, 0));
|
||||
Assert.equal(success, true, "Update from owner succeeds");
|
||||
}
|
||||
|
||||
// lockToken Test
|
||||
function testLockToken() public {
|
||||
ct.mint(user, 1, 10, "");
|
||||
ct.lockToken(1);
|
||||
(MultiERC1155.TokenInfo memory tokenInfo,,, bool locked) = ct.tokens(1);
|
||||
Assert.equal(locked, true, "Token locked");
|
||||
Assert.equal(tokenInfo.enabled, false, "Enabled false");
|
||||
}
|
||||
|
||||
function testLockTokenRevertNonExist() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("lockToken(uint256)", 99));
|
||||
Assert.equal(success, false, "Lock non-exist reverts");
|
||||
}
|
||||
|
||||
function testLockTokenRevertAlreadyLocked() public {
|
||||
ct.mint(user, 1, 10, "");
|
||||
ct.lockToken(1);
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("lockToken(uint256)", 1));
|
||||
Assert.equal(success, false, "Lock already locked reverts");
|
||||
}
|
||||
|
||||
function testLockTokenRevertNoSupply() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("lockToken(uint256)", 1));
|
||||
Assert.equal(success, false, "Lock no supply reverts");
|
||||
}
|
||||
|
||||
function testLockTokenOnlyOwner() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("lockToken(uint256)", 1));
|
||||
Assert.equal(success, false, "Lock no supply fails"); // Test with supply
|
||||
}
|
||||
|
||||
// mint Test
|
||||
function testMint() public {
|
||||
ct.mint(user, 1, 10, "");
|
||||
Assert.equal(ct.balanceOf(user, 1), 10, "User balance 10");
|
||||
(,uint currentSupply,,) = ct.tokens(1);
|
||||
Assert.equal(currentSupply, 10, "Token supply 10");
|
||||
}
|
||||
|
||||
function testMintRevertLockedContract() public {
|
||||
ct.lockContract();
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 10, ""));
|
||||
Assert.equal(success, false, "Mint locked contract reverts");
|
||||
}
|
||||
|
||||
function testMintRevertMintingDisabled() public {
|
||||
ct.toggleMinting(false);
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 10, ""));
|
||||
Assert.equal(success, false, "Mint disabled reverts");
|
||||
}
|
||||
|
||||
function testMintRevertInvalidCaller() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 10, ""));
|
||||
Assert.equal(success, true, "Mint from owner succeeds");
|
||||
}
|
||||
|
||||
function testMintRevertNonExist() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 99, 10, ""));
|
||||
Assert.equal(success, false, "Mint non-exist reverts");
|
||||
}
|
||||
|
||||
function testMintRevertLockedToken() public {
|
||||
ct.mint(user, 1, 10, "");
|
||||
ct.lockToken(1);
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 5, ""));
|
||||
Assert.equal(success, false, "Mint locked token reverts");
|
||||
}
|
||||
|
||||
function testMintRevertDisabledToken() public {
|
||||
ct.updateToken(1, false, 0);
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 10, ""));
|
||||
Assert.equal(success, false, "Mint disabled token reverts");
|
||||
}
|
||||
|
||||
function testMintRevertSupplyExceeded() public {
|
||||
ct.updateToken(1, true, 5);
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 10, ""));
|
||||
Assert.equal(success, false, "Mint supply exceeded reverts");
|
||||
}
|
||||
|
||||
function testMintRevertZeroAmount() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("mint(address,uint256,uint256,bytes)", user, 1, 0, ""));
|
||||
Assert.equal(success, false, "Mint zero amount reverts");
|
||||
}
|
||||
|
||||
// _update Test (via transfer/burn)
|
||||
function testUpdateMint() public {
|
||||
ct.mint(user, 1, 10, "");
|
||||
(,uint currentSupply,,) = ct.tokens(1);
|
||||
Assert.equal(currentSupply, 10, "Supply after mint");
|
||||
}
|
||||
|
||||
function testUpdateBurn() public {
|
||||
ct.mint(user, 1, 10, "");
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("safeTransferFrom(address,address,uint256,uint256,bytes)", user, address(0), 1, 5, ""));
|
||||
Assert.equal(success, true, "Burn succeeds");
|
||||
(,uint currentSupply,,) = ct.tokens(1);
|
||||
Assert.equal(currentSupply, 5, "Supply after burn");
|
||||
}
|
||||
|
||||
function testUpdateTransfer() public {
|
||||
ct.mint(user, 1, 10, "");
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("safeTransferFrom(address,address,uint256,uint256,bytes)", user, recipient, 1, 5, ""));
|
||||
Assert.equal(success, true, "Transfer succeeds");
|
||||
(,uint currentSupply,,) = ct.tokens(1);
|
||||
Assert.equal(currentSupply, 10, "Supply unchanged on transfer");
|
||||
}
|
||||
|
||||
// uri Test
|
||||
function testUri() public {
|
||||
string memory json = Base64.encode(bytes('{"name":"Test Token","description":"Test Description","image":"https://test.com/image.png","properties":{}}'));
|
||||
string memory expected = string.concat("data:application/json;base64,", json);
|
||||
Assert.equal(ct.uri(1), expected, "URI matches");
|
||||
}
|
||||
|
||||
function testUriRevertNonExist() public {
|
||||
(bool success, ) = address(ct).call(abi.encodeWithSignature("uri(uint256)", 99));
|
||||
Assert.equal(success, false, "URI non-exist reverts");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
pragma solidity >=0.4.22 <0.9.0;
|
||||
|
||||
// This import is automatically injected by Remix
|
||||
import "remix_tests.sol";
|
||||
|
||||
// This import is required to use custom transaction context
|
||||
// Although it may fail compilation in 'Solidity Compiler' plugin
|
||||
// But it will work fine in 'Solidity Unit Testing' plugin
|
||||
import "remix_accounts.sol";
|
||||
import "../contracts/NFTMinter.sol";
|
||||
import "../contracts/NFTNumbered.sol";
|
||||
|
||||
// File name has to end with '_test.sol', this file can contain more than one testSuite contracts
|
||||
contract NFTMinterTest {
|
||||
NFTNumbered s;
|
||||
NFTMinter m;
|
||||
address public owner = address(this);
|
||||
|
||||
function beforeAll() public {
|
||||
s = new NFTNumbered(
|
||||
"SimpleX NFT: SMPX testnet access",
|
||||
"SIMPLEXNFT",
|
||||
"https://ipfs.io/ipfs/abcd"
|
||||
);
|
||||
m = new NFTMinter(address(s), 0, 0, false);
|
||||
}
|
||||
|
||||
function testCreateMinter() public {
|
||||
Assert.equal(address(m.nft()), address(s), "bad nft contract");
|
||||
Assert.equal(m.mintEndTime(), 0, "bad time");
|
||||
Assert.equal(m.owner(), owner, "bad owner");
|
||||
}
|
||||
|
||||
function testMinting() public {
|
||||
m.setMintStartTime(block.timestamp + 86400);
|
||||
try m.mint() {
|
||||
Assert.ok(false, "expected revert");
|
||||
} catch Error(string memory reason) {
|
||||
Assert.equal(reason, "Minting not started", "bad reason");
|
||||
} catch (bytes memory) {
|
||||
Assert.ok(false, "unexpected error");
|
||||
}
|
||||
m.setMintStartTime(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
pragma solidity >=0.7.0 <0.9.0;
|
||||
import "remix_tests.sol";
|
||||
import "remix_accounts.sol";
|
||||
import "../contracts/NFTNumbered.sol";
|
||||
|
||||
contract NFTNumberedTest {
|
||||
NFTNumbered s;
|
||||
address public owner = address(this);
|
||||
address public user1 = address(0x1);
|
||||
address public user2 = address(0x2);
|
||||
address public user3 = address(0x3);
|
||||
address public user4 = TestsAccounts.getAccount(1);
|
||||
address public minter = address(0x5);
|
||||
|
||||
function beforeAll () public {
|
||||
s = new NFTNumbered(
|
||||
"SimpleX NFT: SMPX testnet access",
|
||||
"SIMPLEXNFT",
|
||||
"https://ipfs.io/ipfs/abcd"
|
||||
);
|
||||
}
|
||||
|
||||
function testCreateToken () public {
|
||||
Assert.equal(s.name(), "SimpleX NFT: SMPX testnet access", "bad name");
|
||||
Assert.equal(s.symbol(), "SIMPLEXNFT", "bad symbol");
|
||||
Assert.equal(s.nextTokenId(), 1, "bad next token ID");
|
||||
Assert.equal(s.minter(), s.owner(), "minter different from owner");
|
||||
Assert.equal(s.mintingLocked(), false, "minting locked");
|
||||
Assert.equal(s.owner(), owner, "bad owner");
|
||||
}
|
||||
|
||||
function testTransferToken() public {
|
||||
Assert.equal(s.balanceOf(user3), 0, "bad balance");
|
||||
s.mint(user4);
|
||||
Assert.equal(s.balanceOf(user4), 1, "bad balance");
|
||||
/// #sender: account-1
|
||||
// try s.safeTransferFrom(user4, user3, 1) {
|
||||
// Assert.ok(false, "expected revert");
|
||||
// } catch Error(string memory reason) {
|
||||
// Assert.equal(reason, "Token is soulbound: transfers are prohibited", "bad reason");
|
||||
// } catch (bytes memory data) {
|
||||
// Assert.ok(false, "unexpected error 2");
|
||||
// }
|
||||
}
|
||||
|
||||
function testMinting () public {
|
||||
s.mint(user1);
|
||||
Assert.equal(s.balanceOf(user1), 1, "bad balance");
|
||||
Assert.equal(s.tokenURI(2), "https://ipfs.io/ipfs/abcd", "bad URI");
|
||||
try s.mint(user1) {
|
||||
Assert.ok(false, "expected revert");
|
||||
} catch Error(string memory reason) {
|
||||
Assert.equal(reason, "Soulbound token: only 1 per address", "bad reason");
|
||||
} catch (bytes memory) {
|
||||
Assert.ok(false, "unexpected error");
|
||||
}
|
||||
Assert.equal(s.nextTokenId(), 3, "bad next token ID");
|
||||
s.mint(user2);
|
||||
Assert.equal(s.balanceOf(user2), 1, "bad balance");
|
||||
Assert.equal(s.tokenURI(3), "https://ipfs.io/ipfs/abcd", "bad URI");
|
||||
Assert.equal(s.nextTokenURI(), "https://ipfs.io/ipfs/abcd", "bad URI");
|
||||
s.setNextTokenURI("https://ipfs.io/ipfs/efgh");
|
||||
Assert.equal(s.nextTokenURI(), "https://ipfs.io/ipfs/efgh", "bad URI");
|
||||
Assert.equal(s.balanceOf(user3), 0, "bad balance");
|
||||
s.mint(user3);
|
||||
Assert.equal(s.balanceOf(user3), 1, "bad balance");
|
||||
Assert.equal(s.tokenURI(4), "https://ipfs.io/ipfs/efgh", "bad URI");
|
||||
}
|
||||
|
||||
function testMintingLock () public {
|
||||
s.lockMintingPermanently();
|
||||
try s.mint(user2) {
|
||||
Assert.ok(false, "expected revert");
|
||||
} catch Error(string memory reason) {
|
||||
Assert.equal(reason, "Contract permanently locked for changes and minting", "bad reason");
|
||||
} catch (bytes memory) {
|
||||
Assert.ok(false, "unexpected error");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,27 @@
|
||||
</description>
|
||||
|
||||
<releases>
|
||||
<release version="6.4.7" date="2025-11-03">
|
||||
<url type="details">https://simplex.chat/blog/20250729-simplex-chat-v6-4-1-welcome-contacts-protect-groups-app-security.html</url>
|
||||
<description>
|
||||
<p>New in v6.4.7:</p>
|
||||
<ul>
|
||||
<li>fix exporting database larger than 4gb.</li>
|
||||
</ul>
|
||||
<p>New in v6.4-6.4.6:</p>
|
||||
<ul>
|
||||
<li>new UX to connect.</li>
|
||||
<li>review new group members.</li>
|
||||
<li>chat with group admins.</li>
|
||||
<li>new UI languages: Catalan, Indonesian, Romanian and Vietnamese.</li>
|
||||
<li>Linux app builds for aarch64 CPUs</li>
|
||||
<li>UI support for bot commands.</li>
|
||||
<li>support markdown hyperlinks, such as [click here](https://example.com).</li>
|
||||
<li>option to remove tracking parameters from the links.</li>
|
||||
<li>better information about network errors.</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="6.4.6" date="2025-10-05">
|
||||
<url type="details">https://simplex.chat/blog/20250729-simplex-chat-v6-4-1-welcome-contacts-protect-groups-app-security.html</url>
|
||||
<description>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"https://github.com/simplex-chat/simplexmq.git"."1ae3e8d0be957aa5090e88f25e6dc42d4af1a334" = "1cwahakq63jk7g0bbkdgpnnwa8i0i8s8j7azdpjral4d6cj4q4q0";
|
||||
"https://github.com/simplex-chat/simplexmq.git"."3016b929b48d3116f8ee60169c06383ca57f78e0" = "1gvv96w1ag8xh19an5j50isjw0yq1cbsywii5s1adaplr6fw34mb";
|
||||
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
|
||||
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
|
||||
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
|
||||
"https://github.com/simplex-chat/aeson.git"."aab7b5a14d6c5ea64c64dcaee418de1bb00dcc2b" = "0jz7kda8gai893vyvj96fy962ncv8dcsx71fbddyy8zrvc88jfrr";
|
||||
"https://github.com/simplex-chat/haskell-terminal.git"."f708b00009b54890172068f168bf98508ffcd495" = "0zmq7lmfsk8m340g47g5963yba7i88n4afa6z93sg9px5jv1mijj";
|
||||
"https://github.com/simplex-chat/android-support.git"."9aa09f148089d6752ce563b14c2df1895718d806" = "0pbf2pf13v2kjzi397nr13f1h3jv0imvsq8rpiyy2qyx5vd50pqn";
|
||||
"https://github.com/simplex-chat/zip.git"."bd421c6b19cc4c465cd7af1f6f26169fb8ee1ebc" = "1csqfjhvc8wb5h4kxxndmb6iw7b4ib9ff2n81hrizsmnf45a6gg0";
|
||||
"https://github.com/simplex-chat/zip.git"."2eff156c3aac389e35d38bf10a52733d7061640a" = "052vahd5d4lxnazjrb6l60i261aycn2js7jhzafyb72n15ns4r6p";
|
||||
"https://github.com/yesodweb/wai.git"."ec5e017d896a78e787a5acea62b37a4e677dec2e" = "1ckcpmpjfy9jiqrb52q20lj7ln4hmq9v2jk6kpkf3m68c1m9c2bx";
|
||||
"https://github.com/simplex-chat/wai.git"."2f6e5aa5f05ba9140ac99e195ee647b4f7d926b0" = "199g4rjdf1zp1fcw8nqdsyr1h36hmg424qqx03071jk7j00z7ay4";
|
||||
}
|
||||
+2
-2
@@ -5,7 +5,7 @@ cabal-version: 1.12
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
name: simplex-chat
|
||||
version: 6.5.0.3
|
||||
version: 6.5.0.4
|
||||
category: Web, System, Services, Cryptography
|
||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||
author: simplex.chat
|
||||
@@ -313,7 +313,7 @@ library
|
||||
, unliftio-core ==0.2.*
|
||||
, uri-bytestring >=0.3.3.1 && <0.4
|
||||
, uuid ==1.3.*
|
||||
, zip ==2.0.*
|
||||
, zip ==2.2.*
|
||||
, zstd ==0.1.3.*
|
||||
default-language: Haskell2010
|
||||
if flag(swift)
|
||||
|
||||
@@ -1799,8 +1799,9 @@ processChatCommand vr nm = \case
|
||||
incognitoProfile <- if incognito then Just <$> liftIO generateRandomProfile else pure Nothing
|
||||
subMode <- chatReadVar subscriptionMode
|
||||
let userData = contactShortLinkData (userProfileDirect user incognitoProfile Nothing True) Nothing
|
||||
userLinkData = UserInvLinkData userData
|
||||
-- TODO [certs rcv]
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a nm (aUserId user) True False SCMInvitation (Just userData) Nothing IKPQOn subMode
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a nm (aUserId user) True False SCMInvitation (Just userLinkData) Nothing IKPQOn subMode
|
||||
ccLink' <- shortenCreatedLink ccLink
|
||||
-- TODO PQ pass minVersion from the current range
|
||||
conn <- withFastStore' $ \db -> createDirectConnection db user connId ccLink' Nothing ConnNew incognitoProfile subMode initialChatVersion PQSupportOn
|
||||
@@ -1838,11 +1839,11 @@ processChatCommand vr nm = \case
|
||||
recreateConn user conn@PendingContactConnection {customUserProfileId, connLinkInv} newUser = do
|
||||
subMode <- chatReadVar subscriptionMode
|
||||
let short = isJust $ connShortLink =<< connLinkInv
|
||||
userData_
|
||||
| short = Just $ contactShortLinkData (userProfileDirect newUser Nothing Nothing True) Nothing
|
||||
userLinkData_
|
||||
| short = Just $ UserInvLinkData $ contactShortLinkData (userProfileDirect newUser Nothing Nothing True) Nothing
|
||||
| otherwise = Nothing
|
||||
-- TODO [certs rcv]
|
||||
(agConnId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a nm (aUserId newUser) True False SCMInvitation userData_ Nothing IKPQOn subMode
|
||||
(agConnId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a nm (aUserId newUser) True False SCMInvitation userLinkData_ Nothing IKPQOn subMode
|
||||
ccLink' <- shortenCreatedLink ccLink
|
||||
conn' <- withFastStore' $ \db -> do
|
||||
deleteConnectionRecord db user connId
|
||||
@@ -2036,8 +2037,9 @@ processChatCommand vr nm = \case
|
||||
-- TODO - add relay key, identity to link data
|
||||
-- TODO - validate short link is created (returned by agent)
|
||||
let userData = contactShortLinkData (userProfileDirect user Nothing Nothing True) Nothing
|
||||
userLinkData = UserContactLinkData UserContactData {direct = True, owners = [], relays = [], userData}
|
||||
-- TODO [certs rcv]
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a nm (aUserId user) True True SCMContact (Just userData) Nothing IKPQOn subMode
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a nm (aUserId user) True True SCMContact (Just userLinkData) Nothing IKPQOn subMode
|
||||
ccLink' <- shortenCreatedLink ccLink
|
||||
let ccLink'' = if isTrue userChatRelay then createdRelayLink ccLink' else ccLink'
|
||||
withFastStore $ \db -> createUserContactLink db user connId ccLink'' subMode
|
||||
@@ -2660,9 +2662,10 @@ processChatCommand vr nm = \case
|
||||
groupLinkId <- GroupLinkId <$> drgRandomBytes 16
|
||||
subMode <- chatReadVar subscriptionMode
|
||||
let userData = encodeShortLinkData $ GroupShortLinkData groupProfile
|
||||
userLinkData = UserContactLinkData UserContactData {direct = True, owners = [], relays = [], userData}
|
||||
crClientData = encodeJSON $ CRDataGroup groupLinkId
|
||||
-- TODO [certs rcv]
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a nm (aUserId user) True True SCMContact (Just userData) (Just crClientData) IKPQOff subMode
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a nm (aUserId user) True True SCMContact (Just userLinkData) (Just crClientData) IKPQOff subMode
|
||||
ccLink' <- createdGroupLink <$> shortenCreatedLink ccLink
|
||||
gVar <- asks random
|
||||
gLink <- withFastStore $ \db -> createGroupLink db gVar user gInfo connId ccLink' groupLinkId mRole subMode
|
||||
@@ -3326,7 +3329,8 @@ processChatCommand vr nm = \case
|
||||
let shortLinkProfile = userProfileDirect user Nothing Nothing True
|
||||
-- TODO [short links] do not save address to server if data did not change, spinners, error handling
|
||||
userData = contactShortLinkData shortLinkProfile $ Just addressSettings
|
||||
sLnk <- shortenShortLink' =<< withAgent (\a -> setConnShortLink a nm (aConnId conn) SCMContact userData Nothing)
|
||||
userLinkData = UserContactLinkData UserContactData {direct = True, owners = [], relays = [], userData}
|
||||
sLnk <- shortenShortLink' =<< withAgent (\a -> setConnShortLink a nm (aConnId conn) SCMContact userLinkData Nothing)
|
||||
withFastStore' $ \db -> setUserContactLinkShortLink db userContactLinkId sLnk
|
||||
let autoAccept' = (\aa -> aa {acceptIncognito = False}) <$> autoAccept addressSettings
|
||||
ucl' = (ucl :: UserContactLink) {connLinkContact = CCLink connFullLink (Just sLnk), shortLinkDataSet = True, shortLinkLargeDataSet = BoolDef True, addressSettings = addressSettings {autoAccept = autoAccept'}}
|
||||
@@ -3734,7 +3738,7 @@ processChatCommand vr nm = \case
|
||||
l' <- restoreShortLink' l
|
||||
(cReq, cData) <- withAgent $ \a -> getConnShortLink a nm (aUserId user) l'
|
||||
case cData of
|
||||
ContactLinkData {direct} | not direct -> throwChatError CEUnsupportedConnReq
|
||||
ContactLinkData _ UserContactData {direct} | not direct -> throwChatError CEUnsupportedConnReq
|
||||
_ -> pure ()
|
||||
pure (cReq, cData)
|
||||
-- This function is needed, as UI uses simplex:/ schema in message view, so that the links can be handled without browser,
|
||||
@@ -3754,7 +3758,8 @@ processChatCommand vr nm = \case
|
||||
updatePCCShortLinkData conn@PendingContactConnection {connLinkInv} profile =
|
||||
forM (connShortLink =<< connLinkInv) $ \_ -> do
|
||||
let userData = contactShortLinkData profile Nothing
|
||||
shortenShortLink' =<< withAgent (\a -> setConnShortLink a nm (aConnId' conn) SCMInvitation userData Nothing)
|
||||
userLinkData = UserInvLinkData userData
|
||||
shortenShortLink' =<< withAgent (\a -> setConnShortLink a nm (aConnId' conn) SCMInvitation userLinkData Nothing)
|
||||
updateCIGroupInvitationStatus :: User -> GroupInfo -> CIGroupInvitationStatus -> CM ()
|
||||
updateCIGroupInvitationStatus user GroupInfo {groupId} newStatus = do
|
||||
AChatItem _ _ cInfo ChatItem {content, meta = CIMeta {itemId}} <- withFastStore $ \db -> getChatItemByGroupId db vr user groupId
|
||||
|
||||
@@ -1232,8 +1232,9 @@ setGroupLinkData nm user gInfo@GroupInfo {groupProfile} gLink@GroupLink {groupLi
|
||||
vr <- chatVersionRange
|
||||
conn <- withFastStore $ \db -> getGroupLinkConnection db vr user gInfo
|
||||
let userData = encodeShortLinkData $ GroupShortLinkData groupProfile
|
||||
userLinkData = UserContactLinkData UserContactData {direct = True, owners = [], relays = [], userData}
|
||||
crClientData = encodeJSON $ CRDataGroup groupLinkId
|
||||
sLnk <- shortenShortLink' . toShortGroupLink =<< withAgent (\a -> setConnShortLink a nm (aConnId conn) SCMContact userData (Just crClientData))
|
||||
sLnk <- shortenShortLink' . toShortGroupLink =<< withAgent (\a -> setConnShortLink a nm (aConnId conn) SCMContact userLinkData (Just crClientData))
|
||||
withFastStore' $ \db -> setGroupLinkShortLink db gLink sLnk
|
||||
|
||||
encodeShortLinkData :: J.ToJSON a => a -> UserLinkData
|
||||
|
||||
+14
-5
@@ -53,7 +53,7 @@ const globalConfig = {
|
||||
}
|
||||
|
||||
const translationsDirectoryPath = './langs'
|
||||
const supportedRoutes = ["blog", "contact", "invitation", "docs", "fdroid", ""]
|
||||
const supportedRoutes = ["blog", "contact", "invitation", "messaging", "docs", "fdroid", ""]
|
||||
let supportedLangs = []
|
||||
fs.readdir(translationsDirectoryPath, (err, files) => {
|
||||
if (err) {
|
||||
@@ -69,6 +69,13 @@ fs.readdir(translationsDirectoryPath, (err, files) => {
|
||||
const translations = require("./translations.json")
|
||||
|
||||
module.exports = function (ty) {
|
||||
// Add this after your markdownLib definition
|
||||
ty.addShortcode("mdInclude", function (filepath) {
|
||||
const fullPath = path.join(__dirname, 'src/_includes', filepath);
|
||||
const content = fs.readFileSync(fullPath, 'utf8');
|
||||
return markdownLib.render(content);
|
||||
});
|
||||
|
||||
ty.addShortcode("cfg", (name) => globalConfig[name])
|
||||
|
||||
ty.addFilter("getlang", (path) => {
|
||||
@@ -106,9 +113,10 @@ module.exports = function (ty) {
|
||||
|
||||
allContentNodes.forEach((node) => {
|
||||
const regex = new RegExp(`(?<![/#])\\b${term.term}\\b`, 'gi')
|
||||
const replacement = `<span data-glossary="tooltip-${id}" class="glossary-term">${term.term}</span>`
|
||||
const beforeContent = node.innerHTML
|
||||
node.innerHTML = node.innerHTML.replace(regex, replacement)
|
||||
node.innerHTML = node.innerHTML.replace(regex, (match) => {
|
||||
return `<span data-glossary="tooltip-${id}" class="glossary-term">${match}</span>`
|
||||
})
|
||||
if (beforeContent !== node.innerHTML && !changeNoted) {
|
||||
changeNoted = true
|
||||
}
|
||||
@@ -256,8 +264,9 @@ module.exports = function (ty) {
|
||||
else if (obj.lang === "en")
|
||||
return `${obj.url}`
|
||||
return `/${obj.lang}${obj.url}`
|
||||
}
|
||||
else if (supportedLangs.includes(urlParts[1])) {
|
||||
} else if (urlParts[1] === "old") {
|
||||
return `/${obj.lang}${obj.url}`
|
||||
} else if (supportedLangs.includes(urlParts[1])) {
|
||||
if (urlParts[2] == "blog")
|
||||
return `/blog`
|
||||
else if (obj.lang === "en")
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# SimpleX Chat website
|
||||
|
||||
## License
|
||||
|
||||
SimpleX Chat website code is licensed under the GNU Affero General Public License version 3 (AGPLv3). See the [LICENSE](../LICENSE) file for details.
|
||||
|
||||
The SimpleX and SimpleX Chat name, logo, and associated branding materials are not covered by this license and are subject to the terms outlined in the [TRADEMARK](./docs/TRADEMARK.md) file.
|
||||
|
||||
Graphic designs, artworks and layouts are not licensed for re-use. If you want to use them in your publications, please ask for permission. Texts can be used as direct quotes, referencing the source.
|
||||
@@ -21,7 +21,7 @@
|
||||
"smp-protocol": "СМП Протокол",
|
||||
"chat-protocol": "Чат протокол",
|
||||
"donate": "Дарете",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Проект с отворен код",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Проект с отворен код",
|
||||
"simplex-chat-protocol": "SimpleX Чат протокол",
|
||||
"terminal-cli": "Системна конзола",
|
||||
"terms-and-privacy-policy": "Политика за поверителност",
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"smp-protocol": "SMP protokol",
|
||||
"chat-protocol": "Chat protokol",
|
||||
"donate": "Darovat",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Projekt s otevřeným zdrojovým kódem",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Projekt s otevřeným zdrojovým kódem",
|
||||
"simplex-chat-protocol": "SimpleX Chat protokol",
|
||||
"terminal-cli": "Terminálové rozhraní příkazového řádku",
|
||||
"terms-and-privacy-policy": "Ochrana soukromí",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"smp-protocol": "SMP-Protokoll",
|
||||
"chat-bot-example": "Beispiel für einen Chatbot",
|
||||
"donate": "Spenden",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Open-Source-Projekt",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Open-Source-Projekt",
|
||||
"chat-protocol": "Chat-Protokoll",
|
||||
"simplex-chat-protocol": "SimpleX-Chat-Protokoll",
|
||||
"terminal-cli": "Terminal-Kommandozeilen-Schnittstelle",
|
||||
@@ -283,7 +283,7 @@
|
||||
"index-token-h2": "Communities, die Bestand haben",
|
||||
"index-token-p1": "Sie werden Ihre Lieblingsgruppen mit zukünftigen Community-Gutscheinen unterstützen.",
|
||||
"index-token-p2": "Server werden mit Gutscheinen bezahlt, damit Ihre Communities kostenlos und unabhängig bleiben können.",
|
||||
"index-token-cta": "Erfahren Sie mehr und <strong>holen Sie sich Ihren kostenlosen NFT</strong><br>für 20 % Rabatt auf SimpleX-Token!",
|
||||
"index-token-cta": "Erfahren Sie mehr und <strong>holen Sie sich Ihren kostenlosen NFT</strong><br>zum frühzeitigen ausprobieren.",
|
||||
"index-roadmap-h2": "SimpleX - Roadmap zum freien Internet",
|
||||
"index-roadmap-2025": "2025",
|
||||
"index-roadmap-2025-title": "Skalierung auf große Communities",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"reference": "Reference",
|
||||
"blog": "Blog",
|
||||
"features": "Features",
|
||||
"navbar-token": "Token",
|
||||
"why-simplex": "Why SimpleX",
|
||||
"simplex-privacy": "SimpleX privacy",
|
||||
"simplex-network": "SimpleX network",
|
||||
@@ -22,7 +23,7 @@
|
||||
"smp-protocol": "SMP protocol",
|
||||
"chat-protocol": "Chat protocol",
|
||||
"donate": "Donate",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Open-Source Project",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Open-Source Project",
|
||||
"simplex-chat-protocol": "SimpleX Chat protocol",
|
||||
"terminal-cli": "Terminal CLI",
|
||||
"about-and-contact-us": "About & Contact us",
|
||||
|
||||
+11
-11
@@ -10,8 +10,8 @@
|
||||
"simplex-explained-tab-3-p-2": "El usuario puede mejorar aún más la privacidad de sus metadatos, haciendo uso de la red Tor para acceder a los servidores, evitando así la correlación por dirección IP.",
|
||||
"smp-protocol": "Protocolo SMP",
|
||||
"donate": "Donación",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Proyecto de Código Abierto",
|
||||
"simplex-chat-protocol": "Protocolo de SimpleX Chat",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Proyecto de Código Abierto",
|
||||
"simplex-chat-protocol": "Protocolo SimpleX Chat",
|
||||
"terms-and-privacy-policy": "Política de Privacidad",
|
||||
"hero-header": "Privacidad redefinida",
|
||||
"hero-overlay-1-textlink": "¿Por qué los ID de usuario son perjudiciales para la privacidad?",
|
||||
@@ -267,37 +267,37 @@
|
||||
"index-security-assessment-title": "Auditorías de seguridad",
|
||||
"index-security-review-2022-title": "Auditoría de Seguridad 2022",
|
||||
"index-security-review-2024-title": "Auditoría de Seguridad 2024",
|
||||
"index-security-audits-label": "Auditorías en<br>Seguridad",
|
||||
"index-security-audits-label": "Auditorías<br>en Seguridad",
|
||||
"index-publications-privacy-guides-title": "Recomendaciones de mensajería de Privacy Guides",
|
||||
"index-publications-whonix-title": "Recomendación de mensajería de Whonix",
|
||||
"index-publications-heise-title": "Publicaciones Heise Online",
|
||||
"index-publications-kuketz-title": "Revisión por Mike Kuketz",
|
||||
"index-publications-optout-title": "Entrevista en podcast de OptOut",
|
||||
"worlds-most-secure-messaging": "Mensajería Más Segura Del Mundo",
|
||||
"index-messaging-p1": "Le mensajería SimpleX dispone de cifrado de extremo a extremo de vanguardia.",
|
||||
"index-messaging-p1": "La mensajería SimpleX posee un cifrado de extremo a extremo de vanguardia.",
|
||||
"index-messaging-p2": "Para tu seguridad y privacidad los servidores no pueden ver tus mensajes <span>ni con quién te comunicas</span>.",
|
||||
"index-messaging-cta": "Descubre más sobre la mensajería SimpleX",
|
||||
"index-nextweb-h2": "Tu Posees<br>La Próxima Web",
|
||||
"index-nextweb-h2": "La Web<br>Del Futuro<br>Te Pertenece",
|
||||
"index-nextweb-p1": "SimpleX se funda en la creencia de que <span>debes ser el propietario de tu identidad, contactos y comunidades</span>.",
|
||||
"index-nextweb-p2": "Una red abierta y descentralizada que te permite conectarte con personas y compartir ideas: libre y segura.",
|
||||
"index-token-h2": "Comunidades Duraderas",
|
||||
"index-token-p1": "Podrás apoyar a tus grupos favoritos con los futuros Vales Comunitarios.",
|
||||
"index-token-p2": "Los vales costearán los servidores para que tus comunidades sigan siendo libres e independientes.",
|
||||
"index-token-cta": "Descubre más y <strong>obtén tu NFT gratuito</strong><br>con 20% de descuento en SimpleX Token!",
|
||||
"index-roadmap-h2": "Ruta de SimpleX hacía el Internet Libre",
|
||||
"index-token-cta": "Descubre más y <strong>obtén tu NFT gratuito</strong><br>por participar en las pruebas.",
|
||||
"index-roadmap-h2": "Ruta SimpleX hacía el Internet Libre",
|
||||
"index-roadmap-2025": "2025",
|
||||
"index-roadmap-2025-title": "Escalar a Comunidades Grandes",
|
||||
"index-roadmap-2025-desc": "Huyendo de plataformas centralizadas",
|
||||
"index-roadmap-2025-desc": "Huir de plataformas centralizadas",
|
||||
"index-roadmap-2026": "2026",
|
||||
"index-roadmap-2026-title": "Comunidades y Servidores Sostenibles",
|
||||
"index-roadmap-2026-desc": "Lanzamiento de Vales Comunitarios",
|
||||
"index-roadmap-2027": "2027",
|
||||
"index-roadmap-2027-title": "Haz Crecer Tus Comunidades",
|
||||
"index-roadmap-2027-desc": "Herramientas para promocionarlas",
|
||||
"index-roadmap-2027-desc": "Herramientas para la promoción",
|
||||
"index-directory-h2": "Únete a las Comunidades SimpleX",
|
||||
"index-directory-p1": "Cientos de miles de personas confían ya en la mensajería SimpleX.",
|
||||
"index-directory-p1": "Miles de personas confían ya en la mensajería SimpleX.",
|
||||
"index-directory-p2": "¡Encuentra comunidades en el directorio SimpleX y crea la tuya!",
|
||||
"index-directory-cta": "Ver el Directorio SimpleX",
|
||||
"index-directory-cta": "Ir al Directorio SimpleX",
|
||||
"index-directory-users-group-title": "SimpleX users group",
|
||||
"how-secure-comparison-title": "Comparativa del cifrado de extremo a extremo en los distintos mensajeros",
|
||||
"how-secure-message-padding": "Relleno de mensajes",
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
"simplex-explained-tab-1-p-1": "Voit luoda yhteyshenkilöitä ja ryhmiä sekä käydä kaksisuuntaisia keskusteluja kuten missä tahansa muussa viestisovelluksessa.",
|
||||
"simplex-explained-tab-3-p-1": "Palvelimilla on erilliset anonyymit tunnistetiedot kullekin jonolle, eivätkä ne tiedä, mille käyttäjille ne kuuluvat.",
|
||||
"donate": "Lahjoita",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Avoin projekti",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Avoin projekti",
|
||||
"hero-p-1": "Muissa sovelluksissa on käyttäjätunnuksia: Signal, Matrix, Session, Briar, Jami, Cwtch, jne.<br> SimpleX ei käytä niitä, <strong>ei edes satunnaisia numeroita</strong>.<br> Tämä parantaa yksityisyyttäsi radikaalisti.",
|
||||
"simplex-private-1-title": "2 kerrosta päästä päähän salattua viestintää",
|
||||
"simplex-private-2-title": "Lisäkerros palvelimen salaukselle",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"smp-protocol": "Protocole SMP",
|
||||
"chat-protocol": "Protocole de chat",
|
||||
"donate": "Faire un don",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Projet Open-Source",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Projet Open-Source",
|
||||
"simplex-chat-protocol": "Protocole SimpleX Chat",
|
||||
"terminal-cli": "Terminal CLI",
|
||||
"terms-and-privacy-policy": "Politique de confidentialité",
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"smp-protocol": "פרוטוקול SMP",
|
||||
"chat-protocol": "פרוטוקול צ'אט",
|
||||
"donate": "תרומה",
|
||||
"copyright-label": "© 2020-2025 SimpleX | פרויקט קוד פתוח",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | פרויקט קוד פתוח",
|
||||
"hero-p-1": "לאפליקציות אחרות יש מזהי משתמש: Signal, Matrix, Session, Briar, Jami, Cwtch וכו'.<br> ל-SimpleX אין, <strong>אפילו לא מספרים אקראיים</strong>.<br> זה משפר באופן קיצוני את הפרטיות שלך.",
|
||||
"hero-overlay-2-title": "מדוע מזהי משתמש מזיקים לפרטיות?",
|
||||
"feature-6-title": "שיחות שמע ווידאו<br>מוצפנות מקצה לקצה",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"smp-protocol": "SMP-protokoll",
|
||||
"chat-protocol": "Csevegési protokoll",
|
||||
"donate": "Adományozás",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Nyílt forráskódú projekt",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Nyílt forráskódú projekt",
|
||||
"simplex-chat-protocol": "A SimpleX Chat protokoll",
|
||||
"terminal-cli": "Terminál CLI",
|
||||
"terms-and-privacy-policy": "Adatvédelmi irányelvek",
|
||||
@@ -283,7 +283,7 @@
|
||||
"index-token-h2": "Időtálló közösségek",
|
||||
"index-token-p1": "A jövőben közösségi utalványokkal támogathatja a kedvenc csoportjait.",
|
||||
"index-token-p2": "Az utalványokkal fizetni tudja a kiszolgálókat, hogy a közösségek szabadok és függetlenek maradhassanak.",
|
||||
"index-token-cta": "Tudjon meg többet, és <strong>szerezzen ingyenes NFT-t</strong><br>20% kedvezménnyel a SimpleX Tokenre!",
|
||||
"index-token-cta": "Tudjon meg többet, és <strong>szerezzen ingyenes NFT-t</strong><br>az előzetes tesztelésért.",
|
||||
"index-roadmap-h2": "A SimpleX ütemterve a szabad internethez",
|
||||
"index-roadmap-2025": "2025",
|
||||
"index-roadmap-2025-title": "Skálázódás nagy közösségekre",
|
||||
@@ -305,11 +305,11 @@
|
||||
"how-secure-forward-secrecy": "Kompromittálás előtti titkosságvédelem",
|
||||
"how-secure-break-in-recovery": "Kompromittálás utáni titkosságvédelem",
|
||||
"how-secure-two-factor-key-exchange": "Kétlépcsős kulcscsere",
|
||||
"how-secure-post-quantum-hybrid-crypto": "Hibrid kriptográfia a kvantum számítógépek megjelenése utánra",
|
||||
"how-secure-post-quantum-hybrid-crypto": "Kvantumbiztos, hibrid kriptográfia",
|
||||
"messengers-comparison-section-list-point-1": "A Briar 1024 bájtra, a Signal pedig 160 bájtra kerekítve tölti ki az üzenetek tartalmát",
|
||||
"messengers-comparison-section-list-point-2": "A letagadhatóság nem foglalja magába a kliens és a kiszolgáló közötti kapcsolatot.",
|
||||
"messengers-comparison-section-list-point-3": "Úgy tűnik, hogy a kriptográfiai aláírások használata rontja a letagadhatóságot, de ez tisztázásra szorul.",
|
||||
"messengers-comparison-section-list-point-4": "A többeszközös megvalósítás rontja a dupla racsni kompromittálás utáni biztonságát",
|
||||
"messengers-comparison-section-list-point-5": "A kétlépcsős kulcscsere nem követelmény a biztonsági kód ellenőrzéséhez.",
|
||||
"messengers-comparison-section-list-point-6": "A posztkvantum kulcscsere „ritka” — csak a racsnis lépések egy részét védi."
|
||||
"messengers-comparison-section-list-point-6": "A kvantumbiztos kulcscsere „ritka” — csak a racsnis lépések egy részét védi."
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
"simplex-explained-tab-2-text": "2. Bagaimana cara kerjanya",
|
||||
"simplex-chat-protocol": "Protokol SimpleX Chat",
|
||||
"hero-overlay-2-title": "Mengapa ID pengguna buruk untuk privasi?",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Open-Source Project",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Open-Source Project",
|
||||
"simplex-explained-tab-3-text": "3. Apa yang dilihat server",
|
||||
"smp-protocol": "Protokol SMP",
|
||||
"please-use-link-in-mobile-app": "Mohon gunakan tautan di aplikasi seluler",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"simplex-explained-tab-3-p-1": "I server hanno credenziali anonime separate per ogni coda e non sanno a quali utenti appartengano.",
|
||||
"chat-protocol": "Protocollo di chat",
|
||||
"donate": "Dona",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Progetto Open-Source",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Progetto Open-Source",
|
||||
"simplex-chat-protocol": "Protocollo di SimpleX Chat",
|
||||
"terminal-cli": "Terminale CLI",
|
||||
"terms-and-privacy-policy": "Informativa sulla privacy",
|
||||
@@ -283,7 +283,7 @@
|
||||
"index-token-h2": "Comunità fatte per restare",
|
||||
"index-token-p1": "Sosterrai i tuoi gruppi preferiti con futuri buoni comunitari.",
|
||||
"index-token-p2": "I buoni pagheranno i server, per consentire alle tue comunità di rimanere libere e indipendenti.",
|
||||
"index-token-cta": "Scopri di più e <strong>ricevi un NFT gratuito</strong><br>per uno sconto del 20% su SimpleX Token!",
|
||||
"index-token-cta": "Scopri di più e <strong>ricevi un NFT gratuito</strong><br>per provarlo in anticipo.",
|
||||
"index-roadmap-h2": "Tabella di marcia per un internet libero",
|
||||
"index-roadmap-2025": "2025",
|
||||
"index-roadmap-2025-title": "Scalabilità per comunità numerose",
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
"chat-protocol": "チャットプロトコル",
|
||||
"chat-bot-example": "チャットボットの例",
|
||||
"donate": "寄付",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Open-Source Project",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Open-Source Project",
|
||||
"hero-p-1": "他のアプリにはユーザー ID があります: Signal、Matrix、Session、Briar、Jami、Cwtch など。<br> SimpleX にはありません。<strong>乱数さえもありません</strong>。<br> これにより、プライバシーが大幅に向上します。",
|
||||
"copy-the-command-below-text": "以下のコマンドをコピーしてチャットで使用します:",
|
||||
"simplex-private-card-9-point-1": "各メッセージ キューは、異なる送信アドレスと受信アドレスを使用してメッセージを一方向に渡します。",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"chat-bot-example": "Chatbot voorbeeld",
|
||||
"smp-protocol": "SMP protocol",
|
||||
"donate": "Doneer",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Open-sourceproject",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Open-sourceproject",
|
||||
"simplex-chat-protocol": "SimpleX Chat protocol",
|
||||
"terminal-cli": "Terminal CLI",
|
||||
"terms-and-privacy-policy": "Privacybeleid",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"smp-protocol": "Protokół SMP",
|
||||
"chat-protocol": "Protokół czatu",
|
||||
"donate": "Darowizna",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Projekt Open-Source",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Projekt Open-Source",
|
||||
"simplex-chat-protocol": "Protokół SimpleX Chat",
|
||||
"terminal-cli": "Terminal CLI",
|
||||
"terms-and-privacy-policy": "Polityka prywatności",
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"smp-protocol": "Protocolo SMP",
|
||||
"chat-protocol": "Protocolo de bate-papo",
|
||||
"donate": "Doar",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Projeto de Código Livre",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Projeto de Código Livre",
|
||||
"simplex-chat-protocol": "Protocolo Chat SimpleX",
|
||||
"terminal-cli": "CLI Terminal",
|
||||
"hero-header": "Privacidade redefinida",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"smp-protocol": "Protocolul SMP",
|
||||
"chat-protocol": "Protocol de chat",
|
||||
"donate": "Donează",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Proiect Open-Source",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Proiect Open-Source",
|
||||
"simplex-chat-protocol": "Protocolul SimpleX Chat",
|
||||
"terminal-cli": "Terminal CLI",
|
||||
"terms-and-privacy-policy": "Politică de confidențialitate",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"copy-the-command-below-text": "скопируйте приведенную ниже команду и используйте ее в чате:",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Проект с открытым исходным кодом",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Проект с открытым исходным кодом",
|
||||
"chat-bot-example": "Пример Чат бота",
|
||||
"simplex-private-card-9-point-1": "Каждая очередь сообщений передает сообщения в одном направлении с разными адресами отправки и получения.",
|
||||
"simplex-private-card-1-point-2": "NaCL cryptobox в каждой очереди для предотвращения корреляции трафика между очередями сообщений, в случае компрометированного TLS.",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"smp-protocol": "SMP Protokolü",
|
||||
"chat-protocol": "Sohbet Protokolü",
|
||||
"donate": "Bağış Yap",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Açık Kaynak Projesi",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Açık Kaynak Projesi",
|
||||
"simplex-chat-protocol": "SimpleX Sohbet Protokolü",
|
||||
"terminal-cli": "Terminal Komut Satırı Arayüzü",
|
||||
"terms-and-privacy-policy": "Gizlilik Politikası",
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
"smp-protocol": "Протокол SMP",
|
||||
"chat-protocol": "Протокол чату",
|
||||
"donate": "Пожертвувати",
|
||||
"copyright-label": "© 2020-2025 SimpleX | Проект з відкритим кодом",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | Проект з відкритим кодом",
|
||||
"simplex-chat-protocol": "Протокол чату SimpleX",
|
||||
"terminal-cli": "Термінал CLI",
|
||||
"hero-header": "Приватність переосмислена",
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
"simplex-chat-protocol": "SimpleX 聊天协议",
|
||||
"smp-protocol": "SMP协议",
|
||||
"chat-protocol": "聊天协议",
|
||||
"copyright-label": "© 2020-2025 SimpleX | 开源项目",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat | 开源项目",
|
||||
"terminal-cli": "命令行程式",
|
||||
"simplex-explained-tab-1-p-1": "您可以创建联系人和群组,并进行双向对话,就像是任何其他即时通讯软件一样。",
|
||||
"hero-p-1": "其他应用——如Signal、Matrix、Session、Briar、Jami、Cwtch 等——都需要用户 ID。<br>而SimpleX 不需要用户ID,连<strong>随机生成</strong>的也不需要。<br>这从根本上改善了您的隐私。",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"simplex-explained-tab-2-p-2": "伺服器僅單向傳遞消息,無法全面瞭解使用者的對話記錄或連接。",
|
||||
"simplex-explained-tab-2-p-1": "對於每個連接,您可以使用兩個單獨的消息佇列通過不同的伺服器發送和接收消息。",
|
||||
"chat-protocol": "聊天協定",
|
||||
"copyright-label": "© 2020-2025 SimpleX |開源專案",
|
||||
"copyright-label": "© 2020-2025 SimpleX Chat |開源專案",
|
||||
"donate": "捐助",
|
||||
"simplex-explained-tab-1-p-1": "你可以建立聯絡人和群組,並進行雙向對話,就像在任何其他即時通訊軟件中一樣。",
|
||||
"simplex-explained-tab-1-p-2": "它如何在沒有使用者個人檔案識別符的情況下使用單向佇列?",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"@11ty/eleventy-plugin-rss": "^1.2.0",
|
||||
"@simplex-chat/webrtc": "^0.1.1",
|
||||
"common-tags": "^1.8.2",
|
||||
"ethers": "^6.15.0",
|
||||
"fast-uri": "^2.1.0",
|
||||
"markdown-it-anchor": "^8.6.4",
|
||||
"markdown-it-replace-link": "^1.1.0",
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
"url": "/docs/directory.html"
|
||||
},
|
||||
{
|
||||
"title": "docs-dropdown-3",
|
||||
"url": "/docs/sql.html"
|
||||
"title": "docs-dropdown-2",
|
||||
"url": "/docs/android.html"
|
||||
},
|
||||
{
|
||||
"title": "docs-dropdown-4",
|
||||
|
||||
@@ -103,6 +103,10 @@
|
||||
"term": "Post-quantum cryptography",
|
||||
"definition": "Post-quantum cryptography"
|
||||
},
|
||||
{
|
||||
"term": "Post-quantum hybrid crypto",
|
||||
"definition": "Post-quantum cryptography"
|
||||
},
|
||||
{
|
||||
"term": "Proxied peer-to-peer",
|
||||
"definition": "Proxied peer-to-peer"
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
"label": "en",
|
||||
"name": "English",
|
||||
"flag": "/img/flags/en.svg",
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"home": true
|
||||
},
|
||||
{
|
||||
"label": "ar",
|
||||
@@ -25,13 +26,15 @@
|
||||
"label": "de",
|
||||
"name": "Deutsch",
|
||||
"flag": "/img/flags/de.svg",
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"home": true
|
||||
},
|
||||
{
|
||||
"label": "es",
|
||||
"name": "Español",
|
||||
"flag": "/img/flags/es.svg",
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"home": true
|
||||
},
|
||||
{
|
||||
"label": "fi",
|
||||
@@ -56,13 +59,22 @@
|
||||
"label": "hu",
|
||||
"name": "Magyar",
|
||||
"flag": "/img/flags/hu.svg",
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"home": true
|
||||
},
|
||||
{
|
||||
"label": "id",
|
||||
"name": "Indonesia",
|
||||
"flag": "/img/flags/id.svg",
|
||||
"enabled": true,
|
||||
"home": true
|
||||
},
|
||||
{
|
||||
"label": "it",
|
||||
"name": "Italiano",
|
||||
"flag": "/img/flags/it.svg",
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"home": true
|
||||
},
|
||||
{
|
||||
"label": "ja",
|
||||
@@ -110,7 +122,8 @@
|
||||
"label": "ru",
|
||||
"name": "Русский",
|
||||
"flag": "/img/flags/ru.svg",
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"home": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{% set lang = page.url | getlang %}
|
||||
<section class="bg-[#D9E7ED] dark:bg-[#0E2B57] py-[50px]">
|
||||
<section class="bg-[#D3E9FF] dark:bg-[#080D25] py-[50px] footer page">
|
||||
<div class="container">
|
||||
<div class="flex flex-col lg:flex-row justify-between">
|
||||
<div class="flex flex-col items-center lg:items-start">
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<p class="text-center text-[16px] leading-[24px] tracking-[0.04em] text-white">PLAY</p>
|
||||
</div> #}
|
||||
</div>
|
||||
<div class="w-full md:hidden my-10 relative flex items-center justify-center bg-[#17203D]">
|
||||
<div class="w-full md:hidden my-10 relative flex items-center justify-center bg-[#071C46]">
|
||||
<video class="w-full" controls>
|
||||
<source src="/video/connect.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
@@ -27,17 +27,18 @@
|
||||
<link rel="stylesheet" href="/css/blog.css" />
|
||||
<link id="prism-theme" rel="stylesheet" href="/css/prism-light.min.css"/>
|
||||
<link href="/css/style.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/css/design3-nav.css">
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="bg-[#F3F6F7] dark:bg-[#0C0B13]">
|
||||
<body class="bg-[#F3FAFF] dark:bg-[#000832]">
|
||||
{% include "navbar.html" %}
|
||||
|
||||
<div class="container px-5">
|
||||
<div class="container px-5 mt-[66px]">
|
||||
<a class="inline-block text-grey-black dark:text-white my-5 underline underline-offset-2" href="/blog">< Back to list</a>
|
||||
</div>
|
||||
|
||||
<section id="article" class="container mb-[75px] bg-white dark:bg-[#17203D] px-5">
|
||||
<section id="article" class="container mb-[75px] bg-white dark:bg-[#071C46] px-5">
|
||||
<div class="py-6 md:p-[60px]">{{ content | safe }}</div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -19,15 +19,14 @@
|
||||
<link id="prism-theme" rel="stylesheet" href="/css/prism-light.min.css"/>
|
||||
<link href="/css/style.css" rel="stylesheet"/>
|
||||
<link rel="stylesheet" href="/css/doc.css"/>
|
||||
<link rel="stylesheet" href="/css/design3-nav.css">
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="bg-[#F3F6F7] dark:bg-[#0C0B13]">
|
||||
<section class="w-full bg-transparent fixed top-0 z-50">
|
||||
{% include "navbar.html" %}
|
||||
</section>
|
||||
<body class="bg-white dark:bg-[#000832]">
|
||||
{% include "navbar.html" %}
|
||||
|
||||
<section id="doc" class="bg-white dark:bg-[#17203D] mt-[66px]">
|
||||
<section id="doc" class="bg-white dark:bg-[#000832] mt-[66px]">
|
||||
<div>
|
||||
<main>
|
||||
<aside class="sidebar px-4 lg:px-7">
|
||||
@@ -78,7 +77,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="sticky top-[66px] bg-white dark:bg-[#17203D] z-[49] !py-2 lg:hidden">
|
||||
<div class="sticky top-[66px] bg-white dark:bg-[#071C46] z-[49] !py-2 lg:hidden">
|
||||
<div class="relative flex items-center justify-between">
|
||||
<button class="menu flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24" class="menu-icon h-4 w-4 fill-[rgb(60,60,60)] dark:fill-white">
|
||||
|
||||
@@ -18,15 +18,14 @@
|
||||
<link id="prism-theme" rel="stylesheet" href="/css/prism-light.min.css" />
|
||||
<link href="/css/style.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/css/doc.css" />
|
||||
<link rel="stylesheet" href="/css/design3-nav.css">
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="bg-[#F3F6F7] dark:bg-[#0C0B13]">
|
||||
<section class="w-full bg-transparent fixed top-0 z-50">
|
||||
{% include "navbar.html" %}
|
||||
</section>
|
||||
<body class="bg-[#F3FAFF] dark:bg-[#000832]">
|
||||
{% include "navbar.html" %}
|
||||
|
||||
<section id="doc" class="bg-white dark:bg-[#17203D] mt-[66px]">
|
||||
<section id="doc" class="bg-[#F3FAFF] dark:bg-[#071C46] mt-[66px]">
|
||||
<main class="container px-4 lg:px-7 py-10 md:py-16">
|
||||
<div>{{ content | wrapH3s(page) | safe }}</div>
|
||||
</main>
|
||||
|
||||
@@ -27,22 +27,21 @@
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="/img/favicon.ico"/>
|
||||
|
||||
<link rel="stylesheet" href="/css/swiper-bundle.min.css">
|
||||
<link rel="stylesheet" href="/css/blog.css">
|
||||
<link href="/css/tailwind.css" rel="stylesheet"/>
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<link rel="stylesheet" href="/css/design3-nav.css">
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
<script src="/js/flag-anchor.js"></script>
|
||||
{% block js_scripts %}{% endblock %}
|
||||
</head>
|
||||
<body class="bg-white dark:bg-[#0C0B13]">
|
||||
<section class="w-full bg-transparent fixed top-0 z-50">
|
||||
{% include "navbar.html" %}
|
||||
</section>
|
||||
<body class="bg-[#F3FAFF] dark:bg-[#000832]">
|
||||
{% include "navbar.html" %}
|
||||
|
||||
{{ content | applyGlossary | safe }}
|
||||
|
||||
{% include "footer.html" %}
|
||||
|
||||
<script src="/js/animation.js"></script>
|
||||
<script src="/js/swiper-bundle.min.js"></script>
|
||||
<script src="/js/script.js"></script>
|
||||
</body>
|
||||
|
||||
@@ -26,13 +26,14 @@
|
||||
<link href="/css/tailwind.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/css/blog.css" />
|
||||
<link href="/css/style.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/css/design3-nav.css">
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="bg-[#F3F6F7] dark:bg-[#0C0B13]">
|
||||
<body class="bg-[#F3FAFF] dark:bg-[#000832]">
|
||||
{% include "navbar.html" %}
|
||||
|
||||
<section id="article" class="container mt-[25px] mb-[75px] bg-white dark:bg-[#17203D] px-5">
|
||||
<section id="article" class="container mt-[66px] mb-[75px] bg-white dark:bg-[#071C46] px-5">
|
||||
<div class="py-6 md:p-[60px]">{{ content | safe }}</div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -0,0 +1,809 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ page.url | getlang }}"
|
||||
{% for language in languages.languages %}
|
||||
{% if language.label == page.url | getlang %}
|
||||
dir="{{ "rtl" if language.rtl else "ltr" }}"
|
||||
{% endif %}
|
||||
{% endfor %}>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{{ title }}</title>
|
||||
<meta name="Content-Type" content="text/html;charset=utf-8" />
|
||||
<meta http-equiv="onion-location" content="{% cfg 'onionLocation' %}{{ permalink }}" />
|
||||
<meta property="og:url" content="{% cfg 'siteLocation' %}{{ permalink }}" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:title" content="{{ title }}" />
|
||||
<meta property="og:image" content="{% cfg 'siteLocation' %}/img/share_simplex.png" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="/img/favicon.ico" />
|
||||
<link href="/css/tailwind.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/css/blog.css" />
|
||||
<link id="prism-theme" rel="stylesheet" href="/css/prism-light.min.css"/>
|
||||
<link href="/css/style.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/css/design3-nav.css">
|
||||
<script src="/js/ethers.umd.min.js"></script>
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
<style>
|
||||
.dark #nft-app-content {
|
||||
color: white;
|
||||
}
|
||||
#nft-app-content .nft-display {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
#nft-app-content .metadata p {
|
||||
margin: 5px 0;
|
||||
}
|
||||
#nft-app-content .account-info {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#nft-app-content .switch-link {
|
||||
background: none;
|
||||
border: none;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
}
|
||||
#nft-app-content .btn {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
}
|
||||
#nft-app-content a {
|
||||
cursor: pointer;
|
||||
}
|
||||
#nft-app-content .btn-primary {
|
||||
background: -webkit-linear-gradient(to bottom, #53C1FF -50%, #0053D0 160%);
|
||||
background: linear-gradient(to bottom, #53C1FF -50%, #0053D0 160%);
|
||||
color: white;
|
||||
}
|
||||
.dark #nft-app-content .btn-primary {
|
||||
background: -webkit-linear-gradient(to bottom, #70F0F9 0%, #70F0F9 33%, #50D8F1 100%);
|
||||
background: linear-gradient(to bottom, #70F0F9 0%, #70F0F9 33%, #50D8F1 100%);
|
||||
color: rgb(13, 14, 18);
|
||||
}
|
||||
#nft-app-content #connect.btn-primary {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
#nft-app-content .btn-large {
|
||||
padding: 10px 25px;
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#nft-app-content .spinner {
|
||||
border: 4px solid rgba(0, 0, 0, 0.1);
|
||||
border-left-color: #007bff;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: progress_spin 1s linear infinite;
|
||||
margin: 20px;
|
||||
}
|
||||
@keyframes progress_spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
#nft-app-content #nft-image-container {
|
||||
min-width: 420px;
|
||||
min-height: 420px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
#nft-app-content .nft-image {
|
||||
max-width: 420px;
|
||||
display: block;
|
||||
}
|
||||
#nft-app-content .nft-id-overlay {
|
||||
position: absolute;
|
||||
top: 6.5%;
|
||||
right: 4%;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
font-family: "GT-Walsheim", "Manrope", sans-serif;
|
||||
text-align: right;
|
||||
color: #023787;
|
||||
}
|
||||
#nft-app-content #next-nft-image-container {
|
||||
min-width: 200px;
|
||||
min-height: 200px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
#nft-app-content .next-nft-image {
|
||||
max-width: 200px;
|
||||
display: block;
|
||||
}
|
||||
#nft-app-content .mint-it-overlay {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
font-family: "GT-Walsheim", "Manrope", sans-serif;
|
||||
color: white;
|
||||
}
|
||||
#nft-app-content .congrats {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
font-family: "GT-Walsheim", "Manrope", sans-serif;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#nft-app-content .owned-text,
|
||||
#nft-app-content .next-text {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#nft-app-content .metadata {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
max-width: 80%;
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
#nft-app-content #nft-image-container {
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
#nft-app-content .nft-image {
|
||||
max-width: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@media (min-width: 960px) {
|
||||
#nft-app-content .nft-display {
|
||||
align-items: flex-start;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#nft-app-content .metadata {
|
||||
text-align: left;
|
||||
justify-content: left;
|
||||
max-width: 420px;
|
||||
}
|
||||
}
|
||||
#nft-app-content .error {
|
||||
color: red;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#nft-app-content .no-metamask {
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#nft-app-content .no-metamask img {
|
||||
display: inline;
|
||||
width: 200px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
#nft-app-content .trait-line {
|
||||
font-size: 0.85em;
|
||||
}
|
||||
.dark #nft-app-content .trait-line {
|
||||
color: lightgray;
|
||||
}
|
||||
#nft-app-content .more-link,
|
||||
#nft-app-content .collapse-link {
|
||||
margin-left: 5px;
|
||||
text-decoration: none;
|
||||
color: darkgray;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="bg-[#F3FAFF] dark:bg-[#000832]">
|
||||
{% include "navbar.html" %}
|
||||
|
||||
<section id="article" class="container mb-[75px] bg-white dark:bg-[#071C46] px-5 mt-[66px]">
|
||||
<div class="py-6 md:p-[60px]">{{ content | safe }}</div>
|
||||
</section>
|
||||
|
||||
<div id="mint-simplex-nft" class="overlay hidden fixed top-0 left-0 bottom-0 right-0 before:absolute before:w-full before:h-full bg-transparent before:bg-secondary-bg-light dark:before:bg-primary-bg-dark before:opacity-90 items-center justify-center p-3 md:p-10 z-[10000]">
|
||||
<div class="overlay-card w-full md:max-w-[1276px] bg-white dark:bg-card-bg-dark opacity-100 h-full md:max-h-[720px] z-[10001] rounded-md shadow-[0px_3px_12px_rgba(0,0,0,0.2)] p-6 py-10 sm:p-14 overflow-auto scale-100">
|
||||
<h1 id="nft-app-title" class="text-4xl font-bold text-active-blue mb-6 text-center gradient-text">Mint SimpleX NFT</h1>
|
||||
<div id="nft-app-content"></div>
|
||||
|
||||
<script>
|
||||
window.addEventListener("hashchange", showNftApp);
|
||||
window.addEventListener("load", showNftApp);
|
||||
|
||||
let appState;
|
||||
|
||||
function showNftApp() {
|
||||
if (window.location.hash === "#mint-simplex-nft") {
|
||||
if (!appState) initNftApp();
|
||||
renderNftApp();
|
||||
} else if (nextPollInterval) {
|
||||
clearInterval(nextPollInterval);
|
||||
}
|
||||
}
|
||||
|
||||
const selectedNetwork = 'ethereum'; // Options: 'ethereum', 'arbitrum', 'hoodi'
|
||||
const networks = {
|
||||
ethereum: {
|
||||
name: 'Ethereum (mainnet)',
|
||||
chainId: '0x1',
|
||||
minterAddress: '0x048F9C5B0b74761d34e03cfa79D04f20445D7D22',
|
||||
explorerHost: 'etherscan.io'
|
||||
},
|
||||
arbitrum: {
|
||||
name: 'Arbitrum One network',
|
||||
chainId: '0xa4b1',
|
||||
minterAddress: '0x386E2B9f5d5c17049a1ADaf62928b3f3C834Ff28',
|
||||
explorerHost: 'arbiscan.io'
|
||||
},
|
||||
hoodi: {
|
||||
name: 'Ethereum Hoodi testnet',
|
||||
chainId: '0x88bb0',
|
||||
minterAddress: '0xdaF242166be93A7f9835C2792958F3b6c424F845',
|
||||
explorerHost: 'hoodi.etherscan.io'
|
||||
}
|
||||
};
|
||||
const currentConfig = networks[selectedNetwork];
|
||||
const minterAddress = currentConfig.minterAddress;
|
||||
|
||||
const nftABI = [
|
||||
'function name() view returns (string)',
|
||||
'function balanceOf(address owner) view returns (uint)',
|
||||
'function tokenOfOwnerByIndex(address owner, uint index) view returns (uint)',
|
||||
'function tokenURI(uint tokenId) view returns (string)',
|
||||
'function mintingLocked() view returns (bool)',
|
||||
'function nextTokenId() view returns (uint)',
|
||||
'function nextTokenURI() view returns (string)',
|
||||
'function totalSupply() view returns (uint)'
|
||||
];
|
||||
|
||||
const minterABI = [
|
||||
'function nft() view returns (address)',
|
||||
'function mintCount() view returns (uint)', // not used
|
||||
'function mintStartTime() view returns (uint)',
|
||||
'function mintEndTime() view returns (uint)',
|
||||
'function paused() view returns (bool)',
|
||||
'function mint()'
|
||||
];
|
||||
|
||||
const STATES = {
|
||||
NOT_CONNECTED: 'not_connected',
|
||||
LOADING: 'loading',
|
||||
OWNED: 'owned',
|
||||
NO_NFT: 'no_nft',
|
||||
MINTING: 'minting',
|
||||
MINTED: 'minted',
|
||||
ERROR: 'error'
|
||||
};
|
||||
|
||||
let provider;
|
||||
let signer;
|
||||
let nftContract;
|
||||
let minterContract;
|
||||
let ownedPollInterval;
|
||||
let nextPollInterval;
|
||||
let mintPollInterval;
|
||||
|
||||
function initNftApp() {
|
||||
appState = {
|
||||
state: STATES.NOT_CONNECTED,
|
||||
address: '',
|
||||
nftAddress: '',
|
||||
hasToken: false,
|
||||
tokenId: null,
|
||||
name: 'Mint SimpleX NFT',
|
||||
metadata: null,
|
||||
nextId: null,
|
||||
nextUri: null,
|
||||
nextMetadata: null,
|
||||
totalMinted: null,
|
||||
canMint: true,
|
||||
currentTime: null,
|
||||
mintStartTime: 0,
|
||||
mintEndTime: 0,
|
||||
paused: false,
|
||||
locked: false,
|
||||
openedTraits: new Set(),
|
||||
nextOpenedTraits: new Set(),
|
||||
error: null,
|
||||
lastRetry: null
|
||||
};
|
||||
|
||||
if (window.ethereum) {
|
||||
window.ethereum.on('accountsChanged', async accounts => {
|
||||
if (accounts.length > 0) {
|
||||
await loadAccount(accounts);
|
||||
} else {
|
||||
resetConnection();
|
||||
}
|
||||
renderNftApp();
|
||||
});
|
||||
|
||||
window.ethereum.on('chainChanged', () => {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function resetConnection() {
|
||||
appState.error = null;
|
||||
appState.state = STATES.NOT_CONNECTED;
|
||||
appState.address = '';
|
||||
provider = null;
|
||||
signer = null;
|
||||
nftContract = null;
|
||||
minterContract = null;
|
||||
if (ownedPollInterval) clearInterval(ownedPollInterval);
|
||||
ownedPollInterval = null;
|
||||
if (nextPollInterval) clearInterval(nextPollInterval);
|
||||
nextPollInterval = null;
|
||||
}
|
||||
|
||||
async function connectWallet() {
|
||||
if (!window.ethereum) {
|
||||
appState.error = null;
|
||||
appState.state = STATES.NOT_CONNECTED;
|
||||
renderNftApp();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
|
||||
await loadAccount(accounts);
|
||||
} catch (error) {
|
||||
handleError(error, connectWallet);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadAccount(accounts) {
|
||||
appState.address = accounts[0];
|
||||
provider = new ethers.BrowserProvider(window.ethereum);
|
||||
signer = await provider.getSigner();
|
||||
const network = await provider.getNetwork();
|
||||
|
||||
if (network.chainId.toString(16) !== currentConfig.chainId.slice(2).toLowerCase()) {
|
||||
await window.ethereum.request({
|
||||
method: 'wallet_switchEthereumChain',
|
||||
params: [{ chainId: currentConfig.chainId }]
|
||||
});
|
||||
}
|
||||
|
||||
minterContract = new ethers.Contract(minterAddress, minterABI, signer);
|
||||
|
||||
appState.error = null;
|
||||
appState.state = STATES.LOADING;
|
||||
renderNftApp();
|
||||
await loadData();
|
||||
}
|
||||
|
||||
async function switchAccount() {
|
||||
try {
|
||||
await window.ethereum.request({
|
||||
method: 'wallet_requestPermissions',
|
||||
params: [{ eth_accounts: {} }]
|
||||
});
|
||||
} catch (error) {
|
||||
handleError(error, switchAccount);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadData() { // TODO rename, make local
|
||||
try {
|
||||
appState.nftAddress = await minterContract.nft();
|
||||
nftContract = new ethers.Contract(appState.nftAddress, nftABI, signer);
|
||||
await checkCanMint();
|
||||
await checkBalance();
|
||||
} catch (error) {
|
||||
handleError(error, loadData);
|
||||
}
|
||||
}
|
||||
|
||||
async function checkCanMint() {
|
||||
appState.locked = await nftContract.mintingLocked();
|
||||
appState.mintStartTime = Number(await minterContract.mintStartTime());
|
||||
appState.mintEndTime = Number(await minterContract.mintEndTime());
|
||||
appState.paused = await minterContract.paused();
|
||||
appState.currentTime = Math.floor(Date.now() / 1000);
|
||||
appState.canMint = !appState.locked
|
||||
&& !appState.paused
|
||||
&& appState.currentTime >= appState.mintStartTime
|
||||
&& (appState.mintEndTime == 0 || appState.currentTime < appState.mintEndTime);
|
||||
}
|
||||
|
||||
async function checkBalance() {
|
||||
appState.name = await nftContract.name();
|
||||
appState.totalMinted = await nftContract.totalSupply();
|
||||
const balance = Number(await nftContract.balanceOf(appState.address));
|
||||
if (balance > 0) {
|
||||
appState.hasToken = true;
|
||||
appState.tokenId = Number(await nftContract.tokenOfOwnerByIndex(appState.address, 0));
|
||||
const uri = await nftContract.tokenURI(appState.tokenId);
|
||||
appState.metadata = await loadMetadata(uri);
|
||||
appState.error = null;
|
||||
appState.state = STATES.OWNED;
|
||||
startOwnedPolling();
|
||||
} else {
|
||||
appState.hasToken = false;
|
||||
await loadNext();
|
||||
appState.error = null;
|
||||
appState.state = STATES.NO_NFT;
|
||||
startNextPolling();
|
||||
}
|
||||
renderNftApp();
|
||||
}
|
||||
|
||||
async function loadNext() {
|
||||
try {
|
||||
appState.totalMinted = await nftContract.totalSupply();
|
||||
appState.nextId = Number(await nftContract.nextTokenId());
|
||||
const newNextUri = await nftContract.nextTokenURI();
|
||||
if (newNextUri !== appState.nextUri) {
|
||||
appState.nextUri = newNextUri;
|
||||
appState.nextMetadata = await loadMetadata(newNextUri);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load next:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function replaceIPFS(uri) {
|
||||
return uri ? uri.replace(/^ipfs:\/\//, 'https://ipfs.io/ipfs/') : '';
|
||||
}
|
||||
|
||||
async function loadMetadata(uri) {
|
||||
let proxyUri = replaceIPFS(uri)
|
||||
const response = await fetch(proxyUri);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
function startOwnedPolling() {
|
||||
if (ownedPollInterval) clearInterval(ownedPollInterval);
|
||||
ownedPollInterval = setInterval(async () => {
|
||||
if (appState.state === STATES.OWNED || appState.state === STATES.MINTED) {
|
||||
const balance = Number(await nftContract.balanceOf(appState.address));
|
||||
const totalMinted = await nftContract.totalSupply();
|
||||
if (balance === 0) {
|
||||
appState.hasToken = false;
|
||||
appState.state = STATES.NO_NFT;
|
||||
appState.openedTraits.clear(); // Optional: Reset owned traits
|
||||
await checkCanMint();
|
||||
await loadNext();
|
||||
renderNftApp();
|
||||
startNextPolling();
|
||||
} else if (appState.totalMinted != totalMinted) {
|
||||
appState.totalMinted = totalMinted;
|
||||
renderNftApp();
|
||||
}
|
||||
} else {
|
||||
clearInterval(ownedPollInterval);
|
||||
ownedPollInterval = null;
|
||||
}
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
function startNextPolling() {
|
||||
if (nextPollInterval) clearInterval(nextPollInterval);
|
||||
if (ownedPollInterval) clearInterval(ownedPollInterval);
|
||||
ownedPollInterval = null;
|
||||
nextPollInterval = setInterval(async () => {
|
||||
if (appState.state === STATES.NO_NFT) {
|
||||
await checkCanMint();
|
||||
await loadNext();
|
||||
renderNftApp();
|
||||
} else {
|
||||
clearInterval(nextPollInterval);
|
||||
nextPollInterval = null;
|
||||
}
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
async function mintNft() {
|
||||
if (!appState.canMint) return;
|
||||
appState.error = null;
|
||||
appState.state = STATES.MINTING;
|
||||
renderNftApp();
|
||||
try {
|
||||
const tx = await minterContract.mint();
|
||||
await tx.wait();
|
||||
mintPollInterval = setInterval(async () => {
|
||||
try {
|
||||
const balance = Number(await nftContract.balanceOf(appState.address));
|
||||
if (balance > 0) {
|
||||
clearInterval(mintPollInterval);
|
||||
mintPollInterval = null;
|
||||
appState.hasToken = true;
|
||||
appState.tokenId = Number(await nftContract.tokenOfOwnerByIndex(appState.address, 0));
|
||||
const uri = await nftContract.tokenURI(appState.tokenId);
|
||||
appState.totalMinted = await nftContract.totalSupply();
|
||||
appState.metadata = await loadMetadata(uri);
|
||||
appState.error = null;
|
||||
appState.state = STATES.MINTED;
|
||||
renderNftApp();
|
||||
startOwnedPolling();
|
||||
}
|
||||
} catch (error) {
|
||||
// TODO show error
|
||||
console.error('Polling error:', error);
|
||||
}
|
||||
}, 5000);
|
||||
} catch (error) {
|
||||
handleError(error, mintNft);
|
||||
appState.state = STATES.NO_NFT;
|
||||
renderNftApp();
|
||||
}
|
||||
}
|
||||
|
||||
function handleError(error, retryFunc) {
|
||||
console.error(error);
|
||||
appState.error = error.reason || error.message || 'An unknown error occurred';
|
||||
appState.lastRetry = retryFunc;
|
||||
renderNftApp();
|
||||
}
|
||||
|
||||
function renderNftApp() {
|
||||
const title = document.getElementById('nft-app-title');
|
||||
title.innerText = appState.metadata?.name ?? appState.name
|
||||
|
||||
const content = document.getElementById('nft-app-content');
|
||||
content.innerHTML = '';
|
||||
|
||||
if (appState.address) {
|
||||
const ellipsisAddr = appState.address.slice(0, 6) + '...' + appState.address.slice(-4);
|
||||
content.innerHTML += `<div class="account-info"><span>Account: ${ellipsisAddr}</span><a id="switchAccount" class="switch-link">Change</a></div>`;
|
||||
setTimeout(() => document.getElementById('switchAccount').onclick = switchAccount, 0);
|
||||
}
|
||||
|
||||
switch (appState.state) {
|
||||
case STATES.NOT_CONNECTED:
|
||||
if (window.ethereum) {
|
||||
content.innerHTML += `<div style="text-align: center; margin-top: 20px;">
|
||||
<p class="mb-5"><img src="/img/design_3/simplex_nft_smpx.jpg" width="200" style="display: inline; border-radius: 10px;"></p>
|
||||
<button class="btn btn-primary" id="connect">Connect Wallet</button>
|
||||
<p>${currentConfig.name}</p>
|
||||
</div>`;
|
||||
setTimeout(() => document.getElementById('connect').onclick = connectWallet, 0);
|
||||
} else {
|
||||
content.innerHTML += `<p class="no-metamask"><img src="/img/design_3/simplex_nft_smpx.jpg"></p>
|
||||
<p class="no-metamask">
|
||||
<a href="https://metamask.io/download/" target="_blank">Install MetaMask wallet</a>
|
||||
</p>`;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATES.LOADING:
|
||||
content.innerHTML += `<div style="display: flex; justify-content: center; align-items: center; margin: 0 auto;">
|
||||
<p>Connecting...</p>
|
||||
<div class="spinner" style="margin-left: 10px;"></div>
|
||||
</div>`;
|
||||
break;
|
||||
|
||||
case STATES.MINTED:
|
||||
case STATES.OWNED:
|
||||
const meta = appState.metadata;
|
||||
let html = `<div class="nft-display">`;
|
||||
if (meta) {
|
||||
title.innerText = `Your ${meta.name}`;
|
||||
if (meta.image) {
|
||||
html += `<div id="nft-image-container">
|
||||
<img src="${replaceIPFS(meta.image)}" alt="NFT Image" class="nft-image">
|
||||
<div class="nft-id-overlay">#${appState.tokenId}</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
html += `<div class="metadata">`;
|
||||
html += appState.state == STATES.MINTED
|
||||
? `<p class="congrats">You minted SimpleX NFT #${appState.tokenId}!</p>`
|
||||
: `<p class="congrats">You have SimpleX NFT #${appState.tokenId}</p>`;
|
||||
if (meta) {
|
||||
if (meta.description) html += `<p>${meta.description}</p>`;
|
||||
html += renderAttributes(meta.attributes, appState.openedTraits);
|
||||
html += '<p>';
|
||||
html += `<strong>${appState.totalMinted} NFTs minted</strong>. `;
|
||||
html += `<a href="https://${currentConfig.explorerHost}/nft/${appState.nftAddress}/${appState.tokenId}" target="_blank"><span>Explorer ${linkSvg}</span></a>`;
|
||||
html += '</p>';
|
||||
}
|
||||
html += `</div></div>`;
|
||||
content.innerHTML += html
|
||||
|
||||
content.innerHTML += renderSignupForm();
|
||||
break;
|
||||
|
||||
case STATES.NO_NFT:
|
||||
if (appState.canMint) {
|
||||
title.innerText = `${appState.nextMetadata?.name}`;
|
||||
content.innerHTML += renderNextNFT() + renderMintButton();
|
||||
} else {
|
||||
content.innerHTML += renderNextNFT(false) + renderCannotMint() + renderSignupForm();
|
||||
}
|
||||
break;
|
||||
|
||||
case STATES.MINTING:
|
||||
content.innerHTML += renderNextNFT();
|
||||
content.innerHTML += `<div style="display: flex; justify-content: center; align-items: center; margin: 0 auto;">
|
||||
<p>Minting... Please wait.</p>
|
||||
<div class="spinner" style="margin-left: 10px;"></div>
|
||||
</div>`;
|
||||
break;
|
||||
}
|
||||
if (appState.error) {
|
||||
content.innerHTML += renderError();
|
||||
}
|
||||
}
|
||||
|
||||
const linkSvg = '<svg style="display: inline-block;" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>'
|
||||
|
||||
function renderNextNFT(withAttributes = true) {
|
||||
let html = '';
|
||||
const nextMeta = appState.nextMetadata;
|
||||
if (nextMeta) {
|
||||
html += `<div class="nft-display">`;
|
||||
if (nextMeta.image) {
|
||||
const img = `<img src="${replaceIPFS(nextMeta.image)}" alt="Next NFT Image" class="next-nft-image">`;
|
||||
if (appState.canMint && appState.state == STATES.NO_NFT) {
|
||||
html += `<div id="next-nft-image-container" style="cursor: pointer">
|
||||
${img}
|
||||
<div class="mint-it-overlay">Mint it</div>
|
||||
</div>`;
|
||||
setTimeout(() => document.getElementById('next-nft-image-container').onclick = mintNft, 0);
|
||||
} else {
|
||||
html += `<div id="next-nft-image-container">${img}</div>`;
|
||||
}
|
||||
}
|
||||
html += `<div class="metadata">`;
|
||||
if (nextMeta.description) html += `<p>${nextMeta.description}</p>`;
|
||||
html += '<p>';
|
||||
html += `<strong>${appState.totalMinted} NFTs minted</strong>. `;
|
||||
html += `<a href="https://${currentConfig.explorerHost}/token/${appState.nftAddress}" target="_blank"><span>Explorer ${linkSvg}</span></a>`;
|
||||
html += '</p>';
|
||||
if (withAttributes) {
|
||||
html += renderAttributes(nextMeta.attributes, appState.nextOpenedTraits);
|
||||
}
|
||||
html += `</div></div>`;
|
||||
}
|
||||
return html
|
||||
}
|
||||
|
||||
function renderMintButton() {
|
||||
let html = '<div style="text-align: center; margin-top: 20px;">';
|
||||
html += `<button class="btn btn-primary btn-large" id="mintBtn">Mint SimpleX NFT #${appState.nextId}</button>`;
|
||||
if (appState.mintEndTime > 0) {
|
||||
const endDate = new Date(appState.mintEndTime * 1000).toLocaleString();
|
||||
html += `<p>Until ${endDate}</p>`;
|
||||
}
|
||||
html += '</div>';
|
||||
setTimeout(() => document.getElementById('mintBtn').onclick = mintNft, 0);
|
||||
return html;
|
||||
}
|
||||
|
||||
function renderCannotMint() {
|
||||
let html = '<div style="text-align: center; margin-top: 20px; font-size: 1.5em;">';
|
||||
if (appState.locked) {
|
||||
html += `<p>NFT minting ended.</p>`;
|
||||
} else if (appState.paused) {
|
||||
html += `<p>NFT minting is temporarily paused.</p>`;
|
||||
} else {
|
||||
if (appState.currentTime > appState.mintEndTime && appState.mintEndTime > 0) {
|
||||
const endDate = new Date(appState.mintEndTime * 1000).toLocaleString();
|
||||
html += `<p>Minting ended on ${endDate}.</p>`;
|
||||
} else if (appState.currentTime <= appState.mintStartTime) {
|
||||
const startDate = new Date(appState.mintStartTime * 1000).toLocaleString();
|
||||
html += `<p>Minting will start on ${startDate}.</p>`;
|
||||
}
|
||||
}
|
||||
html += '</div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
function renderAttributes(attributes, openedTraits) {
|
||||
let html = '';
|
||||
if (Array.isArray(attributes)) {
|
||||
attributes.forEach((attr, i) => {
|
||||
if (attr.trait_type && attr.value) {
|
||||
const isOpened = openedTraits.has(String(i));
|
||||
let truncatedValue = attr.value;
|
||||
html += `<p class="trait-line" data-key="${i}">`
|
||||
if (attr.value.length > 41) {
|
||||
truncatedValue = attr.value.slice(0, 41) + '...';
|
||||
html += `<span class="trait-type">${attr.trait_type}: </span>
|
||||
<span class="truncated-value" style="display: ${isOpened ? 'none' : 'inline'};">${truncatedValue}</span>
|
||||
<a href="#" class="more-link" style="display: ${!isOpened ? 'inline' : 'none'};">More</a>
|
||||
<span class="full-value" style="display: ${isOpened ? 'inline' : 'none'};">${attr.value}</span>
|
||||
<a href="#" class="collapse-link" style="display: ${isOpened ? 'inline' : 'none'};">◀</a>`;
|
||||
} else {
|
||||
html += `<span class="trait-type">${attr.trait_type}: </span>
|
||||
<span class="full-value">${attr.value}</span>`;
|
||||
}
|
||||
html += '</p>';
|
||||
}
|
||||
});
|
||||
}
|
||||
setTimeout(() => {
|
||||
document.querySelectorAll('.trait-line').forEach(line => {
|
||||
const key = line.dataset.key;
|
||||
const truncated = line.querySelector('.truncated-value');
|
||||
const more = line.querySelector('.more-link');
|
||||
const full = line.querySelector('.full-value');
|
||||
const collapse = line.querySelector('.collapse-link');
|
||||
if (more) {
|
||||
more.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
truncated.style.display = 'none';
|
||||
more.style.display = 'none';
|
||||
full.style.display = 'inline';
|
||||
collapse.style.display = 'inline';
|
||||
openedTraits.add(key);
|
||||
});
|
||||
}
|
||||
if (collapse) {
|
||||
collapse.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
full.style.display = 'none';
|
||||
collapse.style.display = 'none';
|
||||
truncated.style.display = 'inline';
|
||||
more.style.display = 'inline';
|
||||
openedTraits.delete(key);
|
||||
});
|
||||
}
|
||||
});
|
||||
}, 0);
|
||||
return html;
|
||||
}
|
||||
|
||||
function renderSignupForm() {
|
||||
return `<form class="flex items-center w-full max-w-[540px]" action="https://chat.us2.list-manage.com/subscribe/post?u=ddd892b258ae36e5438e6d4e1&id=ad6037a2fe" method="post" target="_blank" novalidate="" style="margin: 20px auto 0;">
|
||||
<input name="EMAIL" type="text" class="h-[44px] ltr:rounded-l-[34px] rtl:rounded-r-[34px] bg-transparent border border-primary-light dark:border-primary-dark focus:outline-none text-primary-light dark:text-primary-dark text-base w-full max-w-[400px] px-5 placeholder:text-grey-black placeholder:dark:text-white placeholder:text-base placeholder:font-normal placeholder:tracking-[0.01em]" placeholder="Enter email address for updates">
|
||||
<span aria-hidden="true" class="hidden">
|
||||
<input type="text" name="b_ddd892b258ae36e5438e6d4e1_ad6037a2fe" tabindex="-1" value="">
|
||||
</span>
|
||||
<input type="submit" class="h-[44px] ltr:rounded-r-[34px] rtl:rounded-l-[34px] bg-primary-light dark:bg-primary-dark text-white dark:text-black text-center px-8">
|
||||
</form>`;
|
||||
}
|
||||
|
||||
function renderError() {
|
||||
setTimeout(() => document.getElementById('retry_after_error').onclick = async () => {
|
||||
appState.error = null;
|
||||
appState.state = STATES.LOADING; // Or keep current state, but reload data
|
||||
renderNftApp();
|
||||
try {
|
||||
await appState.lastRetry();
|
||||
} catch (error) {
|
||||
handleError(error, appState.lastRetry);
|
||||
}
|
||||
}, 0);
|
||||
return `<div style="text-align: center; margin-top: 20px;">
|
||||
<span class="error">Error: ${appState.error}</span> <a id="retry_after_error">Retry</a>
|
||||
</div>`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svg class="close-overlay-btn" id="cross" width="16" height="16" viewBox="0 0 13 13" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.7973 11.5525L7.59762 6.49833L12.7947 1.44675C13.055 1.19371 13.0658 0.771991 12.8188 0.505331C12.5718 0.238674 12.1602 0.227644 11.8999 0.480681L6.65343 5.58028L1.09979 0.182228C0.839522 -0.070157 0.427909 -0.059127 0.18094 0.207531C-0.0660305 0.474191 -0.0552645 0.895911 0.205003 1.14894L5.70862 6.49833L0.20247 11.851C-0.0577975 12.104 -0.0685635 12.5257 0.178407 12.7924C0.306324 12.9306 0.477936 13 0.650181 13C0.811033 13 0.971873 12.9397 1.09726 12.817L6.65343 7.41639L11.9025 12.5186C12.0285 12.6406 12.1893 12.7015 12.3495 12.7015C12.5218 12.7015 12.6934 12.6321 12.8213 12.4939C13.0689 12.2273 13.0582 11.8062 12.7973 11.5525Z"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "footer.html" %}
|
||||
<script src="/js/prism.min.js"></script>
|
||||
<script src="/js/swiper-bundle.min.js"></script>
|
||||
<script src="/js/script.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+161
-203
@@ -6,199 +6,167 @@
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<header class="">
|
||||
<div class="flex items-center flex-row justify-end m-auto px-4 lg:px-7 h-[66px]">
|
||||
<a href="/{{ '' if lang == 'en' else lang }}" class="h-full hidden dark:hidden lg:flex items-center ltr:mr-auto rtl:ml-auto"><img class="w-auto max-h-[50px] pr-10" src="/img/new/logo-light.png" alt="logo" /></a>
|
||||
<a href="/{{ '' if lang == 'en' else lang }}" class="h-full hidden dark:lg:flex items-center ltr:mr-auto rtl:ml-auto"><img class="w-auto max-h-[50px] pr-10" src="/img/new/logo-dark.png" alt="logo" /></a>
|
||||
<a href="/{{ '' if lang == 'en' else lang }}" class="dark:hidden lg:hidden ltr:mr-auto rtl:ml-auto"><img class="h-[32px]" src="/img/new/logo-symbol-light.svg" alt="" srcset=""></a>
|
||||
<a href="/{{ '' if lang == 'en' else lang }}" class="hidden dark:inline-block dark:lg:hidden lg:hidden ltr:mr-auto rtl:ml-auto"><img class="h-[32px]" src="/img/new/logo-symbol-dark.svg" alt="" srcset=""></a>
|
||||
<header id="navbar">
|
||||
<a href="/{{ '' if lang == 'en' else lang }}" class="logo flex dark:hidden ltr:mr-auto rtl:ml-auto"><img src="/img/new/logo-light.png" alt="logo"></a>
|
||||
<a href="/{{ '' if lang == 'en' else lang }}" class="logo hidden dark:flex ltr:mr-auto rtl:ml-auto"><img src="/img/new/logo-dark.png" alt="logo"></a>
|
||||
|
||||
<nav class="bg-[#F0F1F2] dark:bg-gradient-radial-mobile dark:lg:bg-none lg:bg-transparent fixed top-[66px] left-0 right-0 bottom-0 h-[calc(100vh-66px)] lg:h-[66px] lg:top-0 lg:relative" id="menu">
|
||||
<div class="flex flex-col lg:flex-row justify-between lg:items-center gap-5 xl:gap-10 px-4 lg:px-0 h-full">
|
||||
<ul class="flex flex-col lg:flex-row lg:items-center gap-3 py-4 lg:py-0 lg:gap-5 xl:gap-8">
|
||||
<nav id="menu">
|
||||
<ul>
|
||||
<li class="nav-link {% if active_home %}active{% endif %}">
|
||||
<a href="/{{ '' if lang == 'en' else lang }}">
|
||||
<span class="nav-link-text">{{ "home" | i18n({}, lang ) | safe }}</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-link relative {% if active_home %}active{% endif %}">
|
||||
<a href="/{{ '' if lang == 'en' else lang }}" class="flex items-center justify-between gap-2 lg:py-5 whitespace-nowrap">
|
||||
<span class="text-[16px] leading-[26px] tracking-[0.01em] nav-link-text text-black dark:text-white before:bg-black dark:before:bg-white">{{ "home" | i18n({}, lang ) | safe }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<hr>
|
||||
|
||||
<hr class="dark:opacity-[0.1]" >
|
||||
<li class="nav-link {% if active_directory %}active{% endif %}">
|
||||
<a href="/directory/">
|
||||
<span class="nav-link-text">{{ "directory" | i18n({}, lang ) | safe }}</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-link relative {% if active_directory %}active{% endif %}">
|
||||
<a href="/directory/" class="flex items-center justify-between gap-2 lg:py-5 whitespace-nowrap">
|
||||
<span class="text-[16px] leading-[26px] tracking-[0.01em] nav-link-text text-black dark:text-white before:bg-black dark:before:bg-white">{{ "directory" | i18n({}, lang ) | safe }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<hr>
|
||||
|
||||
<hr class="dark:opacity-[0.1]" >
|
||||
|
||||
<li class="nav-link relative">
|
||||
<a href="javascript:void(0);" class="flex items-center justify-between gap-2 lg:py-5">
|
||||
<span class="text-[16px] leading-[26px] tracking-[0.01em] text-black dark:text-white before:bg-black dark:before:bg-white">{{ "guide" | i18n({}, lang ) | safe }}</span>
|
||||
<span href="" id="btn-mobile" class="flex items-center justify-center h-[36px] w-[36px] lg:h-auto lg:w-auto mt-1">
|
||||
<svg class="fill-black dark:fill-white" width="10" height="6" viewBox="0 0 10 6" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.50447 0.902966C1.21571 0.627397 0.747525 0.627397 0.458761 0.902966C0.169996 1.17853 0.169996 1.62532 0.458761 1.90089L4.21933 5.48961C4.25543 5.52406 4.29433 5.5542 4.33533 5.58003C4.62234 5.76088 5.01237 5.73074 5.26504 5.48961L9.02561 1.90089C9.31438 1.62532 9.31438 1.17853 9.02561 0.902966C8.73685 0.627397 8.26867 0.627397 7.97991 0.902966L4.74219 3.99273L1.50447 0.902966Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<ul class="flex flex-col items-start gap-2 lg:h-fit lg:absolute lg:bg-white dark:lg:bg-black top-full lg:mt-[10px] lg:py-4 min-w-[180px] rounded-md lg:shadow-[0_0_3px_rgb(60_72_88_/_15%)] sub-menu">
|
||||
{% for guide in guide_dropdown.items %}
|
||||
<li><a href="{{ guide.url | url }}" class="{{ "active" if page.url == guide.url | url else '' }} lg:px-[20px] inline-block whitespace-nowrap">{{ guide.title | i18n({}, lang ) | safe }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<hr class="dark:opacity-[0.1]" >
|
||||
|
||||
<li class="nav-link relative">
|
||||
<a href="javascript:void(0);" class="flex items-center justify-between gap-2 lg:py-5">
|
||||
<span class="text-[16px] leading-[26px] tracking-[0.01em] text-black dark:text-white before:bg-black dark:before:bg-white">{{ "reference" | i18n({}, lang ) | safe }}</span>
|
||||
<span href="" id="btn-mobile" class="flex items-center justify-center h-[36px] w-[36px] lg:h-auto lg:w-auto mt-1">
|
||||
<svg class="fill-black dark:fill-white" width="10" height="6" viewBox="0 0 10 6" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.50447 0.902966C1.21571 0.627397 0.747525 0.627397 0.458761 0.902966C0.169996 1.17853 0.169996 1.62532 0.458761 1.90089L4.21933 5.48961C4.25543 5.52406 4.29433 5.5542 4.33533 5.58003C4.62234 5.76088 5.01237 5.73074 5.26504 5.48961L9.02561 1.90089C9.31438 1.62532 9.31438 1.17853 9.02561 0.902966C8.73685 0.627397 8.26867 0.627397 7.97991 0.902966L4.74219 3.99273L1.50447 0.902966Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<ul class="flex flex-col items-start gap-2 lg:h-fit lg:absolute lg:bg-white dark:lg:bg-black top-full lg:mt-[10px] lg:py-4 min-w-[180px] rounded-md lg:shadow-[0_0_3px_rgb(60_72_88_/_15%)] sub-menu">
|
||||
<li><a href="https://github.com/simplex-chat/simplexmq/blob/stable/protocol/overview-tjr.md"
|
||||
target="_blank" class="lg:px-[20px] flex items-center gap-1"
|
||||
>Whitepaper
|
||||
<svg class="float-right" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a></li>
|
||||
<li><a href="/privacy" class="lg:px-[20px] inline-block"
|
||||
>{{ "terms-and-privacy-policy" | i18n({}, lang ) | safe }}</a></li>
|
||||
<li><a href="https://github.com/simplex-chat/simplexmq/blob/stable/protocol/simplex-messaging.md"
|
||||
target="_blank" class="lg:px-[20px] flex items-center gap-1"
|
||||
>{{ "smp-protocol" | i18n({}, lang ) | safe }}
|
||||
<svg class="float-right" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a></li>
|
||||
<li><a href="/docs/protocol/simplex-chat.html" class="lg:px-[20px] inline-block"
|
||||
>{{ "chat-protocol" | i18n({}, lang ) | safe }}</a></li>
|
||||
<li><a href="/docs/glossary.html" class="lg:px-[20px] inline-block"
|
||||
>{{ "glossary" | i18n({}, lang ) | safe }}</a></li>
|
||||
|
||||
<hr class=" h-[1px] w-full dark:opacity-[0.1]">
|
||||
|
||||
{% for doc in docs_dropdown.items %}
|
||||
<li><a href="{{ doc.url | url }}" class="{{ "active" if page.url == doc.url | url else '' }} lg:px-[20px] inline-block whitespace-nowrap">{{ doc.title | i18n({}, lang ) | safe }}</a></li>
|
||||
{% endfor %}
|
||||
|
||||
<hr class=" h-[1px] w-full dark:opacity-[0.1]">
|
||||
|
||||
<li><a href="/docs/translations.html"
|
||||
class="lg:px-[20px] flex items-center gap-1"
|
||||
>{{ "docs-dropdown-7" | i18n({}, lang ) | safe }}
|
||||
</a></li>
|
||||
<li><a href="/docs/android.html"
|
||||
class="lg:px-[20px] flex items-center gap-1"
|
||||
>{{ "docs-dropdown-2" | i18n({}, lang ) | safe }}
|
||||
</a></li>
|
||||
<li><a href="https://github.com/simplex-chat/simplex-chat/blob/stable/apps/simplex-bot-advanced/Main.hs"
|
||||
target="_blank" class="lg:px-[20px] flex items-center gap-1"
|
||||
>{{ "chat-bot-example" | i18n({}, lang ) | safe }}
|
||||
<svg class="float-right" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a></li>
|
||||
<li><a href="https://github.com/simplex-chat/simplex-chat/tree/stable/packages/simplex-chat-client/typescript"
|
||||
target="_blank" class="lg:px-[20px] flex items-center gap-1"
|
||||
>TypeScript SDK
|
||||
<svg class="float-right" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a></li>
|
||||
<li><a href="/docs/cli.html" class="lg:px-[20px] inline-block"
|
||||
>{{ "terminal-cli" | i18n({}, lang ) | safe }}</a></li>
|
||||
<li><a href="https://github.com/simplex-chat/simplexmq"
|
||||
target="_blank" class="lg:px-[20px] flex items-center gap-1"
|
||||
>SimpleXMQ
|
||||
<svg class="float-right" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<hr class="dark:opacity-[0.1]" >
|
||||
|
||||
<li class="nav-link relative {% if active_blog %}active{% endif %}">
|
||||
<a href="/blog" class="flex items-center justify-between gap-2 lg:py-5">
|
||||
<span class="text-[16px] leading-[26px] tracking-[0.01em] nav-link-text text-black dark:text-white before:bg-black dark:before:bg-white">{{ "blog" | i18n({}, lang ) | safe }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<a href="https://github.com/simplex-chat/simplex-chat#please-support-us-with-your-donations"
|
||||
target="_blank" class="whitespace-nowrap flex items-center gap-1 self-center text-white dark:text-black text-[16px] font-medium tracking-[0.02em] rounded-[34px] bg-primary-light dark:bg-primary-dark py-3 lg:py-2 px-20 lg:px-5 mb-auto lg:mb-0"
|
||||
>{{ "donate" | i18n({}, lang ) | safe }}
|
||||
<li class="nav-link">
|
||||
<a href="javascript:void(0);">
|
||||
<span class="">{{ "guide" | i18n({}, lang ) | safe }}</span>
|
||||
<span href="" id="btn-mobile">
|
||||
<svg viewBox="0 0 10 6" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.50447 0.902966C1.21571 0.627397 0.747525 0.627397 0.458761 0.902966C0.169996 1.17853 0.169996 1.62532 0.458761 1.90089L4.21933 5.48961C4.25543 5.52406 4.29433 5.5542 4.33533 5.58003C4.62234 5.76088 5.01237 5.73074 5.26504 5.48961L9.02561 1.90089C9.31438 1.62532 9.31438 1.17853 9.02561 0.902966C8.73685 0.627397 8.26867 0.627397 7.97991 0.902966L4.74219 3.99273L1.50447 0.902966Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<div class="inline-block dark:hidden self-center mt-[8px]">
|
||||
<a class="github-button" href="https://github.com/simplex-chat/simplex-chat" data-size="large"
|
||||
data-show-count="true" aria-label="Star simplex-chat on GitHub">Star</a>
|
||||
</div>
|
||||
<ul class="sub-menu">
|
||||
{% for guide in guide_dropdown.items %}
|
||||
<li><a href="{{ guide.url | url }}" class="{{ "active" if page.url == guide.url | url else '' }}">{{ guide.title | i18n({}, lang ) | safe }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<div class="hidden dark:inline-block self-center mt-[8px]">
|
||||
<a class="github-button" href="https://github.com/simplex-chat/simplex-chat" data-size="large"
|
||||
data-color-scheme="no-preference: dark; light: dark; dark: dark;"
|
||||
data-show-count="true" aria-label="Star simplex-chat on GitHub">Star</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<hr>
|
||||
|
||||
{% if ('blog' not in page.url) and ('jobs' not in page.url) and ('about' not in page.url) and ('privacy' not in page.url) and ('directory' not in page.url) %}
|
||||
<div class="nav-link relative flag-container">
|
||||
<a href="javascript:void(0);" class="flex items-center justify-end ltr:ml-8 ltr:lg:ml-5 ltr:xl:ml-10 rtl:mr-8 rtl:lg:mr-5 rtl:xl:mr-10 h-6 w-8 whitespace-nowrap">
|
||||
<li class="nav-link">
|
||||
<a href="javascript:void(0);">
|
||||
<span class="">{{ "reference" | i18n({}, lang ) | safe }}</span>
|
||||
<span href="" id="btn-mobile">
|
||||
<svg viewBox="0 0 10 6" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.50447 0.902966C1.21571 0.627397 0.747525 0.627397 0.458761 0.902966C0.169996 1.17853 0.169996 1.62532 0.458761 1.90089L4.21933 5.48961C4.25543 5.52406 4.29433 5.5542 4.33533 5.58003C4.62234 5.76088 5.01237 5.73074 5.26504 5.48961L9.02561 1.90089C9.31438 1.62532 9.31438 1.17853 9.02561 0.902966C8.73685 0.627397 8.26867 0.627397 7.97991 0.902966L4.74219 3.99273L1.50447 0.902966Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<ul class="sub-menu">
|
||||
<li><a href="https://github.com/simplex-chat/simplexmq/blob/stable/protocol/overview-tjr.md"
|
||||
target="_blank">Whitepaper
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a></li>
|
||||
<li><a href="/privacy">{{ "terms-and-privacy-policy" | i18n({}, lang ) | safe }}</a></li>
|
||||
<li><a href="https://github.com/simplex-chat/simplexmq/blob/stable/protocol/simplex-messaging.md"
|
||||
target="_blank">{{ "smp-protocol" | i18n({}, lang ) | safe }}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a></li>
|
||||
<li><a href="/docs/protocol/simplex-chat.html">{{ "chat-protocol" | i18n({}, lang ) | safe }}</a></li>
|
||||
<li><a href="/docs/glossary.html">{{ "glossary" | i18n({}, lang ) | safe }}</a></li>
|
||||
|
||||
<hr>
|
||||
|
||||
{% for doc in docs_dropdown.items %}
|
||||
<li><a href="{{ doc.url | url }}" class="{{ "active" if page.url == doc.url | url else '' }} lg:px-[20px] inline-block whitespace-nowrap">{{ doc.title | i18n({}, lang ) | safe }}</a></li>
|
||||
{% endfor %}
|
||||
|
||||
<hr>
|
||||
|
||||
<li><a href="/docs/translations.html"
|
||||
>{{ "docs-dropdown-7" | i18n({}, lang ) | safe }}
|
||||
</a></li>
|
||||
<li><a href="/docs/android.html"
|
||||
>{{ "docs-dropdown-2" | i18n({}, lang ) | safe }}
|
||||
</a></li>
|
||||
<li><a href="https://github.com/simplex-chat/simplex-chat/blob/stable/apps/simplex-bot-advanced/Main.hs"
|
||||
target="_blank">{{ "chat-bot-example" | i18n({}, lang ) | safe }}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a></li>
|
||||
<li><a href="https://github.com/simplex-chat/simplex-chat/tree/stable/packages/simplex-chat-client/typescript"
|
||||
target="_blank">TypeScript SDK
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a></li>
|
||||
<li><a href="/docs/cli.html">{{ "terminal-cli" | i18n({}, lang ) | safe }}</a></li>
|
||||
<li><a href="https://github.com/simplex-chat/simplexmq"
|
||||
target="_blank">SimpleXMQ
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<hr>
|
||||
|
||||
<li class="nav-link {% if active_blog %}active{% endif %}">
|
||||
<a href="/blog">
|
||||
<span class="nav-link-text">{{ "blog" | i18n({}, lang ) | safe }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<div class="right-links">
|
||||
{% if ('old' not in page.url) %}
|
||||
<a class="box-btn token md:hidden" href="/token">
|
||||
{{ 'navbar-token' | i18n({}, lang) }}
|
||||
</a>
|
||||
{% endif %}
|
||||
<button href="#" class="theme-switch-btn">
|
||||
<svg class="sun" width="469" height="469" viewBox="0 0 469 469" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M225.768 1.44594C220.301 3.84594 214.701 10.6459 213.768 15.9793C213.234 18.3793 213.101 31.7126 213.368 45.7126L213.768 71.1793L217.634 76.1126C226.701 88.1126 242.968 87.5793 252.301 75.0459C254.968 71.5793 255.101 69.5793 255.101 42.2459C255.101 14.9126 254.968 12.9126 252.301 9.44594C250.834 7.44594 248.034 4.51261 246.168 3.17928C241.768 -0.154057 231.101 -1.08739 225.768 1.44594Z"/>
|
||||
<path d="M72.9687 65.3128C63.7687 71.5794 60.1687 81.4461 63.7687 91.1794C65.502 95.4461 98.702 129.446 104.035 132.379C106.035 133.446 110.569 134.246 114.035 134.246C126.035 134.246 134.435 125.846 134.435 113.846C134.435 110.379 133.635 105.846 132.569 103.846C129.635 98.5128 95.6353 65.3128 91.3687 63.5794C85.102 61.3128 77.902 61.9794 72.9687 65.3128Z"/>
|
||||
<path d="M377.102 63.7128C373.102 65.3128 338.969 98.7794 336.302 103.846C335.236 105.846 334.436 110.379 334.436 113.846C334.436 125.846 342.836 134.246 354.836 134.246C358.302 134.246 362.836 133.446 364.836 132.379C370.169 129.446 403.369 95.4461 405.102 91.1794C408.702 81.4461 405.102 71.5794 395.902 65.3128C391.102 61.9794 383.102 61.3128 377.102 63.7128Z"/>
|
||||
<path d="M211.635 108.246C185.635 113.179 163.502 125.046 144.302 144.112C117.902 170.512 104.968 203.579 106.835 240.246C109.768 297.712 149.102 344.912 205.902 359.179C218.568 362.379 250.302 362.379 262.968 359.179C310.435 347.312 345.768 312.646 358.702 265.046C362.435 251.446 362.835 219.446 359.368 205.712C347.368 158.112 312.302 122.379 265.235 110.112C251.768 106.512 225.502 105.579 211.635 108.246Z"/>
|
||||
<path d="M12.4349 214.779C-0.498477 220.379 -4.09848 237.579 5.23486 248.246C11.2349 255.046 15.6349 255.846 45.3682 255.313C74.0349 254.913 75.1015 254.646 81.6349 245.713C85.9015 239.979 85.5015 228.113 80.8349 221.979C74.4349 213.713 71.2349 212.913 42.1682 212.913C23.7682 213.046 15.2349 213.579 12.4349 214.779Z"/>
|
||||
<path d="M396.035 215.179C393.635 216.379 390.035 219.445 388.035 221.979C383.368 228.112 382.968 239.979 387.235 245.712C394.035 254.779 394.301 254.912 426.435 254.912C458.568 254.912 458.835 254.779 465.635 245.712C469.501 240.512 469.501 227.979 465.635 222.779C458.968 213.845 458.301 213.579 428.035 213.179C404.435 212.912 399.768 213.179 396.035 215.179Z"/>
|
||||
<path d="M103.101 336.779C96.7013 340.779 65.368 373.179 63.768 377.313C57.368 394.513 74.168 411.313 91.368 404.913C95.6347 403.179 129.635 369.979 132.568 364.646C135.368 359.446 134.968 349.046 131.768 343.846C126.168 334.646 112.035 331.179 103.101 336.779Z"/>
|
||||
<path d="M344.035 336.912C341.635 338.379 338.569 341.445 337.102 343.845C333.902 349.045 333.502 359.445 336.302 364.645C339.235 369.979 373.235 403.179 377.502 404.912C387.235 408.512 397.102 404.912 403.369 395.712C406.702 390.779 407.369 383.579 405.102 377.312C403.369 373.045 370.169 339.045 364.835 336.112C359.635 333.312 349.235 333.712 344.035 336.912Z"/>
|
||||
<path d="M225.368 385.712C222.968 387.046 219.368 390.112 217.368 392.646L213.768 397.312V426.379C213.768 458.246 213.901 458.779 222.968 465.446C228.168 469.312 240.701 469.312 245.901 465.446C254.834 458.779 255.101 457.979 255.501 428.246C256.034 397.579 255.234 394.379 246.834 387.979C241.101 383.579 231.634 382.512 225.368 385.712Z"/>
|
||||
</svg>
|
||||
|
||||
<svg class="moon" width="469" height="469" viewBox="5 5 20 23" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.895 7.574c0 7.55 5.179 13.67 11.567 13.67 1.588 0 3.101-0.38 4.479-1.063-1.695 4.46-5.996 7.636-11.051 7.636-6.533 0-11.83-5.297-11.83-11.83 0-4.82 2.888-8.959 7.023-10.803-0.116 0.778-0.188 1.573-0.188 2.39z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{% if ('blog' not in page.url) and ('about' not in page.url) and ('privacy' not in page.url) and ('directory' not in page.url) and ('token' not in page.url) %}
|
||||
<div class="nav-link flag-container">
|
||||
<a href="javascript:void(0);">
|
||||
{% for language in languages.languages %}
|
||||
{% if language.label == page.url | getlang %}
|
||||
{% if language.flag %}
|
||||
<img src="{{ language.flag }}" alt="" srcset="">
|
||||
{% else %}
|
||||
<div class="flex items-center justify-center" style="background-color:{{ language.iconBg }}; color:{{ language.textColor }}; width:32px; height:24px">
|
||||
<p style="text-align:center; font-size:9px">{{ language.iconText }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
<p style="text-align:center;">{{ language.label }}</p>
|
||||
<svg viewBox="0 0 10 6" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.50447 0.902966C1.21571 0.627397 0.747525 0.627397 0.458761 0.902966C0.169996 1.17853 0.169996 1.62532 0.458761 1.90089L4.21933 5.48961C4.25543 5.52406 4.29433 5.5542 4.33533 5.58003C4.62234 5.76088 5.01237 5.73074 5.26504 5.48961L9.02561 1.90089C9.31438 1.62532 9.31438 1.17853 9.02561 0.902966C8.73685 0.627397 8.26867 0.627397 7.97991 0.902966L4.74219 3.99273L1.50447 0.902966Z"/>
|
||||
</svg>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</a>
|
||||
|
||||
<ul class="flex flex-col items-start gap-2 h-fit absolute top-11 -left-10 bg-white dark:bg-black mt-[10px] py-4 min-w-[170px] rounded-md shadow-[0_0_3px_rgb(60_72_88_/_15%)] sub-menu overflow-auto">
|
||||
{% if ("docs" in page.url) or ('downloads' in page.url) %}
|
||||
<ul class="sub-menu">
|
||||
{% if ("docs" in page.url) or ('downloads' in page.url) or ('security' in page.url) or ('transparency' in page.url) or ('jobs' in page.url) or ('faq' in page.url) %}
|
||||
{% for supportedLang in supportedLangsForDoc %}
|
||||
{% for language in languages.languages %}
|
||||
{% if language.label == supportedLang %}
|
||||
<li>
|
||||
{% if language.flag %}
|
||||
<a href="{% completeRoute {url:page.url,lang:language.label} %}" class="px-[20px] flex items-center gap-4 flag-anchor whitespace-nowrap">
|
||||
<img class="h-4" src="{{ language.flag }}" alt="" srcset="">
|
||||
<p>{{ language.name }}</p>
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{% completeRoute {url:page.url,lang:language.label} %}" class="px-[20px] flex items-center gap-4 flag-anchor whitespace-nowrap">
|
||||
<div class="flex items-center justify-center" style="background-color:{{ language.iconBg }}; color:{{ language.textColor }}; width:21.33px; height:16px">
|
||||
<p style="text-align:center; font-size:7px">{{ language.iconText }}</p>
|
||||
</div>
|
||||
<p>{{ language.name }}</p>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{% completeRoute {url: page.url, lang: language.label} %}" class="flag-anchor">
|
||||
<p>{{ language.name }}</p>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% for language in languages.languages %}
|
||||
{% if language.enabled %}
|
||||
{% if language.enabled and (language.home or (page.url != '/' and page.url != '/' + lang + '/')) %}
|
||||
<li>
|
||||
{% if language.flag %}
|
||||
<a href="{% completeRoute {url:page.url,lang:language.label} %}" class="px-[20px] flex items-center gap-4 flag-anchor whitespace-nowrap">
|
||||
<img class="h-4" src="{{ language.flag }}" alt="" srcset="">
|
||||
<p>{{ language.name }}</p>
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{% completeRoute {url:page.url,lang:language.label} %}" class="px-[20px] flex items-center gap-4 flag-anchor whitespace-nowrap">
|
||||
<div class="flex items-center justify-center" style="background-color:{{ language.iconBg }}; color:{{ language.textColor }}; width:21.33px; height:16px">
|
||||
<p style="text-align:center; font-size:7px">{{ language.iconText }}</p>
|
||||
</div>
|
||||
<p>{{ language.name }}</p>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{% completeRoute {url: page.url, lang: language.label} %}" class="flag-anchor">
|
||||
<p>{{ language.name }}</p>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
@@ -207,22 +175,28 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<button href="#" class="flex items-center justify-center h-[36px] w-[36px] ltr:ml-8 ltr:lg:ml-4 ltr:xl:ml-8 rtl:mr-8 rtl:lg:mr-4 rtl:xl:mr-8 theme-switch-btn">
|
||||
<img src="/img/new/sun.svg" alt="" srcset="" class="sun">
|
||||
<img src="/img/new/moon.svg" alt="" srcset="" class="moon">
|
||||
</button>
|
||||
|
||||
<button href="" id="btn-mobile" class="flex lg:hidden items-center justify-center h-[36px] w-[36px] ltr:ml-8 ltr:lg:ml-5 ltr:xl:ml-10 rtl:mr-8 rtl:lg:mr-5 rtl:xl:mr-10 nav-toggle-btn">
|
||||
<img src="/img/new/hamburger.svg" id="hamburger" alt="" srcset="">
|
||||
<svg class="fill-black dark:fill-white hidden" id="cross" width="13" height="13" viewBox="0 0 13 13" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.7973 11.5525L7.59762 6.49833L12.7947 1.44675C13.055 1.19371 13.0658 0.771991 12.8188 0.505331C12.5718 0.238674 12.1602 0.227644 11.8999 0.480681L6.65343 5.58028L1.09979 0.182228C0.839522 -0.070157 0.427909 -0.059127 0.18094 0.207531C-0.0660305 0.474191 -0.0552645 0.895911 0.205003 1.14894L5.70862 6.49833L0.20247 11.851C-0.0577975 12.104 -0.0685635 12.5257 0.178407 12.7924C0.306324 12.9306 0.477936 13 0.650181 13C0.811033 13 0.971873 12.9397 1.09726 12.817L6.65343 7.41639L11.9025 12.5186C12.0285 12.6406 12.1893 12.7015 12.3495 12.7015C12.5218 12.7015 12.6934 12.6321 12.8213 12.4939C13.0689 12.2273 13.0582 11.8062 12.7973 11.5525Z" />
|
||||
</svg>
|
||||
<button id="cross-btn" class="nav-toggle-btn">
|
||||
<svg id="cross" viewBox="0 0 13 13" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.7973 11.5525L7.59762 6.49833L12.7947 1.44675C13.055 1.19371 13.0658 0.771991 12.8188 0.505331C12.5718 0.238674 12.1602 0.227644 11.8999 0.480681L6.65343 5.58028L1.09979 0.182228C0.839522 -0.070157 0.427909 -0.059127 0.18094 0.207531C-0.0660305 0.474191 -0.0552645 0.895911 0.205003 1.14894L5.70862 6.49833L0.20247 11.851C-0.0577975 12.104 -0.0685635 12.5257 0.178407 12.7924C0.306324 12.9306 0.477936 13 0.650181 13C0.811033 13 0.971873 12.9397 1.09726 12.817L6.65343 7.41639L11.9025 12.5186C12.0285 12.6406 12.1893 12.7015 12.3495 12.7015C12.5218 12.7015 12.6934 12.6321 12.8213 12.4939C13.0689 12.2273 13.0582 11.8062 12.7973 11.5525Z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobile-header">
|
||||
<a href="/{{ '' if lang == 'en' else lang }}" class="logo flex dark:hidden ltr:mr-auto rtl:ml-auto"><img src="/img/new/logo-symbol-light.svg" alt="" srcset=""></a>
|
||||
<a href="/{{ '' if lang == 'en' else lang }}" class="logo hidden dark:flex ltr:mr-auto rtl:ml-auto"><img src="/img/new/logo-symbol-dark.svg" alt="" srcset=""></a>
|
||||
|
||||
<button id="hamburger" class="nav-toggle-btn">
|
||||
<svg viewBox="0 0 100 80" width="36" height="36">
|
||||
<rect width="100" height="15"></rect>
|
||||
<rect y="30" width="100" height="15"></rect>
|
||||
<rect y="60" width="100" height="15"></rect>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<SCript>
|
||||
<script>
|
||||
// switch theme
|
||||
const sunIcon = document.querySelector('.sun');
|
||||
const moonIcon = document.querySelector('.moon');
|
||||
@@ -251,6 +225,7 @@ const themeCheck = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
themeCheck();
|
||||
|
||||
const themeSwitch = () => {
|
||||
if(document.documentElement.classList.contains('dark')){
|
||||
@@ -271,7 +246,8 @@ const themeSwitch = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const nav = document.querySelector('header nav');
|
||||
const nav = document.querySelector('header#navbar');
|
||||
|
||||
window.addEventListener('click',(e)=>{
|
||||
if(e.target.closest('.nav-link')){
|
||||
if(e.target.closest('.nav-link').classList.contains('active')){
|
||||
@@ -283,37 +259,19 @@ window.addEventListener('click',(e)=>{
|
||||
}
|
||||
}
|
||||
else if(e.target.closest('.nav-toggle-btn')){
|
||||
document.body.classList.toggle('lock-scroll');
|
||||
if(nav.classList.contains('open')){
|
||||
nav.classList.remove('open');
|
||||
document.getElementById('hamburger').classList.remove('hidden');
|
||||
document.getElementById('cross').classList.add('hidden');
|
||||
document.getElementById('mobile-header').classList.remove('nav-open');
|
||||
document.documentElement.classList.remove('lock-scroll');
|
||||
}
|
||||
else{
|
||||
document.documentElement.classList.add('lock-scroll');
|
||||
document.getElementById('mobile-header').classList.add('nav-open');
|
||||
nav.classList.add('open');
|
||||
document.getElementById('hamburger').classList.add('hidden');
|
||||
document.getElementById('cross').classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
else if(e.target.closest('.theme-switch-btn')){
|
||||
themeSwitch();
|
||||
}
|
||||
})
|
||||
|
||||
themeCheck();
|
||||
|
||||
const changeHeaderBg = ()=>{
|
||||
const header = document.querySelector('header')
|
||||
const scrollValue = window.scrollY
|
||||
if(scrollValue > 5){
|
||||
header.classList.add('bg-primary-bg-light');
|
||||
header.classList.add('dark:bg-primary-bg-dark');
|
||||
}
|
||||
else{
|
||||
header.classList.remove('bg-primary-bg-light');
|
||||
header.classList.remove('dark:bg-primary-bg-dark');
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('scroll',changeHeaderBg);
|
||||
</SCript>
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,21 @@
|
||||
# The World's Most Secure Messaging
|
||||
|
||||
<img src="/img/design_3/secure_messaging_light.jpg" width="33%" class="float-to-right dark:hidden">
|
||||
|
||||
<img src="/img/design_3/secure_messaging_dark.jpg" width="33%" class="float-to-right hidden dark:block">
|
||||
|
||||
**Ultimate security**: SimpleX network uses the most secure end-to-end encryption, with continuous post-quantum key exchange to protect all messages and metadata.
|
||||
|
||||
**Unique privacy**: SimpleX network has no user profile IDs, not even random numbers or keys. It provides better privacy of your contacts, protecting who you talk with from network servers.
|
||||
|
||||
**No spam**: nobody can contact you unless you share 1-time link or long-term address.
|
||||
|
||||
**Data ownership**: only your device stores your profiles, contacts and messages. You can securely move your data to another device. Servers store encrypted messages only while your device is offline.
|
||||
|
||||
**Secure decentralization**: you control which servers to connect to. For security 4 different servers are used in each chat — they can't observe which IP addresses talk to each other.
|
||||
|
||||
#### How to connect to others
|
||||
|
||||
- Tap new chat button in the corner, then create 1-time link.
|
||||
- Share the link with your contact via any other messenger or email - it is secure.
|
||||
- Ask your contact to use the link in the app - click it after the app is installed or paste into the search field in the app.
|
||||
@@ -11,7 +11,7 @@
|
||||
}
|
||||
.dark .tab-button{
|
||||
color: #fff;
|
||||
background: linear-gradient(#0C0B13, #0C0B13) padding-box,
|
||||
background: linear-gradient(#000832, #000832) padding-box,
|
||||
linear-gradient(to bottom, #01F1FF, transparent) border-box;
|
||||
}
|
||||
.tab-button.active {
|
||||
@@ -127,7 +127,7 @@ window.addEventListener("load", function () {
|
||||
targetFrame = 0;
|
||||
animateToTarget();
|
||||
}
|
||||
}else if(index === 1){
|
||||
}else if(index === 1){
|
||||
if (currentFrame !== 35) {
|
||||
targetFrame = 35;
|
||||
animateToTarget();
|
||||
@@ -144,7 +144,7 @@ window.addEventListener("load", function () {
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const targetNode = document.querySelector(".simplex-explained-swiper .swiper-pagination");
|
||||
observer.observe(targetNode, { attributes: true });
|
||||
|
||||
@@ -41,14 +41,14 @@ active_blog: true
|
||||
|
||||
<section class="py-10 px-5 mt-[66px]" id="blog-list">
|
||||
<div class="container">
|
||||
<h1 class="text-[38px] text-center font-bold text-active-blue mb-9">Latest news</h1>
|
||||
<h1 class="text-[38px] text-center font-bold mb-9">Latest news</h1>
|
||||
|
||||
{% for blog in collections.blogs %}
|
||||
{% if not(blog.data.draft) %}
|
||||
<article
|
||||
class="w-full flex flex-col items-start md:flex-row rounded-[4px] overflow-hidden shadow-[0px_20px_30px_rgba(0,0,0,0.12)] dark:shadow-none bg-white dark:bg-[#11182F] mb-8">
|
||||
class="w-full flex flex-col items-start md:flex-row rounded-[4px] overflow-hidden shadow-[0px_20px_30px_rgba(0,0,0,0.12)] dark:shadow-none bg-white dark:bg-[#0B2A59] mb-8">
|
||||
<div
|
||||
class="min-h-[200px] h-[inherit] self-stretch md:w-[168px] bg-[#D9E7ED] dark:bg-[#17203D] flex items-center justify-center flex-[1] relative">
|
||||
class="min-h-[200px] h-[inherit] self-stretch md:w-[168px] bg-[#DBEEFF] dark:bg-[#071C46] flex items-center justify-center flex-[1] relative">
|
||||
<div class="min-h-[inherit] h-full w-full flex items-end px-4 pt-4 justify-center relative">
|
||||
{% if blog.data.image %}
|
||||
{% if blog.data.imageBottom %}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
h1,
|
||||
#article h1 {
|
||||
font-size: 38px;
|
||||
font-weight: 700;
|
||||
@@ -19,9 +20,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.dark h1,
|
||||
.dark #article h1 {
|
||||
background: -webkit-linear-gradient(to bottom, #70F0F9 100%, #70F0F9 100%);
|
||||
background: linear-gradient(to bottom, #70F0F9 100%, #70F0F9 100%);
|
||||
background: -webkit-linear-gradient(to bottom, #70F0F9 0%, #70F0F9 33%, #50D8F1 100%);
|
||||
background: linear-gradient(to bottom, #70F0F9 0%, #70F0F9 33%, #50D8F1 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
@@ -190,12 +192,12 @@ h3::before {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
#article h1,
|
||||
#article h2,
|
||||
#article h3,
|
||||
#article h4,
|
||||
#article h5,
|
||||
#article h6 {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
@@ -220,7 +222,7 @@ h6 {
|
||||
}
|
||||
|
||||
@media (max-width:768px) {
|
||||
img {
|
||||
#article img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,644 @@
|
||||
:root {
|
||||
--nav-color: #001796;
|
||||
}
|
||||
|
||||
:root.dark {
|
||||
--nav-color: #ffffff;
|
||||
}
|
||||
|
||||
body.change-nav-color {
|
||||
--nav-color: #001796;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 960px) {
|
||||
.logo {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
border-bottom-right-radius: 12px;
|
||||
padding-right: 24px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.dark .logo {
|
||||
background: rgba(19, 29, 73, 0.005);
|
||||
}
|
||||
|
||||
nav#menu {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
padding: 0px 50px;
|
||||
border-bottom-right-radius: 12px;
|
||||
border-bottom-left-radius: 12px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.dark nav#menu {
|
||||
background: rgba(19, 29, 73, 0.005);
|
||||
}
|
||||
|
||||
.right-links {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
border-bottom-left-radius: 12px;
|
||||
padding-left: 24px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.dark .right-links {
|
||||
background: rgba(19, 29, 73, 0.005);
|
||||
}
|
||||
}
|
||||
|
||||
/* NavBar */
|
||||
header#navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 50000;
|
||||
background: none;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 54px;
|
||||
}
|
||||
|
||||
header#navbar>a.logo {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
padding-left: 30px;
|
||||
padding-top: 2px;
|
||||
height: 100%;
|
||||
/* display: flex; */
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
header#navbar>a.logo img {
|
||||
height: 40px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
header#navbar nav#menu>ul>hr {
|
||||
display: none;
|
||||
}
|
||||
|
||||
header#navbar nav#menu ul.sub-menu hr {
|
||||
border-top-width: 1px;
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
color: #000;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.dark header#navbar nav#menu ul.sub-menu hr {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
header#navbar ul {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 60px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1279px) {
|
||||
header#navbar ul {
|
||||
gap: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
header#navbar ul {
|
||||
gap: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
header#navbar ul a {
|
||||
font-family: "Manrope", sans-serif;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
padding: 8px 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 960px) {
|
||||
header#navbar ul .nav-link a,
|
||||
header#navbar ul .nav-link-text {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
header#navbar ul .nav-link .sub-menu a {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.box-btn {
|
||||
height: 36px;
|
||||
padding: 0 11px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 21px !important;
|
||||
font-family: 'Manrope', sans-serif !important;
|
||||
font-weight: 700 !important;
|
||||
letter-spacing: -0.25px !important;
|
||||
border-radius: 6px !important;
|
||||
}
|
||||
|
||||
.box-btn.btn-1 {
|
||||
background-color: #639bd9;
|
||||
}
|
||||
|
||||
.dark .box-btn.btn-1 {
|
||||
background-color: #44547D;
|
||||
}
|
||||
|
||||
.box-btn.token {
|
||||
height: 34px;
|
||||
font-size: 17px !important;
|
||||
font-weight: 500 !important;
|
||||
background: linear-gradient(90deg, #019bfe 0%, #2e3fa0 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.box-btn.gold-gradient,
|
||||
.dark .box-btn.token {
|
||||
background: linear-gradient(90deg,
|
||||
#ffb55d 0%,
|
||||
#fff494 50%,
|
||||
#fbffdd 100%);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.change-nav-color .box-btn.token {
|
||||
background: linear-gradient(90deg, #019bfe 0%, #2e3fa0 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
header#navbar ul a span {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
header#navbar ul a>span:first-child {
|
||||
transform: translateY(-1.5px);
|
||||
}
|
||||
|
||||
header#navbar ul a span svg {
|
||||
fill: #001796;
|
||||
width: 10px;
|
||||
height: auto;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.dark header#navbar ul a span svg {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 960px) {
|
||||
header#navbar nav#menu>ul>li>a {
|
||||
color: var(--nav-color);
|
||||
}
|
||||
|
||||
header#navbar nav#menu>ul>li>a svg {
|
||||
fill: var(--nav-color);
|
||||
}
|
||||
|
||||
header#navbar nav#menu li.nav-link:hover span svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
header#navbar ul.sub-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
gap: 0.5rem;
|
||||
max-height: calc(100vh - 70px);
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
border: solid 1px #f2f2f7;
|
||||
top: calc(100% + 8px);
|
||||
padding: 16px 0;
|
||||
min-width: 180px;
|
||||
border-radius: 8px;
|
||||
transition: all .3s ease !important;
|
||||
overflow: auto;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.dark header#navbar ul.sub-menu {
|
||||
background: #181e43;
|
||||
border: none;
|
||||
}
|
||||
|
||||
header#navbar ul.sub-menu li a {
|
||||
padding: 3px 20px;
|
||||
font-weight: 400;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: #001796;
|
||||
}
|
||||
|
||||
.dark header#navbar ul.sub-menu li a {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
header#navbar ul.sub-menu li a img {
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
header#navbar .nav-link.flag-container ul.sub-menu li a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
header#navbar nav#menu,
|
||||
header#navbar nav#menu>ul {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
header#navbar .nav-link {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
header#navbar .nav-link:hover .sub-menu,
|
||||
header#navbar .nav-link:focus-within .sub-menu {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.flag-container>a {
|
||||
background-color: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
color: #001796;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.dark .flag-container>a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.flag-container>a svg {
|
||||
fill: #001796;
|
||||
width: 10px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.dark .flag-container>a svg {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 960px) {
|
||||
.flag-container>a {
|
||||
color: var(--nav-color) !important;
|
||||
}
|
||||
|
||||
.flag-container>a svg {
|
||||
fill: var(--nav-color) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.flag-container>a p {
|
||||
font-size: 14px;
|
||||
font-family: "Manrope", sans-serif;
|
||||
font-weight: 500;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
line-height: 1rem;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.flag-container .sub-menu a div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.flag-container .sub-menu {
|
||||
top: 100%;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
header#navbar button.theme-switch-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
header#navbar button.theme-switch-btn svg {
|
||||
width: 20px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
header#navbar button.theme-switch-btn svg path {
|
||||
fill: #001796;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.dark header#navbar button.theme-switch-btn svg path {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 960px) {
|
||||
header#navbar button.theme-switch-btn svg path {
|
||||
fill: var(--nav-color) !important;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.right-links {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0px;
|
||||
padding-right: 20px;
|
||||
height: 54px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
button#cross-btn {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#cross {
|
||||
fill: #001796;
|
||||
width: 13px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.dark #cross {
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
||||
#mobile-header {
|
||||
display: none;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
#mobile-header a.logo img {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
#mobile-header button#hamburger {
|
||||
height: 36px;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#mobile-header button#hamburger svg {
|
||||
fill: var(--nav-color) !important;
|
||||
width: 20px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 959px) {
|
||||
#mobile-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 54px;
|
||||
background: transparent;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
z-index: 50000;
|
||||
}
|
||||
|
||||
header#navbar {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: all .3s ease;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.dark header#navbar {
|
||||
background: #0a0f2b;
|
||||
}
|
||||
|
||||
header#navbar.open {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
z-index: 60000;
|
||||
}
|
||||
|
||||
header#navbar>a.logo {
|
||||
height: fit-content;
|
||||
top: 16px;
|
||||
}
|
||||
|
||||
header#navbar>a.logo img {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.right-links {
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
header#navbar ul a span svg {
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
header#navbar nav#menu>ul {
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
header#navbar nav#menu {
|
||||
position: fixed !important;
|
||||
top: 54px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: calc(100% - 54px);
|
||||
overflow: auto;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
header#navbar nav#menu .nav-link {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
header#navbar nav#menu .nav-link a {
|
||||
font-family: "Manrope", "GT-Walsheim", sans-serif;
|
||||
font-weight: 300;
|
||||
font-size: 18px;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
padding: 0px;
|
||||
padding: 6px 2rem;
|
||||
color: #001796;
|
||||
}
|
||||
|
||||
.dark header#navbar nav#menu .nav-link a {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
header#navbar nav#menu .nav-link>a {
|
||||
font-size: 28px;
|
||||
padding: 1rem 2rem;
|
||||
}
|
||||
|
||||
header#navbar nav#menu ul.sub-menu hr {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
header#navbar nav#menu ul.sub-menu hr {
|
||||
margin: 1rem 2rem;
|
||||
width: calc(100% - 4rem);
|
||||
}
|
||||
|
||||
header#navbar nav#menu ul.sub-menu {
|
||||
position: static;
|
||||
}
|
||||
|
||||
header#navbar nav#menu .sub-menu {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transform: translateY(-10px);
|
||||
transition: all .7s ease !important;
|
||||
overflow: hidden;
|
||||
border-radius: 0;
|
||||
background-color: transparent;
|
||||
margin-top: 0;
|
||||
padding: 0rem 1.5rem;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
header#navbar nav#menu .sub-menu li {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
header#navbar nav#menu .sub-menu li a {
|
||||
font-family: "Manrope", "GT-Walsheim", sans-serif;
|
||||
font-weight: 300;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dark header#navbar nav#menu .sub-menu li a {
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
header#navbar nav#menu .active .sub-menu {
|
||||
max-height: 1000px;
|
||||
transform: translateY(0px);
|
||||
padding: 0.5rem 1.5rem;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
button#cross-btn {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
/* underline animation on hover */
|
||||
@media (min-width:950px) {
|
||||
.nav-link-text {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-link-text::before,
|
||||
.active .nav-link-text::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 1px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-color: var(--nav-color);
|
||||
transition: width 0.25s ease-out;
|
||||
}
|
||||
|
||||
.nav-link:hover .nav-link-text::before,
|
||||
.active .nav-link-text::before {
|
||||
width: 100%;
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
}
|
||||
|
||||
#mobile-header.cover {
|
||||
background: #d7fbfe09;
|
||||
}
|
||||
|
||||
.dark #mobile-header.cover {
|
||||
background: #283b630a;
|
||||
}
|
||||
|
||||
#mobile-header.main {
|
||||
background: #ffefd60e;
|
||||
}
|
||||
|
||||
.dark #mobile-header.main {
|
||||
background: #fff6e00a;
|
||||
}
|
||||
|
||||
#mobile-header.nav-open {
|
||||
background: #ffffff0c;
|
||||
}
|
||||
|
||||
.dark #mobile-header.nav-open {
|
||||
background: #0a0f2b0f;
|
||||
}
|
||||
|
||||
#mobile-header.footer {
|
||||
background: #d3e9ff11;
|
||||
}
|
||||
|
||||
.dark #mobile-header.footer {
|
||||
background: #080d250e;
|
||||
--nav-color: #ffffff;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -87,8 +87,8 @@ header {
|
||||
}
|
||||
|
||||
.dark #doc h1 {
|
||||
background: -webkit-linear-gradient(to bottom, #70F0F9 100%, #70F0F9 100%);
|
||||
background: linear-gradient(to bottom, #70F0F9 100%, #70F0F9 100%);
|
||||
background: -webkit-linear-gradient(to bottom, #70F0F9 0%, #70F0F9 33%, #50D8F1 100%);
|
||||
background: linear-gradient(to bottom, #70F0F9 0%, #70F0F9 33%, #50D8F1 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
@@ -235,7 +235,7 @@ header {
|
||||
}
|
||||
|
||||
.dark #doc main aside {
|
||||
background-color: #17203D;
|
||||
background-color: #000832;
|
||||
}
|
||||
|
||||
#doc main aside ul {
|
||||
@@ -305,13 +305,13 @@ header {
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #F3F6F7;
|
||||
background-color: #F3FAFF;
|
||||
opacity: 0.9;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.dark #doc main.overlay::after {
|
||||
background-color: #0C0B13;
|
||||
background-color: #000832;
|
||||
}
|
||||
|
||||
#doc main article {
|
||||
|
||||
+190
-161
@@ -1,3 +1,130 @@
|
||||
/* =======================
|
||||
GT-Walsheim (WOFF2)
|
||||
Family: "GT-Walsheim"
|
||||
Weights mapped: Thin(100), Ultra-Light(200), Light(300), Regular(400),
|
||||
Medium(500), Bold(700), Ultra-Bold(800), Black(900)
|
||||
======================= */
|
||||
|
||||
/* Light */
|
||||
@font-face {
|
||||
font-family: "GT-Walsheim";
|
||||
src: url("/fonts/GT-Walsheim/GT-Walsheim-LC-Light.woff2") format("woff2");
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "GT-Walsheim";
|
||||
src: url("/fonts/GT-Walsheim/GT-Walsheim-LC-Light-Oblique.woff2") format("woff2");
|
||||
font-weight: 300;
|
||||
font-style: oblique;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* Regular */
|
||||
@font-face {
|
||||
font-family: "GT-Walsheim";
|
||||
src: url("/fonts/GT-Walsheim/GT-Walsheim-LC-Regular.woff2") format("woff2");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "GT-Walsheim";
|
||||
src: url("/fonts/GT-Walsheim/GT-Walsheim-LC-Regular-Oblique.woff2") format("woff2");
|
||||
font-weight: 400;
|
||||
font-style: oblique;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* Medium */
|
||||
@font-face {
|
||||
font-family: "GT-Walsheim";
|
||||
src: url("/fonts/GT-Walsheim/GT-Walsheim-LC-Medium.woff2") format("woff2");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "GT-Walsheim";
|
||||
src: url("/fonts/GT-Walsheim/GT-Walsheim-LC-Medium-Oblique.woff2") format("woff2");
|
||||
font-weight: 500;
|
||||
font-style: oblique;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* Bold */
|
||||
@font-face {
|
||||
font-family: "GT-Walsheim";
|
||||
src: url("/fonts/GT-Walsheim/GT-Walsheim-LC-Bold.woff2") format("woff2");
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "GT-Walsheim";
|
||||
src: url("/fonts/GT-Walsheim/GT-Walsheim-LC-Bold-Oblique.woff2") format("woff2");
|
||||
font-weight: 700;
|
||||
font-style: oblique;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* =======================
|
||||
Manrope (TTF)
|
||||
Family: "Manrope"
|
||||
Weights mapped per name
|
||||
======================= */
|
||||
|
||||
@font-face {
|
||||
font-family: "Manrope";
|
||||
src: url("/fonts/Manrope/Manrope-ExtraLight.ttf") format("truetype");
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Manrope";
|
||||
src: url("/fonts/Manrope/Manrope-Light.ttf") format("truetype");
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Manrope";
|
||||
src: url("/fonts/Manrope/Manrope-Regular.ttf") format("truetype");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Manrope";
|
||||
src: url("/fonts/Manrope/Manrope-Medium.ttf") format("truetype");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Manrope";
|
||||
src: url("/fonts/Manrope/Manrope-SemiBold.ttf") format("truetype");
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Manrope";
|
||||
src: url("/fonts/Manrope/Manrope-Bold.ttf") format("truetype");
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Manrope";
|
||||
src: url("/fonts/Manrope/Manrope-ExtraBold.ttf") format("truetype");
|
||||
font-weight: 800;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Gilroy;
|
||||
src: url("/fonts/GilroyRegular/font.woff2") format("woff2"), url("webFonts/GilroyRegular/font.woff") format("woff");
|
||||
@@ -35,7 +162,7 @@
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
font-family: Gilroy, Helvetica, sans-serif;;
|
||||
font-family: GT-Walsheim, Gilroy, Helvetica, sans-serif;;
|
||||
letter-spacing: 0.003em;
|
||||
}
|
||||
|
||||
@@ -137,9 +264,18 @@ a{
|
||||
text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.dark .gradient-text {
|
||||
background: -webkit-linear-gradient(to bottom, #70F0F9 0%, #70F0F9 33%, #50D8F1 100%);
|
||||
background: linear-gradient(to bottom, #70F0F9 0%, #70F0F9 33%, #50D8F1 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.dark .border-gradient {
|
||||
background:
|
||||
linear-gradient(#11182F, #11182F) padding-box,
|
||||
linear-gradient(#0B2A59, #0B2A59) padding-box,
|
||||
linear-gradient(to bottom, transparent, #01F1FF 58%) border-box;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
@@ -158,7 +294,7 @@ a{
|
||||
|
||||
.dark .unique-swiper .border-gradient{
|
||||
background:
|
||||
linear-gradient(#0C0B13, #0C0B13) padding-box,
|
||||
linear-gradient(#000832, #000832) padding-box,
|
||||
linear-gradient(to bottom, transparent, #01F1FF 58%) border-box;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
@@ -177,154 +313,6 @@ a{
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.menu-link{
|
||||
font-size: 16px;
|
||||
line-height: 33.42px;
|
||||
color: #0D0E12;
|
||||
}
|
||||
.dark .menu-link{
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-link ul li a.active{
|
||||
color: #0053D0;
|
||||
|
||||
}
|
||||
.dark .nav-link ul li a.active{
|
||||
color: #66D9E2;
|
||||
}
|
||||
|
||||
@media (min-width:1024px) {
|
||||
.nav-link-text,
|
||||
.menu-link {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
color: #0D0E12;
|
||||
}
|
||||
|
||||
.nav-link-text::before,
|
||||
.active .nav-link-text::before,
|
||||
.menu-link::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 1px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
/* background-color: initial; */
|
||||
transition: width 0.25s ease-out;
|
||||
}
|
||||
|
||||
.menu-link::before {
|
||||
background-color: #0D0E12;
|
||||
}
|
||||
.dark .menu-link::before {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.active .nav-link-text::before {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-link:hover .nav-link-text::before,
|
||||
.menu-link:hover::before {
|
||||
width: 100%;
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.sub-menu {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
color: #505158;
|
||||
}
|
||||
|
||||
.sub-menu .no-hover{
|
||||
color: #505158 !important;
|
||||
}
|
||||
|
||||
.dark .sub-menu,
|
||||
.dark .sub-menu .no-hover {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.dark .sub-menu li:hover {
|
||||
color: #66D9E2;
|
||||
}
|
||||
|
||||
.sub-menu li:hover {
|
||||
color: #0053D0;
|
||||
}
|
||||
|
||||
.sub-menu {
|
||||
transition: all .3s ease !important;
|
||||
}
|
||||
|
||||
.nav-link span svg,
|
||||
header nav {
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.nav-link:hover span svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* @media (max-width: 1400px) {
|
||||
.landing-page-header-article-paragraph {
|
||||
width: 21rem;
|
||||
}
|
||||
|
||||
.socials {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
} */
|
||||
|
||||
@media (min-width:1024px) {
|
||||
|
||||
.nav-link:hover .sub-menu,
|
||||
.nav-link:focus-within .sub-menu {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.sub-menu {
|
||||
max-height: 0;
|
||||
transform: translateY(-10px);
|
||||
transition: all .7s ease !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.active .sub-menu {
|
||||
max-height: 1000px;
|
||||
transform: translateY(0px);
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
header nav {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
header nav.open {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.flag-container .sub-menu{
|
||||
max-height: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
.lock-scroll {
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -496,33 +484,74 @@ header nav {
|
||||
|
||||
|
||||
/* comparison */
|
||||
#comparison table thead th{
|
||||
#comparison table thead th,
|
||||
#messengers-comparison table thead th{
|
||||
font-size: 16px;
|
||||
line-height: 36px;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
}
|
||||
#comparison table tbody td{
|
||||
#comparison table tbody td,
|
||||
#messengers-comparison table tbody td{
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 500;
|
||||
}
|
||||
#comparison table tbody tr > td:first-child{
|
||||
#comparison table tbody tr > td:first-child,
|
||||
#messengers-comparison table tbody tr > td:first-child{
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
[dir="rtl"] #comparison table tbody tr > td:first-child{
|
||||
[dir="rtl"] #comparison table tbody tr > td:first-child,
|
||||
[dir="rtl"] #messengers-comparison table tbody tr > td:first-child{
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
#comparison table tbody tr > td:first-child{
|
||||
#comparison table tbody tr > td:first-child,
|
||||
#messengers-comparison table tbody tr > td:first-child{
|
||||
font-size: 18px;
|
||||
line-height: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#messengers-comparison table td.criteria {
|
||||
min-width: 100px;
|
||||
height: 52px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#messengers-comparison table tbody span.criteria-mark {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
#messengers-comparison table tbody sup {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
#messengers-comparison table tbody span.criteria-mark {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
#messengers-comparison table tbody sup {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
#messengers-comparison table .green-check {
|
||||
color: #1DB100;
|
||||
}
|
||||
|
||||
#messengers-comparison table .yellow-check {
|
||||
color: #FFD932;
|
||||
}
|
||||
|
||||
#messengers-comparison table .red-ballot-x {
|
||||
color: #EE220C;
|
||||
}
|
||||
|
||||
/* hero */
|
||||
@@ -740,7 +769,7 @@ p a{
|
||||
position: fixed;
|
||||
width: 320px;
|
||||
max-width: 100%;
|
||||
z-index: 10001;
|
||||
z-index: 10001;
|
||||
transition: opacity .5s;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
@@ -810,13 +839,13 @@ p a{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color:#F3F6F7;
|
||||
background-color:#F3FAFF;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.dark .glossary-overlay::before {
|
||||
content: '';
|
||||
background-color: #0C0B13;
|
||||
background-color: #000832;
|
||||
}
|
||||
|
||||
.glossary-overlay .overlay-card{
|
||||
@@ -835,7 +864,7 @@ p a{
|
||||
}
|
||||
|
||||
.dark .glossary-overlay .overlay-card{
|
||||
background-color: #17203D;
|
||||
background-color: #071C46;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
|
||||
@@ -9,7 +9,6 @@ active_directory: true
|
||||
{% set lang = page.url | getlang %}
|
||||
{% block js_scripts %}
|
||||
<script src="/js/flag-anchor.js"></script>
|
||||
<script async defer src="/js/directory.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
<style>
|
||||
@@ -149,12 +148,12 @@ active_directory: true
|
||||
}
|
||||
|
||||
.dark .pagination button:hover {
|
||||
background-color: #1f2937;
|
||||
background-color: #0B2A50;
|
||||
}
|
||||
|
||||
.pagination button.active {
|
||||
font-weight: bold;
|
||||
color: #11182F;
|
||||
color: #0B2A59;
|
||||
}
|
||||
|
||||
.dark .pagination button.active {
|
||||
@@ -213,9 +212,9 @@ active_directory: true
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
background-color: #f2f2f7;
|
||||
background-color: white;
|
||||
color: #000000;
|
||||
outline: none;
|
||||
outline: solid 1px #f2f2ff;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZT0iIzg4ODg4OCI+CjxjaXJjbGUgY3g9IjEwLjUiIGN5PSIxMC41IiByPSI3LjUiIC8+CjxsaW5lIHgxPSIxNiIgeTE9IjE2IiB4Mj0iMjEiIHkyPSIyMSIgLz4KPC9nPgo8L3N2Zz4=');
|
||||
background-position: 8px center;
|
||||
@@ -228,9 +227,10 @@ active_directory: true
|
||||
}
|
||||
|
||||
.dark #search {
|
||||
background-color: #1f2937;
|
||||
background-color: #0B2A50;
|
||||
color: #ffffff;
|
||||
background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZT0iI2JiYmJiYiI+CjxjaXJjbGUgY3g9IjEwLjUiIGN5PSIxMC41IiByPSI3LjUiIC8+CjxsaW5lIHgxPSIxNiIgeTE9IjE2IiB4Mj0iMjEiIHkyPSIyMSIgLz4KPC9nPgo8L3N2Zz4=');
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.dark #search::placeholder {
|
||||
@@ -271,4 +271,6 @@ active_directory: true
|
||||
<div id="directory" style="height: 3000px;"></div>
|
||||
<div id="bottom-pagination" class="pagination"></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<script src="/js/directory.js"></script>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
Please note that these fonts are not free open-source and cannot be re-used in other projects.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 301 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 846 KiB |
Loaded 100 of 174 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user