main f6d8405

chat-window-state.ts RawHistoryFolder

1// Chat window state persistence utility
2// Stores and retrieves window position, size, and UI state from localStorage
3
4export interface ChatWindowState {
5	width: number;
6	height: number;
7	x: number;
8	y: number;
9	isMaximized: boolean;
10	isMinimized: boolean;
11	showUserList: boolean;
12	isCentered: boolean; // true = window stays centered on resize, false = user has manually positioned
13}
14
15const STORAGE_KEY = 'pdraim-chat-window';
16
17// Default values for desktop (800x600 - 16:10 aspect ratio, centered)
18export const DEFAULT_WINDOW_STATE: ChatWindowState = {
19	width: 800,
20	height: 600,
21	x: -1, // -1 means "center" - will be calculated on load
22	y: -1, // -1 means "center" - will be calculated on load
23	isMaximized: false,
24	isMinimized: false,
25	showUserList: false,
26	isCentered: true // default to centered, set to false when user drags window
27};
28
29/**
30 * Load window state from localStorage
31 * Returns saved state merged with defaults, or just defaults if nothing saved
32 */
33export function loadWindowState(): ChatWindowState {
34	if (typeof window === 'undefined') {
35		return DEFAULT_WINDOW_STATE;
36	}
37
38	try {
39		const stored = localStorage.getItem(STORAGE_KEY);
40		if (stored) {
41			const parsed = JSON.parse(stored);
42			// Merge with defaults to ensure all fields exist
43			return {
44				...DEFAULT_WINDOW_STATE,
45				...parsed
46			};
47		}
48	} catch (error) {
49		console.warn('Failed to load chat window state from localStorage:', error);
50	}
51
52	return DEFAULT_WINDOW_STATE;
53}
54
55/**
56 * Save window state to localStorage
57 * Debounced externally - this just does the save
58 */
59export function saveWindowState(state: Partial<ChatWindowState>): void {
60	if (typeof window === 'undefined') {
61		return;
62	}
63
64	try {
65		const currentState = loadWindowState();
66		const newState = { ...currentState, ...state };
67		localStorage.setItem(STORAGE_KEY, JSON.stringify(newState));
68	} catch (error) {
69		console.warn('Failed to save chat window state to localStorage:', error);
70	}
71}
72
73/**
74 * Clear saved window state
75 */
76export function clearWindowState(): void {
77	if (typeof window === 'undefined') {
78		return;
79	}
80
81	try {
82		localStorage.removeItem(STORAGE_KEY);
83	} catch (error) {
84		console.warn('Failed to clear chat window state from localStorage:', error);
85	}
86}
87
88/**
89 * Simple debounce function for save operations
90 */
91export function debounce<T extends (...args: Parameters<T>) => void>(
92	fn: T,
93	delay: number
94): (...args: Parameters<T>) => void {
95	let timeoutId: ReturnType<typeof setTimeout> | null = null;
96
97	return (...args: Parameters<T>) => {
98		if (timeoutId) {
99			clearTimeout(timeoutId);
100		}
101		timeoutId = setTimeout(() => {
102			fn(...args);
103			timeoutId = null;
104		}, delay);
105	};
106}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 3

Tags 8

↑↓ moveenter openesc close