Separate floating sidebar hidden state

This commit is contained in:
Gregory Schier
2024-03-22 10:43:10 -07:00
parent 7d272f3cd6
commit 10443b3c02
6 changed files with 57 additions and 42 deletions

View File

@@ -56,7 +56,7 @@ interface TreeNode {
}
export function Sidebar({ className }: Props) {
const { hidden, show, hide } = useSidebarHidden();
const [hidden, setHidden] = useSidebarHidden();
const sidebarRef = useRef<HTMLLIElement>(null);
const activeRequest = useActiveRequest();
const activeEnvironmentId = useActiveEnvironmentId();
@@ -241,16 +241,15 @@ export function Sidebar({ className }: Props) {
useKeyPressEvent('Delete', handleDeleteKey);
useHotKey('sidebar.focus', async () => {
console.log('sidebar.focus', { hidden, hasFocus });
// Hide the sidebar if it's already focused
if (!hidden && hasFocus) {
await hide();
await setHidden(true);
return;
}
// Show the sidebar if it's hidden
if (hidden) {
await show();
await setHidden(false);
}
// Select 0 index on focus if none selected

View File

@@ -1,12 +1,22 @@
import { memo } from 'react';
import { useMemo } from 'react';
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar';
import { useSidebarHidden } from '../hooks/useSidebarHidden';
import { trackEvent } from '../lib/analytics';
import { IconButton } from './core/IconButton';
import { HStack } from './core/Stacks';
import { CreateDropdown } from './CreateDropdown';
export const SidebarActions = memo(function SidebarActions() {
const { hidden, show, hide } = useSidebarHidden();
export function SidebarActions() {
const floating = useShouldFloatSidebar();
const [normalHidden, setNormalHidden] = useSidebarHidden();
const [floatingHidden, setFloatingHidden] = useFloatingSidebarHidden();
const hidden = floating ? floatingHidden : normalHidden;
const setHidden = useMemo(
() => (floating ? setFloatingHidden : setNormalHidden),
[floating, setFloatingHidden, setNormalHidden],
);
return (
<HStack className="h-full" alignItems="center">
@@ -14,10 +24,9 @@ export const SidebarActions = memo(function SidebarActions() {
onClick={async () => {
trackEvent('sidebar', 'toggle');
// NOTE: We're not using `toggle` because it may be out of sync
// from changes in other windows
if (hidden) await show();
else await hide();
// NOTE: We're not using the (h) => !h pattern here because the data
// might be different if another window changed it (out of sync)
await setHidden(!hidden);
}}
className="pointer-events-auto"
size="sm"
@@ -35,4 +44,4 @@ export const SidebarActions = memo(function SidebarActions() {
</CreateDropdown>
</HStack>
);
});
}

View File

@@ -6,14 +6,16 @@ import type {
MouseEvent as ReactMouseEvent,
ReactNode,
} from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useCallback, useMemo, useRef, useState } from 'react';
import { useWindowSize } from 'react-use';
import { useActiveRequest } from '../hooks/useActiveRequest';
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
import { useImportData } from '../hooks/useImportData';
import { useIsFullscreen } from '../hooks/useIsFullscreen';
import { useOsInfo } from '../hooks/useOsInfo';
import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar';
import { useSidebarHidden } from '../hooks/useSidebarHidden';
import { useSidebarWidth } from '../hooks/useSidebarWidth';
import { useWorkspaces } from '../hooks/useWorkspaces';
@@ -37,34 +39,22 @@ const head = { gridArea: 'head' };
const body = { gridArea: 'body' };
const drag = { gridArea: 'drag' };
const WINDOW_FLOATING_SIDEBAR_WIDTH = 600;
export default function Workspace() {
const workspaces = useWorkspaces();
const activeWorkspace = useActiveWorkspace();
const activeWorkspaceId = useActiveWorkspaceId();
const { setWidth, width, resetWidth } = useSidebarWidth();
const { hide, show, hidden } = useSidebarHidden();
const [sidebarHidden, setSidebarHidden] = useSidebarHidden();
const [floatingSidebarHidden, setFloatingSidebarHidden] = useFloatingSidebarHidden();
const activeRequest = useActiveRequest();
const windowSize = useWindowSize();
const importData = useImportData();
const [floating, setFloating] = useState<boolean>(false);
const floating = useShouldFloatSidebar();
const [isResizing, setIsResizing] = useState<boolean>(false);
const moveState = useRef<{ move: (e: MouseEvent) => void; up: (e: MouseEvent) => void } | null>(
null,
);
// float/un-float sidebar on window resize
useEffect(() => {
const shouldHide = windowSize.width <= WINDOW_FLOATING_SIDEBAR_WIDTH;
if (shouldHide && !floating) {
setFloating(true);
hide().catch(console.error);
} else if (!shouldHide && floating) {
setFloating(false);
}
}, [floating, hide, windowSize.width]);
const unsub = () => {
if (moveState.current !== null) {
document.documentElement.removeEventListener('mousemove', moveState.current.move);
@@ -84,10 +74,10 @@ export default function Workspace() {
e.preventDefault(); // Prevent text selection and things
const newWidth = startWidth + (e.clientX - mouseStartX);
if (newWidth < 50) {
await hide();
await setSidebarHidden(true);
resetWidth();
} else {
await show();
await setSidebarHidden(false);
setWidth(newWidth);
}
},
@@ -101,10 +91,10 @@ export default function Workspace() {
document.documentElement.addEventListener('mouseup', moveState.current.up);
setIsResizing(true);
},
[setWidth, resetWidth, width, hide, show],
[width, setSidebarHidden, resetWidth, setWidth],
);
const sideWidth = hidden ? 0 : width;
const sideWidth = sidebarHidden ? 0 : width;
const styles = useMemo<CSSProperties>(
() => ({
gridTemplate: floating
@@ -144,7 +134,11 @@ export default function Workspace() {
)}
>
{floating ? (
<Overlay open={!hidden} portalName="sidebar" onClose={hide}>
<Overlay
open={!floatingSidebarHidden}
portalName="sidebar"
onClose={() => setFloatingSidebarHidden(true)}
>
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}

View File

@@ -0,0 +1,13 @@
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
import { useKeyValue } from './useKeyValue';
export function useFloatingSidebarHidden() {
const activeWorkspaceId = useActiveWorkspaceId();
const { set, value } = useKeyValue<boolean>({
namespace: 'no_sync',
key: ['floating_sidebar_hidden', activeWorkspaceId ?? 'n/a'],
fallback: false,
});
return [value, set] as const;
}

View File

@@ -0,0 +1,8 @@
import { useWindowSize } from 'react-use';
const WINDOW_FLOATING_SIDEBAR_WIDTH = 600;
export function useShouldFloatSidebar() {
const windowSize = useWindowSize();
return windowSize.width <= WINDOW_FLOATING_SIDEBAR_WIDTH;
}

View File

@@ -1,4 +1,3 @@
import { useMemo } from 'react';
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
import { useKeyValue } from './useKeyValue';
@@ -10,12 +9,5 @@ export function useSidebarHidden() {
fallback: false,
});
return useMemo(() => {
return {
show: () => set(false),
hide: () => set(true),
toggle: () => set((h) => !h),
hidden: value,
};
}, [set, value]);
return [value, set] as const;
}