diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-08-16 15:29:11 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-08-16 15:29:11 +0200 |
| commit | 84e778d5cdd1bb5cded8a7c0238797c17d48666c (patch) | |
| tree | d26f1d20735ba2db81da812371c92d257179882c /packages/meshbay-hub/src/meshbay_hub/static/locales | |
| parent | 188a76f52d2f30609147b1beee7754f2cbd1e778 (diff) | |
| download | meshbay-84e778d5cdd1bb5cded8a7c0238797c17d48666c.tar.gz | |
feat(hub): chat, presence, a Profile page, and downloads that do not freeze
Chat opens on the newest hundred messages, loads fifty older on demand with the
reading position anchored — the distance from the *bottom*, since everything
above the viewport just grew — and follows new messages only when the reader was
already at the end. Day separators, sender grouping, an unread marker, and a
jump-to-latest pill. Messages are keyed by id: index keys plus prepending makes
Preact reuse the wrong bubbles.
A presence dot per group in the sidebar, three states, each backed by something:
the hub's registry, or a connection this browser made or failed to make. Never
colour alone — red and green are the pair colour-blind readers cannot separate —
so each dot carries a title and an aria-label.
Profile is split out of Settings: identity, node link, pinned node identities and
account deletion. Mixing them put an irreversible button two scrolls under a
theme picker. The create-group page loses its centred 520 px card, which left
190 px of margin either side, and its two button panels become a radio group —
a button conveys no chosen state to a screen reader, and side by side they read
as two independent actions rather than one either/or.
The Files toolbar shows its actions as icon buttons the moment Select is on,
disabled when they do not apply rather than appearing and vanishing. On a phone
the right-hand group could not wrap and ran 130 px off the screen.
Streamed downloads no longer freeze after one chunk. `registration.active` says
a worker exists, not that this page is controlled by it — and an uncontrolled
page's requests never reach its fetch handler, so the worker took the stream and
was never asked for it, leaving `writer.write()` waiting on backpressure that
would never lift. The page now requires control and the worker confirms it
actually served the request before the sink is trusted.
Fixed on the way: `setActionsOpen` outlived the state it belonged to and threw
on every Files action; the chat scrollbar stopped short of the bottom; the
owner's row sat lower than the rest; About showed a version hardcoded two
releases ago.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/locales')
10 files changed, 170 insertions, 0 deletions
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 1ff4687..f045243 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js @@ -404,4 +404,21 @@ export default { other: '{n} Dateien gefunden', }, 'search.hint': 'Durchsucht Dateinamen in allen zwischengespeicherten Gruppenindexen.', + + // Presence, chat paging, leaving a group, the profile page + 'presence.online': 'Ein Node, der diese Gruppe hostet, ist online', + 'presence.offline': 'Kein Node für diese Gruppe erreichbar', + 'presence.unknown': 'Noch nicht geprüft', + 'chat.load_older': '{n} ältere Nachrichten laden', + 'chat.start_of_history': 'Anfang des Gesprächs', + 'chat.today': 'Heute', + 'chat.yesterday': 'Gestern', + 'chat.unread': 'Neue Nachrichten', + 'chat.jump_latest': 'Zu den neuesten springen', + 'chat.jump_new': 'Neue Nachrichten', + 'group.leave': 'Gruppe verlassen', + 'group.leave_confirm': '„{name}“ verlassen? Sie verlieren den Zugang zu ihren Dateien und zum Chat. Hochgeladene Dateien bleiben auf dem Node, und der Node behält die für Sie gemerkte Identität, bis sein Betreiber sie entfernt.', + 'profile.title': 'Profil', + 'usermenu.profile': 'Profil', + 'create_group.public_is_open': 'Eine öffentliche Gruppe kann jeder finden und ihr beitreten. Wenn Sie auswählen möchten, wer hereinkommt, erstellen Sie sie privat.', }; 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 0e4427d..25c1f6c 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js @@ -389,4 +389,21 @@ export default { other: '{n} files found', }, 'search.hint': 'Search file names across all cached group indexes.', + + // Presence, chat paging, leaving a group, the profile page + 'presence.online': 'A node serving this group is online', + 'presence.offline': 'No node is reachable for this group', + 'presence.unknown': 'Not checked yet', + 'chat.load_older': 'Load {n} older messages', + 'chat.start_of_history': 'Beginning of the conversation', + 'chat.today': 'Today', + 'chat.yesterday': 'Yesterday', + 'chat.unread': 'New messages', + 'chat.jump_latest': 'Jump to latest', + 'chat.jump_new': 'New messages', + 'group.leave': 'Leave group', + 'group.leave_confirm': 'Leave “{name}”? You will lose access to its files and chat. Files you uploaded stay on the node, and the node keeps the identity it pinned for you until its operator removes it.', + 'profile.title': 'Profile', + 'usermenu.profile': 'Profile', + 'create_group.public_is_open': 'Anyone can find and join a public group. To choose who comes in, make it private.', }; 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 c09175b..0799ec5 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js @@ -399,4 +399,21 @@ export default { other: '{n} archivos encontrados', }, 'search.hint': 'Busca nombres de archivo en todos los índices de grupo en caché.', + + // Presence, chat paging, leaving a group, the profile page + 'presence.online': 'Un node que sirve este grupo está en línea', + 'presence.offline': 'Ningún node accesible para este grupo', + 'presence.unknown': 'Aún sin comprobar', + 'chat.load_older': 'Cargar {n} mensajes anteriores', + 'chat.start_of_history': 'Inicio de la conversación', + 'chat.today': 'Hoy', + 'chat.yesterday': 'Ayer', + 'chat.unread': 'Mensajes nuevos', + 'chat.jump_latest': 'Ir a lo más reciente', + 'chat.jump_new': 'Mensajes nuevos', + 'group.leave': 'Salir del grupo', + 'group.leave_confirm': '¿Salir de «{name}»? Perderá el acceso a sus archivos y a su chat. Los archivos que subió permanecen en el node, y este conserva la identidad que fijó para usted hasta que su operador la retire.', + 'profile.title': 'Perfil', + 'usermenu.profile': 'Perfil', + 'create_group.public_is_open': 'Cualquiera puede encontrar un grupo público y unirse a él. Para elegir quién entra, créelo privado.', }; 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 845e7ce..32d0461 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js @@ -404,4 +404,21 @@ export default { other: '{n} fichiers trouvés', }, 'search.hint': 'Recherche les noms de fichiers dans tous les index de groupe en cache.', + + // Presence, chat paging, leaving a group, the profile page + 'presence.online': 'Un node servant ce groupe est en ligne', + 'presence.offline': 'Aucun node joignable pour ce groupe', + 'presence.unknown': 'Pas encore vérifié', + 'chat.load_older': 'Charger {n} messages plus anciens', + 'chat.start_of_history': 'Début de la conversation', + 'chat.today': 'Aujourd’hui', + 'chat.yesterday': 'Hier', + 'chat.unread': 'Nouveaux messages', + 'chat.jump_latest': 'Aller au plus récent', + 'chat.jump_new': 'Nouveaux messages', + 'group.leave': 'Quitter le groupe', + 'group.leave_confirm': 'Quitter « {name} » ? Vous perdrez l’accès à ses fichiers et à sa discussion. Les fichiers que vous avez envoyés restent sur le node, et celui-ci conserve l’identité qu’il a épinglée pour vous jusqu’à ce que son opérateur la retire.', + 'profile.title': 'Profil', + 'usermenu.profile': 'Profil', + 'create_group.public_is_open': 'N’importe qui peut trouver un groupe public et le rejoindre. Pour choisir qui entre, créez-le en privé.', }; 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 e3c92ef..32d7922 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js @@ -401,4 +401,21 @@ export default { other: '{n} file trovati', }, 'search.hint': 'Cerca i nomi dei file in tutti gli indici di gruppo in cache.', + + // Presence, chat paging, leaving a group, the profile page + 'presence.online': 'Un node che ospita questo gruppo è online', + 'presence.offline': 'Nessun node raggiungibile per questo gruppo', + 'presence.unknown': 'Non ancora verificato', + 'chat.load_older': 'Carica {n} messaggi precedenti', + 'chat.start_of_history': 'Inizio della conversazione', + 'chat.today': 'Oggi', + 'chat.yesterday': 'Ieri', + 'chat.unread': 'Nuovi messaggi', + 'chat.jump_latest': 'Vai ai più recenti', + 'chat.jump_new': 'Nuovi messaggi', + 'group.leave': 'Esci dal gruppo', + 'group.leave_confirm': 'Uscire da «{name}»? Perderà l’accesso ai suoi file e alla chat. I file che ha caricato restano sul node, e il node mantiene l’identità che ha fissato per lei finché il suo operatore non la rimuove.', + 'profile.title': 'Profilo', + 'usermenu.profile': 'Profilo', + 'create_group.public_is_open': 'Chiunque può trovare un gruppo pubblico e parteciparvi. Per scegliere chi entra, lo crei privato.', }; 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 f9fd5ac..0adc51c 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js @@ -390,4 +390,21 @@ export default { other: '{n} 個のファイルが見つかりました', }, 'search.hint': 'キャッシュされたすべてのグループインデックスからファイル名を検索します。', + + // Presence, chat paging, leaving a group, the profile page + 'presence.online': 'このグループをホストする node が稼働中です', + 'presence.offline': 'このグループに到達できる node がありません', + 'presence.unknown': '未確認', + 'chat.load_older': '以前のメッセージを {n} 件読み込む', + 'chat.start_of_history': '会話のはじまり', + 'chat.today': '今日', + 'chat.yesterday': '昨日', + 'chat.unread': '新しいメッセージ', + 'chat.jump_latest': '最新へ移動', + 'chat.jump_new': '新しいメッセージ', + 'group.leave': 'グループを退出', + 'group.leave_confirm': '「{name}」を退出しますか?ファイルとチャットへのアクセスがなくなります。アップロードしたファイルは node に残り、node は固定した識別情報を運営者が削除するまで保持します。', + 'profile.title': 'プロフィール', + 'usermenu.profile': 'プロフィール', + 'create_group.public_is_open': '公開グループは誰でも見つけて参加できます。参加者を選びたい場合は、非公開で作成してください。', }; 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 2f778b3..947724f 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js @@ -403,4 +403,21 @@ export default { other: '{n} bestanden gevonden', }, 'search.hint': 'Zoekt bestandsnamen in alle groepsindexen in de cache.', + + // Presence, chat paging, leaving a group, the profile page + 'presence.online': 'Een node die deze groep host is online', + 'presence.offline': 'Geen node bereikbaar voor deze groep', + 'presence.unknown': 'Nog niet gecontroleerd', + 'chat.load_older': '{n} oudere berichten laden', + 'chat.start_of_history': 'Begin van het gesprek', + 'chat.today': 'Vandaag', + 'chat.yesterday': 'Gisteren', + 'chat.unread': 'Nieuwe berichten', + 'chat.jump_latest': 'Naar de nieuwste', + 'chat.jump_new': 'Nieuwe berichten', + 'group.leave': 'Groep verlaten', + 'group.leave_confirm': '„{name}” verlaten? U verliest de toegang tot de bestanden en de chat ervan. Bestanden die u hebt geüpload blijven op de node, en de node houdt de voor u vastgezette identiteit tot zijn beheerder die weghaalt.', + 'profile.title': 'Profiel', + 'usermenu.profile': 'Profiel', + 'create_group.public_is_open': 'Iedereen kan een openbare groep vinden en eraan deelnemen. Wilt u kiezen wie binnenkomt, maak de groep dan privé.', }; 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 d77a160..687b93b 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js @@ -416,4 +416,21 @@ export default { other: 'Znaleziono {n} pliku', }, 'search.hint': 'Przeszukuje nazwy plików we wszystkich zbuforowanych indeksach grup.', + + // Presence, chat paging, leaving a group, the profile page + 'presence.online': 'Node hostujący tę grupę jest dostępny', + 'presence.offline': 'Brak osiągalnego node dla tej grupy', + 'presence.unknown': 'Jeszcze nie sprawdzono', + 'chat.load_older': 'Wczytaj {n} starszych wiadomości', + 'chat.start_of_history': 'Początek rozmowy', + 'chat.today': 'Dziś', + 'chat.yesterday': 'Wczoraj', + 'chat.unread': 'Nowe wiadomości', + 'chat.jump_latest': 'Przejdź do najnowszych', + 'chat.jump_new': 'Nowe wiadomości', + 'group.leave': 'Opuść grupę', + 'group.leave_confirm': 'Opuścić grupę „{name}”? Utraci Pan(i) dostęp do jej plików i czatu. Wysłane pliki pozostaną na node, a node zachowa przypiętą dla Pana/Pani tożsamość do czasu, aż jego operator ją usunie.', + 'profile.title': 'Profil', + 'usermenu.profile': 'Profil', + 'create_group.public_is_open': 'Grupę publiczną każdy może znaleźć i do niej dołączyć. Aby decydować, kto wchodzi, proszę utworzyć grupę prywatną.', }; 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 9d00ece..56bfbdd 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 @@ -400,4 +400,21 @@ export default { other: '{n} arquivos encontrados', }, 'search.hint': 'Pesquisa nomes de arquivo em todos os índices de grupo em cache.', + + // Presence, chat paging, leaving a group, the profile page + 'presence.online': 'Um node que hospeda este grupo está on-line', + 'presence.offline': 'Nenhum node acessível para este grupo', + 'presence.unknown': 'Ainda não verificado', + 'chat.load_older': 'Carregar {n} mensagens anteriores', + 'chat.start_of_history': 'Início da conversa', + 'chat.today': 'Hoje', + 'chat.yesterday': 'Ontem', + 'chat.unread': 'Mensagens novas', + 'chat.jump_latest': 'Ir para a mais recente', + 'chat.jump_new': 'Mensagens novas', + 'group.leave': 'Sair do grupo', + 'group.leave_confirm': 'Sair de “{name}”? Você perderá o acesso aos arquivos e à conversa. Os arquivos que você enviou permanecem no node, e ele mantém a identidade que fixou para você até que o operador dele a remova.', + 'profile.title': 'Perfil', + 'usermenu.profile': 'Perfil', + 'create_group.public_is_open': 'Qualquer pessoa pode encontrar um grupo público e entrar nele. Para escolher quem entra, crie-o como privado.', }; 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 bfa6d05..40a40a4 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 @@ -373,4 +373,21 @@ export default { other: '找到 {n} 个文件', }, 'search.hint': '在所有已缓存的群组索引中搜索文件名。', + + // Presence, chat paging, leaving a group, the profile page + 'presence.online': '有一个服务本群组的 node 在线', + 'presence.offline': '本群组没有可达的 node', + 'presence.unknown': '尚未检测', + 'chat.load_older': '加载更早的 {n} 条消息', + 'chat.start_of_history': '对话开头', + 'chat.today': '今天', + 'chat.yesterday': '昨天', + 'chat.unread': '新消息', + 'chat.jump_latest': '跳到最新', + 'chat.jump_new': '新消息', + 'group.leave': '退出群组', + 'group.leave_confirm': '退出“{name}”?您将失去其文件和聊天的访问权。您上传的文件仍留在 node 上,node 也会保留它为您固定的身份,直到其运营者将其移除。', + 'profile.title': '个人资料', + 'usermenu.profile': '个人资料', + 'create_group.public_is_open': '任何人都可以找到并加入公开群组。若要挑选谁能进来,请创建为私密群组。', }; |