diff --git a/README.md b/README.md index 488ffb2..7de0b06 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ The app checks for new releases in-app and updates itself. Settings → **Tray icon** picks what sits next to the clock. Settings → **Taskbar strip** puts logos with session and weekly numbers into the taskbar: choose up to 6 providers and their order, the font and size, and a color scale that warms up as you use more. +Choose **Left** to place the strip at the taskbar's left edge, or **Right** to keep it beside the notification area. **Offset (px)** adds spacing inward from that edge (0–4096, scaled with the display). The default stays Right with an 8 px offset. Placement is saved and applies to every selected taskbar. Large offsets are clamped to keep the strip on the taskbar and outside the tray; if the strip is too wide to fit, it hides. It does not reserve space for Start, Widgets or app buttons, so adjust the offset to avoid them. + ## At Home on Windows 11 ![The panel in the pure black dark theme and in the light theme](docs/images/themes.webp) diff --git a/src-tauri/src/taskbar_strip.rs b/src-tauri/src/taskbar_strip.rs index 9124f82..df52b47 100644 --- a/src-tauri/src/taskbar_strip.rs +++ b/src-tauri/src/taskbar_strip.rs @@ -1,5 +1,5 @@ //! Experimental taskbar strip: provider logos with session/weekly numbers inside the Windows 11 -//! taskbar, left of the notification area (what macOS shows as menu bar text). +//! taskbar, at its left edge or left of the notification area. //! //! Windows has no API for this (deskbands are gone in Windows 11), so like TrafficMonitor each //! strip is a layered window made a child of a taskbar: the main one (`Shell_TrayWnd`) and, when the @@ -13,6 +13,9 @@ use std::sync::{Mutex, OnceLock}; use tauri::AppHandle; +mod placement; +pub use placement::Placement; + #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct StripImage { @@ -82,6 +85,7 @@ struct Shared { /// One image per monitor scale; empty = no strip. images: Vec, choice: Choice, + placement: Placement, /// The strip thread (for `PostThreadMessageW`); 0 while it hasn't started yet. thread_id: u32, thread_running: bool, @@ -194,8 +198,10 @@ pub fn set_taskbar_strip( app_handle: AppHandle, images: Option>, monitors: Option, + placement: Option, ) -> Result<(), String> { let _ = APP.set(app_handle); + let placement = placement.unwrap_or_default().validate()?; let choice = monitors .map(Choice::try_from) .transpose()? @@ -212,6 +218,7 @@ pub fn set_taskbar_strip( let show = !pixels.is_empty(); state.images = pixels; state.choice = choice; + state.placement = placement; #[cfg(windows)] { if state.thread_running { @@ -285,8 +292,6 @@ mod win { const WM_APP_RECONCILE: u32 = WM_APP + 1; const CLASS_NAME: &str = "OpenTokenUsageTaskbarStrip"; - /// Space between the strip and the notification area at 100 %. - const GAP: i32 = 8; /// Taskbars change without telling us (Explorer restarts, monitors come and go): look again. const RECONCILE_MS: u32 = 2000; /// A secondary Windows 11 taskbar has no notification-area window to measure: its clock and @@ -697,12 +702,12 @@ mod win { } } - /// Puts a strip left of its taskbar's notification area (or clock), vertically centered, and draws it. + /// Places a strip at the chosen edge, vertically centered, and draws it. fn place(strip: &Strip) { unsafe { // Copy out: the calls below talk to Explorer, never hold the lock across them. - let pixels = match shared().lock() { - Ok(state) => image_for(&state.images, strip.dpi).cloned(), + let (pixels, placement) = match shared().lock() { + Ok(state) => (image_for(&state.images, strip.dpi).cloned(), state.placement), Err(_) => return, }; let Some(pixels) = pixels else { @@ -732,12 +737,10 @@ mod win { } else { bar.right - scaled(SECONDARY_CLOCK_WIDTH, strip.dpi) }; - let x = right - bar.left - pixels.width - scaled(GAP, strip.dpi); - // Wider than the free space: it would cover Start and the app buttons (and catch their clicks). - if x < 0 { + let Some(x) = placement.x(right - bar.left, pixels.width, strip.dpi) else { ShowWindow(strip.hwnd, SW_HIDE); return; - } + }; let y = (bar.bottom - bar.top - pixels.height) / 2; SetWindowPos( strip.hwnd, diff --git a/src-tauri/src/taskbar_strip/placement.rs b/src-tauri/src/taskbar_strip/placement.rs new file mode 100644 index 0000000..fef17a8 --- /dev/null +++ b/src-tauri/src/taskbar_strip/placement.rs @@ -0,0 +1,92 @@ +//! Taskbar-relative coordinates; offsets are logical pixels at 96 DPI. + +#[derive(Clone, Copy, Debug, Default, serde::Deserialize)] +#[serde(rename_all = "lowercase")] +enum Side { + Left, + #[default] + Right, +} + +#[derive(Clone, Copy, Debug, serde::Deserialize)] +pub struct Placement { + side: Side, + offset: u32, +} + +impl Default for Placement { + fn default() -> Self { + Self { + side: Side::Right, + offset: 8, + } + } +} + +impl Placement { + pub fn validate(self) -> Result { + if self.offset > 4096 { + return Err("strip offset out of range".into()); + } + Ok(self) + } + + /// `available` ends at the notification area/clock, in taskbar-local physical pixels. + /// Clamp an oversized inset, but hide a strip that cannot fit at all. + pub fn x(self, available: i32, width: i32, dpi: u32) -> Option { + if width <= 0 || available < width { + return None; + } + let max_x = available - width; + let inset = (self.offset as i64 * dpi as i64 / 96).min(max_x as i64) as i32; + Some(match self.side { + Side::Left => inset, + Side::Right => max_x - inset, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn preserves_default_and_scales_both_edges() { + assert_eq!(Placement::default().x(1800, 200, 96), Some(1592)); + let left = Placement { + side: Side::Left, + offset: 24, + }; + let right = Placement { + side: Side::Right, + offset: 24, + }; + assert_eq!(left.x(1800, 200, 144), Some(36)); + assert_eq!(right.x(1800, 200, 144), Some(1564)); + assert_eq!(left.x(2700, 300, 144), Some(36)); + } + + #[test] + fn stays_inside_each_taskbar_and_out_of_the_tray() { + for side in [Side::Left, Side::Right] { + let p = Placement { side, offset: 4096 }; + let x = p.x(500, 200, 480).unwrap(); + assert!((0..=300).contains(&x)); + assert_eq!(p.x(200, 200, 96), Some(0)); + assert_eq!(p.x(100, 200, 96), None); + assert_eq!(p.x(-10, 200, 96), None); + } + } + + #[test] + fn rejects_invalid_ipc_values() { + assert!(serde_json::from_str::(r#"{"side":"center","offset":8}"#).is_err()); + assert!(serde_json::from_str::(r#"{"side":"left","offset":-1}"#).is_err()); + assert!(Placement { + side: Side::Left, + offset: 4097, + } + .validate() + .is_err()); + } +} diff --git a/src/components/strip-placement.test.tsx b/src/components/strip-placement.test.tsx new file mode 100644 index 0000000..f1b6f07 --- /dev/null +++ b/src/components/strip-placement.test.tsx @@ -0,0 +1,67 @@ +import { useState } from "react" +import { fireEvent, render, screen } from "@testing-library/react" +import userEvent from "@testing-library/user-event" +import { expect, it, vi } from "vitest" +import { StripPlacement } from "@/components/strip-placement" + +function renderControls() { + const onChange = vi.fn() + function Controls() { + const [placement, setPlacement] = useState({ position: "right" as "left" | "right", offset: 8 }) + return ( + { + onChange(patch) + setPlacement((previous) => ({ ...previous, ...patch })) + }} + /> + ) + } + render() + return onChange +} + +it("selects either side and accepts only whole, bounded offsets", () => { + const onChange = renderControls() + expect(screen.getByRole("radio", { name: "Right" })).toHaveAttribute("aria-checked", "true") + fireEvent.click(screen.getByRole("radio", { name: "Left" })) + expect(onChange).toHaveBeenLastCalledWith({ position: "left" }) + expect(screen.getByRole("radio", { name: "Left" })).toHaveAttribute("aria-checked", "true") + fireEvent.click(screen.getByRole("radio", { name: "Right" })) + expect(onChange).toHaveBeenLastCalledWith({ position: "right" }) + + const input = screen.getByRole("spinbutton", { name: "Offset (px)" }) + fireEvent.change(input, { target: { value: "120" } }) + expect(onChange).toHaveBeenLastCalledWith({ offset: 120 }) + expect(input).toHaveValue(120) + onChange.mockClear() + for (const value of ["", "-1", "1.5", "4097"]) fireEvent.change(input, { target: { value } }) + expect(onChange).not.toHaveBeenCalled() + for (const value of ["0", "4096"]) { + fireEvent.change(input, { target: { value } }) + expect(onChange).toHaveBeenLastCalledWith({ offset: Number(value) }) + } +}) + +it("lets users clear and retype an offset, and restores invalid drafts on blur", async () => { + const user = userEvent.setup() + const onChange = renderControls() + const input = screen.getByRole("spinbutton", { name: "Offset (px)" }) + await user.clear(input) + expect(input).toHaveValue(null) + expect(onChange).not.toHaveBeenCalled() + await user.type(input, "120") + expect(input).toHaveValue(120) + expect(onChange).toHaveBeenLastCalledWith({ offset: 120 }) + await user.tab() + expect(input).toHaveValue(120) + + await user.clear(input) + await user.tab() + expect(input).toHaveValue(120) + fireEvent.change(input, { target: { value: "4097" } }) + expect(input).toHaveValue(4097) + fireEvent.blur(input) + expect(input).toHaveValue(120) +}) diff --git a/src/components/strip-placement.tsx b/src/components/strip-placement.tsx new file mode 100644 index 0000000..4ed3100 --- /dev/null +++ b/src/components/strip-placement.tsx @@ -0,0 +1,53 @@ +import { useState } from "react" +import { SegmentedControl } from "@/components/settings-section" +import { t } from "@/lib/i18n" +import type { SettingOption, TaskbarStripStyle } from "@/lib/settings" + +const POSITIONS: SettingOption[] = [ + { value: "left", labelKey: "settings.strip.positionLeft" }, + { value: "right", labelKey: "settings.strip.positionRight" }, +] + +export function StripPlacement({ + position, + offset, + onChange, +}: { + position: TaskbarStripStyle["position"] + offset: number + onChange: (patch: Partial) => void +}) { + // Allow empty/invalid text while editing; only valid offsets reach the saved settings. + const [draft, setDraft] = useState(null) + return ( +
+
+
{t("settings.strip.position")}
+ onChange({ position: next })} + ariaLabel={t("settings.strip.position")} + /> +
+ +

{t("settings.strip.positionHint")}

+
+ ) +} diff --git a/src/components/taskbar-strip-section.tsx b/src/components/taskbar-strip-section.tsx index 1552c58..874cb2d 100644 --- a/src/components/taskbar-strip-section.tsx +++ b/src/components/taskbar-strip-section.tsx @@ -29,6 +29,7 @@ import { colorOnScale, stripPluginSettings } from "@/lib/taskbar-strip" import { cn } from "@/lib/utils" import { useAppPluginStore } from "@/stores/app-plugin-store" import { useAppPreferencesStore } from "@/stores/app-preferences-store" +import { StripPlacement } from "@/components/strip-placement" const FONT_SIZES = [10, 11, 12, 13, 14, 15] @@ -295,6 +296,7 @@ export function TaskbarStripSection({ onMenubarIconStyleChange }: { onMenubarIco )} update({ monitors })} /> +
diff --git a/src/hooks/app/use-taskbar-strip.ts b/src/hooks/app/use-taskbar-strip.ts index 765455b..f46b8b0 100644 --- a/src/hooks/app/use-taskbar-strip.ts +++ b/src/hooks/app/use-taskbar-strip.ts @@ -108,7 +108,11 @@ export function useTaskbarStrip(args: { ) render() .then((images) => - invoke("set_taskbar_strip", { images, monitors: stripMonitorsArg(style.monitors) }).then( + invoke("set_taskbar_strip", { + images, + monitors: stripMonitorsArg(style.monitors), + placement: { side: style.position, offset: style.offset }, + }).then( () => (showingRef.current = images !== null) ) ) diff --git a/src/lib/settings.test.ts b/src/lib/settings.test.ts index 41bb301..6ab2f28 100644 --- a/src/lib/settings.test.ts +++ b/src/lib/settings.test.ts @@ -19,6 +19,7 @@ import { loadResetTimerDisplayMode, loadStartOnLogin, loadTimeFormatMode, + loadTaskbarStripStyle, migrateLegacyTraySettings, migrateWindsurfToDevin, loadThemeMode, @@ -32,6 +33,7 @@ import { saveStartOnLogin, saveThemeMode, saveTimeFormatMode, + saveTaskbarStripStyle, } from "@/lib/settings" import type { PluginMeta } from "@/lib/plugin-types" @@ -69,6 +71,13 @@ describe("settings", () => { await expect(loadPluginSettings()).resolves.toEqual(DEFAULT_PLUGIN_SETTINGS) }) + it("saves strip placement and restores it after reloading settings", async () => { + const original = await loadTaskbarStripStyle() + await saveTaskbarStripStyle({ ...original, position: "left", offset: 120 }) + expect(storeSaveMock).toHaveBeenCalled() + await expect(loadTaskbarStripStyle()).resolves.toEqual({ ...original, position: "left", offset: 120 }) + }) + it("sanitizes stored settings", async () => { storeState.set("plugins", { order: ["a"], disabled: "nope" }) await expect(loadPluginSettings()).resolves.toEqual({ diff --git a/src/lib/settings.ts b/src/lib/settings.ts index cb1ee8d..f21e8df 100644 --- a/src/lib/settings.ts +++ b/src/lib/settings.ts @@ -510,6 +510,9 @@ const MAX_STRIP_MONITORS = 16; /** Look of the taskbar strip; everything the user can restyle. */ export type TaskbarStripStyle = { + /** Left taskbar edge or right notification-area edge; offset uses logical pixels. */ + position: "left" | "right"; + offset: number; /** Providers shown, in strip order (own order, independent of the nav); null = first enabled ones. */ providers: string[] | null; font: TaskbarStripFont; @@ -530,6 +533,8 @@ export type TaskbarStripStyle = { }; export const DEFAULT_TASKBAR_STRIP_STYLE: TaskbarStripStyle = { + position: "right", + offset: 8, providers: null, font: "segoe-variable", fontSize: 12, @@ -580,6 +585,11 @@ export function normalizeTaskbarStripStyle(value: unknown): TaskbarStripStyle { : null; return { providers, + position: raw.position === "left" ? "left" : d.position, + offset: + typeof raw.offset === "number" && Number.isInteger(raw.offset) && raw.offset >= 0 && raw.offset <= 4096 + ? raw.offset + : d.offset, font: TASKBAR_STRIP_FONTS.some((font) => font.id === raw.font) ? (raw.font as TaskbarStripFont) : d.font, fontSize: typeof raw.fontSize === "number" && raw.fontSize >= 10 && raw.fontSize <= 15 ? raw.fontSize : d.fontSize, bold: typeof raw.bold === "boolean" ? raw.bold : d.bold, diff --git a/src/lib/taskbar-strip.test.ts b/src/lib/taskbar-strip.test.ts index ef55c92..cb3b51d 100644 --- a/src/lib/taskbar-strip.test.ts +++ b/src/lib/taskbar-strip.test.ts @@ -146,6 +146,17 @@ describe("makeTaskbarStripSvg", () => { }) describe("normalizeTaskbarStripStyle", () => { + it("preserves old placement and validates saved positions and offsets", () => { + expect(normalizeTaskbarStripStyle({}).position).toBe("right") + expect(normalizeTaskbarStripStyle({}).offset).toBe(8) + expect(normalizeTaskbarStripStyle({ position: "left", offset: 120 })).toMatchObject({ position: "left", offset: 120 }) + expect(normalizeTaskbarStripStyle({ position: "center", offset: -1 })).toMatchObject({ position: "right", offset: 8 }) + for (const offset of [NaN, Infinity, 1.5, 4097, "20", null]) { + expect(normalizeTaskbarStripStyle({ offset }).offset).toBe(8) + } + for (const offset of [0, 4096]) expect(normalizeTaskbarStripStyle({ offset }).offset).toBe(offset) + }) + it("keeps valid fields and replaces broken ones", () => { const stored = { font: "comic-sans", diff --git a/src/locales/de.ts b/src/locales/de.ts index c267343..6a698d3 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -65,7 +65,12 @@ export const de: Messages = { "settings.tray.logos": "Logo je Anbieter", "settings.tray.logoColors": "Farbige Logos", "settings.strip.title": "Taskleisten-Leiste (experimentell)", - "settings.strip.desc": "Anbieterlogos mit Sitzungs- und Wochennutzung links neben den Infobereich-Symbolen.", + "settings.strip.desc": "Anbieterlogos mit Sitzungs- und Wochennutzung in der Taskleiste.", + "settings.strip.position": "Position", + "settings.strip.positionLeft": "Links", + "settings.strip.positionRight": "Rechts", + "settings.strip.offset": "Abstand (px)", + "settings.strip.positionHint": "Links beginnt am Rand der Taskleiste, rechts neben dem Infobereich. Der Abstand wirkt nach innen und wird mit der Anzeige skaliert.", "settings.strip.enable": "In der Taskleiste anzeigen", "settings.strip.enableHint": "Windows bietet dafür keinen offiziellen Platz, daher kann ein Update die Anzeige verschieben oder ausblenden. Solange sie an ist, zeigt der Infobereich nur das App-Symbol; ein anderer Symbolstil schaltet die Leiste aus.", "settings.strip.preview": "Vorschau", diff --git a/src/locales/en.lock.json b/src/locales/en.lock.json index 747b2bf..072bcef 100644 --- a/src/locales/en.lock.json +++ b/src/locales/en.lock.json @@ -59,7 +59,12 @@ "settings.tray.logos": "321b05e93a", "settings.tray.logoColors": "411e65f476", "settings.strip.title": "70c8adb44b", - "settings.strip.desc": "5bc2ca49e7", + "settings.strip.desc": "a086d0001e", + "settings.strip.position": "cf1c85adba", + "settings.strip.positionLeft": "8ae1c34bd3", + "settings.strip.positionRight": "954daa8b00", + "settings.strip.offset": "6acd57112b", + "settings.strip.positionHint": "9bc6e0a86d", "settings.strip.enable": "7191c94a82", "settings.strip.enableHint": "60a3bb6c07", "settings.strip.preview": "f1fbb2b43d", diff --git a/src/locales/en.ts b/src/locales/en.ts index 259e02c..1e591e8 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -65,7 +65,12 @@ export const en = { "settings.tray.logos": "Logo per provider", "settings.tray.logoColors": "Colored logos", "settings.strip.title": "Taskbar strip (experimental)", - "settings.strip.desc": "Provider logos with session and weekly usage, left of the tray icons.", + "settings.strip.desc": "Provider logos with session and weekly usage on the taskbar.", + "settings.strip.position": "Position", + "settings.strip.positionLeft": "Left", + "settings.strip.positionRight": "Right", + "settings.strip.offset": "Offset (px)", + "settings.strip.positionHint": "Left starts at the taskbar edge; right starts beside the tray. Offset moves inward and scales with your display.", "settings.strip.enable": "Show on the taskbar", "settings.strip.enableHint": "Windows has no official place for this, so an update may move or hide it. While it's on, the tray shows only the app icon; picking another tray style turns the strip off.", "settings.strip.preview": "Preview", diff --git a/src/locales/es-419.ts b/src/locales/es-419.ts index d3c4dbe..8d90e16 100644 --- a/src/locales/es-419.ts +++ b/src/locales/es-419.ts @@ -65,7 +65,12 @@ export const es419: Messages = { "settings.tray.logos": "Logo por proveedor", "settings.tray.logoColors": "Logos a color", "settings.strip.title": "Franja en la barra de tareas (experimental)", - "settings.strip.desc": "Logos de los proveedores con el uso de sesión y semanal, a la izquierda de los íconos del área de notificación.", + "settings.strip.desc": "Logotipos de proveedores con uso de la sesión y semanal en la barra de tareas.", + "settings.strip.position": "Posición", + "settings.strip.positionLeft": "Izquierda", + "settings.strip.positionRight": "Derecha", + "settings.strip.offset": "Separación (px)", + "settings.strip.positionHint": "Izquierda parte del borde de la barra de tareas; derecha, junto a la bandeja. La separación se aplica hacia adentro y se ajusta a la escala de la pantalla.", "settings.strip.enable": "Mostrar en la barra de tareas", "settings.strip.enableHint": "Windows no tiene un lugar oficial para esto, así que una actualización puede moverla u ocultarla. Mientras esté activa, el área de notificación muestra solo el ícono de la app; elegir otro estilo de ícono desactiva la franja.", "settings.strip.preview": "Vista previa", diff --git a/src/locales/es-ES.ts b/src/locales/es-ES.ts index 9b9fe73..a1f2f02 100644 --- a/src/locales/es-ES.ts +++ b/src/locales/es-ES.ts @@ -65,7 +65,12 @@ export const esES: Messages = { "settings.tray.logos": "Logotipo por proveedor", "settings.tray.logoColors": "Logotipos en color", "settings.strip.title": "Franja en la barra de tareas (experimental)", - "settings.strip.desc": "Logotipos de los proveedores con el uso de sesión y semanal, a la izquierda de los iconos del área de notificación.", + "settings.strip.desc": "Logotipos de proveedores con uso de la sesión y semanal en la barra de tareas.", + "settings.strip.position": "Posición", + "settings.strip.positionLeft": "Izquierda", + "settings.strip.positionRight": "Derecha", + "settings.strip.offset": "Separación (px)", + "settings.strip.positionHint": "Izquierda parte del borde de la barra de tareas; derecha, junto a la bandeja. La separación se aplica hacia dentro y se ajusta a la escala de la pantalla.", "settings.strip.enable": "Mostrar en la barra de tareas", "settings.strip.enableHint": "Windows no tiene un sitio oficial para esto, así que una actualización puede moverla u ocultarla. Mientras esté activa, el área de notificación muestra solo el icono de la aplicación; elegir otro estilo de icono desactiva la franja.", "settings.strip.preview": "Vista previa", diff --git a/src/locales/fr.ts b/src/locales/fr.ts index 6af0f07..62467f8 100644 --- a/src/locales/fr.ts +++ b/src/locales/fr.ts @@ -65,7 +65,12 @@ export const fr: Messages = { "settings.tray.logos": "Un logo par fournisseur", "settings.tray.logoColors": "Logos en couleur", "settings.strip.title": "Bande de la barre des tâches (expérimental)", - "settings.strip.desc": "Logos des fournisseurs avec l'utilisation de session et hebdomadaire, à gauche des icônes de notification.", + "settings.strip.desc": "Logos des fournisseurs avec utilisation de la session et de la semaine dans la barre des tâches.", + "settings.strip.position": "Position", + "settings.strip.positionLeft": "Gauche", + "settings.strip.positionRight": "Droite", + "settings.strip.offset": "Décalage (px)", + "settings.strip.positionHint": "À gauche, le point de départ est le bord de la barre des tâches ; à droite, la zone de notification. Le décalage va vers l’intérieur et suit la mise à l’échelle de l’écran.", "settings.strip.enable": "Afficher dans la barre des tâches", "settings.strip.enableHint": "Windows ne prévoit pas d'emplacement officiel pour cela : une mise à jour peut la déplacer ou la masquer. Tant qu'elle est active, la zone de notification n'affiche que l'icône de l'app ; choisir un autre style d'icône désactive la bande.", "settings.strip.preview": "Aperçu", diff --git a/src/locales/it.ts b/src/locales/it.ts index ebef47b..860149e 100644 --- a/src/locales/it.ts +++ b/src/locales/it.ts @@ -65,7 +65,12 @@ export const it: Messages = { "settings.tray.logos": "Logo per provider", "settings.tray.logoColors": "Loghi a colori", "settings.strip.title": "Striscia nella barra delle applicazioni (sperimentale)", - "settings.strip.desc": "Loghi dei provider con utilizzo di sessione e settimanale, a sinistra delle icone dell'area di notifica.", + "settings.strip.desc": "Loghi dei fornitori con utilizzo della sessione e settimanale sulla barra delle applicazioni.", + "settings.strip.position": "Posizione", + "settings.strip.positionLeft": "Sinistra", + "settings.strip.positionRight": "Destra", + "settings.strip.offset": "Distanza (px)", + "settings.strip.positionHint": "A sinistra si parte dal bordo della barra delle applicazioni; a destra, accanto all’area di notifica. La distanza va verso l’interno e segue il ridimensionamento dello schermo.", "settings.strip.enable": "Mostra nella barra delle applicazioni", "settings.strip.enableHint": "Windows non ha un posto ufficiale per questo, quindi un aggiornamento può spostarla o nasconderla. Quando è attiva, l'area di notifica mostra solo l'icona dell'app; scegliere un altro stile di icona disattiva la striscia.", "settings.strip.preview": "Anteprima", diff --git a/src/locales/ja.ts b/src/locales/ja.ts index 6d6d45e..2c84fe5 100644 --- a/src/locales/ja.ts +++ b/src/locales/ja.ts @@ -65,7 +65,12 @@ export const ja: Messages = { "settings.tray.logos": "プロバイダーごとのロゴ", "settings.tray.logoColors": "カラーのロゴ", "settings.strip.title": "タスク バー表示(試験的)", - "settings.strip.desc": "通知領域アイコンの左に、プロバイダーのロゴとセッション・週間の使用量を表示します。", + "settings.strip.desc": "タスクバーにプロバイダーのロゴとセッション・週間の使用状況を表示します。", + "settings.strip.position": "位置", + "settings.strip.positionLeft": "左", + "settings.strip.positionRight": "右", + "settings.strip.offset": "余白 (px)", + "settings.strip.positionHint": "左はタスクバーの端、右は通知領域の隣を基準にします。余白は内側に適用され、画面の拡大率に合わせて調整されます。", "settings.strip.enable": "タスク バーに表示", "settings.strip.enableHint": "Windows には公式の表示場所がないため、更新で位置がずれたり非表示になったりすることがあります。オンの間は通知領域にアプリのアイコンだけが表示され、別のアイコン スタイルを選ぶとこの表示はオフになります。", "settings.strip.preview": "プレビュー", diff --git a/src/locales/ko.ts b/src/locales/ko.ts index 89ed7be..b39b4c5 100644 --- a/src/locales/ko.ts +++ b/src/locales/ko.ts @@ -65,7 +65,12 @@ export const ko: Messages = { "settings.tray.logos": "공급자별 로고", "settings.tray.logoColors": "컬러 로고", "settings.strip.title": "작업 표시줄 표시(실험적)", - "settings.strip.desc": "알림 영역 아이콘 왼쪽에 공급자 로고와 세션·주간 사용량을 표시합니다.", + "settings.strip.desc": "작업 표시줄에 공급자 로고와 세션 및 주간 사용량을 표시합니다.", + "settings.strip.position": "위치", + "settings.strip.positionLeft": "왼쪽", + "settings.strip.positionRight": "오른쪽", + "settings.strip.offset": "간격 (px)", + "settings.strip.positionHint": "왼쪽은 작업 표시줄 가장자리, 오른쪽은 알림 영역 옆을 기준으로 합니다. 간격은 안쪽으로 적용되며 디스플레이 배율에 따라 조정됩니다.", "settings.strip.enable": "작업 표시줄에 표시", "settings.strip.enableHint": "Windows에는 공식 위치가 없어 업데이트로 위치가 바뀌거나 숨겨질 수 있습니다. 켜져 있는 동안 알림 영역에는 앱 아이콘만 표시되며, 다른 아이콘 스타일을 고르면 이 표시가 꺼집니다.", "settings.strip.preview": "미리 보기", diff --git a/src/locales/pt-BR.ts b/src/locales/pt-BR.ts index 23a33ff..425f8c8 100644 --- a/src/locales/pt-BR.ts +++ b/src/locales/pt-BR.ts @@ -65,7 +65,12 @@ export const ptBR: Messages = { "settings.tray.logos": "Logo por provedor", "settings.tray.logoColors": "Logos coloridos", "settings.strip.title": "Faixa na barra de tarefas (experimental)", - "settings.strip.desc": "Logos dos provedores com uso da sessão e semanal, à esquerda dos ícones da área de notificação.", + "settings.strip.desc": "Logotipos dos provedores com uso da sessão e semanal na barra de tarefas.", + "settings.strip.position": "Posição", + "settings.strip.positionLeft": "Esquerda", + "settings.strip.positionRight": "Direita", + "settings.strip.offset": "Espaçamento (px)", + "settings.strip.positionHint": "À esquerda, começa na borda da barra de tarefas; à direita, ao lado da bandeja. O espaçamento avança para dentro e acompanha a escala da tela.", "settings.strip.enable": "Mostrar na barra de tarefas", "settings.strip.enableHint": "O Windows não tem um lugar oficial para isso, então uma atualização pode movê-la ou ocultá-la. Enquanto estiver ativa, a área de notificação mostra só o ícone do app; escolher outro estilo de ícone desativa a faixa.", "settings.strip.preview": "Prévia", diff --git a/src/locales/tr.ts b/src/locales/tr.ts index 4d9c5b4..71e0f88 100644 --- a/src/locales/tr.ts +++ b/src/locales/tr.ts @@ -65,7 +65,12 @@ export const tr: Messages = { "settings.tray.logos": "Sağlayıcı başına logo", "settings.tray.logoColors": "Renkli logolar", "settings.strip.title": "Görev çubuğu şeridi (deneysel)", - "settings.strip.desc": "Tepsi simgelerinin solunda logolar ile oturum ve haftalık kullanım.", + "settings.strip.desc": "Görev çubuğunda sağlayıcı logoları ile oturum ve haftalık kullanım.", + "settings.strip.position": "Konum", + "settings.strip.positionLeft": "Sol", + "settings.strip.positionRight": "Sağ", + "settings.strip.offset": "Boşluk (px)", + "settings.strip.positionHint": "Sol, görev çubuğunun kenarından; sağ, bildirim alanının yanından başlar. Boşluk içeriye doğru uygulanır ve ekran ölçeğine göre ayarlanır.", "settings.strip.enable": "Görev çubuğunda göster", "settings.strip.enableHint": "Windows'ta bunun resmi bir yeri yok; bir güncelleme yerini kaydırabilir veya gizleyebilir. Açıkken bildirim alanında yalnızca uygulama simgesi kalır; başka bir simge stili seçmek şeridi kapatır.", "settings.strip.preview": "Önizleme", diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index afbe1d5..007a8de 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -65,7 +65,12 @@ export const zhCN: Messages = { "settings.tray.logos": "每个提供商一个徽标", "settings.tray.logoColors": "彩色徽标", "settings.strip.title": "任务栏显示(实验性)", - "settings.strip.desc": "在通知区域图标左侧显示提供商徽标及会话和每周用量。", + "settings.strip.desc": "在任务栏上显示提供商标志及会话和每周用量。", + "settings.strip.position": "位置", + "settings.strip.positionLeft": "左侧", + "settings.strip.positionRight": "右侧", + "settings.strip.offset": "偏移量 (px)", + "settings.strip.positionHint": "左侧从任务栏边缘开始,右侧从通知区域旁开始。偏移量向内应用,并随显示缩放比例调整。", "settings.strip.enable": "在任务栏显示", "settings.strip.enableHint": "Windows 没有为此提供官方位置,因此更新可能会移动或隐藏它。开启时通知区域只显示应用图标;选择其他图标样式会关闭此显示。", "settings.strip.preview": "预览",