mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-20 16:43:53 +01:00
Separate floating sidebar hidden state
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
13
src-web/hooks/useFloatingSidebarHidden.ts
Normal file
13
src-web/hooks/useFloatingSidebarHidden.ts
Normal 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;
|
||||
}
|
||||
8
src-web/hooks/useShouldFloatSidebar.ts
Normal file
8
src-web/hooks/useShouldFloatSidebar.ts
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user