Skip to content

Commit 67ee75b

Browse files
Nagi-ovoclaude
andcommitted
fix(chatWidth): adapt width for split-screen / narrow windows
Use screen-relative pixel max-width instead of viewport-relative vw units so chat content fills available space when the window is smaller than the user's intended width (e.g. Windows split-screen). Closes #371 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Entire-Checkpoint: c63020c0c264
1 parent f0cd0a8 commit 67ee75b

2 files changed

Lines changed: 40 additions & 4 deletions

File tree

src/pages/content/chatWidth/__tests__/chatWidth.test.ts

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
22

33
const STYLE_ID = 'gemini-voyager-chat-width';
44
const STORAGE_KEY = 'geminiChatWidth';
5+
const MOCK_SCREEN_WIDTH = 1920;
56

67
type StorageChangeListener = (
78
changes: Record<string, chrome.storage.StorageChange>,
@@ -14,10 +15,15 @@ function getInjectedStyle(): HTMLStyleElement {
1415
return style as HTMLStyleElement;
1516
}
1617

17-
function expectTableRuleWidth(styleText: string, widthVw: number): void {
18-
const escapedWidth = widthVw.toString().replace('.', '\\.');
18+
function percentToPixels(percent: number): number {
19+
return Math.round((percent / 100) * MOCK_SCREEN_WIDTH);
20+
}
21+
22+
function expectTableRuleWidth(styleText: string, percent: number): void {
23+
const px = percentToPixels(percent);
24+
const escapedWidth = px.toString();
1925
const tableRulePattern = new RegExp(
20-
String.raw`\/\* Gemini table containers \*\/[\s\S]*table-block,[\s\S]*\.table-block,[\s\S]*\.table-block \.table-content[\s\S]*\{[\s\S]*max-width: ${escapedWidth}vw !important;[\s\S]*width: min\(100%, ${escapedWidth}vw\) !important;`,
26+
String.raw`\/\* Gemini table containers \*\/[\s\S]*table-block,[\s\S]*\.table-block,[\s\S]*\.table-block \.table-content[\s\S]*\{[\s\S]*max-width: ${escapedWidth}px !important;[\s\S]*width: min\(100%, ${escapedWidth}px\) !important;`,
2127
);
2228
expect(styleText).toMatch(tableRulePattern);
2329
}
@@ -40,6 +46,13 @@ describe('chatWidth', () => {
4046
document.head.innerHTML = '';
4147
document.body.innerHTML = '<main></main>';
4248

49+
// Mock screen dimensions for deterministic tests
50+
Object.defineProperty(window, 'screen', {
51+
value: { availWidth: MOCK_SCREEN_WIDTH, width: MOCK_SCREEN_WIDTH },
52+
writable: true,
53+
configurable: true,
54+
});
55+
4356
storageChangeListeners = [];
4457

4558
(chrome.storage.sync.get as unknown as ReturnType<typeof vi.fn>).mockImplementation(
@@ -86,4 +99,22 @@ describe('chatWidth', () => {
8699
expect(styleText).toContain('table-block .table-content');
87100
expectSingleTableScrollbarRules(styleText);
88101
});
102+
103+
it('adapts width for narrow viewports (split-screen behavior)', async () => {
104+
// Simulate: user sets 70% on a 1920px screen → 1344px max-width
105+
// In split-screen (960px viewport), min(100%, 1344px) fills the viewport
106+
(chrome.storage.sync.get as unknown as ReturnType<typeof vi.fn>).mockImplementation(
107+
(_defaults: Record<string, unknown>, callback: (value: Record<string, unknown>) => void) => {
108+
callback({ [STORAGE_KEY]: 70 });
109+
},
110+
);
111+
112+
const { startChatWidthAdjuster } = await import('../index');
113+
startChatWidthAdjuster();
114+
115+
const styleText = getInjectedStyle().textContent ?? '';
116+
const expectedPx = percentToPixels(70); // 1344
117+
expect(styleText).toContain(`max-width: ${expectedPx}px !important`);
118+
expect(styleText).toContain(`width: min(100%, ${expectedPx}px) !important`);
119+
});
89120
});

src/pages/content/chatWidth/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,12 @@ const normalizePercent = (value: number, fallback: number) => {
6161

6262
function applyWidth(widthPercent: number) {
6363
const normalizedPercent = normalizePercent(widthPercent, DEFAULT_PERCENT);
64-
const widthValue = `${normalizedPercent}vw`;
64+
// Use screen width as reference to compute pixel-based max-width.
65+
// This provides adaptive behavior for split-screen / narrow windows:
66+
// - Fullscreen: width ≈ percent% of screen (as intended by the slider)
67+
// - Split-screen: content fills available space since pixel max-width > viewport
68+
const screenWidth = screen.availWidth || screen.width || 1920;
69+
const widthValue = `${Math.round((normalizedPercent / 100) * screenWidth)}px`;
6570

6671
let style = document.getElementById(STYLE_ID) as HTMLStyleElement;
6772
if (!style) {

0 commit comments

Comments
 (0)