Settings: language and theme, kept in the app
Appearance in Settings chooses the language (the system's, or one of the nine the app has; the window opens again in it, its replies and shells let go first) and the theme (the account's, or Moria or Shire, drawn at once and the window painted in it). Kept in localStorage on this computer: /api/v2 has no PATCH /me for either yet, so the account's own stay as they are. i18n.js reads the choice and carries each language's own name from the server's catalogue. Tests E5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
9 files changed
+354
-18
No files matched your search
+30
-1
@@ -1,10 +1,12 @@
|
||||
// Settings: the app's, not the server's (no admin page here, ever -- an admin sees what everyone
|
||||
// sees). Grouped, with the groups listed beside them: the account (the server and the app's
|
||||
// sign-in), the agent and the folders it may work in, notifications, and this release.
|
||||
// sign-in), the agent and the folders it may work in, the language and theme, notifications, and
|
||||
// this release.
|
||||
|
||||
import { $, h, clear, icon, ICONS } from "./dom.js"
|
||||
import { invoke, listen } from "./bridge.js"
|
||||
import { agentBlock, onAgentChange, link } from "./agent.js"
|
||||
import { chosenTheme, chooseTheme, accountTheme, chosenLanguage, chooseLanguage } from "./look.js"
|
||||
|
||||
let folderError = ""
|
||||
let current = () => null
|
||||
@@ -13,6 +15,7 @@ const SECTIONS = [
|
||||
["account", ICONS.user, () => t("Account")],
|
||||
["agent", ICONS.terminal, () => t("Agent")],
|
||||
["folders", ICONS.folder, () => t("Project folders")],
|
||||
["look", ICONS.contrast, () => t("Appearance")],
|
||||
["notify", ICONS.bell, () => t("Notifications")],
|
||||
["about", ICONS.info, () => t("About")],
|
||||
]
|
||||
@@ -118,6 +121,8 @@ export function renderSettings(s) {
|
||||
)
|
||||
}
|
||||
|
||||
box.append(lookSection())
|
||||
|
||||
box.append(
|
||||
section(
|
||||
"notify",
|
||||
@@ -143,6 +148,30 @@ export function renderSettings(s) {
|
||||
)
|
||||
}
|
||||
|
||||
/** The language and the theme: this app's choice over the system's language and the account's theme. */
|
||||
function lookSection() {
|
||||
const named = (code) => LEMBAS_LANGS[code] || code
|
||||
const language = h(
|
||||
"select",
|
||||
{ id: "set-language", "aria-label": t("Language"), onchange: (e) => chooseLanguage(e.target.value) },
|
||||
[["", t("This computer's (%(language)s)", { language: named(LEMBAS_SYSTEM_LANG) })], ...Object.keys(LEMBAS_LANGS).map((code) => [code, named(code)])].map(([v, label]) =>
|
||||
h("option", { value: v, text: label, selected: chosenLanguage() === v, lang: v || undefined }),
|
||||
),
|
||||
)
|
||||
const label = (name) => `${name === "shire" ? "Shire" : "Moria"} — ${name === "shire" ? t("light") : t("dark")}`
|
||||
const theme = h(
|
||||
"select",
|
||||
{ id: "set-theme", "aria-label": t("Theme"), onchange: (e) => chooseTheme(e.target.value) },
|
||||
[["", t("The account's (%(theme)s)", { theme: label(accountTheme()) })], ["moria", label("moria")], ["shire", label("shire")]].map(([v, text]) => h("option", { value: v, text, selected: chosenTheme() === v })),
|
||||
)
|
||||
return section(
|
||||
"look",
|
||||
t("Appearance"),
|
||||
line(t("Language"), `${t("The interface only. Models answer in the language you write to them in, whatever this says.")} ${t("Kept in this app on this computer. The window opens again in the language chosen.")}`, language),
|
||||
line(t("Theme"), t("Kept in this app on this computer; the account's theme stays as it is."), theme),
|
||||
)
|
||||
}
|
||||
|
||||
export function initSettings(getStatus) {
|
||||
current = getStatus
|
||||
listen("remote-error", (e) => {
|
||||
|
||||
Reference in new issue
Block a user