Compare commits

...

2 Commits

Author SHA1 Message Date
Tom Moor bee7911bee Types cleanup 2024-11-20 19:12:43 -05:00
Tom Moor 86714a353f fix: Rare loop of storage events between tabs causing flickering UI 2024-11-20 18:51:58 -05:00
6 changed files with 63 additions and 82 deletions
+4 -2
View File
@@ -47,14 +47,16 @@ export default function LanguagePrompt() {
<br />
<Link
onClick={async () => {
ui.setLanguagePromptDismissed();
ui.set({ languagePromptDismissed: true });
await user.save({ language });
}}
>
{t("Change Language")}
</Link>{" "}
&middot;{" "}
<Link onClick={ui.setLanguagePromptDismissed}>{t("Dismiss")}</Link>
<Link onClick={() => ui.set({ languagePromptDismissed: true })}>
{t("Dismiss")}
</Link>
</span>
</Flex>
</Wrapper>
+2 -2
View File
@@ -32,13 +32,13 @@ function Right({ children, border, className }: Props) {
Math.min(window.innerWidth - event.pageX, maxWidth),
minWidth
);
ui.setRightSidebarWidth(width);
ui.set({ sidebarRightWidth: width });
},
[minWidth, maxWidth, ui]
);
const handleReset = React.useCallback(() => {
ui.setRightSidebarWidth(theme.sidebarRightWidth);
ui.set({ sidebarRightWidth: theme.sidebarRightWidth });
}, [ui, theme.sidebarRightWidth]);
const handleStopDrag = React.useCallback(() => {
+12 -13
View File
@@ -46,7 +46,6 @@ const Sidebar = React.forwardRef<HTMLDivElement, Props>(function _Sidebar(
const maxWidth = theme.sidebarMaxWidth;
const minWidth = theme.sidebarMinWidth + 16; // padding
const setWidth = ui.setSidebarWidth;
const [offset, setOffset] = React.useState(0);
const [isHovering, setHovering] = React.useState(false);
const [isAnimating, setAnimating] = React.useState(false);
@@ -62,13 +61,13 @@ const Sidebar = React.forwardRef<HTMLDivElement, Props>(function _Sidebar(
const width = Math.min(event.pageX - offset, maxWidth);
const isSmallerThanCollapsePoint = width < minWidth / 2;
if (isSmallerThanCollapsePoint) {
setWidth(theme.sidebarCollapsedWidth);
} else {
setWidth(width);
}
ui.set({
sidebarWidth: isSmallerThanCollapsePoint
? theme.sidebarCollapsedWidth
: width,
});
},
[theme, offset, minWidth, maxWidth, setWidth]
[ui, theme, offset, minWidth, maxWidth]
);
const handleStopDrag = React.useCallback(() => {
@@ -86,13 +85,13 @@ const Sidebar = React.forwardRef<HTMLDivElement, Props>(function _Sidebar(
setCollapsing(true);
ui.collapseSidebar();
} else {
setWidth(minWidth);
ui.set({ sidebarWidth: minWidth });
setAnimating(true);
}
} else {
setWidth(width);
ui.set({ sidebarWidth: width });
}
}, [ui, isSmallerThanMinimum, minWidth, width, setWidth]);
}, [ui, isSmallerThanMinimum, minWidth, width]);
const handleBlur = React.useCallback(() => {
setHovering(false);
@@ -149,11 +148,11 @@ const Sidebar = React.forwardRef<HTMLDivElement, Props>(function _Sidebar(
React.useEffect(() => {
if (isCollapsing) {
setTimeout(() => {
setWidth(minWidth);
ui.set({ sidebarWidth: minWidth });
setCollapsing(false);
}, ANIMATION_MS);
}
}, [setWidth, minWidth, isCollapsing]);
}, [ui, minWidth, isCollapsing]);
React.useEffect(() => {
if (isResizing) {
@@ -174,7 +173,7 @@ const Sidebar = React.forwardRef<HTMLDivElement, Props>(function _Sidebar(
}, [isResizing, handleDrag, handleBlur, handleStopDrag]);
const handleReset = React.useCallback(() => {
ui.setSidebarWidth(theme.sidebarWidth);
ui.set({ sidebarWidth: theme.sidebarWidth });
}, [ui, theme.sidebarWidth]);
React.useEffect(() => {
+6 -2
View File
@@ -103,6 +103,10 @@ function DocumentHeader({
});
}, [onSave]);
const handleToggle = React.useCallback(() => {
ui.set({ tocVisible: !ui.tocVisible });
}, [ui]);
const context = useActionContext({
activeDocumentId: document?.id,
});
@@ -129,7 +133,7 @@ function DocumentHeader({
placement="bottom"
>
<Button
onClick={showContents ? ui.hideTableOfContents : ui.showTableOfContents}
onClick={handleToggle}
icon={<TableOfContentsIcon />}
borderOnHover
neutral
@@ -180,7 +184,7 @@ function DocumentHeader({
useKeyDown(
(event) => event.ctrlKey && event.altKey && event.key === "˙",
ui.tocVisible ? ui.hideTableOfContents : ui.showTableOfContents,
handleToggle,
{
allowInInput: true,
}
+9 -20
View File
@@ -7,31 +7,19 @@ import { CustomTheme } from "@shared/types";
import Storage from "@shared/utils/Storage";
import { getCookieDomain, parseDomain } from "@shared/utils/domains";
import RootStore from "~/stores/RootStore";
import Policy from "~/models/Policy";
import Team from "~/models/Team";
import User from "~/models/User";
import env from "~/env";
import { setPostLoginPath } from "~/hooks/useLastVisitedPath";
import { PartialExcept } from "~/types";
import { client } from "~/utils/ApiClient";
import Desktop from "~/utils/Desktop";
import Logger from "~/utils/Logger";
import isCloudHosted from "~/utils/isCloudHosted";
import Store from "./base/Store";
type PersistedData = {
user?: PartialExcept<User, "id">;
team?: PartialExcept<Team, "id">;
collaborationToken?: string;
availableTeams?: {
id: string;
name: string;
avatarUrl: string;
url: string;
isSignedIn: boolean;
}[];
policies?: Policy[];
};
type PersistedData = Pick<
AuthStore,
"user" | "team" | "collaborationToken" | "availableTeams" | "policies"
>;
type Provider = {
id: string;
@@ -165,9 +153,10 @@ export default class AuthStore extends Store<Team> {
/** The current team's policies */
@computed
get policies() {
return this.currentTeamId
? [this.rootStore.policies.get(this.currentTeamId)]
: [];
const policy = this.currentTeamId
? this.rootStore.policies.get(this.currentTeamId)
: undefined;
return policy ? [policy] : [];
}
/** Whether the user is signed in */
@@ -177,7 +166,7 @@ export default class AuthStore extends Store<Team> {
}
@computed
get asJson() {
get asJson(): PersistedData {
return {
user: this.user,
team: this.team,
+30 -43
View File
@@ -1,4 +1,4 @@
import { action, autorun, computed, observable } from "mobx";
import { action, computed, observable } from "mobx";
import { flushSync } from "react-dom";
import { light as defaultTheme } from "@shared/styles/theme";
import Storage from "@shared/utils/Storage";
@@ -23,15 +23,16 @@ export enum SystemTheme {
Dark = "dark",
}
type PersistedData = {
languagePromptDismissed: boolean | undefined;
theme: Theme;
sidebarCollapsed: boolean;
sidebarWidth: number;
sidebarRightWidth: number;
tocVisible: boolean | undefined;
commentsExpanded: string[];
};
type PersistedData = Pick<
UiStore,
| "languagePromptDismissed"
| "commentsExpanded"
| "theme"
| "sidebarWidth"
| "sidebarRightWidth"
| "sidebarCollapsed"
| "tocVisible"
>;
class UiStore {
// has the user seen the prompt to change the UI language and actioned it
@@ -134,10 +135,6 @@ class UiStore {
this.tocVisible = newData.tocVisible;
}
});
autorun(() => {
Storage.set(UI_STORE, this.asJson);
});
}
@action
@@ -147,12 +144,7 @@ class UiStore {
this.theme = theme;
});
});
Storage.set("theme", this.theme);
};
@action
setLanguagePromptDismissed = () => {
this.languagePromptDismissed = true;
this.persist();
};
@action
@@ -205,25 +197,24 @@ class UiStore {
this.activeCollectionId = undefined;
};
@action
setSidebarWidth = (width: number): void => {
this.sidebarWidth = width;
};
@action
setRightSidebarWidth = (width: number): void => {
this.sidebarRightWidth = width;
};
@action
collapseSidebar = () => {
this.sidebarCollapsed = true;
this.set({ sidebarCollapsed: true });
};
@action
expandSidebar = () => {
sidebarHidden = false;
this.sidebarCollapsed = false;
this.set({ sidebarCollapsed: false });
};
@action
set = (data: Partial<PersistedData>) => {
for (const key in data) {
// @ts-expect-error doesn't understand PersistedData is subset of keys
this[key] = data[key];
}
this.persist();
};
@action
@@ -231,6 +222,7 @@ class UiStore {
this.commentsExpanded = this.commentsExpanded.filter(
(id) => id !== documentId
);
this.persist();
};
@action
@@ -238,6 +230,7 @@ class UiStore {
if (!this.commentsExpanded.includes(documentId)) {
this.commentsExpanded.push(documentId);
}
this.persist();
};
@action
@@ -252,17 +245,7 @@ class UiStore {
@action
toggleCollapsedSidebar = () => {
sidebarHidden = false;
this.sidebarCollapsed = !this.sidebarCollapsed;
};
@action
showTableOfContents = () => {
this.tocVisible = true;
};
@action
hideTableOfContents = () => {
this.tocVisible = false;
this.set({ sidebarCollapsed: !this.sidebarCollapsed });
};
@action
@@ -324,6 +307,10 @@ class UiStore {
theme: this.theme,
};
}
private persist = () => {
Storage.set(UI_STORE, this.asJson);
};
}
export default UiStore;