aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-11 13:05:21 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-11 13:05:21 +0200
commitcab9ba28cfba9d90d0a6c4c00dbba852825f66c2 (patch)
tree890ce73f8d9d401b779245b851862721810800f0 /packages/meshbay-hub/src
parente3c68b3416f8ea2c033d41ac263552833370ba18 (diff)
downloadmeshbay-cab9ba28cfba9d90d0a6c4c00dbba852825f66c2.tar.gz
feat(hub): say what MeshBay is on the sign-in page
The browser sign-in page now carries the project's pitch beside the form: what MeshBay is, the applications, what it is for, and what meshbay.org does and never sees, with links to the downloads and the legal pages. Text on the left and the form on the right on a desktop; one column, form first, below 1000px. Not shown in the desktop application, whose user has already downloaded it. All ten catalogues carry the text. Every claim is held to MESHBAY_DESIGN.md 2.3: the page says content never reaches the hub, not that the hub can read nothing (T3), and "end-to-end" means device to node. Signed out there is no sidebar, so the 960px main column sat at the left of the window and the sign-in, register and reset forms were centred in it (x=290 in 1440). `.page-center` pages now lift that cap. test_welcome_layout_measured.py measures the real stylesheet in Chrome: no horizontal overflow from 320 to 1440px, form first on narrow screens, form right of the text on desktops, pair centred in the window. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D9MCBBWSm9GhBESmqzJxNy
Diffstat (limited to 'packages/meshbay-hub/src')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/auth-page.js62
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/de.js24
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/en.js24
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/es.js24
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js24
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/it.js24
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js24
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js24
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js24
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js24
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js24
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/style.css159
12 files changed, 459 insertions, 2 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/auth-page.js b/packages/meshbay-hub/src/meshbay_hub/static/auth-page.js
index 4c00137..9ded87b 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/auth-page.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/auth-page.js
@@ -6,6 +6,7 @@ import {
hubFetch, navigate, session, HUB, loadAuth, _storeRecoveryKey,
} from './hub-client.js';
import * as platform from './platform.js';
+import { Icon } from './icon.js';
const PASSWORD_MIN_BITS = 60;
const PASSWORD_MIN_LEN = 12;
@@ -166,6 +167,7 @@ export function LoginPage({ onLogin }) {
return html`
<div class="page-center">
+ <div class="welcome">
<div class="card login-card">
<h2>${t('login.title')}</h2>
<form onSubmit=${onSubmit}>
@@ -192,10 +194,70 @@ export function LoginPage({ onLogin }) {
<a href="#/reset">${t('login.forgot')}</a>
</div>
</div>
+ ${!platform.isNative && html`<${WelcomePitch} />`}
+ </div>
</div>
`;
}
+// What MeshBay is, beside the sign-in form. Browser only: inside the desktop
+// application the reader has already downloaded it, and the links point at the
+// project's own site rather than at whichever hub the application is set to.
+//
+// Every sentence here is held to MESHBAY_DESIGN.md §2.3. "Data never transits
+// the hub" is a claim the design makes; "the hub cannot read anything" is one it
+// forbids (T3), which is why the list below says what never *reaches* the hub
+// and stops there. "End-to-end" means device to node, as §2.3 defines it.
+const WELCOME_APPS = [
+ ['chat', 'welcome.app_chat'], ['image', 'welcome.app_photos'],
+ ['video', 'welcome.app_media'], ['play', 'welcome.app_video'],
+ ['music', 'welcome.app_music'],
+];
+const WELCOME_USES = [
+ ['chat', 'welcome.use_chat'], ['image', 'welcome.use_photos'],
+ ['cast', 'welcome.use_media'], ['pencil', 'welcome.use_apps'],
+];
+const WELCOME_NEVER = ['welcome.never_transit', 'welcome.never_stored', 'welcome.never_e2e'];
+
+function WelcomePitch() {
+ return html`
+ <section class="welcome-pitch" aria-labelledby="welcome-title">
+ <h1 id="welcome-title" class="welcome-title">${t('welcome.title')}</h1>
+ <p class="welcome-lead">${t('welcome.lead')}</p>
+ <ul class="welcome-apps">
+ ${WELCOME_APPS.map(([icon, key]) => html`
+ <li key=${key}><${Icon} name=${icon} />${t(key)}</li>`)}
+ </ul>
+ <p>${t('welcome.groups')}</p>
+ <p class="welcome-e2e"><${Icon} name="lock" /><span>${t('welcome.e2e')}</span></p>
+
+ <h2 class="welcome-h">${t('welcome.uses_title')}</h2>
+ <ul class="welcome-uses">
+ ${WELCOME_USES.map(([icon, key]) => html`
+ <li key=${key}><span class="welcome-use-icon"><${Icon} name=${icon} /></span>
+ <span>${t(key)}</span></li>`)}
+ </ul>
+
+ <div class="welcome-hub">
+ <h2 class="welcome-h">${t('welcome.hub_title')}</h2>
+ <p>${t('welcome.hub_body')}</p>
+ <p class="welcome-hub-never">${t('welcome.hub_never')}</p>
+ <ul class="welcome-never">
+ ${WELCOME_NEVER.map(key => html`
+ <li key=${key}><${Icon} name="check" /><span>${t(key)}</span></li>`)}
+ </ul>
+ <p class="welcome-hub-free">${t('welcome.hub_free')}</p>
+ </div>
+
+ <div class="welcome-links">
+ <a class="welcome-cta" href="https://meshbay.org/downloads/">
+ <${Icon} name="download" />${t('welcome.download')}</a>
+ <a class="welcome-legal" href="https://meshbay.org/legal/">${t('welcome.legal')}</a>
+ </div>
+ </section>
+ `;
+}
+
export function RegisterPage() {
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
index 9d4aef8..116bbe9 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
@@ -86,6 +86,30 @@ export default {
'register.resend_sent': 'Ein neuer Code wurde gesendet.',
'login.pending_verification': 'Ihre E-Mail-Adresse ist noch nicht bestätigt. Bitte prüfen Sie Ihr Postfach auf den Bestätigungscode.',
'login.verify_link': 'E-Mail bestätigen',
+ // Sign-in page: what MeshBay is (browser only)
+ 'welcome.title': 'Das Internet, wie es gedacht war.',
+ 'welcome.lead': 'MeshBay ist Open-Source-Software, mit der Sie aus der Ferne auf Ihre persönlichen Dateien zugreifen und Anwendungen direkt auf dem Speicher Ihres eigenen Computers betreiben:',
+ 'welcome.app_chat': 'Chat',
+ 'welcome.app_photos': 'Fotos',
+ 'welcome.app_media': 'Mediacenter',
+ 'welcome.app_video': 'Videoplayer',
+ 'welcome.app_music': 'Musikplayer',
+ 'welcome.groups': 'Erstellen Sie Gruppen, um Ihren Liebsten Zugriff auf einige dieser Anwendungen zu geben.',
+ 'welcome.e2e': 'Ihre Daten sind Ende-zu-Ende-verschlüsselt und gehen Peer-to-Peer direkt von jedem Gerät zu dem Computer, auf dem sie liegen (Ihrem Node). Sie laufen niemals über den Hub meshbay.org.',
+ 'welcome.uses_title': 'Was Sie damit tun können',
+ 'welcome.use_chat': 'Sofortnachrichten innerhalb einer Gruppe',
+ 'welcome.use_photos': 'Fotoalben mit Familie und Freunden teilen',
+ 'welcome.use_media': 'Von überall auf Ihr Mediacenter zu Hause zugreifen, für Sie und Ihren Haushalt (mit Streaming und Chromecast über die Desktop-App)',
+ 'welcome.use_apps': 'Eigene Anwendungen auf dem Node entwickeln, den Sie betreiben',
+ 'welcome.hub_title': 'Was meshbay.org tut',
+ 'welcome.hub_body': 'meshbay.org ist lediglich ein Signalisierungsdienst: Er meldet Sie an und verbindet die Beteiligten miteinander (Plug-and-Play, über Heimnetzwerke hinweg).',
+ 'welcome.hub_never': 'Ihre Inhalte erreichen ihn nie:',
+ 'welcome.never_transit': 'Nichts läuft über ihn: keine Inhalte, keine Indexierung',
+ 'welcome.never_stored': 'Keine Ihrer Dateien oder Nachrichten wird dort gespeichert',
+ 'welcome.never_e2e': 'Durchgehende Verschlüsselung, von jedem Gerät bis zu Ihrem Node',
+ 'welcome.hub_free': 'Der Dienst ist kostenlos. Es gibt bewusst kein Geschäftsmodell, kein Tracking und keine Werbung. Viel Spaß!',
+ 'welcome.download': 'Herunterladen (Beta)',
+ 'welcome.legal': 'Rechtliche Hinweise',
'register.err_mismatch': 'Die Passwörter stimmen nicht überein',
'register.err_min_len': {
one: 'Verwenden Sie mindestens {n} Zeichen',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
index 8385caf..80dd819 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
@@ -89,6 +89,30 @@ export default {
'register.resend_sent': 'A new code has been sent.',
'login.pending_verification': 'Your email is not yet verified. Please check your inbox for the verification code.',
'login.verify_link': 'Verify email',
+ // Sign-in page: what MeshBay is (browser only)
+ 'welcome.title': 'The Internet as it was meant to be.',
+ 'welcome.lead': 'MeshBay is open-source software that gives you remote access to your personal files, and runs applications on top of the storage on your own computer:',
+ 'welcome.app_chat': 'Chat',
+ 'welcome.app_photos': 'Photos',
+ 'welcome.app_media': 'Media center',
+ 'welcome.app_video': 'Video player',
+ 'welcome.app_music': 'Music player',
+ 'welcome.groups': 'Create groups to give the people close to you access to some of these applications.',
+ 'welcome.e2e': 'Your data is end-to-end encrypted and travels peer to peer, from each device to the computer that hosts it (your node). It never passes through the meshbay.org hub.',
+ 'welcome.uses_title': 'What you can do with it',
+ 'welcome.use_chat': 'Instant messaging within a group',
+ 'welcome.use_photos': 'Share photo albums with your family and friends',
+ 'welcome.use_media': 'Reach your home media center from anywhere, for the whole household (streaming, plus Chromecast from the desktop app)',
+ 'welcome.use_apps': 'Build your own applications on the node you host',
+ 'welcome.hub_title': 'What meshbay.org does',
+ 'welcome.hub_body': 'meshbay.org is only a signaling service: it signs you in and connects the parties to one another, plug-and-play, across home networks.',
+ 'welcome.hub_never': 'Your content never reaches it:',
+ 'welcome.never_transit': 'Nothing passes through it: no content, no indexing',
+ 'welcome.never_stored': 'None of your files or messages are stored on it',
+ 'welcome.never_e2e': 'Encryption runs end to end, from each device to your node',
+ 'welcome.hub_free': 'The service is free. There is no business model by design, no tracking and no ads. Enjoy!',
+ 'welcome.download': 'Download (beta)',
+ 'welcome.legal': 'Legal information',
'register.err_mismatch': 'Passwords do not match',
'register.err_min_len': {
one: 'Use at least {n} character',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
index cb8f312..9f8b60e 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
@@ -85,6 +85,30 @@ export default {
'register.resend_sent': 'Se ha enviado un nuevo código.',
'login.pending_verification': 'Su correo electrónico aún no ha sido verificado. Revise su bandeja de entrada para obtener el código de verificación.',
'login.verify_link': 'Verificar correo',
+ // Sign-in page: what MeshBay is (browser only)
+ 'welcome.title': 'Internet como debió ser.',
+ 'welcome.lead': 'MeshBay es un software de código abierto que le da acceso remoto a sus archivos personales y ejecuta aplicaciones sobre el almacenamiento de su propio ordenador:',
+ 'welcome.app_chat': 'Chat',
+ 'welcome.app_photos': 'Fotos',
+ 'welcome.app_media': 'Centro multimedia',
+ 'welcome.app_video': 'Reproductor de vídeo',
+ 'welcome.app_music': 'Reproductor de música',
+ 'welcome.groups': 'Cree grupos para dar a sus allegados acceso a algunas de estas aplicaciones.',
+ 'welcome.e2e': 'Sus datos están cifrados de extremo a extremo y viajan entre pares, directamente de cada dispositivo al ordenador que los aloja: su nodo. Nunca pasan por el hub meshbay.org.',
+ 'welcome.uses_title': 'Qué puede hacer con él',
+ 'welcome.use_chat': 'Mensajería instantánea dentro de un grupo',
+ 'welcome.use_photos': 'Compartir álbumes de fotos con su familia y amigos',
+ 'welcome.use_media': 'Acceder desde cualquier lugar a su centro multimedia, para usted y su hogar, con streaming y Chromecast desde la aplicación de escritorio',
+ 'welcome.use_apps': 'Crear sus propias aplicaciones en el nodo que aloja',
+ 'welcome.hub_title': 'Qué hace meshbay.org',
+ 'welcome.hub_body': 'meshbay.org es solo un servicio de señalización: le autentica y conecta a las partes entre sí, sin configuración, a través de redes domésticas.',
+ 'welcome.hub_never': 'Su contenido nunca llega a él:',
+ 'welcome.never_transit': 'Nada pasa por él: ni contenido ni indexación',
+ 'welcome.never_stored': 'Ninguno de sus archivos o mensajes se almacena en él',
+ 'welcome.never_e2e': 'Cifrado de extremo a extremo, de cada dispositivo a su nodo',
+ 'welcome.hub_free': 'El servicio es gratuito. Deliberadamente no hay modelo de negocio, ni rastreo, ni publicidad. ¡Disfrútelo!',
+ 'welcome.download': 'Descargar (beta)',
+ 'welcome.legal': 'Información legal',
'register.err_mismatch': 'Las contraseñas no coinciden',
'register.err_min_len': {
one: 'Use al menos {n} carácter',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
index 608da62..d928f52 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
@@ -85,6 +85,30 @@ export default {
'register.resend_sent': 'Un nouveau code a été envoyé.',
'login.pending_verification': 'Votre e-mail n\'est pas encore vérifié. Consultez votre boîte de réception pour le code de vérification.',
'login.verify_link': 'Vérifier l\'e-mail',
+ // Sign-in page: what MeshBay is (browser only)
+ 'welcome.title': 'L’Internet tel qu’il aurait dû être.',
+ 'welcome.lead': 'MeshBay est un logiciel open source qui vous donne accès à distance à vos fichiers personnels et fait tourner des applications sur le stockage de votre ordinateur :',
+ 'welcome.app_chat': 'Messagerie',
+ 'welcome.app_photos': 'Photos',
+ 'welcome.app_media': 'Médiathèque',
+ 'welcome.app_video': 'Lecteur vidéo',
+ 'welcome.app_music': 'Lecteur de musique',
+ 'welcome.groups': 'Créez des groupes pour donner accès à certaines de ces applications à vos proches.',
+ 'welcome.e2e': 'Vos données sont chiffrées de bout en bout et circulent en pair à pair, de chaque appareil jusqu’à l’ordinateur qui les héberge (votre nœud). Elles ne passent jamais par le hub meshbay.org.',
+ 'welcome.uses_title': 'Ce que vous pouvez en faire',
+ 'welcome.use_chat': 'Messagerie instantanée au sein d’un groupe',
+ 'welcome.use_photos': 'Partager des albums photo avec votre famille et vos amis',
+ 'welcome.use_media': 'Accéder à distance à votre médiathèque personnelle, pour vous et votre foyer (en streaming, et avec Chromecast depuis l’application de bureau)',
+ 'welcome.use_apps': 'Créer vos propres applications sur le nœud que vous hébergez',
+ 'welcome.hub_title': 'Le rôle de meshbay.org',
+ 'welcome.hub_body': 'meshbay.org est un simple service de signalisation : il vous authentifie et met les participants en relation, sans configuration, à travers les réseaux domestiques.',
+ 'welcome.hub_never': 'Vos contenus ne l’atteignent jamais :',
+ 'welcome.never_transit': 'Rien ne transite par lui : aucun contenu, aucune indexation',
+ 'welcome.never_stored': 'Aucun de vos fichiers ou messages n’y est stocké',
+ 'welcome.never_e2e': 'Chiffrement de bout en bout, de chaque appareil jusqu’à votre nœud',
+ 'welcome.hub_free': 'Le service est gratuit : aucun modèle économique (c’est voulu), aucun traçage, aucune publicité. Profitez-en !',
+ 'welcome.download': 'Télécharger (bêta)',
+ 'welcome.legal': 'Informations légales',
'register.err_mismatch': 'Les mots de passe ne correspondent pas',
'register.err_min_len': {
one: 'Utilisez au moins {n} caractère',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
index be5fe29..58e2389 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
@@ -86,6 +86,30 @@ export default {
'register.resend_sent': 'Un nuovo codice è stato inviato.',
'login.pending_verification': 'Il suo indirizzo e-mail non è ancora verificato. Controlli la sua casella di posta per il codice di verifica.',
'login.verify_link': 'Verifica e-mail',
+ // Sign-in page: what MeshBay is (browser only)
+ 'welcome.title': 'Internet come doveva essere.',
+ 'welcome.lead': 'MeshBay è un software open source che le permette di accedere da remoto ai suoi file personali e di usare applicazioni basate sullo spazio di archiviazione del suo computer:',
+ 'welcome.app_chat': 'Chat',
+ 'welcome.app_photos': 'Foto',
+ 'welcome.app_media': 'Media center',
+ 'welcome.app_video': 'Lettore video',
+ 'welcome.app_music': 'Lettore musicale',
+ 'welcome.groups': 'Crei gruppi per dare alle persone a lei care l’accesso ad alcune di queste applicazioni.',
+ 'welcome.e2e': 'I suoi dati sono cifrati end-to-end e viaggiano peer-to-peer, direttamente da ogni dispositivo al computer che li ospita: il suo nodo. Non passano mai dall’hub meshbay.org.',
+ 'welcome.uses_title': 'Cosa può farci',
+ 'welcome.use_chat': 'Messaggistica istantanea all’interno di un gruppo',
+ 'welcome.use_photos': 'Condividere album fotografici con famiglia e amici',
+ 'welcome.use_media': 'Accedere ovunque al media center di casa, per lei e la sua famiglia, con streaming e Chromecast dall’app desktop',
+ 'welcome.use_apps': 'Creare le proprie applicazioni sul nodo che ospita',
+ 'welcome.hub_title': 'Cosa fa meshbay.org',
+ 'welcome.hub_body': 'meshbay.org è solo un servizio di segnalazione: la autentica e mette in contatto le parti, plug-and-play, attraverso le reti domestiche.',
+ 'welcome.hub_never': 'I suoi contenuti non lo raggiungono mai:',
+ 'welcome.never_transit': 'Nulla passa da lì: nessun contenuto, nessuna indicizzazione',
+ 'welcome.never_stored': 'Nessun suo file o messaggio vi è archiviato',
+ 'welcome.never_e2e': 'Crittografia end-to-end, da ogni dispositivo al suo nodo',
+ 'welcome.hub_free': 'Il servizio è gratuito. Nessun modello di business (per scelta), nessun tracciamento, nessuna pubblicità. Buon divertimento!',
+ 'welcome.download': 'Scarica (beta)',
+ 'welcome.legal': 'Note legali',
'register.err_mismatch': 'Le password non coincidono',
'register.err_min_len': {
one: 'Usi almeno {n} carattere',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
index f2d94d9..234b238 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
@@ -86,6 +86,30 @@ export default {
'register.resend_sent': '新しいコードを送信しました。',
'login.pending_verification': 'メールアドレスがまだ確認されていません。受信トレイで確認コードをご確認ください。',
'login.verify_link': 'メールを確認',
+ // Sign-in page: what MeshBay is (browser only)
+ 'welcome.title': '本来あるべき姿のインターネット。',
+ 'welcome.lead': 'MeshBay は、個人のファイルにどこからでもアクセスでき、自分のパソコンのストレージ上でアプリを動かせるオープンソースソフトウェアです。',
+ 'welcome.app_chat': 'チャット',
+ 'welcome.app_photos': '写真',
+ 'welcome.app_media': 'メディアセンター',
+ 'welcome.app_video': '動画プレーヤー',
+ 'welcome.app_music': '音楽プレーヤー',
+ 'welcome.groups': 'グループを作成して、家族や友人に一部のアプリへのアクセスを許可できます。',
+ 'welcome.e2e': 'データはエンドツーエンドで暗号化され、各デバイスからデータを保管するパソコン(あなたのノード)へピアツーピアで直接届きます。meshbay.org のハブを経由することは一切ありません。',
+ 'welcome.uses_title': 'できること',
+ 'welcome.use_chat': 'グループ内でのインスタントメッセージ',
+ 'welcome.use_photos': '家族や友人とのフォトアルバム共有',
+ 'welcome.use_media': '自宅のメディアセンターに外出先からアクセス。ご家族みんなで使え、ストリーミングに対応し、デスクトップアプリからは Chromecast も利用できます',
+ 'welcome.use_apps': 'ホストしているノード上で独自のアプリを開発',
+ 'welcome.hub_title': 'meshbay.org の役割',
+ 'welcome.hub_body': 'meshbay.org はシグナリング専用のサービスです。ログインを処理し、家庭のネットワーク越しに参加者同士を設定不要でつなぎます。',
+ 'welcome.hub_never': 'あなたのコンテンツが届くことはありません:',
+ 'welcome.never_transit': '何も経由しません(コンテンツもインデックスもなし)',
+ 'welcome.never_stored': 'ファイルやメッセージは一切保存されません',
+ 'welcome.never_e2e': '各デバイスからノードまでエンドツーエンドで暗号化',
+ 'welcome.hub_free': 'サービスは無料です。ビジネスモデルは意図的に持たず、トラッキングも広告もありません。どうぞお楽しみください!',
+ 'welcome.download': 'ダウンロード(ベータ版)',
+ 'welcome.legal': '法的情報',
'register.err_mismatch': 'パスワードが一致しません',
'register.err_min_len': {
other: '{n} 文字以上でご入力ください',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
index f7f0775..72511f5 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
@@ -86,6 +86,30 @@ export default {
'register.resend_sent': 'Er is een nieuwe code verzonden.',
'login.pending_verification': 'Uw e-mailadres is nog niet geverifieerd. Controleer uw inbox voor de verificatiecode.',
'login.verify_link': 'E-mail verifiëren',
+ // Sign-in page: what MeshBay is (browser only)
+ 'welcome.title': 'Het internet zoals het bedoeld was.',
+ 'welcome.lead': 'MeshBay is opensourcesoftware waarmee u op afstand bij uw persoonlijke bestanden kunt, en die toepassingen draait bovenop de opslag van uw eigen computer:',
+ 'welcome.app_chat': 'Chat',
+ 'welcome.app_photos': 'Foto’s',
+ 'welcome.app_media': 'Mediacenter',
+ 'welcome.app_video': 'Videospeler',
+ 'welcome.app_music': 'Muziekspeler',
+ 'welcome.groups': 'Maak groepen aan om uw naasten toegang te geven tot een aantal van deze toepassingen.',
+ 'welcome.e2e': 'Uw gegevens zijn end-to-end versleuteld en gaan peer-to-peer, rechtstreeks van elk apparaat naar de computer waarop ze staan: uw node. Ze gaan nooit via de hub meshbay.org.',
+ 'welcome.uses_title': 'Wat u ermee kunt doen',
+ 'welcome.use_chat': 'Chatten binnen een groep',
+ 'welcome.use_photos': 'Fotoalbums delen met familie en vrienden',
+ 'welcome.use_media': 'Overal bij uw mediacenter thuis, voor u en uw huishouden, met streaming en Chromecast via de desktop-app',
+ 'welcome.use_apps': 'Uw eigen toepassingen bouwen op de node die u host',
+ 'welcome.hub_title': 'Wat meshbay.org doet',
+ 'welcome.hub_body': 'meshbay.org is alleen een signaleringsdienst: het meldt u aan en brengt de partijen met elkaar in contact, plug-and-play, over thuisnetwerken heen.',
+ 'welcome.hub_never': 'Uw inhoud komt er nooit terecht:',
+ 'welcome.never_transit': 'Er gaat niets doorheen: geen inhoud, geen indexering',
+ 'welcome.never_stored': 'Geen van uw bestanden of berichten wordt er opgeslagen',
+ 'welcome.never_e2e': 'End-to-end versleuteling, van elk apparaat tot uw node',
+ 'welcome.hub_free': 'De dienst is gratis. Er is bewust geen verdienmodel, geen tracking en geen advertenties. Veel plezier!',
+ 'welcome.download': 'Downloaden (bèta)',
+ 'welcome.legal': 'Juridische informatie',
'register.err_mismatch': 'De wachtwoorden komen niet overeen',
'register.err_min_len': {
one: 'Gebruik minstens {n} teken',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
index 8c50790..12a31aa 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
@@ -89,6 +89,30 @@ export default {
'register.resend_sent': 'Nowy kod został wysłany.',
'login.pending_verification': 'Twój adres e-mail nie został jeszcze zweryfikowany. Sprawdź skrzynkę odbiorczą.',
'login.verify_link': 'Zweryfikuj e-mail',
+ // Sign-in page: what MeshBay is (browser only)
+ 'welcome.title': 'Internet taki, jaki miał być.',
+ 'welcome.lead': 'MeshBay to oprogramowanie open source, które daje zdalny dostęp do Twoich plików osobistych i uruchamia aplikacje korzystające z pamięci Twojego własnego komputera:',
+ 'welcome.app_chat': 'Czat',
+ 'welcome.app_photos': 'Zdjęcia',
+ 'welcome.app_media': 'Centrum multimedialne',
+ 'welcome.app_video': 'Odtwarzacz wideo',
+ 'welcome.app_music': 'Odtwarzacz muzyki',
+ 'welcome.groups': 'Twórz grupy, aby dać bliskim dostęp do wybranych aplikacji.',
+ 'welcome.e2e': 'Twoje dane są szyfrowane end-to-end i przesyłane bezpośrednio (peer-to-peer) z każdego urządzenia do komputera, który je przechowuje (Twojego węzła). Nigdy nie przechodzą przez hub meshbay.org.',
+ 'welcome.uses_title': 'Co możesz z nim robić',
+ 'welcome.use_chat': 'Komunikator w obrębie grupy',
+ 'welcome.use_photos': 'Udostępnianie albumów ze zdjęciami rodzinie i znajomym',
+ 'welcome.use_media': 'Zdalny dostęp do domowego centrum multimedialnego dla Ciebie i domowników (ze streamingiem i Chromecastem w aplikacji desktopowej)',
+ 'welcome.use_apps': 'Tworzenie własnych aplikacji na węźle, który hostujesz',
+ 'welcome.hub_title': 'Czym zajmuje się meshbay.org',
+ 'welcome.hub_body': 'meshbay.org to wyłącznie usługa sygnalizacyjna: uwierzytelnia Cię i łączy uczestników ze sobą, bez konfiguracji, także przez sieci domowe.',
+ 'welcome.hub_never': 'Twoje treści nigdy do niego nie trafiają:',
+ 'welcome.never_transit': 'Nic przez niego nie przechodzi: żadnych treści, żadnego indeksowania',
+ 'welcome.never_stored': 'Żadne Twoje pliki ani wiadomości nie są na nim przechowywane',
+ 'welcome.never_e2e': 'Szyfrowanie end-to-end, od każdego urządzenia do Twojego węzła',
+ 'welcome.hub_free': 'Usługa jest bezpłatna. Celowo nie ma modelu biznesowego, śledzenia ani reklam. Miłego korzystania!',
+ 'welcome.download': 'Pobierz (beta)',
+ 'welcome.legal': 'Informacje prawne',
'register.err_mismatch': 'Hasła nie są zgodne',
'register.err_min_len': {
one: 'Proszę użyć co najmniej {n} znaku',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
index 8f903ba..c5f826b 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
@@ -87,6 +87,30 @@ export default {
'register.resend_sent': 'Um novo código foi enviado.',
'login.pending_verification': 'Seu e-mail ainda não foi verificado. Verifique sua caixa de entrada.',
'login.verify_link': 'Verificar e-mail',
+ // Sign-in page: what MeshBay is (browser only)
+ 'welcome.title': 'A internet como deveria ser.',
+ 'welcome.lead': 'O MeshBay é um software de código aberto que dá acesso remoto aos seus arquivos pessoais e executa aplicativos sobre o armazenamento do seu próprio computador:',
+ 'welcome.app_chat': 'Chat',
+ 'welcome.app_photos': 'Fotos',
+ 'welcome.app_media': 'Central de mídia',
+ 'welcome.app_video': 'Player de vídeo',
+ 'welcome.app_music': 'Player de música',
+ 'welcome.groups': 'Crie grupos para dar às pessoas próximas acesso a alguns desses aplicativos.',
+ 'welcome.e2e': 'Seus dados são criptografados de ponta a ponta e trafegam ponto a ponto, direto de cada dispositivo para o computador que os hospeda: o seu nó. Eles nunca passam pelo hub meshbay.org.',
+ 'welcome.uses_title': 'O que você pode fazer com ele',
+ 'welcome.use_chat': 'Mensagens instantâneas dentro de um grupo',
+ 'welcome.use_photos': 'Compartilhar álbuns de fotos com a família e os amigos',
+ 'welcome.use_media': 'Acessar de qualquer lugar a sua central de mídia, para você e sua casa, com streaming e Chromecast pelo app para desktop',
+ 'welcome.use_apps': 'Criar seus próprios aplicativos no nó que você hospeda',
+ 'welcome.hub_title': 'O que o meshbay.org faz',
+ 'welcome.hub_body': 'O meshbay.org é apenas um serviço de sinalização: ele autentica você e conecta as partes entre si, plug-and-play, através de redes domésticas.',
+ 'welcome.hub_never': 'Seu conteúdo nunca chega até ele:',
+ 'welcome.never_transit': 'Nada passa por ele: nenhum conteúdo, nenhuma indexação',
+ 'welcome.never_stored': 'Nenhum dos seus arquivos ou mensagens fica armazenado nele',
+ 'welcome.never_e2e': 'Criptografia de ponta a ponta, de cada dispositivo até o seu nó',
+ 'welcome.hub_free': 'O serviço é gratuito. Não há modelo de negócio (de propósito), rastreamento nem anúncios. Aproveite!',
+ 'welcome.download': 'Baixar (beta)',
+ 'welcome.legal': 'Informações legais',
'register.err_mismatch': 'As senhas não coincidem',
'register.err_min_len': {
one: 'Use pelo menos {n} caractere',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
index c836de3..e06c5c6 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
@@ -86,6 +86,30 @@ export default {
'register.resend_sent': '新验证码已发送。',
'login.pending_verification': '您的邮箱尚未验证。请查看收件箱中的验证码。',
'login.verify_link': '验证邮箱',
+ // Sign-in page: what MeshBay is (browser only)
+ 'welcome.title': '互联网本该有的样子。',
+ 'welcome.lead': 'MeshBay 是一款开源软件,让您远程访问个人文件,并在您自己电脑的存储之上运行应用:',
+ 'welcome.app_chat': '聊天',
+ 'welcome.app_photos': '照片',
+ 'welcome.app_media': '媒体中心',
+ 'welcome.app_video': '视频播放器',
+ 'welcome.app_music': '音乐播放器',
+ 'welcome.groups': '创建群组,让亲友使用其中部分应用。',
+ 'welcome.e2e': '您的数据经过端到端加密,以点对点方式从每台设备直接传输到存放数据的电脑(也就是您的节点)。数据从不经过 meshbay.org 中心服务器。',
+ 'welcome.uses_title': '您可以用它做什么',
+ 'welcome.use_chat': '群组内即时通讯',
+ 'welcome.use_photos': '与家人朋友分享相册',
+ 'welcome.use_media': '随时随地访问家中的媒体中心,供您和家人使用(支持流媒体播放,桌面应用还支持 Chromecast)',
+ 'welcome.use_apps': '在您托管的节点上开发自己的应用',
+ 'welcome.hub_title': 'meshbay.org 的作用',
+ 'welcome.hub_body': 'meshbay.org 仅是一个信令服务:它负责登录验证,并以即插即用的方式跨家庭网络连接各方。',
+ 'welcome.hub_never': '您的内容永远不会到达这里:',
+ 'welcome.never_transit': '没有任何数据经过它:没有内容,也没有索引',
+ 'welcome.never_stored': '不存储您的任何文件或消息',
+ 'welcome.never_e2e': '从每台设备到您的节点全程端到端加密',
+ 'welcome.hub_free': '本服务免费。我们刻意不设商业模式,没有跟踪,也没有广告。尽情享用吧!',
+ 'welcome.download': '下载(测试版)',
+ 'welcome.legal': '法律信息',
'register.err_mismatch': '两次输入的密码不一致',
'register.err_min_len': {
other: '请至少使用 {n} 个字符',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/style.css b/packages/meshbay-hub/src/meshbay_hub/static/style.css
index d51e5b0..ff6fe57 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/style.css
+++ b/packages/meshbay-hub/src/meshbay_hub/static/style.css
@@ -478,8 +478,11 @@ a:hover { text-decoration: underline; }
exactly that much — 48px, and a scrollbar on sign-in at every window size.
Measured, not deduced: `.page-center` ended at 795 and `main` at 819.
The page brings its own 24px, so dropping main's here changes nothing
- visible and removes the duplicated arithmetic rather than adding more. */
-.main:has(> .page-center) { padding: 0; }
+ visible and removes the duplicated arithmetic rather than adding more.
+ `max-width` goes too: signed out there is no sidebar, so the 960px column sat
+ at the left of the window and a "centred" form was centred in that — at
+ x=290 in a 1440px window. */
+.main:has(> .page-center) { padding: 0; max-width: none; }
/* ── Sticky chrome ────────────────────────────────────────────────────────── */
@@ -631,6 +634,158 @@ a:hover { text-decoration: underline; }
color: var(--text-dim);
}
+/* ── Welcome (sign-in page, browser only) ─────────────────────────────────── */
+
+/* What MeshBay is on the left, the form on the right and level with the
+ title; stacked, form first, once the text would be narrower than the form.
+ The form comes first in the markup (first on a phone, first to the
+ keyboard) and `row-reverse` is what moves it right. Headings are
+ `.welcome-pitch .welcome-h` rather than a bare class so they outrank
+ `.main h2`. */
+.welcome {
+ display: flex;
+ flex-direction: row-reverse;
+ align-items: flex-start;
+ justify-content: center;
+ gap: 96px;
+ width: 100%;
+ max-width: 1180px;
+}
+.welcome > .login-card { flex: 0 0 380px; }
+
+.welcome-pitch {
+ flex: 1 1 0;
+ min-width: 0;
+ max-width: 660px;
+ color: var(--text-secondary);
+ font-size: 0.95rem;
+ line-height: 1.5;
+}
+.welcome-pitch p { margin-bottom: 10px; }
+
+.welcome-apps, .welcome-uses, .welcome-never { list-style: none; }
+
+.welcome-title {
+ margin-bottom: 10px;
+ color: var(--text);
+ font-size: 1.9em;
+ font-weight: 700;
+ line-height: 1.2;
+ letter-spacing: -0.02em;
+ text-wrap: balance;
+}
+.welcome-lead { font-size: 1.05em; }
+
+.welcome-apps { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 14px; }
+.welcome-apps li {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 5px 12px;
+ border: 1px solid var(--border);
+ border-radius: 999px;
+ background: var(--bg-surface);
+ color: var(--text);
+ font-size: 0.88em;
+}
+.welcome-apps .icon { color: var(--accent); }
+
+.welcome-e2e {
+ display: flex;
+ align-items: flex-start;
+ gap: 10px;
+ padding: 8px 14px;
+ border-left: 3px solid var(--accent);
+ border-radius: 0 6px 6px 0;
+ background: var(--accent-bg);
+ color: var(--text);
+}
+.welcome-e2e .icon { margin-top: 0.3em; color: var(--accent); }
+
+.welcome-pitch .welcome-h {
+ margin: 18px 0 8px;
+ color: var(--text-dim);
+ font-size: 0.78em;
+ font-weight: 600;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+}
+
+.welcome-uses { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 18px; }
+.welcome-uses li {
+ display: flex;
+ align-items: flex-start;
+ gap: 10px;
+ color: var(--text);
+ font-size: 0.92em;
+ line-height: 1.45;
+}
+.welcome-use-icon {
+ display: inline-flex;
+ flex: 0 0 auto;
+ align-items: center;
+ justify-content: center;
+ width: 32px;
+ height: 32px;
+ border-radius: 8px;
+ background: var(--accent-bg);
+ color: var(--accent);
+ font-size: 17px;
+}
+
+.welcome-hub {
+ margin-top: 18px;
+ padding: 12px 18px;
+ border: 1px solid var(--border);
+ border-radius: 8px;
+ background: var(--bg-surface);
+ font-size: 0.92em;
+}
+.welcome-pitch .welcome-hub .welcome-h { margin-top: 0; }
+.welcome-pitch .welcome-hub-never { margin-bottom: 6px; color: var(--text); font-weight: 600; }
+.welcome-never { display: flex; flex-direction: column; gap: 4px; color: var(--text); }
+.welcome-never li { display: flex; align-items: flex-start; gap: 8px; }
+.welcome-never .icon { margin-top: 0.3em; color: var(--success); }
+.welcome-pitch .welcome-hub-free {
+ margin: 10px 0 0;
+ padding-top: 8px;
+ border-top: 1px solid var(--border);
+ color: var(--text);
+ font-weight: 500;
+}
+
+.welcome-links {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 12px 20px;
+ margin-top: 14px;
+}
+.welcome-cta {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 10px 18px;
+ border-radius: 6px;
+ background: var(--accent);
+ color: var(--accent-text);
+ font-size: 0.95em;
+ font-weight: 600;
+}
+.welcome-cta:hover { background: var(--accent-hover); text-decoration: none; }
+.welcome-legal { color: var(--text-secondary); font-size: 0.9em; }
+.welcome-legal:hover { color: var(--accent); }
+
+@media (max-width: 1000px) {
+ .welcome { flex-direction: column; align-items: center; gap: 36px; }
+ .welcome > .login-card { flex: none; }
+ .welcome-pitch { flex: none; width: 100%; max-width: 520px; }
+}
+@media (max-width: 520px) {
+ .welcome-title { font-size: 1.6em; }
+ .welcome-uses { grid-template-columns: 1fr; }
+}
+
/* ── Form elements ────────────────────────────────────────────────────────── */
input[type="text"],