new website (#6412)

* website: started new design (#6279)

* upload assets & change font to gt-walsheim

* fix language issue in learn-more page

* design cover for desktop

* website: home page sections (#6285)

* upload assets & change font to gt-walsheim

* fix language issue in learn-more page

* design cover for desktop

* add section 2, 3 & 4 for desktop

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* website: more sections (#6289)

* upload assets & change font to gt-walsheim

* fix language issue in learn-more page

* design cover for desktop

* add section 2, 3 & 4 for desktop

* website: directory page (#6283)

* website: directory page

* core: use markdown in directory entries

* render markdown on directory page

* update markdown

* toggle secrets on click

* update listings asynchronously

* add group links to the listing

* cleanup

* better directory layout with pagination

* script to run website

* update page navigation

* search

* readable markdown colors, better "read less"

* core: atomic update of directory listings, to avoid files unavailable

* fix symlink, sort entries on page with new first

* update listings every 15 min, add activeAt time

* fix sorting in the page and listing url

* replace simplex:/ links on desktop

* website: fix search in directory

* add section 5 for Desktop

* android, desktop: update dependency

* website(directory): add bot address, open simplex links in new tab, improve error handling

* made cover responsive

* directory: show only recent groups in active/new tabs, page improvements (#6290)

* directory: show only recent groups as active or new

* round times

* sorting order

* fix links

* improve

* directory: disable search autocomplete

* directory: show approximate activity/creation time

* scripts: suffix deb packages with distribution codename (#6273)

* directory: show default image in case of loading error (can happen when group is delisted)

* website: add directory to nav bar, fixes (#6293)

* website: add directory to nav bar, fixes

* docs: update readme

* add responsiveness

* add socials

* remove white redundent line

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: sh <37271604+shumvgolove@users.noreply.github.com>

* website: navbar (#6307)

* add navbar for desktop

* website: complete navbar (#6313)

* website: desktop layout for section 2 3 4 5 (#6317)

* desktop layout for section 2 3 4 5

* improve mobile layout

* resolve navbar issues

* delete unwanted svg

* cover layout

* update section 5 for mobile

* section 5 desktop

* website: improve layout & section 6 (#6321)

* improve layout

* add section 6

* website: promoted groups on home page (#6323)

* website: promoted groups on home page

* use local images when fallback listing is used, replace image on download error with group icon

* welcome message

* more links

* rename CSS classes

* website: adding footer (#6326)

* adding footer

* add footer

* update nav

* improve spaces in .group-images

* quick fix

* add community vouchers page

* fix footer problem

* disable pull to refresh

* address bar now hide in safari

* website: fallback group images (#6342)

* website: new things (#6344)

* add learn_more.md section in /learn-more page

* fix cover swiping bug & improve gradient

* fix click bug of group-images

* website: improve layout (#6361)

* website: improve layout

* fix footer for iphone

* add light mode (#6368)

* website: important updates (#6375)

* design improvements for desktop

* design improvements for mobile

* same navbar for all pages

* add comparison table

* update z-index

* quick fix

* add glassy effect to nav

* quick improvement

* favicon

* quick fix

* update nav glassy effect

* quick nav update

* improve mobile layout

* improve mobile layout

* improve mobile layout

* rotate gradients for mobile

* safearea

* almost remove background from nav

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* website: cover updates (#6380)

* remove background from nav

* add publications

* add security btns

* quick fixes

* quick fixes

* add all btns & made them responsive

* add hash & update pages

* Revert "remove background from nav"

This reverts commit ee27d17484.

* fix web.sh

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* website: translation strings (#6384)

* add translation strings for home page

* add translation strings for comparison table

* update strings

* website: update text (#6387)

* website: update text

* website: additional translation strings

* comparison table

* update colors

* update glossary

* website: fix glossary capitalize issue (#6388)

* fix glossary capitalize issue

* fix gradient scroll issue

* fix gradient scroll issue

* website: community vouchers and token (#6389)

* website: community vouchers and token

* website: change translation string

* update name

* website: update translations, fonts, fix language navigation (#6395)

* website: update translations

* website: update fonts, fix language navigation

* website: update texts (#6404)

* website: update texts

* website: update texts

* update the text

* website: update texts

* update

* web: mobile layout / safe area (#6408)

* improve status bar / safe area coloring

* improve status coloring

* website: popup to mint nft (WIP) (#6410)

* website: popup to mint nft (WIP)

* update dApp

* minting works

* update dApp

* update

* update app

* improve

* update network to arbitrum

* update copyright

* website: layout fixes, token button (#6415)

* update images, add note about arbitrum

* update colors

* website: update tokens, switch dApp to Ethereum

---------

Co-authored-by: M. Sarmad Qadeer <MSarmadQadeer@gmail.com>
Co-authored-by: sh <37271604+shumvgolove@users.noreply.github.com>
This commit is contained in:
Evgeny
2025-10-28 22:09:17 +00:00
committed by GitHub
parent f0e54754fe
commit 7a858695bf
142 changed files with 4557 additions and 693 deletions
+1
View File
@@ -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*
+2
View File
@@ -425,6 +425,8 @@ 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.
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://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)
&nbsp;
[![Android app](https://github.com/simplex-chat/.github/blob/master/profile/images/google_play.svg)](https://play.google.com/store/apps/details?id=chat.simplex.app)
+7 -3
View File
@@ -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)
+11 -3
View File
@@ -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
}
+9
View File
@@ -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.
+1 -1
View File
@@ -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": "Политика за поверителност",
+1 -1
View File
@@ -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í",
+1 -1
View File
@@ -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",
+2 -1
View File
@@ -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",
+1 -1
View File
@@ -10,7 +10,7 @@
"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",
"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",
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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é",
+1 -1
View File
@@ -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>מוצפנות מקצה לקצה",
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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": "各メッセージ キューは、異なる送信アドレスと受信アドレスを使用してメッセージを一方向に渡します。",
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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 -1
View File
@@ -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.",
+1 -1
View File
@@ -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ı",
+1 -1
View File
@@ -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": "Приватність переосмислена",
+1 -1
View File
@@ -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>这从根本上改善了您的隐私。",
+1 -1
View File
@@ -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": "它如何在沒有使用者個人檔案識別符的情況下使用單向佇列?",
+1
View File
@@ -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",
+2 -2
View File
@@ -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",
+4
View File
@@ -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"
+19 -6
View File
@@ -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 -1
View File
@@ -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">
+1 -1
View File
@@ -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>
+4 -3
View File
@@ -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"><&nbsp;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>
+5 -6
View File
@@ -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">
+4 -5
View File
@@ -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>
+4 -5
View File
@@ -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>
+3 -2
View File
@@ -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>
+809
View File
@@ -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'};">&#9664;</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&amp;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>&nbsp;&nbsp;<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>
+157 -189
View File
@@ -6,175 +6,157 @@
{% 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">
<a class="box-btn token md:hidden" href="/token">
{{ 'navbar-token' | i18n({}, lang) }}
</a>
<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="">
<a href="{% completeRoute {url:page.url,lang:language.label} %}" class="flag-anchor">
<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>
<a href="{% completeRoute {url:page.url,lang:language.label} %}" class="flag-anchor">
<p>{{ language.name }}</p>
</a>
{% endif %}
@@ -184,18 +166,14 @@
{% 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="">
<a href="{% completeRoute {url:page.url,lang:language.label} %}" class="flag-anchor">
<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>
<a href="{% completeRoute {url:page.url,lang:language.label} %}" class="flag-anchor">
<p>{{ language.name }}</p>
</a>
{% endif %}
@@ -207,22 +185,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 +235,7 @@ const themeCheck = () => {
}
}
}
themeCheck();
const themeSwitch = () => {
if(document.documentElement.classList.contains('dark')){
@@ -271,7 +256,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 +269,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 &mdash; 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.
+3 -3
View File
@@ -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 });
+3 -3
View File
@@ -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 %}
+11 -9
View File
@@ -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%;
}
}
+644
View File
@@ -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
+5 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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>
+1
View File
@@ -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: 300 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 KiB

+11
View File
@@ -0,0 +1,11 @@
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<!-- Checkmark stroke with painted style -->
<path
d="M 35 100 L 42 108 L 50 118 L 58 128 L 68 138 L 75 145 L 80 148 L 85 145 L 95 135 L 110 115 L 125 95 L 140 75 L 155 55 L 165 42 L 170 35"
stroke="#4CAF50" stroke-width="24" stroke-linecap="round" stroke-linejoin="round" fill="none" />
<!-- Darker overlay for depth -->
<path
d="M 35 100 L 42 108 L 50 118 L 58 128 L 68 138 L 75 145 L 80 148 L 85 145 L 95 135 L 110 115 L 125 95 L 140 75 L 155 55 L 165 42 L 170 35"
stroke="#388E3C" stroke-width="20" stroke-linecap="round" stroke-linejoin="round" fill="none" opacity="0.6" />
</svg>

After

Width:  |  Height:  |  Size: 722 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 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: 42 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<!-- First stroke of X -->
<path d="M 40 40 Q 50 45 100 100 Q 150 155 160 160" stroke="#E63946" stroke-width="28" stroke-linecap="round"
stroke-linejoin="round" fill="none" />
<!-- Second stroke of X -->
<path d="M 160 40 Q 150 45 100 100 Q 50 155 40 160" stroke="#E63946" stroke-width="28" stroke-linecap="round"
stroke-linejoin="round" fill="none" />
</svg>

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Some files were not shown because too many files have changed in this diff Show More