Realtime sync UI preferences between tabs

This commit is contained in:
Tom Moor
2024-04-17 19:50:42 -04:00
parent 30b7079508
commit 2d947fb56b
2 changed files with 41 additions and 17 deletions

View File

@@ -108,22 +108,21 @@ export default class AuthStore extends Store<Team> {
// signin/signout events in other tabs and follow suite.
window.addEventListener("storage", (event) => {
if (event.key === AUTH_STORE && event.newValue) {
const data: PersistedData | null | undefined = JSON.parse(
event.newValue
);
const newData: PersistedData | null = JSON.parse(event.newValue);
// data may be null if key is deleted in localStorage
if (!data) {
if (!newData) {
return;
}
// If we're not signed in then hydrate from the received data, otherwise if
// we are signed in and the received data contains no user then sign out
if (this.authenticated) {
if (data.user === null) {
if (newData.user === null) {
void this.logout(false, false);
}
} else {
this.rehydrate(data);
this.rehydrate(newData);
}
}
});

View File

@@ -20,6 +20,16 @@ export enum SystemTheme {
Dark = "dark",
}
type PersistedData = {
languagePromptDismissed: boolean | undefined;
theme: Theme;
sidebarCollapsed: boolean;
sidebarWidth: number;
sidebarRightWidth: number;
tocVisible: boolean;
commentsExpanded: string[];
};
class UiStore {
// has the user seen the prompt to change the UI language and actioned it
@observable
@@ -74,7 +84,15 @@ class UiStore {
constructor() {
// Rehydrate
const data: Partial<UiStore> = Storage.get(UI_STORE) || {};
const data: PersistedData = Storage.get(UI_STORE) || {};
this.languagePromptDismissed = data.languagePromptDismissed;
this.sidebarCollapsed = !!data.sidebarCollapsed;
this.sidebarWidth = data.sidebarWidth || defaultTheme.sidebarWidth;
this.sidebarRightWidth =
data.sidebarRightWidth || defaultTheme.sidebarRightWidth;
this.tocVisible = !!data.tocVisible;
this.commentsExpanded = data.commentsExpanded || [];
this.theme = data.theme || Theme.System;
// system theme listeners
if (window.matchMedia) {
@@ -93,15 +111,22 @@ class UiStore {
}
}
// persisted keys
this.languagePromptDismissed = data.languagePromptDismissed;
this.sidebarCollapsed = !!data.sidebarCollapsed;
this.sidebarWidth = data.sidebarWidth || defaultTheme.sidebarWidth;
this.sidebarRightWidth =
data.sidebarRightWidth || defaultTheme.sidebarRightWidth;
this.tocVisible = !!data.tocVisible;
this.commentsExpanded = data.commentsExpanded || [];
this.theme = data.theme || Theme.System;
window.addEventListener("storage", (event) => {
if (event.key === UI_STORE && event.newValue) {
const newData: PersistedData | null = JSON.parse(event.newValue);
// data may be null if key is deleted in localStorage
if (!newData) {
return;
}
// Note: we do not sync all properties here, sidebar widths cause fighting between windows
this.theme = newData.theme;
this.languagePromptDismissed = newData.languagePromptDismissed;
this.sidebarCollapsed = !!newData.sidebarCollapsed;
this.tocVisible = !!newData.tocVisible;
}
});
autorun(() => {
Storage.set(UI_STORE, this.asJson);
@@ -265,7 +290,7 @@ class UiStore {
}
@computed
get asJson() {
get asJson(): PersistedData {
return {
tocVisible: this.tocVisible,
sidebarCollapsed: this.sidebarCollapsed,