mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: nav item popup overflow
This commit is contained in:
parent
91e5219627
commit
593446bffe
@ -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'
|
||||
|
@ -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 {
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -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 && (
|
||||
|
@ -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,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));
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user