Browse Source

fix: nav item popup overflow

ascarbek 2 years ago
parent
commit
593446bffe

+ 3 - 1
frontend/appflowy_tauri/src/appflowy_app/components/_shared/Popup.tsx

@@ -12,11 +12,13 @@ export const Popup = ({
   className = '',
   onOutsideClick,
   columns = 1,
+  style,
 }: {
   items: IPopupItem[];
   className: string;
   onOutsideClick?: () => void;
   columns?: 1 | 2 | 3;
+  style?: any;
 }) => {
   const ref = useRef<HTMLDivElement>(null);
   useOutsideClick(ref, () => onOutsideClick && onOutsideClick());
@@ -27,7 +29,7 @@ export const Popup = ({
   };
 
   return (
-    <div ref={ref} className={`${className} rounded-lg bg-white px-2 py-2 shadow-md`}>
+    <div ref={ref} className={`${className} rounded-lg bg-white px-2 py-2 shadow-md`} style={style}>
       <div
         className={`grid ${columns === 1 && 'grid-cols-1'} ${columns === 2 && 'grid-cols-2'} ${
           columns === 3 && 'grid-cols-3'

+ 2 - 0
frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/FolderItem.hooks.ts

@@ -14,6 +14,7 @@ import { INITIAL_FOLDER_HEIGHT, PAGE_ITEM_HEIGHT } from '../../_shared/constants
 export const useFolderEvents = (folder: IFolder, pages: IPage[]) => {
   const appDispatch = useAppDispatch();
   const workspace = useAppSelector((state) => state.workspace);
+  const foldersStore = useAppSelector((state) => state.folders);
 
   const navigate = useNavigate();
 
@@ -64,6 +65,7 @@ export const useFolderEvents = (folder: IFolder, pages: IPage[]) => {
   }, [pages]);
 
   const onFolderNameClick = () => {
+    appDispatch(foldersActions.toggleShowPages({ id: folder.id }));
     if (showPages) {
       setFolderHeight(`${INITIAL_FOLDER_HEIGHT}px`);
     } else {

+ 14 - 17
frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/FolderItem.tsx

@@ -12,8 +12,6 @@ import { useEffect, useRef, useState } from 'react';
 import { DropDownShowSvg } from '../../_shared/svg/DropDownShowSvg';
 import { ANIMATION_DURATION } from '../../_shared/constants';
 
-let timeoutHandle: any;
-
 export const FolderItem = ({
   folder,
   pages,
@@ -47,18 +45,7 @@ export const FolderItem = ({
     setOffsetTop,
   } = useFolderEvents(folder, pages);
 
-  const [hideOverflow, setHideOverflow] = useState(!showPages);
-
-  useEffect(() => {
-    clearTimeout(timeoutHandle);
-    if (showPages) {
-      timeoutHandle = setTimeout(() => {
-        setHideOverflow(!showPages);
-      }, ANIMATION_DURATION);
-    } else {
-      setHideOverflow(!showPages);
-    }
-  }, [showPages]);
+  const [popupY, setPopupY] = useState(0);
 
   const el = useRef<HTMLDivElement>(null);
 
@@ -66,10 +53,17 @@ export const FolderItem = ({
     setOffsetTop(el.current?.offsetTop || 0);
   }, [el, showPages]);
 
+  useEffect(() => {
+    if (el.current) {
+      const { top } = el.current.getBoundingClientRect();
+      setPopupY(top);
+    }
+  }, [showFolderOptions, showNewPageOptions, showRenamePopup]);
+
   return (
-    <div className={'relative'} ref={el}>
+    <div ref={el}>
       <div
-        className={`relative my-2 ${hideOverflow ? 'overflow-hidden' : ''} transition-all `}
+        className={`my-2 overflow-hidden transition-all`}
         style={{ height: folderHeight, transitionDuration: `${ANIMATION_DURATION}ms` }}
       >
         <div
@@ -84,7 +78,7 @@ export const FolderItem = ({
               {folder.title}
             </span>
           </button>
-          <div className={'relative flex items-center'}>
+          <div className={'flex items-center'}>
             <Button size={'box-small-transparent'} onClick={() => onFolderOptionsClick()}>
               <Details2Svg></Details2Svg>
             </Button>
@@ -104,6 +98,7 @@ export const FolderItem = ({
           onDeleteClick={() => deleteFolder()}
           onDuplicateClick={() => duplicateFolder()}
           onClose={() => closePopup()}
+          top={popupY - 124 + 40}
         ></NavItemOptionsPopup>
       )}
       {showNewPageOptions && (
@@ -112,6 +107,7 @@ export const FolderItem = ({
           onBoardClick={() => onAddNewBoardPage()}
           onGridClick={() => onAddNewGridPage()}
           onClose={() => closePopup()}
+          top={popupY - 124 + 40}
         ></NewPagePopup>
       )}
       {showRenamePopup && (
@@ -119,6 +115,7 @@ export const FolderItem = ({
           value={folder.title}
           onChange={(newTitle) => changeFolderTitle(newTitle)}
           onClose={closeRenamePopup}
+          top={popupY - 124 + 40}
         ></RenamePopup>
       )}
     </div>

+ 4 - 1
frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/NavItemOptionsPopup.tsx

@@ -8,11 +8,13 @@ export const NavItemOptionsPopup = ({
   onDeleteClick,
   onDuplicateClick,
   onClose,
+  top,
 }: {
   onRenameClick: () => void;
   onDeleteClick: () => void;
   onDuplicateClick: () => void;
   onClose?: () => void;
+  top: number;
 }) => {
   const items: IPopupItem[] = [
     {
@@ -48,7 +50,8 @@ export const NavItemOptionsPopup = ({
     <Popup
       onOutsideClick={() => onClose && onClose()}
       items={items}
-      className={'absolute right-0 top-[40px] z-10'}
+      className={`absolute right-0`}
+      style={{ top: `${top}px` }}
     ></Popup>
   );
 };

+ 5 - 3
frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/NavigationPanel.tsx

@@ -7,7 +7,7 @@ import { NavigationResizer } from './NavigationResizer';
 import { IFolder } from '../../../stores/reducers/folders/slice';
 import { IPage } from '../../../stores/reducers/pages/slice';
 import { useNavigate } from 'react-router-dom';
-import React, { useEffect, useRef } from 'react';
+import React, { useRef } from 'react';
 import { useDispatch } from 'react-redux';
 import { useAppSelector } from '../../../stores/store';
 import { ANIMATION_DURATION, NAV_PANEL_MINIMUM_WIDTH } from '../../_shared/constants';
@@ -46,8 +46,10 @@ export const NavigationPanel = ({
         <div className={'flex flex-col'}>
           <AppLogo iconToShow={'hide'} onHideMenuClick={onHideMenuClick}></AppLogo>
           <WorkspaceUser></WorkspaceUser>
-          <div className={'flex flex-col overflow-auto px-2'} style={{ height: 'calc(100vh - 300px)' }} ref={el}>
-            <WorkspaceApps folders={folders} pages={pages} onPageClick={onPageClick} />
+          <div className={'relative flex flex-col'} style={{ height: 'calc(100vh - 300px)' }} ref={el}>
+            <div className={'flex flex-col overflow-auto px-2'}>
+              <WorkspaceApps folders={folders} pages={pages} onPageClick={onPageClick} />
+            </div>
           </div>
         </div>
 

+ 4 - 1
frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/NewPagePopup.tsx

@@ -8,11 +8,13 @@ export const NewPagePopup = ({
   onGridClick,
   onBoardClick,
   onClose,
+  top,
 }: {
   onDocumentClick: () => void;
   onGridClick: () => void;
   onBoardClick: () => void;
   onClose?: () => void;
+  top: number;
 }) => {
   const items: IPopupItem[] = [
     {
@@ -48,7 +50,8 @@ export const NewPagePopup = ({
     <Popup
       onOutsideClick={() => onClose && onClose()}
       items={items}
-      className={'absolute right-0 top-[40px] z-10'}
+      className={'absolute right-0'}
+      style={{ top: `${top}px` }}
     ></Popup>
   );
 };

+ 13 - 3
frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/PageItem.tsx

@@ -8,7 +8,7 @@ import { Button } from '../../_shared/Button';
 import { usePageEvents } from './PageItem.hooks';
 import { RenamePopup } from './RenamePopup';
 import { ViewLayoutTypePB } from '../../../../services/backend';
-import { useEffect, useRef } from 'react';
+import { useEffect, useRef, useState } from 'react';
 import { PAGE_ITEM_HEIGHT } from '../../_shared/constants';
 
 export const PageItem = ({ page, onPageClick }: { page: IPage; onPageClick: () => void }) => {
@@ -32,8 +32,17 @@ export const PageItem = ({ page, onPageClick }: { page: IPage; onPageClick: () =
     setOffsetTop(el.current?.offsetTop || 0);
   }, [el.current]);
 
+  const [popupY, setPopupY] = useState(0);
+
+  useEffect(() => {
+    if (showPageOptions && el.current) {
+      const { top } = el.current.getBoundingClientRect();
+      setPopupY(top);
+    }
+  }, [showPageOptions]);
+
   return (
-    <div className={'relative'} ref={el}>
+    <div ref={el}>
       <div
         onClick={() => onPageClick()}
         className={`flex cursor-pointer items-center justify-between rounded-lg pl-8 pr-4 hover:bg-surface-2 ${
@@ -51,7 +60,7 @@ export const PageItem = ({ page, onPageClick }: { page: IPage; onPageClick: () =
             {page.title}
           </span>
         </button>
-        <div className={'relative flex items-center'}>
+        <div className={'flex items-center'}>
           <Button size={'box-small-transparent'} onClick={() => onPageOptionsClick()}>
             <Details2Svg></Details2Svg>
           </Button>
@@ -63,6 +72,7 @@ export const PageItem = ({ page, onPageClick }: { page: IPage; onPageClick: () =
           onDeleteClick={() => deletePage()}
           onDuplicateClick={() => duplicatePage()}
           onClose={() => closePopup()}
+          top={popupY - 124 + 40}
         ></NavItemOptionsPopup>
       )}
       {showRenamePopup && (

+ 3 - 0
frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/RenamePopup.tsx

@@ -6,11 +6,13 @@ export const RenamePopup = ({
   onChange,
   onClose,
   className = '',
+  top,
 }: {
   value: string;
   onChange: (newTitle: string) => void;
   onClose: () => void;
   className?: string;
+  top?: number;
 }) => {
   const ref = useRef<HTMLDivElement>(null);
   const inputRef = useRef<HTMLInputElement>(null);
@@ -32,6 +34,7 @@ export const RenamePopup = ({
       className={
         'absolute left-[50px] top-[40px] z-10 flex w-[300px] rounded bg-white py-1 px-1.5 shadow-md ' + className
       }
+      style={{ top: `${top}px` }}
     >
       <input
         ref={inputRef}

+ 4 - 0
frontend/appflowy_tauri/src/appflowy_app/stores/reducers/folders/slice.ts

@@ -4,6 +4,7 @@ export interface IFolder {
   id: string;
   title: string;
   offsetTop?: number;
+  showPages?: boolean;
 }
 
 const initialState: IFolder[] = [];
@@ -27,6 +28,9 @@ export const foldersSlice = createSlice({
     setOffsetTop(state, action: PayloadAction<{ id: string; offset: number }>) {
       return state.map((f) => (f.id === action.payload.id ? { ...f, offsetTop: action.payload.offset } : f));
     },
+    toggleShowPages(state, action: PayloadAction<{ id: string }>) {
+      return state.map((f) => (f.id === action.payload.id ? { ...f, showPages: !f.showPages } : f));
+    },
   },
 });