Merge remote-tracking branch 'fj/main'

# Conflicts:
#	docs/config.md
This commit is contained in:
orbit-docs 2026-07-04 01:09:17 +00:00
commit 0b8266b6e9
No known key found for this signature in database
4 changed files with 68 additions and 16 deletions

View file

@ -21,8 +21,10 @@ Everything that ties Orbit to a particular network or brand lives in
} }
``` ```
This changes the connect screen, the console title, the network icon, and the CTCP VERSION/SOURCE `branding.name` and `branding.icon` reach **everywhere** the app identifies itself: the connect
replies the client sends. screen, the browser tab title + **favicon**, desktop and Web Push notifications, the PWA install
prompt (name + description, localized), the iOS home-screen title, the network icon, and the CTCP
VERSION/SOURCE replies. Point `icon` at your own logo URL and the tab icon follows.
## Themes ## Themes
@ -49,6 +51,11 @@ Hide whole features per deployment:
{ "features": { "push": true, "imageUpload": true, "register": false } } { "features": { "push": true, "imageUpload": true, "register": false } }
``` ```
- `push` — the Web Push notifications row. - `push` — Web Push notifications: the Settings row **and** the re-subscribe-on-connect.
- `imageUpload` — the composer image button + paste/drag upload. - `imageUpload` — the composer image button **and** paste / drag-drop upload.
- `register` — the "create an account" tab. - `register` — account self-service: the "Create account" button, the "Forgot password" link, and their FAQ entries (all hidden together).
## Languages
The UI and the bundled plugins are fully translated in **10 languages** (auto-detected). Pin a
default with [`defaults.lang`](https://orbit.tchatou.fr/docs/config/); users can switch in Settings.

View file

@ -18,31 +18,47 @@ Merge rules: objects merge key-by-key; **arrays and scalars replace** wholesale.
| Key | Type | What it does | | Key | Type | What it does |
|-----|------|--------------| |-----|------|--------------|
| `server.url` | string | WebSocket URL of the IRCv3 server. | | `server.url` | string | WebSocket URL of the IRCv3 server. |
| `server.guestIdent` | string | Ident for **guests** (not logged in) — e.g. `Foo!Invité@…`. Folded to ASCII (IRC idents are `[A-Za-z0-9._-]`, so `Invité``Invite`). Logged-in members use their own nick as the ident. |
| `startup.channels` | string[] | Channels auto-joined (first = active). A `?channel=` URL param overrides. | | `startup.channels` | string[] | Channels auto-joined (first = active). A `?channel=` URL param overrides. |
| `branding.name` | string | App/network name shown in the UI + CTCP VERSION. | | `branding.name` | string | App/network name — UI, tab title, **notifications**, **PWA install prompt**, and CTCP VERSION. |
| `branding.icon` | string | Logo / favicon URL. | | `branding.icon` | string | Logo/icon — connect screen, **browser favicon**, desktop + push notifications, PWA. |
| `branding.url` | string | Homepage (used in CTCP VERSION/SOURCE). | | `branding.url` | string | Homepage (used in CTCP VERSION/SOURCE). |
| `branding.tagline` / `taglineEm` / `subtitle` | string | Connect-screen copy. | | `branding.tagline` / `taglineEm` / `subtitle` | string | Connect-screen copy. |
| `branding.projectUrl` | string | "Powered by Orbit" link in Settings. | | `branding.projectUrl` | string | Orbit project/source link (Settings → About). |
| `turnstile.enabled` / `sitekey` | bool / string | Cloudflare Turnstile on registration. | | `turnstile.enabled` | bool | Render the anti-bot challenge inline (Cloudflare Turnstile). `false` = show the server's verification step as a link, no Cloudflare script. Whether a challenge is *required* is decided server-side. |
| `report.target` | string | Channel that user reports are sent to. | | `turnstile.sitekey` | string | Public Turnstile site key. |
| `report.service` | string | Services pseudo-client that receives reports (e.g. `ReportServ`) — not blocked by a `+n` staff channel. Empty = fall back to `report.target`. |
| `report.target` | string | Channel that reports are sent to when `report.service` is empty. |
| `defaults.theme` | string | `light` · `dark` · `yomirc` · `yomirc-dark`. | | `defaults.theme` | string | `light` · `dark` · `yomirc` · `yomirc-dark`. |
| `defaults.compact` / `sound` / `hideJoinQuit` / `clock24` | bool | Preset new-user prefs. | | `defaults.compact` / `sound` / `hideJoinQuit` / `clock24` | bool | Preset new-user prefs. |
| `defaults.lang` | string | Pin a default UI language (e.g. `en`, `fr`, `de`). Overrides browser detection for users who haven't picked one. Omit to auto-detect. | | `defaults.lang` | string | Force the UI language (`en`, `fr`, `de`, `es`, `it`, `tr`, `ru`, `ne`, `pt-BR`, `pt-PT`). Empty = auto-detect from the browser. |
| `features.push` / `imageUpload` / `register` | bool | Turn whole features on/off. | | `features.push` | bool | Web Push notifications — the Settings row **and** the re-subscribe-on-connect. |
| `features.imageUpload` | bool | Composer image button **and** paste / drag-drop upload. |
| `features.register` | bool | Account self-service: the "Create account" button, the "Forgot password" link, and their FAQ entries. |
| `plugins` | string[] | Plugin script URLs loaded at startup. See [Plugins](https://orbit.tchatou.fr/docs/plugins/). |
> `defaults.*` only seed a user's preferences the **first** time — once someone changes a setting, > `defaults.*` only seed a user's preferences the **first** time — once someone changes a setting,
> it's stored in their browser and the config no longer overrides it. > it's stored in their browser and the config no longer overrides it.
## Languages
The UI ships fully translated in **10 languages** — English, French, German, Spanish,
Italian, Turkish, Russian, Nepali, and Brazilian + European Portuguese. Orbit
auto-detects the visitor's browser language; pin a default with `defaults.lang` (users
can still switch in **Settings**). The bundled plugins are localized too — see
[Plugins](https://orbit.tchatou.fr/docs/plugins/).
## Example ## Example
```json ```json
{ {
"server": { "url": "wss://irc.example.org/ws/" }, "server": { "url": "wss://irc.example.org/ws/", "guestIdent": "Guest" },
"startup": { "channels": ["#lobby", "#help"] }, "startup": { "channels": ["#lobby", "#help"] },
"branding": { "name": "ExampleChat", "tagline": "Chat with", "taglineEm": "everyone." }, "branding": { "name": "ExampleChat", "icon": "https://example.org/logo.svg", "tagline": "Chat with", "taglineEm": "everyone." },
"turnstile":{ "enabled": false, "sitekey": "" }, "turnstile":{ "enabled": false, "sitekey": "" },
"defaults": { "theme": "dark", "compact": true }, "report": { "service": "ReportServ", "target": "#staff" },
"features": { "register": false } "defaults": { "theme": "dark", "compact": true, "lang": "" },
"features": { "push": true, "imageUpload": true, "register": false },
"plugins": []
} }
``` ```

View file

@ -22,6 +22,9 @@ network** and **rebranded** from a single `config.json`, without recompiling.
[config.json reference](https://orbit.tchatou.fr/docs/config/). [config.json reference](https://orbit.tchatou.fr/docs/config/).
- **Installable PWA.** Mobile-first layout, offline app shell, and notifications when the tab is - **Installable PWA.** Mobile-first layout, offline app shell, and notifications when the tab is
closed. closed.
- **Speaks 10 languages.** The UI, system messages, and the bundled plugins are fully translated
and auto-detected (English, French, German, Spanish, Italian, Turkish, Russian, Nepali, and
Brazilian + European Portuguese). Pin a default with `defaults.lang`.
- **Self-hostable.** A static build behind any web server. The project even runs its own git - **Self-hostable.** A static build behind any web server. The project even runs its own git
server with [push-to-deploy](https://orbit.tchatou.fr/docs/push-to-deploy/). server with [push-to-deploy](https://orbit.tchatou.fr/docs/push-to-deploy/).
- **Free software.** AGPL-3.0: use it, modify it, self-host it. - **Free software.** AGPL-3.0: use it, modify it, self-host it.

View file

@ -80,6 +80,10 @@ instead. See **[Compiled plugins](https://orbit.tchatou.fr/docs/compiled-plugins
| `orbit.irc.list()` | request the channel list | | `orbit.irc.list()` | request the channel list |
| `orbit.themes.current()/list()/set(id)` | read/set the theme | | `orbit.themes.current()/list()/set(id)` | read/set the theme |
| `orbit.storage.get(key, def)/set(key, val)` | namespaced persistence | | `orbit.storage.get(key, def)/set(key, val)` | namespaced persistence |
| `orbit.config()` | the resolved runtime config (branding, features, …) |
| `orbit.i18n.language()` | current UI language code (e.g. `es`, `pt-BR`) |
| `orbit.i18n.t(key, opts?)` | translate an app locale key (supports `{{interpolation}}`) |
| `orbit.i18n.pick(table)` | pick a string from a `{ lang: text }` table by the current language |
| `orbit.addUi(slot, render)` | add UI to a slot (returns a remover) | | `orbit.addUi(slot, render)` | add UI to a slot (returns a remover) |
| `orbit.addSettingsSection({label, icon?, render})` | add a whole Settings section | | `orbit.addSettingsSection({label, icon?, render})` | add a whole Settings section |
| `orbit.addMessageDecorator(m => …)` | inline UI after every message's text; `m` = `{id, nick, text, raw, kind, ts, mine}` (`text` is formatting-stripped, `raw` keeps mIRC codes) | | `orbit.addMessageDecorator(m => …)` | inline UI after every message's text; `m` = `{id, nick, text, raw, kind, ts, mine}` (`text` is formatting-stripped, `raw` keeps mIRC codes) |
@ -109,6 +113,28 @@ to reply/react. Every contributed slot, action and decorator renders inside its
own error boundary, so a crashing plugin renders nothing instead of taking down own error boundary, so a crashing plugin renders nothing instead of taking down
the app. the app.
### Localization (i18n)
The UI ships in 10 languages — keep your plugin in step so it isn't stuck in one. Two ways:
- **Self-contained** — carry a `{ lang: text }` table and let Orbit pick the current language:
```js
const LABEL = { en: 'Copy', fr: 'Copier', de: 'Kopieren' };
orbit.html`<button title=${orbit.i18n.pick(LABEL)}>⧉</button>`;
```
- **Interpolated**`orbit.i18n.t('key', { name })` resolves an app locale key with
`{{placeholders}}`, so word order is correct per language. The four bundled plugins
(clock, copy, invite, games) use this.
Read the string **at render time**, not once at load: plugin UI re-renders when the language
changes, so the text follows automatically. `orbit.i18n.language()` returns the current code
if you need to branch.
> `orbit.i18n` and `orbit.config()` were added in **`apiVersion` 4** — guard with
> `if (orbit.apiVersion >= 4)` if your plugin must run on older builds.
## Trust & security ## Trust & security
Plugins are **operator-controlled**: a deployment lists them in `config.json`, so Plugins are **operator-controlled**: a deployment lists them in `config.json`, so