feat: add tab memory with Remember Tabs setting

This commit is contained in:
2026-04-11 05:46:47 -07:00
parent d76136feb5
commit d311bf4a7e
4 changed files with 54 additions and 2 deletions
+4
View File
@@ -33,6 +33,7 @@ export interface AppConfig {
game: {
lastServer: string;
socialTabBehaviour: 'New Window' | 'Same Window';
rememberTabs: boolean;
joinAsSpectator: boolean;
rawInput: boolean;
betterChat: boolean;
@@ -108,6 +109,7 @@ export interface AppConfig {
y: number | undefined;
maximized: boolean;
};
savedTabs: string[];
}
export const DEFAULT_KEYBINDS: AppConfig['keybinds'] = {
@@ -145,6 +147,7 @@ export const config = new Store<AppConfig>({
game: {
lastServer: '',
socialTabBehaviour: 'New Window',
rememberTabs: false,
joinAsSpectator: false,
rawInput: true,
betterChat: true,
@@ -210,5 +213,6 @@ export const config = new Store<AppConfig>({
y: undefined,
maximized: true,
},
savedTabs: [],
},
});
+3
View File
@@ -463,6 +463,9 @@ async function launchApp(): Promise<void> {
win, ses, preloadPath, tabMode, isGameURL,
() => config.get('tabWindow'),
(state) => config.set('tabWindow', state),
() => config.get('savedTabs'),
(urls) => config.set('savedTabs', urls),
() => config.get('game.rememberTabs') ?? false,
);
// Intercept in-page navigation (e.g. window.location = '/social.html')
+39 -1
View File
@@ -42,7 +42,11 @@ export class TabManager {
private recentlyClosed: { url: string; title: string }[] = [];
private getTabWindowState: () => TabWindowState;
private saveTabWindowState: (state: TabWindowState) => void;
private getSavedTabs: () => string[];
private saveTabs: (urls: string[]) => void;
private isRememberEnabled: () => boolean;
private tabSaveTimer: ReturnType<typeof setTimeout> | null = null;
private restoredTabs = false;
constructor(
win: BrowserWindow,
@@ -52,6 +56,9 @@ export class TabManager {
isGameURL: (url: string) => boolean,
getTabWindowState: () => TabWindowState,
saveTabWindowState: (state: TabWindowState) => void,
getSavedTabs: () => string[],
saveTabs: (urls: string[]) => void,
isRememberEnabled: () => boolean,
) {
this.mainWin = win;
this.ses = ses;
@@ -60,6 +67,9 @@ export class TabManager {
this.isGameURL = isGameURL;
this.getTabWindowState = getTabWindowState;
this.saveTabWindowState = saveTabWindowState;
this.getSavedTabs = getSavedTabs;
this.saveTabs = saveTabs;
this.isRememberEnabled = isRememberEnabled;
// ── Tab bar view (shared between both modes) ──
this.tabBarView = new WebContentsView({
@@ -185,8 +195,30 @@ export class TabManager {
});
}
// ── Open a new tab ──
// ── Restore saved tabs on first open, then open the requested tab ──
openTab(url: string): number {
if (!this.restoredTabs) {
this.restoredTabs = true;
const saved = this.isRememberEnabled() ? this.getSavedTabs() : [];
this.saveTabs([]);
if (saved.length > 0) {
for (const savedUrl of saved) {
this.openSingleTab(savedUrl);
}
// If the requested URL is already among the restored tabs, just activate it
const existing = this.tabs.find(t => t.url === url);
if (existing) {
this.switchToTab(existing.id);
this.showTabs();
return existing.id;
}
}
}
return this.openSingleTab(url);
}
// ── Open a single new tab ──
private openSingleTab(url: string): number {
if (this.tabs.length >= MAX_TABS) {
const existing = this.tabs.find(t => t.url === url);
if (existing) {
@@ -489,6 +521,12 @@ export class TabManager {
}
private destroyAllTabs(): void {
// Persist tab URLs so they can be restored later
if (this.tabs.length > 0 && this.isRememberEnabled()) {
this.saveTabs(this.tabs.map(t => t.url));
this.restoredTabs = false;
}
for (const tab of this.tabs) {
this.stopTitleWatcher(tab.id);
if (this.activeTabId === tab.id) {
+8 -1
View File
@@ -555,7 +555,7 @@ function buildGeneralSection(
onChange: (v) => { perf.fpsUnlocked = v; ipcRenderer.invoke('set-config', 'performance', perf); },
}));
const gameDefaults = { lastServer: '', socialTabBehaviour: 'New Window' };
const gameDefaults = { lastServer: '', socialTabBehaviour: 'New Window', rememberTabs: false };
const game = { ...gameDefaults, ...gameConf };
body.appendChild(createSelectRow({
@@ -566,6 +566,13 @@ function buildGeneralSection(
onChange: (v) => { game.socialTabBehaviour = v; ipcRenderer.invoke('set-config', 'game', game); },
}));
body.appendChild(createToggleRow({
label: 'Remember Tabs',
desc: 'Restore your open tabs when you reopen the social/hub window',
checked: game.rememberTabs, instant: true,
onChange: (v) => { game.rememberTabs = v; ipcRenderer.invoke('set-config', 'game', game); },
}));
const uiDefaults = { showExitButton: true, deathscreenAnimation: false, hideMenuPopups: false };
const ui = { ...uiDefaults, ...uiConfRaw };