diff --git a/apps/electron/src/renderer/components/app-shell/ChatDisplay.tsx b/apps/electron/src/renderer/components/app-shell/ChatDisplay.tsx index 1ee9b7973..8a0fd6744 100644 --- a/apps/electron/src/renderer/components/app-shell/ChatDisplay.tsx +++ b/apps/electron/src/renderer/components/app-shell/ChatDisplay.tsx @@ -1699,7 +1699,7 @@ export const ChatDisplay = React.forwardRef
{/* Session-level AnimatePresence: Prevents layout jump when switching sessions */} diff --git a/apps/electron/src/renderer/components/settings/SettingsSegmentedControl.tsx b/apps/electron/src/renderer/components/settings/SettingsSegmentedControl.tsx index 815300b5c..1d1f78b50 100644 --- a/apps/electron/src/renderer/components/settings/SettingsSegmentedControl.tsx +++ b/apps/electron/src/renderer/components/settings/SettingsSegmentedControl.tsx @@ -28,6 +28,12 @@ export interface SettingsSegmentedControlProps { size?: 'sm' | 'md' /** Additional className */ className?: string + /** + * Optional test id. When set, `data-testid` is applied to the group and each + * option button additionally carries a `data-value` attribute, so tests can + * address a specific segment without depending on its (localized) label. + */ + testId?: string } /** @@ -50,11 +56,13 @@ export function SettingsSegmentedControl({ options, size = 'md', className, + testId, }: SettingsSegmentedControlProps) { return (
{options.map((option) => { const isSelected = option.value === value @@ -65,6 +73,7 @@ export function SettingsSegmentedControl({ type="button" role="radio" aria-checked={isSelected} + data-value={testId ? option.value : undefined} onClick={() => onValueChange(option.value)} className={cn( 'flex items-center gap-1.5 rounded-lg transition-all', diff --git a/apps/electron/src/renderer/context/ChatTextSizeContext.tsx b/apps/electron/src/renderer/context/ChatTextSizeContext.tsx new file mode 100644 index 000000000..1a16896b8 --- /dev/null +++ b/apps/electron/src/renderer/context/ChatTextSizeContext.tsx @@ -0,0 +1,90 @@ +/** + * ChatTextSizeContext + * + * App-wide "Chat text size" preference — scales the typography of the + * conversation transcript without resizing the rest of the app. + * + * Unlike the OS-level window zoom wired to the View menu + * (`webContents.setZoomFactor`), which scales the entire UI (sidebar, toolbar, + * composer, icons, spacing), this preference only affects the reading text in + * chat. It works by reflecting the choice onto `` as + * `data-chat-text-size="small|medium|large"`; the global CSS in `index.css` + * maps that to a `--chat-font-scale` custom property, which the chat transcript + * container (`.chat-text-scope` in `ChatDisplay`) consumes via + * `font-size: calc(1em * var(--chat-font-scale))`. Because the scale is + * `em`-relative it is exactly neutral at `medium` (1×) and scales the inherited + * message text up/down at `small` (0.9×) / `large` (1.15×). + * + * The preference is persisted in `localStorage` (renderer-only, no backend), + * mirroring the other lightweight UI prefs in `lib/local-storage.ts` and the + * sibling `ReduceMotionContext`. + */ + +import React, { + createContext, + useContext, + useState, + useEffect, + useCallback, + type ReactNode, +} from 'react' +import * as storage from '@/lib/local-storage' + +export type ChatTextSize = 'small' | 'medium' | 'large' + +const CHAT_TEXT_SIZES: readonly ChatTextSize[] = ['small', 'medium', 'large'] + +const DEFAULT_CHAT_TEXT_SIZE: ChatTextSize = 'medium' + +interface ChatTextSizeContextType { + chatTextSize: ChatTextSize + setChatTextSize: (value: ChatTextSize) => void +} + +const ChatTextSizeContext = createContext(null) + +const CHAT_TEXT_SIZE_ATTR = 'data-chat-text-size' + +/** Guard against malformed persisted values. */ +function normalize(value: unknown): ChatTextSize { + return CHAT_TEXT_SIZES.includes(value as ChatTextSize) + ? (value as ChatTextSize) + : DEFAULT_CHAT_TEXT_SIZE +} + +/** Reflect the preference onto so the global CSS var can react. */ +function applyChatTextSizeAttribute(size: ChatTextSize): void { + document.documentElement.setAttribute(CHAT_TEXT_SIZE_ATTR, size) +} + +export function ChatTextSizeProvider({ children }: { children: ReactNode }) { + const [chatTextSize, setChatTextSizeState] = useState(() => + normalize(storage.get(storage.KEYS.chatTextSize, DEFAULT_CHAT_TEXT_SIZE)), + ) + + // Keep the DOM attribute in sync (also covers the initial value on mount). + useEffect(() => { + applyChatTextSizeAttribute(chatTextSize) + }, [chatTextSize]) + + const setChatTextSize = useCallback((value: ChatTextSize) => { + const next = normalize(value) + setChatTextSizeState(next) + storage.set(storage.KEYS.chatTextSize, next) + applyChatTextSizeAttribute(next) + }, []) + + return ( + + {children} + + ) +} + +export function useChatTextSize(): ChatTextSizeContextType { + const ctx = useContext(ChatTextSizeContext) + if (!ctx) { + throw new Error('useChatTextSize must be used within a ChatTextSizeProvider') + } + return ctx +} diff --git a/apps/electron/src/renderer/index.css b/apps/electron/src/renderer/index.css index 5efb958b0..8d2eeb0a5 100644 --- a/apps/electron/src/renderer/index.css +++ b/apps/electron/src/renderer/index.css @@ -1386,3 +1386,23 @@ html.dark[data-scenic] .fullscreen-overlay-background { transition-delay: 0ms !important; scroll-behavior: auto !important; } + +/* Chat text size: the "Chat text size" control in Appearance settings reflects + its choice onto as data-chat-text-size. That maps to the + --chat-font-scale custom property, which the chat transcript container + (.chat-text-scope) consumes as `font-size: calc(1em * var(--chat-font-scale))`. + Being em-relative keeps the default (medium) exactly neutral and scales only + the conversation's reading text — the sidebar, top bar, composer, and icons + keep their native size. */ +:root { + --chat-font-scale: 1; +} +[data-chat-text-size='small'] { + --chat-font-scale: 0.9; +} +[data-chat-text-size='large'] { + --chat-font-scale: 1.15; +} +.chat-text-scope { + font-size: calc(1em * var(--chat-font-scale)); +} diff --git a/apps/electron/src/renderer/lib/local-storage.ts b/apps/electron/src/renderer/lib/local-storage.ts index 4d6446afd..bc03be0b4 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 + chatTextSize: 'chat-text-size', // Scale conversation text without resizing the app chrome // 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..1eaf65ccb 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 { ChatTextSizeProvider } from './context/ChatTextSizeContext' 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..96adcab02 100644 --- a/apps/electron/src/renderer/pages/settings/AppearanceSettingsPage.tsx +++ b/apps/electron/src/renderer/pages/settings/AppearanceSettingsPage.tsx @@ -15,6 +15,7 @@ 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 { useChatTextSize, type ChatTextSize } from '@/context/ChatTextSizeContext' import { useAppShellContext } from '@/context/AppShellContext' import { routes } from '@/lib/navigate' import { FolderOpen, Monitor, RefreshCw, Sun, Moon } from 'lucide-react' @@ -143,6 +144,9 @@ export default function AppearanceSettingsPage() { // Reduce motion toggle (renderer-only preference, persisted in localStorage) const { reduceMotion, setReduceMotion } = useReduceMotion() + // Chat text size (renderer-only preference, persisted in localStorage) + const { chatTextSize, setChatTextSize } = useChatTextSize() + // Pet companion settings + custom pets (synced via shared Jotai atoms) const { pets, @@ -387,6 +391,21 @@ export default function AppearanceSettingsPage() { onCheckedChange={setReduceMotion} testId="reduce-motion-toggle" /> + + setChatTextSize(value as ChatTextSize)} + testId="chat-text-size-control" + options={[ + { value: 'small', label: t("settings.appearance.chatTextSizeSmall") }, + { value: 'medium', label: t("settings.appearance.chatTextSizeDefault") }, + { value: 'large', label: t("settings.appearance.chatTextSizeLarge") }, + ]} + /> + diff --git a/docs/loop/feature-ledger.md b/docs/loop/feature-ledger.md index 51235562a..35123f8bf 100644 --- a/docs/loop/feature-ledger.md +++ b/docs/loop/feature-ledger.md @@ -32,7 +32,14 @@ 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). | +| chat-text-size | "Chat text size" setting (Small / Default / Large) in Appearance | Claude Desktop "Chat font" + anthropics/claude-code #50543/#48887; ChatGPT desktop font-size requests | frontend-only | pr-open | [#64](https://github.com/modelstudioai/openwork/issues/64) | [#65](https://github.com/modelstudioai/openwork/pull/65) | loop/chat-text-size | 2026-07-07 | Renderer-only pref (localStorage `craft-chat-text-size`) reflected onto `` as `data-chat-text-size` + `--chat-font-scale` CSS var (0.9/1/1.15). Transcript container gets `.chat-text-scope` with `font-size: calc(1em * var(--chat-font-scale))` — em-relative ⇒ neutral at Default, scales only conversation text (chrome untouched). New `ChatTextSizeProvider`; segmented control in Appearance→Interface; `SettingsSegmentedControl` gained optional `testId`/`data-value`; 5 new i18n keys ×7 locales. typecheck/`bun test` **zero-delta vs main** (11 pre-existing tsc errors + 56 pre-existing fail-lines byte-identical); renderer build ✅; i18n parity ✅. CDP assertion authored (drives control, asserts attr/CSS-var/localStorage + probe computed font-size ratio ~1.15/0.9); **could not execute** — Electron runtime binary download is org-egress-policy 403 (same block as #51). | +| conversation-width | "Conversation width" setting (Comfortable / Wide / Full) in Appearance | Claude/ChatGPT/Codex desktop content-width settings | frontend-only | pr-open | [#62](https://github.com/modelstudioai/openwork/issues/62) | [#63](https://github.com/modelstudioai/openwork/pull/63) | loop/conversation-width | 2026-07-07 | Opened by a prior run; reconciled from GitHub. `ConversationWidthProvider` + `data-conversation-width` + `--chat-content-max-width`. Awaiting review. | +| composer-word-count | Live word / character count indicator in the chat composer | Claude/ChatGPT/Codex desktop composer meta | frontend-only | pr-open | [#60](https://github.com/modelstudioai/openwork/issues/60) | [#61](https://github.com/modelstudioai/openwork/pull/61) | loop/composer-word-count | 2026-07-07 | Opened by a prior run; reconciled from GitHub. Awaiting review. | +| shortcuts-search | Search box on the Settings → Keyboard Shortcuts page | VS Code / Codex keyboard-shortcuts search | frontend-only | pr-open | [#58](https://github.com/modelstudioai/openwork/issues/58) | [#59](https://github.com/modelstudioai/openwork/pull/59) | loop/shortcuts-search | 2026-07-07 | Opened by a prior run; reconciled from GitHub. Awaiting review. | +| command-palette-recents | Surface recently-used commands in the Command Palette (⌘K) | Claude Code / 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) | loop/command-palette-recents | 2026-07-07 | Opened by a prior run; reconciled from GitHub. Awaiting review. | +| thinking-menu-shortcut | Keyboard shortcut (⌘⇧E) to open the composer's thinking-effort 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-07 | Opened by a prior run; reconciled from GitHub. Awaiting review. | +| composer-prompt-history | Recall previously-sent prompts in the composer with Up / Down | Claude Code / shell-style prompt history | frontend-only | pr-open | [#52](https://github.com/modelstudioai/openwork/issues/52) | [#53](https://github.com/modelstudioai/openwork/pull/53) | loop/composer-prompt-history | 2026-07-07 | Opened by a 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-07 | **Merged** into `main`. 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. Established the provider+data-attr+CSS pattern reused by chat-text-size and conversation-width. | | 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/chat-text-size.assert.ts b/e2e/assertions/chat-text-size.assert.ts new file mode 100644 index 000000000..e3f72af9b --- /dev/null +++ b/e2e/assertions/chat-text-size.assert.ts @@ -0,0 +1,185 @@ +/** + * Feature assertion: the "Chat text size" segmented control in + * Settings → Appearance actually applies and persists an app-wide preference + * that scales conversation typography. + * + * Drives the real UI over CDP in the draft/no-session state (no seeded + * conversation, no backend): opens Settings → Appearance and clicks through the + * Small / Default / Large segments, asserting the observable effects at each + * step: + * - the selected segment's `aria-checked`, + * - the `data-chat-text-size` attribute on , + * - the resolved `--chat-font-scale` CSS custom property, + * - the persisted `localStorage` value, and + * - crucially, the *rendered* computed `font-size` of a probe element that + * carries the real `.chat-text-scope` class the transcript uses — proving + * the mechanism produces a real pixel-level text-size change, not merely an + * attribute flip. + * + * Cycling Default → Large → Small → Default proves it applies, changes, and + * reverts. + */ + +import type { Assertion } from '../runner'; + +const SETTINGS_NAV = '[data-testid="nav:settings"]'; +const APPEARANCE_NAV = '[data-testid="settings-nav-appearance"]'; +const CONTROL = '[data-testid="chat-text-size-control"]'; +const STORAGE_KEY = 'craft-chat-text-size'; + +/** Selector for a specific segment button. */ +function segment(value: string): string { + return `${CONTROL} [data-value="${value}"]`; +} + +/** aria-checked ("true" | "false" | null) for a specific segment. */ +function ariaCheckedExpr(value: string): string { + return `(() => { + const el = document.querySelector(${JSON.stringify(segment(value))}); + return el ? el.getAttribute('aria-checked') : null; + })()`; +} + +/** The current data-chat-text-size marker on . */ +const htmlAttrExpr = `document.documentElement.getAttribute('data-chat-text-size')`; + +/** The resolved --chat-font-scale custom property (trimmed string). */ +const cssScaleExpr = `getComputedStyle(document.documentElement).getPropertyValue('--chat-font-scale').trim()`; + +/** The persisted localStorage value for the preference. */ +const storedValueExpr = `window.localStorage.getItem(${JSON.stringify(STORAGE_KEY)})`; + +/** + * Computed font-size (px, number) of a hidden probe that carries the real + * `.chat-text-scope` class — i.e. the exact CSS the transcript applies. This + * reflects the live `--chat-font-scale` end-to-end (html attr → CSS var → + * rendered pixels). + */ +const probeFontSizeExpr = `(() => { + let p = document.getElementById('__cts_probe'); + if (!p) { + p = document.createElement('div'); + p.id = '__cts_probe'; + p.className = 'chat-text-scope'; + p.style.position = 'fixed'; + p.style.left = '-9999px'; + p.style.top = '0'; + p.textContent = 'probe'; + document.body.appendChild(p); + } + return parseFloat(getComputedStyle(p).fontSize); +})()`; + +const assertion: Assertion = { + name: 'chat text size control scales conversation typography and persists', + 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 control is the feature under test — its presence is the first signal. + await session.waitForSelector(CONTROL, { + timeoutMs: 15000, + message: 'chat-text-size control did not render', + }); + + // Initial state: Default selected, marked "medium", scale 1. + const initialChecked = await session.evaluate(ariaCheckedExpr('medium')); + if (initialChecked !== 'true') { + throw new Error(`expected Default selected initially, saw medium aria-checked=${initialChecked}`); + } + if (await session.evaluate(htmlAttrExpr) !== 'medium') { + throw new Error('expected data-chat-text-size="medium" initially'); + } + + // Baseline rendered size at Default (scale 1). + const mediumScale = await session.evaluate(cssScaleExpr); + if (mediumScale !== '1') { + throw new Error(`expected --chat-font-scale "1" at Default, saw ${JSON.stringify(mediumScale)}`); + } + const mediumPx = await session.evaluate(probeFontSizeExpr); + if (!(mediumPx > 0)) { + throw new Error(`probe font-size at Default was not positive: ${mediumPx}`); + } + + // ----- Large ----- + await session.click(segment('large')); + await session.waitForFunction(`${ariaCheckedExpr('large')} === 'true'`, { + timeoutMs: 5000, + message: 'Large segment did not become selected', + }); + await session.waitForFunction(`${htmlAttrExpr} === 'large'`, { + timeoutMs: 5000, + message: 'data-chat-text-size was not set to "large"', + }); + const largeScale = await session.evaluate(cssScaleExpr); + if (largeScale !== '1.15') { + throw new Error(`expected --chat-font-scale "1.15" at Large, saw ${JSON.stringify(largeScale)}`); + } + const storedLarge = await session.evaluate(storedValueExpr); + if (storedLarge !== '"large"') { + throw new Error(`expected persisted "large", saw ${JSON.stringify(storedLarge)}`); + } + const largePx = await session.evaluate(probeFontSizeExpr); + // Real rendered effect: Large must be measurably bigger than Default. + if (!(largePx > mediumPx)) { + throw new Error(`expected Large probe font-size (${largePx}px) > Default (${mediumPx}px)`); + } + const largeRatio = largePx / mediumPx; + if (Math.abs(largeRatio - 1.15) > 0.02) { + throw new Error(`expected Large/Default font-size ratio ~1.15, saw ${largeRatio.toFixed(3)}`); + } + + // ----- Small ----- + await session.click(segment('small')); + await session.waitForFunction(`${ariaCheckedExpr('small')} === 'true'`, { + timeoutMs: 5000, + message: 'Small segment did not become selected', + }); + await session.waitForFunction(`${htmlAttrExpr} === 'small'`, { + timeoutMs: 5000, + message: 'data-chat-text-size was not set to "small"', + }); + const smallScale = await session.evaluate(cssScaleExpr); + if (smallScale !== '0.9') { + throw new Error(`expected --chat-font-scale "0.9" at Small, saw ${JSON.stringify(smallScale)}`); + } + const smallPx = await session.evaluate(probeFontSizeExpr); + if (!(smallPx < mediumPx)) { + throw new Error(`expected Small probe font-size (${smallPx}px) < Default (${mediumPx}px)`); + } + const smallRatio = smallPx / mediumPx; + if (Math.abs(smallRatio - 0.9) > 0.02) { + throw new Error(`expected Small/Default font-size ratio ~0.9, saw ${smallRatio.toFixed(3)}`); + } + + // ----- Revert to Default ----- + await session.click(segment('medium')); + await session.waitForFunction(`${ariaCheckedExpr('medium')} === 'true'`, { + timeoutMs: 5000, + message: 'Default segment did not become re-selected', + }); + await session.waitForFunction(`${htmlAttrExpr} === 'medium'`, { + timeoutMs: 5000, + message: 'data-chat-text-size did not revert to "medium"', + }); + const revertedPx = await session.evaluate(probeFontSizeExpr); + if (Math.abs(revertedPx - mediumPx) > 0.5) { + throw new Error(`expected probe font-size to revert to Default (${mediumPx}px), saw ${revertedPx}px`); + } + const storedReverted = await session.evaluate(storedValueExpr); + if (storedReverted !== '"medium"') { + throw new Error(`expected persisted "medium" after revert, saw ${JSON.stringify(storedReverted)}`); + } + }, +}; + +export default assertion; diff --git a/packages/shared/src/i18n/locales/de.json b/packages/shared/src/i18n/locales/de.json index d407e5dbb..bf8f23d3a 100644 --- a/packages/shared/src/i18n/locales/de.json +++ b/packages/shared/src/i18n/locales/de.json @@ -787,6 +787,11 @@ "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.chatTextSize": "Chat-Textgröße", + "settings.appearance.chatTextSizeDesc": "Skaliert den Text in Unterhaltungen, ohne die restliche App zu vergrößern.", + "settings.appearance.chatTextSizeSmall": "Klein", + "settings.appearance.chatTextSizeDefault": "Standard", + "settings.appearance.chatTextSizeLarge": "Groß", "settings.appearance.pet": "Begleiter", "settings.appearance.petDesc": "Ein Begleiter, der auf die Aktivität des Agents reagiert.", "settings.appearance.petEnabled": "Begleiter anzeigen", diff --git a/packages/shared/src/i18n/locales/en.json b/packages/shared/src/i18n/locales/en.json index 6a06e456e..a120f0e71 100644 --- a/packages/shared/src/i18n/locales/en.json +++ b/packages/shared/src/i18n/locales/en.json @@ -787,6 +787,11 @@ "settings.appearance.richToolDescriptions": "Rich tool descriptions", "settings.appearance.reduceMotion": "Reduce motion", "settings.appearance.reduceMotionDesc": "Minimize animations and transitions throughout the app.", + "settings.appearance.chatTextSize": "Chat text size", + "settings.appearance.chatTextSizeDesc": "Scale the text in conversations without resizing the rest of the app.", + "settings.appearance.chatTextSizeSmall": "Small", + "settings.appearance.chatTextSizeDefault": "Default", + "settings.appearance.chatTextSizeLarge": "Large", "settings.appearance.pet": "Pet", "settings.appearance.petDesc": "A companion that reacts to what the agent is doing.", "settings.appearance.petEnabled": "Show pet companion", diff --git a/packages/shared/src/i18n/locales/es.json b/packages/shared/src/i18n/locales/es.json index 6461320a6..474aeae98 100644 --- a/packages/shared/src/i18n/locales/es.json +++ b/packages/shared/src/i18n/locales/es.json @@ -787,6 +787,11 @@ "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.chatTextSize": "Tamaño del texto del chat", + "settings.appearance.chatTextSizeDesc": "Ajusta el tamaño del texto en las conversaciones sin cambiar el resto de la aplicación.", + "settings.appearance.chatTextSizeSmall": "Pequeño", + "settings.appearance.chatTextSizeDefault": "Predeterminado", + "settings.appearance.chatTextSizeLarge": "Grande", "settings.appearance.pet": "Mascota", "settings.appearance.petDesc": "Un compañero que reacciona a lo que hace el agente.", "settings.appearance.petEnabled": "Mostrar mascota", diff --git a/packages/shared/src/i18n/locales/hu.json b/packages/shared/src/i18n/locales/hu.json index 641c6d16f..b287ff5fd 100644 --- a/packages/shared/src/i18n/locales/hu.json +++ b/packages/shared/src/i18n/locales/hu.json @@ -787,6 +787,11 @@ "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.chatTextSize": "Csevegés szövegmérete", + "settings.appearance.chatTextSizeDesc": "A beszélgetések szövegének méretezése az alkalmazás többi részének átméretezése nélkül.", + "settings.appearance.chatTextSizeSmall": "Kicsi", + "settings.appearance.chatTextSizeDefault": "Alapértelmezett", + "settings.appearance.chatTextSizeLarge": "Nagy", "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", diff --git a/packages/shared/src/i18n/locales/ja.json b/packages/shared/src/i18n/locales/ja.json index 5e2191990..6a8f5271a 100644 --- a/packages/shared/src/i18n/locales/ja.json +++ b/packages/shared/src/i18n/locales/ja.json @@ -787,6 +787,11 @@ "settings.appearance.richToolDescriptions": "リッチなツール説明", "settings.appearance.reduceMotion": "モーションを減らす", "settings.appearance.reduceMotionDesc": "アプリ全体のアニメーションとトランジションを最小限にします。", + "settings.appearance.chatTextSize": "チャットの文字サイズ", + "settings.appearance.chatTextSizeDesc": "アプリの他の部分のサイズを変えずに、会話のテキストだけを拡大・縮小します。", + "settings.appearance.chatTextSizeSmall": "小", + "settings.appearance.chatTextSizeDefault": "標準", + "settings.appearance.chatTextSizeLarge": "大", "settings.appearance.pet": "ペット", "settings.appearance.petDesc": "エージェントの動きに反応するコンパニオン。", "settings.appearance.petEnabled": "ペットを表示", diff --git a/packages/shared/src/i18n/locales/pl.json b/packages/shared/src/i18n/locales/pl.json index f85aa9c9f..b67da0420 100644 --- a/packages/shared/src/i18n/locales/pl.json +++ b/packages/shared/src/i18n/locales/pl.json @@ -787,6 +787,11 @@ "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.chatTextSize": "Rozmiar tekstu czatu", + "settings.appearance.chatTextSizeDesc": "Skaluje tekst w rozmowach bez zmiany rozmiaru reszty aplikacji.", + "settings.appearance.chatTextSizeSmall": "Mały", + "settings.appearance.chatTextSizeDefault": "Domyślny", + "settings.appearance.chatTextSizeLarge": "Duży", "settings.appearance.pet": "Maskotka", "settings.appearance.petDesc": "Towarzysz reagujący na to, co robi agent.", "settings.appearance.petEnabled": "Pokaż maskotkę", diff --git a/packages/shared/src/i18n/locales/zh-Hans.json b/packages/shared/src/i18n/locales/zh-Hans.json index 845231913..738fc5dde 100644 --- a/packages/shared/src/i18n/locales/zh-Hans.json +++ b/packages/shared/src/i18n/locales/zh-Hans.json @@ -787,6 +787,11 @@ "settings.appearance.richToolDescriptions": "丰富的工具描述", "settings.appearance.reduceMotion": "减少动态效果", "settings.appearance.reduceMotionDesc": "在整个应用中尽量减少动画和过渡效果。", + "settings.appearance.chatTextSize": "对话文字大小", + "settings.appearance.chatTextSizeDesc": "缩放对话中的文字,而不改变应用其余部分的大小。", + "settings.appearance.chatTextSizeSmall": "小", + "settings.appearance.chatTextSizeDefault": "默认", + "settings.appearance.chatTextSizeLarge": "大", "settings.appearance.pet": "宠物", "settings.appearance.petDesc": "一个会根据 agent 当前状态做出反应的小伙伴。", "settings.appearance.petEnabled": "显示宠物伙伴",