From 2e668edb51b71bcb9536c95cf55d6dcf66d57daa Mon Sep 17 00:00:00 2001 From: John Coffey Date: Fri, 18 Sep 2026 15:58:56 -0700 Subject: [PATCH] Brand the webmail INBUXA: name, mark and wordmark INBUXA is a product suite and ihasmail an independent product, so INBUXA's webmail says INBUXA: the sign-in page, header, page title, installed-app name and About page. The wordmark is drawn in the current text color. ihasmail's version and AGPL source line stay as its credit. Two new strings, in all nine catalogues; three Stalwart-only ones are no longer used. --- INBUXA.md | 11 +++++++++ server/src/config.ts | 2 +- web/index.html | 2 +- web/public/img/inbuxa-mark.png | Bin 0 -> 25072 bytes web/public/manifest.webmanifest | 6 ++--- web/src/lib/brand.ts | 4 ++- web/src/lib/notify/notify.ts | 2 +- web/src/locales/de.ts | 2 ++ web/src/locales/es.ts | 2 ++ web/src/locales/fr.ts | 2 ++ web/src/locales/ja.ts | 2 ++ web/src/locales/nl.ts | 2 ++ web/src/locales/pt-BR.ts | 2 ++ web/src/locales/ru.ts | 2 ++ web/src/locales/uk.ts | 2 ++ web/src/locales/zh-Hans.ts | 2 ++ web/src/ui/InbuxaWordmark.tsx | 30 +++++++++++++++++++++++ web/src/views/AppShell.tsx | 13 +++++++--- web/src/views/Login.tsx | 9 ++++--- web/src/views/settings/AboutSettings.tsx | 25 +++++++------------ 20 files changed, 92 insertions(+), 30 deletions(-) create mode 100644 web/public/img/inbuxa-mark.png create mode 100644 web/src/ui/InbuxaWordmark.tsx diff --git a/INBUXA.md b/INBUXA.md index 0f143cb..5a7f215 100644 --- a/INBUXA.md +++ b/INBUXA.md @@ -20,11 +20,22 @@ keep up. Nothing here is pushed there. no address: only whether this is the person's own device, then the server's page takes it from there. With several servers, the address comes first, since its domain picks the server. +- **Branded INBUXA.** INBUXA is a product suite, and its webmail carries the + INBUXA name, mark and wordmark, so it can't be taken for public ihasmail, + which stays an independent product. The default `APP_NAME` is `INBUXA`; the + sign-in page, header, page title, installed-app name and About page say + INBUXA. ihasmail's version and AGPL source line stay as its credit. Set + `APP_NAME` to something else and that name shows as text, as in public + ihasmail. - **Tenants are offered on every server**, whatever edition it reports. `SHOW_ENTERPRISE_NOTICES` still adds the notice for an upstream Stalwart. ## Configuration +**Before any deployment, set `SOURCE_URL`** to where this fork's source is +published. The AGPL's offer has to point at the source of the code that's +running, and the default still points at public ihasmail. + Server sign-in is on when `OAUTH_CLIENT_SECRET` is set. Without it, ihasmail-inbuxa keeps public ihasmail's password form. diff --git a/server/src/config.ts b/server/src/config.ts index aeebc09..caf14e0 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -278,7 +278,7 @@ if (oauthClientSecret && !publicUrl) { export const config = { isProd, - appName: env("APP_NAME", "ihasmail"), + appName: env("APP_NAME", "INBUXA"), settingsPolicy: readSettingsPolicy(), /** * What this build calls itself: `2.16.57`. Set by the image build from diff --git a/web/index.html b/web/index.html index 0e48c8e..263b085 100644 --- a/web/index.html +++ b/web/index.html @@ -23,7 +23,7 @@ - ihasmail + INBUXA
diff --git a/web/public/img/inbuxa-mark.png b/web/public/img/inbuxa-mark.png new file mode 100644 index 0000000000000000000000000000000000000000..86cfcf838e46c96865973f629052a8dc095a0188 GIT binary patch literal 25072 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 XX!7-@!0_pT00000NkvXXu0mjf*E96A literal 0 HcmV?d00001 diff --git a/web/public/manifest.webmanifest b/web/public/manifest.webmanifest index 3c3d012..c16a603 100644 --- a/web/public/manifest.webmanifest +++ b/web/public/manifest.webmanifest @@ -1,7 +1,7 @@ { - "name": "ihasmail", - "short_name": "ihasmail", - "description": "Fast, friendly JMAP webmail for Stalwart", + "name": "INBUXA", + "short_name": "INBUXA", + "description": "INBUXA webmail", "_comment": "JSON has no comments, so: every URL below is relative on purpose. Manifest members resolve against the manifest's own address, so these follow BASE_PATH with nothing substituted into them at build time. Root-absolute values pinned the installed app, its scope and its shortcuts to the domain root whatever the mount was.", "_comment_id": "There is deliberately no `id`. It is the one member NOT resolved against this file's address -- the spec resolves it against the origin of start_url, so `./`, `mail` and `/mail` all mean the same thing at the domain root and none of them can name a subpath mount. Adding one would therefore break the same thing the note above describes. Worse, the default id IS start_url, which is already mount-correct: writing an id now would give every installed copy a new identity and orphan it as a second app rather than updating it. If one is ever wanted it has to be substituted at build time from BASE_PATH, and the changeover costs everybody their install.", "start_url": "mail", diff --git a/web/src/lib/brand.ts b/web/src/lib/brand.ts index 086a4dc..00e5c1d 100644 --- a/web/src/lib/brand.ts +++ b/web/src/lib/brand.ts @@ -10,4 +10,6 @@ * One constant rather than the string written out at each of them, because * three copies of a default is how two of them end up stale. */ -export const DEFAULT_APP_NAME = "ihasmail"; +// ihasmail-inbuxa: INBUXA's webmail goes by INBUXA, so it can't be taken for +// public ihasmail. APP_NAME still names a deployment whatever it likes. +export const DEFAULT_APP_NAME = "INBUXA"; diff --git a/web/src/lib/notify/notify.ts b/web/src/lib/notify/notify.ts index 55230ea..3790578 100644 --- a/web/src/lib/notify/notify.ts +++ b/web/src/lib/notify/notify.ts @@ -1,6 +1,6 @@ import { withBase } from "../basePath"; -let baseTitle = "ihasmail"; +let baseTitle = "INBUXA"; let faviconCanvas: HTMLCanvasElement | null = null; let baseFavicon: HTMLImageElement | null = null; diff --git a/web/src/locales/de.ts b/web/src/locales/de.ts index 0856551..3fd6bff 100644 --- a/web/src/locales/de.ts +++ b/web/src/locales/de.ts @@ -1242,6 +1242,8 @@ export const catalog: Catalog = { "Could not save filters: {error}": "Filter konnten nicht gespeichert werden: {error}", "Could not send the receipt: {error}": "Die Lesebestätigung konnte nicht gesendet werden: {error}", "Could not sign in.": "Anmeldung fehlgeschlagen.", + "About INBUXA webmail": "Über INBUXA Webmail", + "Mail server": "Mailserver", "You'll enter your password on your mail server's sign-in page.": "Ihr Passwort geben Sie auf der Anmeldeseite Ihres Mailservers ein.", "You'll sign in on your mail server's own page.": "Sie melden sich auf der eigenen Seite Ihres Mailservers an.", "This sign-in didn't start in this browser. Try again.": "Diese Anmeldung wurde nicht in diesem Browser begonnen. Bitte versuchen Sie es erneut.", diff --git a/web/src/locales/es.ts b/web/src/locales/es.ts index a68a676..3e814f4 100644 --- a/web/src/locales/es.ts +++ b/web/src/locales/es.ts @@ -1215,6 +1215,8 @@ export const catalog: Catalog = { "Could not save filters: {error}": "No se pudieron guardar los filtros: {error}", "Could not send the receipt: {error}": "No se pudo enviar la confirmación de lectura: {error}", "Could not sign in.": "No se pudo iniciar sesión.", + "About INBUXA webmail": "Acerca de INBUXA webmail", + "Mail server": "Servidor de correo", "You'll enter your password on your mail server's sign-in page.": "Introducirá su contraseña en la página de inicio de sesión de su servidor de correo.", "You'll sign in on your mail server's own page.": "Iniciará sesión en la propia página de su servidor de correo.", "This sign-in didn't start in this browser. Try again.": "Este inicio de sesión no empezó en este navegador. Inténtelo de nuevo.", diff --git a/web/src/locales/fr.ts b/web/src/locales/fr.ts index 0114003..a18fbae 100644 --- a/web/src/locales/fr.ts +++ b/web/src/locales/fr.ts @@ -1220,6 +1220,8 @@ export const catalog: Catalog = { "Could not save filters: {error}": "Impossible d’enregistrer les filtres : {error}", "Could not send the receipt: {error}": "Impossible d’envoyer l’accusé de lecture : {error}", "Could not sign in.": "Connexion impossible.", + "About INBUXA webmail": "À propos d’INBUXA webmail", + "Mail server": "Serveur de messagerie", "You'll enter your password on your mail server's sign-in page.": "Vous saisirez votre mot de passe sur la page de connexion de votre serveur de messagerie.", "You'll sign in on your mail server's own page.": "Vous vous connecterez sur la page de votre serveur de messagerie.", "This sign-in didn't start in this browser. Try again.": "Cette connexion n’a pas commencé dans ce navigateur. Réessayez.", diff --git a/web/src/locales/ja.ts b/web/src/locales/ja.ts index 75d7bac..1a99e29 100644 --- a/web/src/locales/ja.ts +++ b/web/src/locales/ja.ts @@ -1223,6 +1223,8 @@ export const catalog: Catalog = { "Could not save filters: {error}": "フィルターを保存できませんでした: {error}", "Could not send the receipt: {error}": "開封確認を送信できませんでした: {error}", "Could not sign in.": "サインインできませんでした。", + "About INBUXA webmail": "INBUXA ウェブメールについて", + "Mail server": "メールサーバー", "You'll enter your password on your mail server's sign-in page.": "パスワードはメールサーバーのサインインページで入力します。", "You'll sign in on your mail server's own page.": "メールサーバー自身のページでサインインします。", "This sign-in didn't start in this browser. Try again.": "このサインインはこのブラウザーで開始されたものではありません。もう一度お試しください。", diff --git a/web/src/locales/nl.ts b/web/src/locales/nl.ts index de54627..2e54cb9 100644 --- a/web/src/locales/nl.ts +++ b/web/src/locales/nl.ts @@ -1213,6 +1213,8 @@ export const catalog: Catalog = { "Could not save filters: {error}": "Filters opslaan mislukt: {error}", "Could not send the receipt: {error}": "De leesbevestiging kon niet worden verzonden: {error}", "Could not sign in.": "Aanmelden mislukt.", + "About INBUXA webmail": "Over INBUXA webmail", + "Mail server": "Mailserver", "You'll enter your password on your mail server's sign-in page.": "U voert uw wachtwoord in op de aanmeldpagina van uw mailserver.", "You'll sign in on your mail server's own page.": "U meldt zich aan op de eigen pagina van uw mailserver.", "This sign-in didn't start in this browser. Try again.": "Deze aanmelding is niet in deze browser begonnen. Probeer het opnieuw.", diff --git a/web/src/locales/pt-BR.ts b/web/src/locales/pt-BR.ts index 911b703..39b80f4 100644 --- a/web/src/locales/pt-BR.ts +++ b/web/src/locales/pt-BR.ts @@ -1218,6 +1218,8 @@ export const catalog: Catalog = { "Could not save filters: {error}": "Não foi possível salvar os filtros: {error}", "Could not send the receipt: {error}": "Não foi possível enviar a confirmação de leitura: {error}", "Could not sign in.": "Não foi possível entrar.", + "About INBUXA webmail": "Sobre o INBUXA webmail", + "Mail server": "Servidor de e-mail", "You'll enter your password on your mail server's sign-in page.": "Você vai digitar sua senha na página de entrada do seu servidor de e-mail.", "You'll sign in on your mail server's own page.": "Você vai entrar na própria página do seu servidor de e-mail.", "This sign-in didn't start in this browser. Try again.": "Esta entrada não começou neste navegador. Tente de novo.", diff --git a/web/src/locales/ru.ts b/web/src/locales/ru.ts index 6bafd9a..0240507 100644 --- a/web/src/locales/ru.ts +++ b/web/src/locales/ru.ts @@ -1217,6 +1217,8 @@ export const catalog: Catalog = { "Could not save filters: {error}": "Не удалось сохранить фильтры: {error}", "Could not send the receipt: {error}": "Не удалось отправить уведомление о прочтении: {error}", "Could not sign in.": "Не удалось войти.", + "About INBUXA webmail": "О веб-почте INBUXA", + "Mail server": "Почтовый сервер", "You'll enter your password on your mail server's sign-in page.": "Пароль вводится на странице входа вашего почтового сервера.", "You'll sign in on your mail server's own page.": "Вход выполняется на странице вашего почтового сервера.", "This sign-in didn't start in this browser. Try again.": "Этот вход начат не в этом браузере. Попробуйте ещё раз.", diff --git a/web/src/locales/uk.ts b/web/src/locales/uk.ts index 9c87944..680faa9 100644 --- a/web/src/locales/uk.ts +++ b/web/src/locales/uk.ts @@ -1211,6 +1211,8 @@ export const catalog: Catalog = { "Could not save filters: {error}": "Не вдалося зберегти фільтри: {error}", "Could not send the receipt: {error}": "Не вдалося надіслати сповіщення про прочитання: {error}", "Could not sign in.": "Не вдалося увійти.", + "About INBUXA webmail": "Про вебпошту INBUXA", + "Mail server": "Поштовий сервер", "You'll enter your password on your mail server's sign-in page.": "Пароль вводиться на сторінці входу вашого поштового сервера.", "You'll sign in on your mail server's own page.": "Вхід виконується на сторінці вашого поштового сервера.", "This sign-in didn't start in this browser. Try again.": "Цей вхід розпочато не в цьому браузері. Спробуйте ще раз.", diff --git a/web/src/locales/zh-Hans.ts b/web/src/locales/zh-Hans.ts index b4958b1..0998f14 100644 --- a/web/src/locales/zh-Hans.ts +++ b/web/src/locales/zh-Hans.ts @@ -1222,6 +1222,8 @@ export const catalog: Catalog = { "Could not save filters: {error}": "无法保存过滤器:{error}", "Could not send the receipt: {error}": "无法发送已读回执:{error}", "Could not sign in.": "无法登录。", + "About INBUXA webmail": "关于 INBUXA 网页邮箱", + "Mail server": "邮件服务器", "You'll enter your password on your mail server's sign-in page.": "您将在邮件服务器的登录页面上输入密码。", "You'll sign in on your mail server's own page.": "您将在邮件服务器自己的页面上登录。", "This sign-in didn't start in this browser. Try again.": "此次登录不是在这个浏览器中发起的。请重试。", diff --git a/web/src/ui/InbuxaWordmark.tsx b/web/src/ui/InbuxaWordmark.tsx new file mode 100644 index 0000000..709fd51 --- /dev/null +++ b/web/src/ui/InbuxaWordmark.tsx @@ -0,0 +1,30 @@ +/** + * The INBUXA wordmark, "inbuxa" in Space Grotesk Bold, as vector paths in the + * current text color, so it reads on every palette, light or dark. The mark + * beside it is `/img/inbuxa-mark.png`: ihasmail's own cat and envelope, which + * INBUXA's logo reuses unchanged. The paths are the same ones INBUXA Admin + * draws, from the INBUXA logo bundle. + * + * ihasmail-inbuxa only. Public ihasmail keeps its own name. + */ +export function InbuxaWordmark({ className, height }: { className?: string; height: number }) { + return ( + + + + + + + + + ); +} diff --git a/web/src/views/AppShell.tsx b/web/src/views/AppShell.tsx index 2e26ed9..e0daab5 100644 --- a/web/src/views/AppShell.tsx +++ b/web/src/views/AppShell.tsx @@ -4,6 +4,7 @@ import { BookOpen, Calendar, ChevronsUpDown, FolderOpen, Globe, HelpCircle, LogO import { useSession } from "@/store/session"; import { withBase } from "@/lib/basePath"; import { DEFAULT_APP_NAME } from "@/lib/brand"; +import { InbuxaWordmark } from "@/ui/InbuxaWordmark"; import { useEffectiveTheme, useSettings } from "@/store/settings"; import { toggleTarget } from "@/lib/palette"; import { useMail } from "@/store/mail"; @@ -147,14 +148,18 @@ export function AppShell({ children }: { children: ReactNode }) { - + {/* A product name, not a word: translated it is a different product. Read from the session rather than written here, so a deployment that set APP_NAME is called what it calls itself -- the document title has taken it from there all along. */} - - {appName} - + {appName === DEFAULT_APP_NAME ? ( + + ) : ( + + {appName} + + )}
diff --git a/web/src/views/Login.tsx b/web/src/views/Login.tsx index 6a141f1..92505ee 100644 --- a/web/src/views/Login.tsx +++ b/web/src/views/Login.tsx @@ -7,6 +7,7 @@ import { DEFAULT_SOURCE_URL } from "@/lib/source"; import { APP_VERSION } from "@/lib/version"; import { DEFAULT_APP_NAME } from "@/lib/brand"; import { t } from "@/lib/i18n"; +import { InbuxaWordmark } from "@/ui/InbuxaWordmark"; export function LoginPage() { const login = useSession((s) => s.login); @@ -92,10 +93,12 @@ export function LoginPage() {
- + {/* A product name, not a word: not translated, and not guessed at - from the page it is on. */} -

{appName}

+ from the page it is on. INBUXA's is its wordmark. */} +

+ {appName === DEFAULT_APP_NAME ? : appName} +

{t("Fast, friendly webmail. Your mailbox, your way.")}

{error && ( diff --git a/web/src/views/settings/AboutSettings.tsx b/web/src/views/settings/AboutSettings.tsx index 3a120a0..59ceee9 100644 --- a/web/src/views/settings/AboutSettings.tsx +++ b/web/src/views/settings/AboutSettings.tsx @@ -4,6 +4,7 @@ import { DEFAULT_SOURCE_URL } from "@/lib/source"; import { APP_VERSION } from "@/lib/version"; import { withBase } from "@/lib/basePath"; import { t, tNode } from "@/lib/i18n"; +import { InbuxaWordmark } from "@/ui/InbuxaWordmark"; export function AboutSettings() { const session = useSession((s) => s.session); @@ -12,13 +13,16 @@ export function AboutSettings() { const sourceUrl = session?.ihasmail?.sourceUrl ?? DEFAULT_SOURCE_URL; return (
-

{t("About ihasmail")}

-

{tNode("A fast, friendly, open-source webmail for {server}, built on JMAP.", { server: {t("Stalwart Mail Server")} })}

+ {/* ihasmail-inbuxa: INBUXA's webmail, built on ihasmail, whose version + and source stay here as its credit and the AGPL's offer. */} +

{t("About INBUXA webmail")}

+

{tNode("A fast, friendly, open-source webmail for {server}, built on JMAP.", { server: INBUXA })}

- {t("ihasmail")} +
+ {/* A product name and a version string: neither is a word to translate. */} -
ihasmail v{APP_VERSION}
+
ihasmail v{APP_VERSION}
{tNode("AGPL-3.0-or-later · {source}", { source: {sourceUrl.replace(/^https?:\/\//, "")} })}
@@ -26,7 +30,7 @@ export function AboutSettings() { - + @@ -41,14 +45,3 @@ export function AboutSettings() { ); } - -/** - * Stalwart deliberately withholds its version from clients (it reports a fixed - * "1.0.0" wherever it publishes one at all), so the edition is all there is to - * show. The generation used to be reported here too, back when ihasmail spoke - * to both 0.15 and 0.16; it requires 0.16 now, so signing in at all is the - * answer to that question. - */ -function describeServer(server: { edition?: string | null } | undefined): string { - return server?.edition ? `0.16 or newer (${server.edition})` : "0.16 or newer"; -}
{t("Signed in as")}{session?.username}
{t("Stalwart")}{describeServer(session?.ihasmail?.server)}
{t("Mail server")}INBUXA
{t("Accounts")}{Object.values(session?.accounts ?? {}).map((a) => a.name).join(", ")}
{t("Max upload")}{t("{size} MB", { size: Math.round(client.maxSizeUpload / 1048576) })}
{t("Image privacy proxy")}{session?.ihasmail?.imageProxy ? t("enabled") : t("disabled")}