diff --git a/.changeset/terminal-dock-default-height.md b/.changeset/terminal-dock-default-height.md new file mode 100644 index 000000000..9bdbc46fd --- /dev/null +++ b/.changeset/terminal-dock-default-height.md @@ -0,0 +1,5 @@ +--- +"@inkeep/open-knowledge-app": patch +--- + +The integrated terminal now opens at about one third of the window height on first use, instead of a fixed 240px that was often too short to read a command's output without dragging the divider. The default is computed as a fraction of the window height (so it scales with window size) and still respects the existing 120px floor and 50vh ceiling. A height you set by dragging is remembered as before. diff --git a/packages/app/src/lib/terminal-height-store.test.ts b/packages/app/src/lib/terminal-height-store.test.ts index 961db3f81..ccfd56982 100644 --- a/packages/app/src/lib/terminal-height-store.test.ts +++ b/packages/app/src/lib/terminal-height-store.test.ts @@ -21,10 +21,15 @@ function memoryStorage(initial: Record = {}): HeightStorage { } const TALL = 1000; +const TALL_DEFAULT = 333; describe('readTerminalHeight', () => { - test('absent key returns default', () => { - expect(readTerminalHeight(memoryStorage(), TALL)).toBe(DEFAULT_TERMINAL_HEIGHT); + test('absent key returns the ~1/3-viewport default (1000 → 333)', () => { + expect(readTerminalHeight(memoryStorage(), TALL)).toBe(TALL_DEFAULT); + }); + + test('default below the floor on a short viewport clamps up to MIN (300 → 100 → 120)', () => { + expect(readTerminalHeight(memoryStorage(), 300)).toBe(MIN_TERMINAL_HEIGHT); }); test('valid stored height is returned', () => { @@ -50,18 +55,28 @@ describe('readTerminalHeight', () => { test('non-numeric value falls back to default', () => { const s = memoryStorage({ [TERMINAL_HEIGHT_KEY]: 'not a number' }); - expect(readTerminalHeight(s, TALL)).toBe(DEFAULT_TERMINAL_HEIGHT); + expect(readTerminalHeight(s, TALL)).toBe(TALL_DEFAULT); }); test('empty string falls back to default', () => { const s = memoryStorage({ [TERMINAL_HEIGHT_KEY]: '' }); - expect(readTerminalHeight(s, TALL)).toBe(DEFAULT_TERMINAL_HEIGHT); + expect(readTerminalHeight(s, TALL)).toBe(TALL_DEFAULT); }); test('floating-point value is rounded', () => { const s = memoryStorage({ [TERMINAL_HEIGHT_KEY]: '240.6' }); expect(readTerminalHeight(s, TALL)).toBe(240); }); + + test('throwing storage falls back to the fixed pixel default', () => { + const throwing: HeightStorage = { + getItem() { + throw new Error('SecurityError'); + }, + setItem() {}, + }; + expect(readTerminalHeight(throwing, TALL)).toBe(DEFAULT_TERMINAL_HEIGHT); + }); }); describe('writeTerminalHeight', () => { diff --git a/packages/app/src/lib/terminal-height-store.ts b/packages/app/src/lib/terminal-height-store.ts index 71ffe5316..4cb5f1acc 100644 --- a/packages/app/src/lib/terminal-height-store.ts +++ b/packages/app/src/lib/terminal-height-store.ts @@ -2,6 +2,7 @@ export const TERMINAL_HEIGHT_KEY = 'ok-terminal-height-v1'; export const DEFAULT_TERMINAL_HEIGHT = 240; export const MIN_TERMINAL_HEIGHT = 120; +const DEFAULT_TERMINAL_HEIGHT_FRACTION = 1 / 3; const MAX_TERMINAL_HEIGHT_FRACTION = 0.5; export interface HeightStorage { @@ -14,9 +15,15 @@ function maxHeight(viewportHeight: number): number { return Math.max(MIN_TERMINAL_HEIGHT, Math.round(vh * MAX_TERMINAL_HEIGHT_FRACTION)); } +function defaultHeight(viewportHeight: number): number { + const vh = Number.isFinite(viewportHeight) ? viewportHeight : 0; + if (vh <= 0) return DEFAULT_TERMINAL_HEIGHT; + return Math.round(vh * DEFAULT_TERMINAL_HEIGHT_FRACTION); +} + function clamp(px: number, viewportHeight: number): number { const max = maxHeight(viewportHeight); - if (!Number.isFinite(px)) return Math.min(DEFAULT_TERMINAL_HEIGHT, max); + if (!Number.isFinite(px)) return Math.min(defaultHeight(viewportHeight), max); if (px < MIN_TERMINAL_HEIGHT) return MIN_TERMINAL_HEIGHT; if (px > max) return max; return Math.round(px); @@ -32,9 +39,9 @@ export function readTerminalHeight(storage?: HeightStorage, viewportHeight?: num const s = storage ?? localStorage; const vh = viewportHeight ?? currentViewportHeight(); const raw = s.getItem(TERMINAL_HEIGHT_KEY); - if (raw == null) return clamp(DEFAULT_TERMINAL_HEIGHT, vh); + if (raw == null) return clamp(defaultHeight(vh), vh); const parsed = Number.parseInt(raw, 10); - if (!Number.isFinite(parsed)) return clamp(DEFAULT_TERMINAL_HEIGHT, vh); + if (!Number.isFinite(parsed)) return clamp(defaultHeight(vh), vh); return clamp(parsed, vh); } catch { return DEFAULT_TERMINAL_HEIGHT;