From 4eda03ab6355a6cf280865bca91ce8d2fc6167e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 30 Sep 2026 19:42:05 +0500 Subject: [PATCH] v0.1.3: interface scales with the window, realmlist line per Friends mode, robust close handler Co-Authored-By: Claude Sonnet 5.5 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- package.json | 2 +- src-tauri/tauri.conf.json | 2 +- src/i18n/locales/de.ts | 3 +++ src/i18n/locales/en.ts | 3 +++ src/i18n/locales/es.ts | 3 +++ src/i18n/locales/fr.ts | 3 +++ src/i18n/locales/ru.ts | 3 +++ src/index.css | 6 ++++++ src/lib/selfUpdate.ts | 37 +++++++++++++++++++++---------------- src/screens/FriendsPage.tsx | 33 ++++++++++++++++++++++++++++++++- 12 files changed, 80 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c7f2da..96e64f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -347,7 +347,7 @@ dependencies = [ [[package]] name = "coa-core" -version = "0.1.2" +version = "0.1.3" dependencies = [ "base64 0.22.1", "chrono", @@ -375,7 +375,7 @@ dependencies = [ [[package]] name = "coa-release" -version = "0.1.2" +version = "0.1.3" dependencies = [ "chrono", "coa-core", @@ -384,7 +384,7 @@ dependencies = [ [[package]] name = "coa-server-manager" -version = "0.1.2" +version = "0.1.3" dependencies = [ "coa-core", "serde", diff --git a/Cargo.toml b/Cargo.toml index 85d3932..864976f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "2" members = ["crates/coa-core", "crates/coa-release", "src-tauri"] [workspace.package] -version = "0.1.2" +version = "0.1.3" edition = "2021" license = "AGPL-3.0-only" diff --git a/package.json b/package.json index 27427c1..28a21ef 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "coa-server-manager", "private": true, - "version": "0.1.2", + "version": "0.1.3", "license": "AGPL-3.0-only", "type": "module", "scripts": { diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 415b386..7a7fe33 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "CoA Server Manager", - "version": "0.1.2", + "version": "0.1.3", "identifier": "com.coa.servermanager", "build": { "beforeDevCommand": "npm run dev", diff --git a/src/i18n/locales/de.ts b/src/i18n/locales/de.ts index f99bd68..f492b08 100644 --- a/src/i18n/locales/de.ts +++ b/src/i18n/locales/de.ts @@ -430,6 +430,9 @@ const de: Partial> = { "selfupd.now": "Jetzt installieren", "about.auto": "Updates im Hintergrund laden und beim Schließen des Managers installieren", "about.autoHint": "Ein Manager-Update stoppt oder verändert deine Server nie.", + + // Friends line + "fr.copyLine": "Zeile kopieren", }; export default de; diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index 00d3c29..3d221d9 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -430,6 +430,9 @@ const en = { "selfupd.now": "Install now", "about.auto": "Download updates in the background and install them when I close the Manager", "about.autoHint": "Your servers are never stopped or changed by a Manager update.", + + // Friends line + "fr.copyLine": "Copy line", } as const; export default en; diff --git a/src/i18n/locales/es.ts b/src/i18n/locales/es.ts index a8caa4e..d487e18 100644 --- a/src/i18n/locales/es.ts +++ b/src/i18n/locales/es.ts @@ -430,6 +430,9 @@ const es: Partial> = { "selfupd.now": "Instalar ahora", "about.auto": "Descargar las actualizaciones en segundo plano e instalarlas al cerrar el Manager", "about.autoHint": "Una actualización del Manager nunca detiene ni cambia tus servidores.", + + // Friends line + "fr.copyLine": "Copiar línea", }; export default es; diff --git a/src/i18n/locales/fr.ts b/src/i18n/locales/fr.ts index df005b4..61aeb1e 100644 --- a/src/i18n/locales/fr.ts +++ b/src/i18n/locales/fr.ts @@ -430,6 +430,9 @@ const fr: Partial> = { "selfupd.now": "Installer maintenant", "about.auto": "Télécharger les mises à jour en arrière-plan et les installer à la fermeture du Manager", "about.autoHint": "Une mise à jour du Manager n’arrête ni ne modifie jamais vos serveurs.", + + // Friends line + "fr.copyLine": "Copier la ligne", }; export default fr; diff --git a/src/i18n/locales/ru.ts b/src/i18n/locales/ru.ts index 7889ffb..c75e753 100644 --- a/src/i18n/locales/ru.ts +++ b/src/i18n/locales/ru.ts @@ -430,6 +430,9 @@ const ru: Partial> = { "selfupd.now": "Установить сейчас", "about.auto": "Скачивать обновления в фоне и устанавливать их, когда я закрою менеджер", "about.autoHint": "Обновление менеджера никогда не останавливает и не меняет ваши серверы.", + + // Friends line + "fr.copyLine": "Скопировать строку", }; export default ru; diff --git a/src/index.css b/src/index.css index e6f1ac5..d441f36 100644 --- a/src/index.css +++ b/src/index.css @@ -16,6 +16,12 @@ --font-sans: "Segoe UI Variable Text", "Segoe UI", system-ui, sans-serif; } +/* Everything is sized in rem, so scaling the root font grows the whole interface with the window + (16px up to about 1280px wide, then gradually larger; capped at 26px). */ +html { + font-size: clamp(16px, calc(0.75vw + 6.4px), 26px); +} + html, body, #root { diff --git a/src/lib/selfUpdate.ts b/src/lib/selfUpdate.ts index 47c498c..e73bca6 100644 --- a/src/lib/selfUpdate.ts +++ b/src/lib/selfUpdate.ts @@ -103,22 +103,27 @@ export async function installNow(): Promise { /** Install a downloaded update when the user closes the window. Call once at start-up. */ export function installOnClose(): () => void { let stop: (() => void) | undefined; - void getCurrentWindow() - .onCloseRequested(async (event) => { - if (state.phase !== "ready" || !update || !autoUpdateEnabled()) return; - event.preventDefault(); - try { - set({ phase: "installing" }); - await update.install(); - } catch (e) { - set({ phase: "error", error: String(e) }); - await getCurrentWindow().destroy(); - } - }) - .then((un) => { - stop = un; - }) - .catch(() => {}); + try { + const win = getCurrentWindow(); + void win + .onCloseRequested(async (event) => { + if (state.phase !== "ready" || !update || !autoUpdateEnabled()) return; + event.preventDefault(); + try { + set({ phase: "installing" }); + await update.install(); + } catch (e) { + set({ phase: "error", error: String(e) }); + await win.destroy(); + } + }) + .then((un) => { + stop = un; + }) + .catch(() => {}); + } catch { + /* not running inside the desktop shell (browser preview) */ + } return () => stop?.(); } diff --git a/src/screens/FriendsPage.tsx b/src/screens/FriendsPage.tsx index 3b2cc0e..e723f20 100644 --- a/src/screens/FriendsPage.tsx +++ b/src/screens/FriendsPage.tsx @@ -22,6 +22,30 @@ const MODES: { id: FriendsMode; title: Key; text: Key }[] = [ { id: "private", title: "fr.mode.private.title", text: "fr.mode.private.text" }, ]; +/** A ready-to-paste realmlist line for the friend, shown as soon as the address is known. */ +function RealmlistLine({ host }: { host: string }) { + const t = useT(); + const [copied, setCopied] = useState(false); + const line = `set realmlist ${host}`; + return ( +
+ {line} + +
+ ); +} + export function FriendsPage({ serverId }: { serverId: string }) { const t = useT(); const human = useHuman(); @@ -103,7 +127,12 @@ export function FriendsPage({ serverId }: { serverId: string }) {

{t(m.text)}

- {m.id === "lan" &&

{t("fr.yourLan")} {st.lan_ip ?? t("fr.unknown")}

} + {m.id === "lan" && ( + <> +

{t("fr.yourLan")} {st.lan_ip ?? t("fr.unknown")}

+ {st.lan_ip && cur.mode !== m.id && } + + )} {m.id === "direct" && (
@@ -119,6 +148,7 @@ export function FriendsPage({ serverId }: { serverId: string }) { {net?.public_ip && net.reachability !== "cgnat" && (

{t("fr.publicAddr")} {net.public_ip}{!net.router_found && {t("fr.noRouter")}}

)} + {net?.public_ip && net.reachability !== "cgnat" && cur.mode !== m.id && } {net && !net.public_ip &&

{t("fr.noInternet")}

}
)} @@ -130,6 +160,7 @@ export function FriendsPage({ serverId }: { serverId: string }) { {st.tailscale.connected && <>{t("fr.privateAddr")} {st.tailscale.ip}}

)} + {m.id === "private" && st.tailscale.connected && st.tailscale.ip && cur.mode !== m.id && }