diff --git a/apps/electron/src/renderer/App.tsx b/apps/electron/src/renderer/App.tsx index 8392407f8..cfc83116b 100644 --- a/apps/electron/src/renderer/App.tsx +++ b/apps/electron/src/renderer/App.tsx @@ -17,6 +17,7 @@ import { OnboardingWizard, ReauthScreen } from '@/components/onboarding' import { WorkspacePicker } from '@/components/workspace' import { ResetConfirmationDialog } from '@/components/ResetConfirmationDialog' import { CommandPalette } from '@/components/CommandPalette' +import { ZoomHotkeys } from '@/components/ZoomHotkeys' import { SplashScreen } from '@/components/SplashScreen' import { TooltipProvider } from '@craft-agent/ui' import { FocusProvider } from '@/context/FocusContext' @@ -2500,6 +2501,9 @@ export default function App() { {/* Global command palette (⌘K / Ctrl+K) — search and run any action */} + {/* Interface zoom shortcuts (⌘+ / ⌘- / ⌘0) wired to the action registry */} + + {/* Splash screen overlay - fades out when fully ready */} {showSplash && ( > = { 'nav.goForwardAlt': 'shortcuts.action.goForward', 'view.toggleSidebar': 'shortcuts.action.toggleSidebar', 'view.toggleFocusMode': 'shortcuts.action.toggleFocusMode', + 'view.zoomIn': 'shortcuts.action.zoomIn', + 'view.zoomOut': 'shortcuts.action.zoomOut', + 'view.zoomReset': 'shortcuts.action.zoomReset', 'navigator.selectAll': 'shortcuts.action.selectAll', 'navigator.clearSelection': 'shortcuts.action.clearSelection', 'panel.focusNext': 'shortcuts.action.focusNextPanel', diff --git a/apps/electron/src/renderer/actions/definitions.ts b/apps/electron/src/renderer/actions/definitions.ts index 82ecf3521..8f095fdc9 100644 --- a/apps/electron/src/renderer/actions/definitions.ts +++ b/apps/electron/src/renderer/actions/definitions.ts @@ -143,6 +143,27 @@ export const actions = { defaultHotkey: 'mod+.', category: 'View', }, + 'view.zoomIn': { + id: 'view.zoomIn', + label: 'Zoom In', + description: 'Scale the whole interface up', + defaultHotkey: 'mod+=', + category: 'View', + }, + 'view.zoomOut': { + id: 'view.zoomOut', + label: 'Zoom Out', + description: 'Scale the whole interface down', + defaultHotkey: 'mod+-', + category: 'View', + }, + 'view.zoomReset': { + id: 'view.zoomReset', + label: 'Reset Zoom', + description: 'Reset the interface zoom to 100%', + defaultHotkey: 'mod+0', + category: 'View', + }, // ═══════════════════════════════════════════ // Navigator (scoped — active entity list in middle panel) diff --git a/apps/electron/src/renderer/components/ZoomHotkeys.tsx b/apps/electron/src/renderer/components/ZoomHotkeys.tsx new file mode 100644 index 000000000..27121fe60 --- /dev/null +++ b/apps/electron/src/renderer/components/ZoomHotkeys.tsx @@ -0,0 +1,23 @@ +/** + * ZoomHotkeys + * + * Bridges the interface-zoom preference to the action registry so the standard + * desktop zoom shortcuts (⌘+ / ⌘- / ⌘0) and their Command Palette entries drive + * `ZoomProvider`. Renders nothing — it only registers handlers. + * + * Must be mounted inside both `ZoomProvider` (for `useZoom`) and + * `ActionRegistryProvider` (for `useAction`). + */ + +import { useZoom } from '@/context/ZoomContext' +import { useAction } from '@/actions' + +export function ZoomHotkeys() { + const { zoomIn, zoomOut, resetZoom } = useZoom() + + useAction('view.zoomIn', zoomIn) + useAction('view.zoomOut', zoomOut) + useAction('view.zoomReset', resetZoom) + + return null +} diff --git a/apps/electron/src/renderer/context/ZoomContext.tsx b/apps/electron/src/renderer/context/ZoomContext.tsx new file mode 100644 index 000000000..9b04ec19a --- /dev/null +++ b/apps/electron/src/renderer/context/ZoomContext.tsx @@ -0,0 +1,140 @@ +/** + * ZoomContext + * + * App-wide "interface zoom" preference — scales the whole renderer (sidebar, + * navigator, chat, settings, dialogs) up or down, like the ⌘+ / ⌘- / ⌘0 zoom + * in Claude Desktop, VS Code, and other desktop apps. + * + * The zoom factor is one of a fixed set of Chrome-like steps and is applied by + * setting `document.documentElement.style.zoom` — a Chromium-native property + * that scales the entire tree, including portalled dialogs rendered into + * ``. At 100% the inline style is cleared so the DOM stays clean. + * + * The preference is persisted in `localStorage` (renderer-only, no backend), + * mirroring the other lightweight UI prefs in `lib/local-storage.ts` and the + * merged `ReduceMotionProvider`. + */ + +import React, { + createContext, + useContext, + useState, + useEffect, + useCallback, + useMemo, + type ReactNode, +} from 'react' +import * as storage from '@/lib/local-storage' + +/** Discrete zoom steps (factors), mirroring a browser's zoom ladder. */ +export const ZOOM_STEPS: readonly number[] = [0.5, 0.67, 0.75, 0.8, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2] + +/** The neutral / "actual size" factor. */ +export const DEFAULT_ZOOM = 1 + +interface ZoomContextType { + /** Current zoom factor (e.g. 1 = 100%, 1.1 = 110%). */ + zoom: number + /** Whole-number percentage for display (e.g. 110). */ + zoomPercent: number + /** Step up to the next larger factor (no-op at the max). */ + zoomIn: () => void + /** Step down to the next smaller factor (no-op at the min). */ + zoomOut: () => void + /** Return to 100%. */ + resetZoom: () => void + /** Whether a larger step is available. */ + canZoomIn: boolean + /** Whether a smaller step is available. */ + canZoomOut: boolean +} + +const ZoomContext = createContext(null) + +/** Clamp an arbitrary stored value onto the nearest valid step. */ +function normalizeZoom(value: number): number { + if (!Number.isFinite(value)) return DEFAULT_ZOOM + let nearest = ZOOM_STEPS[0] + let bestDelta = Math.abs(value - nearest) + for (const step of ZOOM_STEPS) { + const delta = Math.abs(value - step) + if (delta < bestDelta) { + nearest = step + bestDelta = delta + } + } + return nearest +} + +/** Reflect the factor onto so the whole renderer scales. */ +function applyZoom(factor: number): void { + const root = document.documentElement + if (factor === DEFAULT_ZOOM) { + root.style.removeProperty('zoom') + } else { + root.style.zoom = String(factor) + } +} + +export function ZoomProvider({ children }: { children: ReactNode }) { + const [zoom, setZoomState] = useState(() => + normalizeZoom(storage.get(storage.KEYS.zoomLevel, DEFAULT_ZOOM)), + ) + + // Keep the DOM in sync (also covers the initial value on mount). + useEffect(() => { + applyZoom(zoom) + }, [zoom]) + + const setZoom = useCallback((factor: number) => { + const next = normalizeZoom(factor) + setZoomState(next) + storage.set(storage.KEYS.zoomLevel, next) + applyZoom(next) + }, []) + + const zoomIn = useCallback(() => { + setZoomState((current) => { + const idx = ZOOM_STEPS.indexOf(normalizeZoom(current)) + const next = ZOOM_STEPS[Math.min(idx + 1, ZOOM_STEPS.length - 1)] + storage.set(storage.KEYS.zoomLevel, next) + applyZoom(next) + return next + }) + }, []) + + const zoomOut = useCallback(() => { + setZoomState((current) => { + const idx = ZOOM_STEPS.indexOf(normalizeZoom(current)) + const next = ZOOM_STEPS[Math.max(idx - 1, 0)] + storage.set(storage.KEYS.zoomLevel, next) + applyZoom(next) + return next + }) + }, []) + + const resetZoom = useCallback(() => setZoom(DEFAULT_ZOOM), [setZoom]) + + const value = useMemo(() => { + const idx = ZOOM_STEPS.indexOf(zoom) + return { + zoom, + zoomPercent: Math.round(zoom * 100), + zoomIn, + zoomOut, + resetZoom, + canZoomIn: idx < ZOOM_STEPS.length - 1, + canZoomOut: idx > 0, + } + }, [zoom, zoomIn, zoomOut, resetZoom]) + + return {children} +} + +export function useZoom(): ZoomContextType { + const ctx = useContext(ZoomContext) + if (!ctx) { + throw new Error('useZoom must be used within a ZoomProvider') + } + return ctx +} diff --git a/apps/electron/src/renderer/lib/local-storage.ts b/apps/electron/src/renderer/lib/local-storage.ts index 4d6446afd..150578608 100644 --- a/apps/electron/src/renderer/lib/local-storage.ts +++ b/apps/electron/src/renderer/lib/local-storage.ts @@ -53,6 +53,7 @@ export const KEYS = { // Appearance showConnectionIcons: 'show-connection-icons', reduceMotion: 'reduce-motion', // Minimize animations/transitions app-wide + zoomLevel: 'zoom-level', // Interface zoom factor (⌘+/⌘-/⌘0), scales the whole renderer // What's New whatsNewLastSeenVersion: 'whats-new-last-seen-version', diff --git a/apps/electron/src/renderer/main.tsx b/apps/electron/src/renderer/main.tsx index 14729366d..79d8bd525 100644 --- a/apps/electron/src/renderer/main.tsx +++ b/apps/electron/src/renderer/main.tsx @@ -7,6 +7,7 @@ import { Provider as JotaiProvider, useAtomValue } from 'jotai' import App from './App' import { ThemeProvider } from './context/ThemeContext' import { ReduceMotionProvider } from './context/ReduceMotionContext' +import { ZoomProvider } from './context/ZoomContext' import { windowWorkspaceIdAtom } from './atoms/sessions' import { Toaster } from '@/components/ui/sonner' import { PetWindowController } from '@/components/pet/PetWindowController' @@ -108,9 +109,11 @@ function Root() { return ( - - - + + + + + ) diff --git a/apps/electron/src/renderer/pages/settings/AppearanceSettingsPage.tsx b/apps/electron/src/renderer/pages/settings/AppearanceSettingsPage.tsx index 4da9ba24c..193104053 100644 --- a/apps/electron/src/renderer/pages/settings/AppearanceSettingsPage.tsx +++ b/apps/electron/src/renderer/pages/settings/AppearanceSettingsPage.tsx @@ -15,9 +15,11 @@ import { HeaderMenu } from '@/components/ui/HeaderMenu' import { EditPopover, EditButton, getEditConfig } from '@/components/ui/EditPopover' import { useTheme } from '@/context/ThemeContext' import { useReduceMotion } from '@/context/ReduceMotionContext' +import { useZoom } from '@/context/ZoomContext' +import { Button } from '@/components/ui/button' import { useAppShellContext } from '@/context/AppShellContext' import { routes } from '@/lib/navigate' -import { FolderOpen, Monitor, RefreshCw, Sun, Moon } from 'lucide-react' +import { FolderOpen, Monitor, RefreshCw, Sun, Moon, Minus, Plus, RotateCcw } from 'lucide-react' import type { DetailsPageMeta } from '@/lib/navigation-registry' import type { ToolIconMapping } from '../../../shared/types' @@ -142,6 +144,7 @@ export default function AppearanceSettingsPage() { // Reduce motion toggle (renderer-only preference, persisted in localStorage) const { reduceMotion, setReduceMotion } = useReduceMotion() + const { zoomPercent, zoomIn, zoomOut, resetZoom, canZoomIn, canZoomOut } = useZoom() // Pet companion settings + custom pets (synced via shared Jotai atoms) const { @@ -387,6 +390,58 @@ export default function AppearanceSettingsPage() { onCheckedChange={setReduceMotion} testId="reduce-motion-toggle" /> + +
+ + + {zoomPercent}% + + + +
+
diff --git a/docs/loop/feature-ledger.md b/docs/loop/feature-ledger.md index 51235562a..c40101c45 100644 --- a/docs/loop/feature-ledger.md +++ b/docs/loop/feature-ledger.md @@ -32,7 +32,16 @@ log, not the system of record. | slug | title | source | feasibility | status | issue | pr | branch | updated | notes | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| reduce-motion | "Reduce motion" accessibility setting in Appearance | Claude desktop / macOS / Windows reduce-motion + `prefers-reduced-motion` | frontend-only | pr-open | [#50](https://github.com/modelstudioai/openwork/issues/50) | [#51](https://github.com/modelstudioai/openwork/pull/51) | loop/reduce-motion | 2026-07-03 | Renderer-only pref (localStorage) applied app-wide via `` + `data-reduce-motion` on `` + global CSS guard. Off ⇒ `reducedMotion="user"` (still honors OS). New `ReduceMotionProvider` in `main.tsx`; toggle in Appearance→Interface; 2 new i18n keys ×7 locales. typecheck/`bun test` zero-delta vs main (56-failure set byte-identical); renderer build ✅; i18n parity ✅. CDP assertion included; **could not run locally** (egress 403s Electron binary download). | +| interface-zoom | Interface zoom (⌘+/⌘-/⌘0) to scale the whole app | Claude Desktop / VS Code / Codex desktop View→Zoom In/Out/Actual Size | frontend-only | pr-open | [#68](https://github.com/modelstudioai/openwork/issues/68) | [#69](https://github.com/modelstudioai/openwork/pull/69) | loop/interface-zoom | 2026-07-08 | New `ZoomProvider` (mirrors `ReduceMotionProvider`) scales whole renderer via `document.documentElement.style.zoom`, discrete 50–200% steps, persisted in localStorage (`craft-zoom-level`). 3 View actions `view.zoomIn/Out/Reset` (`mod+=`/`mod+-`/`mod+0`) → auto in Command Palette + Shortcuts ref, wired via `ZoomHotkeys` bridge. Stepper in Appearance→Interface. 5 i18n keys ×7 locales. typecheck/`bun test` zero-delta vs main (56-failure set byte-identical); renderer build ✅; lint 0 errors; i18n parity ✅ (1549 keys). CDP assertion included; **could not run locally** (org egress 403 on Electron binary download — same block as #51). Distinct from chat-text-size (#64)/conversation-width (#62): scales entire UI, not just chat text. | +| increase-contrast | "Increase contrast" accessibility setting in Appearance | Claude / macOS / Windows increase-contrast | frontend-only | pr-open | [#66](https://github.com/modelstudioai/openwork/issues/66) | [#67](https://github.com/modelstudioai/openwork/pull/67) | — | 2026-07-08 | Opened by a prior run (not this ledger's author); reconciled from GitHub. Awaiting review. | +| chat-text-size | "Chat text size" (Small/Default/Large) in Appearance | Claude / ChatGPT desktop message text size | frontend-only | pr-open | [#64](https://github.com/modelstudioai/openwork/issues/64) | [#65](https://github.com/modelstudioai/openwork/pull/65) | — | 2026-07-08 | Prior run; reconciled from GitHub. Awaiting review. | +| conversation-width | "Conversation width" (Comfortable/Wide/Full) in Appearance | Claude / ChatGPT desktop content width | frontend-only | pr-open | [#62](https://github.com/modelstudioai/openwork/issues/62) | [#63](https://github.com/modelstudioai/openwork/pull/63) | — | 2026-07-08 | Prior run; reconciled from GitHub. Awaiting review. | +| composer-word-count | Live word / character count indicator in the composer | Codex / ChatGPT desktop composer counter | frontend-only | pr-open | [#60](https://github.com/modelstudioai/openwork/issues/60) | [#61](https://github.com/modelstudioai/openwork/pull/61) | — | 2026-07-08 | Prior run; reconciled from GitHub. Awaiting review. | +| shortcuts-search | Search box on Settings → Keyboard Shortcuts page | Claude / VS Code shortcuts search | frontend-only | pr-open | [#58](https://github.com/modelstudioai/openwork/issues/58) | [#59](https://github.com/modelstudioai/openwork/pull/59) | — | 2026-07-08 | Prior run; reconciled from GitHub. Awaiting review. | +| palette-recent | Surface recently-used commands in Command Palette (⌘K) | VS Code / Linear recent commands | frontend-only | pr-open | [#56](https://github.com/modelstudioai/openwork/issues/56) | [#57](https://github.com/modelstudioai/openwork/pull/57) | — | 2026-07-08 | Prior run; reconciled from GitHub. Awaiting review. | +| thinking-menu-shortcut | Keyboard shortcut (⌘⇧E) to open composer thinking menu | Claude Code Desktop ⌘⇧E | frontend-only | pr-open | [#54](https://github.com/modelstudioai/openwork/issues/54) | [#55](https://github.com/modelstudioai/openwork/pull/55) | loop/thinking-menu-shortcut | 2026-07-08 | Prior run; reconciled from GitHub. Awaiting review. | +| recall-prompts | Recall previously-sent prompts with Up/Down in composer | Claude Code / ChatGPT / shell history recall | frontend-only | pr-open | [#52](https://github.com/modelstudioai/openwork/issues/52) | [#53](https://github.com/modelstudioai/openwork/pull/53) | — | 2026-07-08 | Prior run; reconciled from GitHub. Awaiting review. | +| reduce-motion | "Reduce motion" accessibility setting in Appearance | Claude desktop / macOS / Windows reduce-motion + `prefers-reduced-motion` | frontend-only | merged | [#50](https://github.com/modelstudioai/openwork/issues/50) | [#51](https://github.com/modelstudioai/openwork/pull/51) | loop/reduce-motion | 2026-07-06 | **Merged** into `main` (2026-07-06). Renderer-only pref (localStorage) applied app-wide via `` + `data-reduce-motion` on `` + global CSS guard. New `ReduceMotionProvider` in `main.tsx`; toggle in Appearance→Interface; 2 new i18n keys ×7 locales. Provider pattern reused by interface-zoom (#69). | | composer-expand | Expand / collapse (maximize) toggle for the chat composer | Claude/ChatGPT/Codex desktop composer maximize | frontend-only | pr-open | [#48](https://github.com/modelstudioai/openwork/issues/48) | [#49](https://github.com/modelstudioai/openwork/pull/49) | loop/composer-expand | 2026-07-03 | Opened by a prior run. Adds `isComposerExpanded` toggle in `FreeFormInput`; 2 new i18n keys. Awaiting review. | | scroll-to-bottom | "Jump to latest" (scroll-to-bottom) button in the chat transcript | Claude Code / ChatGPT / Codex desktop | frontend-only | pr-open | [#46](https://github.com/modelstudioai/openwork/issues/46) | [#47](https://github.com/modelstudioai/openwork/pull/47) | loop/scroll-to-bottom | 2026-07-02 | Opened by a prior run. Floating jump button in `ChatDisplay` + `seed()` harness hook. Awaiting review. | | thinking-level-picker | Thinking-level (reasoning effort) picker in the chat composer | Claude Code Desktop effort menu (⌘⇧E) + OpenWork's own model picker | frontend-only | merged | [#44](https://github.com/modelstudioai/openwork/issues/44) | [#45](https://github.com/modelstudioai/openwork/pull/45) | loop/thinking-level-picker | 2026-07-03 | **Merged** into `main` (2026-07-02). `thinkingLevel`/`onThinkingLevelChange` already plumbed to `FreeFormInput`; only the UI trigger was missing. Reuses `thinking.*` + `settings.ai.thinking` i18n keys (zero new keys). | diff --git a/e2e/assertions/zoom.assert.ts b/e2e/assertions/zoom.assert.ts new file mode 100644 index 000000000..9abed1b5e --- /dev/null +++ b/e2e/assertions/zoom.assert.ts @@ -0,0 +1,104 @@ +/** + * Feature assertion: the interface-zoom control in Settings → Appearance + * actually scales the whole renderer and persists the preference. + * + * Drives the real UI over CDP entirely in the draft/no-session state (no seeded + * conversation, no backend): opens Settings → Appearance → Interface, uses the + * Zoom stepper, and asserts the observable effects — the displayed percentage, + * the inline `zoom` style on (which is what scales the app), and the + * persisted localStorage value. Zooming in then resetting proves it both + * applies and reverts, not merely renders. + */ + +import type { Assertion } from '../runner'; + +const SETTINGS_NAV = '[data-testid="nav:settings"]'; +const APPEARANCE_NAV = '[data-testid="settings-nav-appearance"]'; +const ZOOM_CONTROL = '[data-testid="zoom-control"]'; +const ZOOM_IN = '[data-testid="zoom-in"]'; +const ZOOM_RESET = '[data-testid="zoom-reset"]'; +const ZOOM_VALUE = '[data-testid="zoom-value"]'; +const STORAGE_KEY = 'craft-zoom-level'; + +/** The stepper's displayed percentage text (e.g. "100%"). */ +function valueTextExpr(): string { + return `(() => { + const el = document.querySelector(${JSON.stringify(ZOOM_VALUE)}); + return el ? el.textContent : null; + })()`; +} + +/** The inline zoom factor applied to ("" when unset). */ +function htmlZoomExpr(): string { + return `document.documentElement.style.zoom`; +} + +/** The persisted localStorage value for the preference. */ +function storedValueExpr(): string { + return `window.localStorage.getItem(${JSON.stringify(STORAGE_KEY)})`; +} + +const assertion: Assertion = { + name: 'interface zoom scales and persists the preference', + async run(app) { + const { session } = app; + + // App fully mounted. + await session.waitForFunction( + '!document.getElementById("_loader") && (document.getElementById("root")?.childElementCount ?? 0) > 0', + { timeoutMs: 30000, message: 'app did not mount' }, + ); + + // Open Settings → Appearance (real user path). + await session.click(SETTINGS_NAV, { timeoutMs: 15000 }); + await session.click(APPEARANCE_NAV, { timeoutMs: 15000 }); + + // The zoom control is the feature under test — its presence is the first signal. + await session.waitForSelector(ZOOM_CONTROL, { + timeoutMs: 15000, + message: 'zoom control did not render', + }); + + // Initial state: 100%, no inline zoom on . + const initialText = await session.evaluate(valueTextExpr()); + if (initialText !== '100%') { + throw new Error(`expected "100%" initially, saw ${JSON.stringify(initialText)}`); + } + const initialZoom = await session.evaluate(htmlZoomExpr()); + if (initialZoom !== '') { + throw new Error(`expected no inline zoom on initially, saw ${JSON.stringify(initialZoom)}`); + } + + // Zoom in → percentage rises, scaled, persisted. + await session.click(ZOOM_IN); + await session.waitForFunction( + `${valueTextExpr()} === '110%'`, + { timeoutMs: 5000, message: 'zoom-in did not raise the displayed percentage to 110%' }, + ); + await session.waitForFunction( + `${htmlZoomExpr()} === '1.1'`, + { timeoutMs: 5000, message: 'zoom-in did not apply zoom:1.1 to ' }, + ); + const storedOn = await session.evaluate(storedValueExpr()); + if (storedOn !== '1.1') { + throw new Error(`expected persisted "1.1" after zoom-in, saw ${JSON.stringify(storedOn)}`); + } + + // Reset → back to 100%, inline zoom cleared, persisted default restored. + await session.click(ZOOM_RESET); + await session.waitForFunction( + `${valueTextExpr()} === '100%'`, + { timeoutMs: 5000, message: 'reset did not return the displayed percentage to 100%' }, + ); + await session.waitForFunction( + `${htmlZoomExpr()} === ''`, + { timeoutMs: 5000, message: 'reset did not clear the inline zoom on ' }, + ); + const storedOff = await session.evaluate(storedValueExpr()); + if (storedOff !== '1') { + throw new Error(`expected persisted "1" after reset, saw ${JSON.stringify(storedOff)}`); + } + }, +}; + +export default assertion; diff --git a/packages/shared/src/i18n/locales/de.json b/packages/shared/src/i18n/locales/de.json index d407e5dbb..b6425a23c 100644 --- a/packages/shared/src/i18n/locales/de.json +++ b/packages/shared/src/i18n/locales/de.json @@ -787,6 +787,8 @@ "settings.appearance.richToolDescriptions": "Ausführliche Werkzeugbeschreibungen", "settings.appearance.reduceMotion": "Bewegung reduzieren", "settings.appearance.reduceMotionDesc": "Animationen und Übergänge in der gesamten App minimieren.", + "settings.appearance.zoom": "Zoom", + "settings.appearance.zoomDesc": "Die gesamte Benutzeroberfläche vergrößern oder verkleinern.", "settings.appearance.pet": "Begleiter", "settings.appearance.petDesc": "Ein Begleiter, der auf die Aktivität des Agents reagiert.", "settings.appearance.petEnabled": "Begleiter anzeigen", @@ -1172,6 +1174,9 @@ "shortcuts.action.stopProcessing": "Verarbeitung stoppen", "shortcuts.action.toggleFocusMode": "Fokusmodus umschalten", "shortcuts.action.toggleSidebar": "Seitenleiste umschalten", + "shortcuts.action.zoomIn": "Vergrößern", + "shortcuts.action.zoomOut": "Verkleinern", + "shortcuts.action.zoomReset": "Zoom zurücksetzen", "shortcuts.action.toggleTheme": "Design umschalten", "shortcuts.addFilterExcluded": "Filter als ausgeschlossen hinzufügen", "shortcuts.agentTree": "Agentenbaum", diff --git a/packages/shared/src/i18n/locales/en.json b/packages/shared/src/i18n/locales/en.json index 6a06e456e..267f0e5f1 100644 --- a/packages/shared/src/i18n/locales/en.json +++ b/packages/shared/src/i18n/locales/en.json @@ -787,6 +787,8 @@ "settings.appearance.richToolDescriptions": "Rich tool descriptions", "settings.appearance.reduceMotion": "Reduce motion", "settings.appearance.reduceMotionDesc": "Minimize animations and transitions throughout the app.", + "settings.appearance.zoom": "Zoom", + "settings.appearance.zoomDesc": "Scale the entire interface up or down.", "settings.appearance.pet": "Pet", "settings.appearance.petDesc": "A companion that reacts to what the agent is doing.", "settings.appearance.petEnabled": "Show pet companion", @@ -1172,6 +1174,9 @@ "shortcuts.action.stopProcessing": "Stop Processing", "shortcuts.action.toggleFocusMode": "Toggle Focus Mode", "shortcuts.action.toggleSidebar": "Toggle Sidebar", + "shortcuts.action.zoomIn": "Zoom In", + "shortcuts.action.zoomOut": "Zoom Out", + "shortcuts.action.zoomReset": "Reset Zoom", "shortcuts.action.toggleTheme": "Toggle Theme", "shortcuts.addFilterExcluded": "Add filter as excluded", "shortcuts.agentTree": "Agent Tree", diff --git a/packages/shared/src/i18n/locales/es.json b/packages/shared/src/i18n/locales/es.json index 6461320a6..60a754165 100644 --- a/packages/shared/src/i18n/locales/es.json +++ b/packages/shared/src/i18n/locales/es.json @@ -787,6 +787,8 @@ "settings.appearance.richToolDescriptions": "Descripciones detalladas de herramientas", "settings.appearance.reduceMotion": "Reducir movimiento", "settings.appearance.reduceMotionDesc": "Minimiza las animaciones y transiciones en toda la aplicación.", + "settings.appearance.zoom": "Zoom", + "settings.appearance.zoomDesc": "Escala toda la interfaz para hacerla más grande o más pequeña.", "settings.appearance.pet": "Mascota", "settings.appearance.petDesc": "Un compañero que reacciona a lo que hace el agente.", "settings.appearance.petEnabled": "Mostrar mascota", @@ -1172,6 +1174,9 @@ "shortcuts.action.stopProcessing": "Detener procesamiento", "shortcuts.action.toggleFocusMode": "Alternar modo enfoque", "shortcuts.action.toggleSidebar": "Alternar barra lateral", + "shortcuts.action.zoomIn": "Acercar", + "shortcuts.action.zoomOut": "Alejar", + "shortcuts.action.zoomReset": "Restablecer zoom", "shortcuts.action.toggleTheme": "Cambiar tema", "shortcuts.addFilterExcluded": "Agregar filtro como excluido", "shortcuts.agentTree": "Árbol de agentes", diff --git a/packages/shared/src/i18n/locales/hu.json b/packages/shared/src/i18n/locales/hu.json index 641c6d16f..be4236aa2 100644 --- a/packages/shared/src/i18n/locales/hu.json +++ b/packages/shared/src/i18n/locales/hu.json @@ -787,6 +787,8 @@ "settings.appearance.richToolDescriptions": "Részletes eszközleírások", "settings.appearance.reduceMotion": "Mozgás csökkentése", "settings.appearance.reduceMotionDesc": "Az animációk és átmenetek minimalizálása az egész alkalmazásban.", + "settings.appearance.zoom": "Nagyítás", + "settings.appearance.zoomDesc": "A teljes felület nagyítása vagy kicsinyítése.", "settings.appearance.pet": "Kabala", "settings.appearance.petDesc": "Egy társ, aki reagál arra, amit az ügynök csinál.", "settings.appearance.petEnabled": "Kabala megjelenítése", @@ -1172,6 +1174,9 @@ "shortcuts.action.stopProcessing": "Feldolgozás leállítása", "shortcuts.action.toggleFocusMode": "Fókusz mód be/ki", "shortcuts.action.toggleSidebar": "Oldalsáv be/ki", + "shortcuts.action.zoomIn": "Nagyítás", + "shortcuts.action.zoomOut": "Kicsinyítés", + "shortcuts.action.zoomReset": "Nagyítás visszaállítása", "shortcuts.action.toggleTheme": "Téma váltása", "shortcuts.addFilterExcluded": "Szűrő hozzáadása kizártként", "shortcuts.agentTree": "Ügynökfa", diff --git a/packages/shared/src/i18n/locales/ja.json b/packages/shared/src/i18n/locales/ja.json index 5e2191990..5b94b3d4c 100644 --- a/packages/shared/src/i18n/locales/ja.json +++ b/packages/shared/src/i18n/locales/ja.json @@ -787,6 +787,8 @@ "settings.appearance.richToolDescriptions": "リッチなツール説明", "settings.appearance.reduceMotion": "モーションを減らす", "settings.appearance.reduceMotionDesc": "アプリ全体のアニメーションとトランジションを最小限にします。", + "settings.appearance.zoom": "ズーム", + "settings.appearance.zoomDesc": "インターフェース全体を拡大または縮小します。", "settings.appearance.pet": "ペット", "settings.appearance.petDesc": "エージェントの動きに反応するコンパニオン。", "settings.appearance.petEnabled": "ペットを表示", @@ -1172,6 +1174,9 @@ "shortcuts.action.stopProcessing": "処理を停止", "shortcuts.action.toggleFocusMode": "フォーカスモードの切り替え", "shortcuts.action.toggleSidebar": "サイドバーの切り替え", + "shortcuts.action.zoomIn": "拡大", + "shortcuts.action.zoomOut": "縮小", + "shortcuts.action.zoomReset": "ズームをリセット", "shortcuts.action.toggleTheme": "テーマの切り替え", "shortcuts.addFilterExcluded": "除外フィルターとして追加", "shortcuts.agentTree": "エージェントツリー", diff --git a/packages/shared/src/i18n/locales/pl.json b/packages/shared/src/i18n/locales/pl.json index f85aa9c9f..7bead0703 100644 --- a/packages/shared/src/i18n/locales/pl.json +++ b/packages/shared/src/i18n/locales/pl.json @@ -787,6 +787,8 @@ "settings.appearance.richToolDescriptions": "Rozbudowane opisy narzędzi", "settings.appearance.reduceMotion": "Ogranicz ruch", "settings.appearance.reduceMotionDesc": "Ogranicz animacje i przejścia w całej aplikacji.", + "settings.appearance.zoom": "Powiększenie", + "settings.appearance.zoomDesc": "Skaluj cały interfejs w górę lub w dół.", "settings.appearance.pet": "Maskotka", "settings.appearance.petDesc": "Towarzysz reagujący na to, co robi agent.", "settings.appearance.petEnabled": "Pokaż maskotkę", @@ -1172,6 +1174,9 @@ "shortcuts.action.stopProcessing": "Zatrzymaj przetwarzanie", "shortcuts.action.toggleFocusMode": "Przełącz tryb skupienia", "shortcuts.action.toggleSidebar": "Przełącz pasek boczny", + "shortcuts.action.zoomIn": "Powiększ", + "shortcuts.action.zoomOut": "Pomniejsz", + "shortcuts.action.zoomReset": "Resetuj powiększenie", "shortcuts.action.toggleTheme": "Przełącz motyw", "shortcuts.addFilterExcluded": "Dodaj filtr jako wykluczony", "shortcuts.agentTree": "Drzewo agentów", diff --git a/packages/shared/src/i18n/locales/zh-Hans.json b/packages/shared/src/i18n/locales/zh-Hans.json index 845231913..c6e680eff 100644 --- a/packages/shared/src/i18n/locales/zh-Hans.json +++ b/packages/shared/src/i18n/locales/zh-Hans.json @@ -787,6 +787,8 @@ "settings.appearance.richToolDescriptions": "丰富的工具描述", "settings.appearance.reduceMotion": "减少动态效果", "settings.appearance.reduceMotionDesc": "在整个应用中尽量减少动画和过渡效果。", + "settings.appearance.zoom": "缩放", + "settings.appearance.zoomDesc": "放大或缩小整个界面。", "settings.appearance.pet": "宠物", "settings.appearance.petDesc": "一个会根据 agent 当前状态做出反应的小伙伴。", "settings.appearance.petEnabled": "显示宠物伙伴", @@ -1172,6 +1174,9 @@ "shortcuts.action.stopProcessing": "停止处理", "shortcuts.action.toggleFocusMode": "切换专注模式", "shortcuts.action.toggleSidebar": "切换侧栏", + "shortcuts.action.zoomIn": "放大", + "shortcuts.action.zoomOut": "缩小", + "shortcuts.action.zoomReset": "重置缩放", "shortcuts.action.toggleTheme": "切换主题", "shortcuts.addFilterExcluded": "添加为排除筛选", "shortcuts.agentTree": "智能体树",