Persist sidebar collapsed preference to localStorage
This commit is contained in:
@@ -40,6 +40,7 @@ import { useBlocklistStatus } from "../hooks/useBlocklist";
|
||||
|
||||
const SIDEBAR_FULL = "240px";
|
||||
const SIDEBAR_COLLAPSED = "48px";
|
||||
const SIDEBAR_COLLAPSED_STORAGE_KEY = "bangui_sidebar_collapsed";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
root: {
|
||||
@@ -220,23 +221,52 @@ export function MainLayout(): React.JSX.Element {
|
||||
const styles = useStyles();
|
||||
const { logout } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
// Initialise collapsed based on screen width so narrow viewports start
|
||||
// with the icon-only sidebar rather than the full-width one.
|
||||
const [collapsed, setCollapsed] = useState(() => window.innerWidth < 640);
|
||||
|
||||
const readSavedCollapsed = (): boolean => {
|
||||
try {
|
||||
const savedValue = localStorage.getItem(SIDEBAR_COLLAPSED_STORAGE_KEY);
|
||||
if (savedValue === "true") {
|
||||
return true;
|
||||
}
|
||||
if (savedValue === "false") {
|
||||
return false;
|
||||
}
|
||||
} catch {
|
||||
// Ignore storage errors and fall back to viewport heuristics.
|
||||
}
|
||||
return window.innerWidth < 640;
|
||||
};
|
||||
|
||||
const [collapsed, setCollapsed] = useState<boolean>(readSavedCollapsed);
|
||||
const { status } = useServerStatus();
|
||||
const { hasErrors: blocklistHasErrors } = useBlocklistStatus();
|
||||
|
||||
/** True only after the first successful poll and fail2ban is unreachable. */
|
||||
const serverOffline = status !== null && !status.online;
|
||||
|
||||
// Auto-collapse / auto-expand when the viewport crosses the 640 px breakpoint.
|
||||
useEffect(() => {
|
||||
try {
|
||||
localStorage.setItem(SIDEBAR_COLLAPSED_STORAGE_KEY, String(collapsed));
|
||||
} catch {
|
||||
// Local storage may be unavailable in some environments.
|
||||
}
|
||||
}, [collapsed]);
|
||||
|
||||
useEffect(() => {
|
||||
const savedValue = localStorage.getItem(SIDEBAR_COLLAPSED_STORAGE_KEY);
|
||||
if (savedValue !== null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const mq = window.matchMedia("(max-width: 639px)");
|
||||
const handler = (e: MediaQueryListEvent): void => {
|
||||
setCollapsed(e.matches);
|
||||
};
|
||||
|
||||
mq.addEventListener("change", handler);
|
||||
return (): void => { mq.removeEventListener("change", handler); };
|
||||
return (): void => {
|
||||
mq.removeEventListener("change", handler);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const toggleCollapse = useCallback(() => {
|
||||
|
||||
Reference in New Issue
Block a user