Merge pull request #176 from ONLYOFFICE/feature/shared-navigation
Feature/shared navigation
This commit is contained in:
commit
2acbd2f4fd
@ -40,7 +40,7 @@ import copy from "copy-to-clipboard";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
|
||||
import Loaders from "@docspace/common/components/Loaders";
|
||||
import Navigation from "@docspace/common/components/Navigation";
|
||||
import Navigation from "@docspace/shared/components/Navigation";
|
||||
import FilesFilter from "@docspace/shared/api/files/filter";
|
||||
import { resendInvitesAgain } from "@docspace/shared/api/people";
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import TrashWarning from "@docspace/common/components/Navigation/sub-components/trash-warning";
|
||||
import TrashWarning from "@docspace/shared/components/Navigation/sub-components/TrashWarning";
|
||||
|
||||
const Warning = () => {
|
||||
const { t } = useTranslation("Files");
|
||||
|
@ -1,202 +0,0 @@
|
||||
import styled, { css } from "styled-components";
|
||||
|
||||
import { tablet, mobile } from "@docspace/shared/utils";
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
${(props) =>
|
||||
!props.isDropBoxComponent &&
|
||||
props.isDesktop &&
|
||||
css`
|
||||
width: fit-content;
|
||||
max-width: ${props.isInfoPanelVisible
|
||||
? `calc(100%)`
|
||||
: `calc(100% - 72px)`};
|
||||
`}
|
||||
|
||||
display: grid;
|
||||
align-items: center;
|
||||
|
||||
margin-right: ${(props) => (props.isTrashFolder ? "16px" : 0)};
|
||||
|
||||
grid-template-columns: ${({ isRootFolder, withLogo }) =>
|
||||
isRootFolder
|
||||
? withLogo
|
||||
? "1fr auto 1fr"
|
||||
: "auto 1fr"
|
||||
: withLogo
|
||||
? "1fr 49px auto 1fr"
|
||||
: "49px auto 1fr"};
|
||||
|
||||
.navigation-logo {
|
||||
display: flex;
|
||||
height: 24px;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 16px;
|
||||
`
|
||||
: css`
|
||||
margin-right: 16px;
|
||||
`}
|
||||
|
||||
@media ${tablet} {
|
||||
.logo-icon_svg {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header_separator {
|
||||
display: ${({ isRootFolder }) => (isRootFolder ? "block" : "none")};
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
border-right: 1px solid #dfe2e3;
|
||||
margin: 0 15px 0 0;
|
||||
`
|
||||
: css`
|
||||
border-left: 1px solid #dfe2e3;
|
||||
margin: 0 0 0 15px;
|
||||
`}
|
||||
|
||||
height: 21px;
|
||||
}
|
||||
|
||||
.header-burger {
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
margin-top: -2px;
|
||||
|
||||
img {
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drop-box-logo {
|
||||
display: none;
|
||||
|
||||
@media ${tablet} {
|
||||
display: grid;
|
||||
}
|
||||
}
|
||||
|
||||
height: 100%;
|
||||
${(props) =>
|
||||
props.isDesktopClient &&
|
||||
props.isDropBoxComponent &&
|
||||
css`
|
||||
max-height: 32px;
|
||||
`}
|
||||
|
||||
.navigation-arrow-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.arrow-button {
|
||||
padding-top: 2px;
|
||||
width: 17px;
|
||||
min-width: 17px;
|
||||
|
||||
svg {
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl" && `transform: scaleX(-1);`}
|
||||
}
|
||||
}
|
||||
|
||||
.title-container {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(1px, max-content) auto;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
.room-title {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.navigation-header-separator {
|
||||
display: block;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
padding-right: 16px;
|
||||
border-left: ${(props) =>
|
||||
`1px solid ${props.theme.navigation.icon.stroke}`};
|
||||
`
|
||||
: css`
|
||||
padding-left: 16px;
|
||||
border-right: ${(props) =>
|
||||
`1px solid ${props.theme.navigation.icon.stroke}`};
|
||||
`}
|
||||
|
||||
height: 21px;
|
||||
@media ${mobile} {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.headline-heading {
|
||||
display: flex;
|
||||
height: 32px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title-block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
gap: 8px;
|
||||
|
||||
.title-icon {
|
||||
min-width: 17px;
|
||||
min-height: 17px;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
|
||||
svg {
|
||||
path,
|
||||
rect {
|
||||
fill: ${({ theme }) => theme.navigation.publicIcon};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
width: 100%;
|
||||
grid-template-columns: ${({ isRootFolder, withLogo }) =>
|
||||
isRootFolder
|
||||
? withLogo
|
||||
? "59px 1fr auto"
|
||||
: "1fr auto"
|
||||
: withLogo
|
||||
? "43px 49px 1fr auto"
|
||||
: "49px 1fr auto"};
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
.navigation-logo {
|
||||
display: none;
|
||||
}
|
||||
|
||||
grid-template-columns: ${(props) =>
|
||||
props.isRootFolder ? "1fr auto" : "29px 1fr auto"};
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledContainer;
|
@ -1 +0,0 @@
|
||||
export default from "./Navigation";
|
@ -1,27 +0,0 @@
|
||||
import React from "react";
|
||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
|
||||
import ArrowPathReactSvgUrl from "PUBLIC_DIR/images/arrow.path.react.svg?url";
|
||||
|
||||
const ArrowButton = ({ isRootFolder, onBackToParentFolder }) => {
|
||||
return (
|
||||
<>
|
||||
{!isRootFolder ? (
|
||||
<div className="navigation-arrow-container">
|
||||
<IconButton
|
||||
iconName={ArrowPathReactSvgUrl}
|
||||
size="17"
|
||||
isFill={true}
|
||||
onClick={onBackToParentFolder}
|
||||
className="arrow-button"
|
||||
/>
|
||||
<div className="navigation-header-separator" />
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ArrowButton);
|
@ -1,259 +0,0 @@
|
||||
import React from "react";
|
||||
import styled, { css } from "styled-components";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { tablet } from "@docspace/shared/utils";
|
||||
import { Base } from "@docspace/shared/themes";
|
||||
import ToggleInfoPanelButton from "./toggle-infopanel-btn";
|
||||
import PlusButton from "./plus-btn";
|
||||
import ContextButton from "./context-btn";
|
||||
import VerticalDotsReactSvgUrl from "PUBLIC_DIR/images/icons/17/vertical-dots.react.svg?url";
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: 16px;
|
||||
`
|
||||
: css`
|
||||
margin-left: 16px;
|
||||
`}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
height: 32px;
|
||||
|
||||
.add-button {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 16px;
|
||||
`
|
||||
: css`
|
||||
margin-right: 16px;
|
||||
`}
|
||||
min-width: 15px;
|
||||
|
||||
@media ${tablet} {
|
||||
display: ${(props) => (props.isFrame ? "flex" : "none")};
|
||||
}
|
||||
}
|
||||
|
||||
.add-drop-down {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.option-button {
|
||||
min-width: 17px;
|
||||
|
||||
/* ${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 16px;
|
||||
`
|
||||
: css`
|
||||
margin-right: 16px;
|
||||
`} */
|
||||
|
||||
/* @media ${tablet} {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 9px;
|
||||
`
|
||||
: css`
|
||||
margin-right: 9px;
|
||||
`}
|
||||
} */
|
||||
}
|
||||
|
||||
.trash-button {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 16px;
|
||||
`
|
||||
: css`
|
||||
margin-right: 16px;
|
||||
`}
|
||||
min-width: 15px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledInfoPanelToggleWrapper = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-self: center;
|
||||
justify-content: center;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: auto;
|
||||
`
|
||||
: css`
|
||||
margin-left: auto;
|
||||
`}
|
||||
|
||||
@media ${tablet} {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: ${(props) => (props.isRootFolder ? "auto" : "0")};
|
||||
`
|
||||
: css`
|
||||
margin-left: ${(props) => (props.isRootFolder ? "auto" : "0")};
|
||||
`}
|
||||
}
|
||||
|
||||
.info-panel-toggle-bg {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background-color: ${(props) =>
|
||||
props.isInfoPanelVisible
|
||||
? props.theme.infoPanel.sectionHeaderToggleBgActive
|
||||
: props.theme.infoPanel.sectionHeaderToggleBg};
|
||||
|
||||
path {
|
||||
fill: ${(props) =>
|
||||
props.isInfoPanelVisible
|
||||
? props.theme.infoPanel.sectionHeaderToggleIconActive
|
||||
: props.theme.infoPanel.sectionHeaderToggleIcon};
|
||||
}
|
||||
}
|
||||
`;
|
||||
StyledInfoPanelToggleWrapper.defaultProps = { theme: Base };
|
||||
|
||||
const ControlButtons = ({
|
||||
personal,
|
||||
isDropBoxComponent,
|
||||
isRootFolder,
|
||||
canCreate,
|
||||
getContextOptionsFolder,
|
||||
getContextOptionsPlus,
|
||||
isEmptyFilesList,
|
||||
clearTrash,
|
||||
isInfoPanelVisible,
|
||||
toggleInfoPanel,
|
||||
toggleDropBox,
|
||||
isDesktop,
|
||||
titles,
|
||||
withMenu,
|
||||
onPlusClick,
|
||||
isFrame,
|
||||
isPublicRoom,
|
||||
isTrashFolder,
|
||||
isMobile,
|
||||
}) => {
|
||||
const toggleInfoPanelAction = () => {
|
||||
toggleInfoPanel && toggleInfoPanel();
|
||||
toggleDropBox && toggleDropBox();
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledContainer isDropBoxComponent={isDropBoxComponent} isFrame={isFrame}>
|
||||
{!isRootFolder || (isTrashFolder && !isEmptyFilesList) ? (
|
||||
<>
|
||||
{!isMobile && canCreate && (
|
||||
<PlusButton
|
||||
className="add-button"
|
||||
getData={getContextOptionsPlus}
|
||||
withMenu={withMenu}
|
||||
onPlusClick={onPlusClick}
|
||||
isFrame={isFrame}
|
||||
title={titles?.actions}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* <ContextMenuButton
|
||||
id="header_optional-button"
|
||||
zIndex={402}
|
||||
className="option-button"
|
||||
directionX="right"
|
||||
iconName={VerticalDotsReactSvgUrl}
|
||||
size={15}
|
||||
isFill
|
||||
getData={getContextOptionsFolder}
|
||||
isDisabled={false}
|
||||
title={titles?.contextMenu}
|
||||
/> */}
|
||||
|
||||
<ContextButton
|
||||
id="header_optional-button"
|
||||
className="option-button"
|
||||
getData={getContextOptionsFolder}
|
||||
withMenu={withMenu}
|
||||
//onPlusClick={onPlusClick}
|
||||
title={titles?.actions}
|
||||
isTrashFolder={isTrashFolder}
|
||||
isMobile={isMobile}
|
||||
/>
|
||||
|
||||
{!isDesktop && (
|
||||
<ToggleInfoPanelButton
|
||||
isRootFolder={isRootFolder}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
toggleInfoPanel={toggleInfoPanelAction}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : canCreate ? (
|
||||
<>
|
||||
{!isMobile && (
|
||||
<PlusButton
|
||||
id="header_add-button"
|
||||
className="add-button"
|
||||
getData={getContextOptionsPlus}
|
||||
withMenu={withMenu}
|
||||
onPlusClick={onPlusClick}
|
||||
isFrame={isFrame}
|
||||
title={titles?.actions}
|
||||
/>
|
||||
)}
|
||||
{!isDesktop && (
|
||||
<ToggleInfoPanelButton
|
||||
isRootFolder={isRootFolder}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
toggleInfoPanel={toggleInfoPanelAction}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{!isDesktop && (
|
||||
<ToggleInfoPanelButton
|
||||
isRootFolder={isRootFolder}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
toggleInfoPanel={toggleInfoPanelAction}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isPublicRoom && (
|
||||
<ContextButton
|
||||
id="header_optional-button"
|
||||
className="option-button"
|
||||
getData={getContextOptionsFolder}
|
||||
withMenu={withMenu}
|
||||
title={titles?.contextMenu}
|
||||
isTrashFolder={isTrashFolder}
|
||||
isMobile={isMobile}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
ControlButtons.propTypes = {
|
||||
personal: PropTypes.bool,
|
||||
isRootFolder: PropTypes.bool,
|
||||
canCreate: PropTypes.bool,
|
||||
getContextOptionsFolder: PropTypes.func,
|
||||
getContextOptionsPlus: PropTypes.func,
|
||||
};
|
||||
|
||||
export default React.memo(ControlButtons);
|
@ -1,246 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import styled, { css, useTheme } from "styled-components";
|
||||
|
||||
import { VariableSizeList } from "react-window";
|
||||
import { CustomScrollbarsVirtualList } from "@docspace/shared/components/scrollbar";
|
||||
|
||||
import ArrowButton from "./arrow-btn";
|
||||
import Text from "./text";
|
||||
import ControlButtons from "./control-btn";
|
||||
import Item from "./item";
|
||||
import StyledContainer from "../StyledNavigation";
|
||||
import NavigationLogo from "./logo-block";
|
||||
|
||||
import { tablet, mobile } from "@docspace/shared/utils";
|
||||
import { ReactSVG } from "react-svg";
|
||||
|
||||
import { Base } from "@docspace/shared/themes";
|
||||
import { DeviceType } from "@docspace/shared/enums";
|
||||
|
||||
const StyledBox = styled.div`
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
right: -20px;
|
||||
${props.withLogo && `right: 207px;`};
|
||||
`
|
||||
: css`
|
||||
left: -20px;
|
||||
${props.withLogo && `left: 207px;`};
|
||||
`}
|
||||
padding: 0 20px;
|
||||
padding-top: 18px;
|
||||
|
||||
width: unset;
|
||||
|
||||
height: ${(props) => (props.height ? `${props.height}px` : "fit-content")};
|
||||
max-height: calc(100vh - 48px);
|
||||
|
||||
z-index: 401;
|
||||
display: table;
|
||||
margin: auto;
|
||||
flex-direction: column;
|
||||
|
||||
background: ${(props) => props.theme.navigation.background};
|
||||
|
||||
box-shadow: ${(props) => props.theme.navigation.boxShadow};
|
||||
border-radius: 0px 0px 6px 6px;
|
||||
|
||||
.title-container {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(1px, max-content) auto;
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
width: ${({ dropBoxWidth }) => dropBoxWidth + "px"};
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
right: -16px;
|
||||
`
|
||||
: css`
|
||||
left: -16px;
|
||||
`}
|
||||
padding: 0 16px;
|
||||
padding-top: 14px;
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
width: ${({ dropBoxWidth }) => dropBoxWidth + "px"};
|
||||
padding-top: 10px !important;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledBox.defaultProps = { theme: Base };
|
||||
|
||||
const Row = React.memo(({ data, index, style }) => {
|
||||
const isRoot = index === data[0].length - 1;
|
||||
return (
|
||||
<Item
|
||||
key={data[0][index].id}
|
||||
id={data[0][index].id}
|
||||
title={data[0][index].title}
|
||||
isRootRoom={data[0][index].isRootRoom}
|
||||
isRoot={isRoot}
|
||||
onClick={data[1]}
|
||||
withLogo={data[2].withLogo}
|
||||
currentDeviceType={data[2].currentDeviceType}
|
||||
style={{ ...style }}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const DropBox = React.forwardRef(
|
||||
(
|
||||
{
|
||||
sectionHeight,
|
||||
showText,
|
||||
dropBoxWidth,
|
||||
isRootFolder,
|
||||
onBackToParentFolder,
|
||||
title,
|
||||
personal,
|
||||
canCreate,
|
||||
navigationItems,
|
||||
getContextOptionsFolder,
|
||||
getContextOptionsPlus,
|
||||
toggleDropBox,
|
||||
toggleInfoPanel,
|
||||
onClickAvailable,
|
||||
isInfoPanelVisible,
|
||||
maxHeight,
|
||||
isOpen,
|
||||
isDesktop,
|
||||
isDesktopClient,
|
||||
showRootFolderNavigation,
|
||||
withLogo,
|
||||
burgerLogo,
|
||||
titleIcon,
|
||||
currentDeviceType,
|
||||
navigationTitleContainerNode,
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const [dropBoxHeight, setDropBoxHeight] = React.useState(0);
|
||||
const countItems = navigationItems.length;
|
||||
|
||||
const getItemSize = (index) => {
|
||||
if (index === countItems - 1) return 51;
|
||||
return currentDeviceType !== DeviceType.desktop ? 36 : 30;
|
||||
};
|
||||
|
||||
const { interfaceDirection } = useTheme();
|
||||
React.useEffect(() => {
|
||||
const itemsHeight = navigationItems.map((item, index) =>
|
||||
getItemSize(index)
|
||||
);
|
||||
|
||||
const currentHeight = itemsHeight.reduce((a, b) => a + b);
|
||||
|
||||
let navHeight = 41;
|
||||
|
||||
if (currentDeviceType === DeviceType.tablet) {
|
||||
navHeight = 49;
|
||||
}
|
||||
|
||||
if (currentDeviceType === DeviceType.mobile) {
|
||||
navHeight = 45;
|
||||
}
|
||||
|
||||
setDropBoxHeight(
|
||||
currentHeight + navHeight > sectionHeight
|
||||
? sectionHeight - navHeight - 20
|
||||
: currentHeight
|
||||
);
|
||||
}, [sectionHeight, currentDeviceType]);
|
||||
|
||||
const isTabletView = currentDeviceType === DeviceType.tablet;
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledBox
|
||||
ref={ref}
|
||||
maxHeight={maxHeight}
|
||||
height={sectionHeight < dropBoxHeight ? sectionHeight : null}
|
||||
showText={showText}
|
||||
dropBoxWidth={dropBoxWidth}
|
||||
isDesktop={isDesktop}
|
||||
withLogo={withLogo}
|
||||
>
|
||||
<StyledContainer
|
||||
canCreate={canCreate}
|
||||
isDropBoxComponent={true}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
isDesktopClient={isDesktopClient}
|
||||
withLogo={!!withLogo && isTabletView}
|
||||
>
|
||||
{withLogo && (
|
||||
<NavigationLogo
|
||||
logo={withLogo}
|
||||
burgerLogo={burgerLogo}
|
||||
className="navigation-logo drop-box-logo"
|
||||
/>
|
||||
)}
|
||||
<ArrowButton
|
||||
isRootFolder={isRootFolder}
|
||||
onBackToParentFolder={onBackToParentFolder}
|
||||
/>
|
||||
|
||||
{navigationTitleContainerNode}
|
||||
|
||||
<ControlButtons
|
||||
isDesktop={isDesktop}
|
||||
isMobile={currentDeviceType !== DeviceType.desktop}
|
||||
personal={personal}
|
||||
isRootFolder={isRootFolder}
|
||||
isDropBoxComponent={true}
|
||||
canCreate={canCreate}
|
||||
getContextOptionsFolder={getContextOptionsFolder}
|
||||
getContextOptionsPlus={getContextOptionsPlus}
|
||||
toggleInfoPanel={toggleInfoPanel}
|
||||
toggleDropBox={toggleDropBox}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
/>
|
||||
</StyledContainer>
|
||||
|
||||
<VariableSizeList
|
||||
direction={interfaceDirection}
|
||||
height={dropBoxHeight}
|
||||
width={"auto"}
|
||||
itemCount={countItems}
|
||||
itemSize={getItemSize}
|
||||
itemData={[
|
||||
navigationItems,
|
||||
onClickAvailable,
|
||||
{ withLogo: !!withLogo, currentDeviceType },
|
||||
]}
|
||||
outerElementType={CustomScrollbarsVirtualList}
|
||||
>
|
||||
{Row}
|
||||
</VariableSizeList>
|
||||
</StyledBox>
|
||||
</>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
DropBox.propTypes = {
|
||||
width: PropTypes.number,
|
||||
changeWidth: PropTypes.bool,
|
||||
isRootFolder: PropTypes.bool,
|
||||
onBackToParentFolder: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
personal: PropTypes.bool,
|
||||
canCreate: PropTypes.bool,
|
||||
navigationItems: PropTypes.arrayOf(PropTypes.object),
|
||||
getContextOptionsFolder: PropTypes.func,
|
||||
getContextOptionsPlus: PropTypes.func,
|
||||
toggleDropBox: PropTypes.func,
|
||||
onClickAvailable: PropTypes.func,
|
||||
};
|
||||
|
||||
export default React.memo(DropBox);
|
@ -1,126 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import styled, { css } from "styled-components";
|
||||
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
|
||||
import DefaultIcon from "PUBLIC_DIR/images/default.react.svg";
|
||||
import RootIcon from "PUBLIC_DIR/images/root.react.svg";
|
||||
import DefaultTabletIcon from "PUBLIC_DIR/images/default.tablet.react.svg";
|
||||
import RootTabletIcon from "PUBLIC_DIR/images/root.tablet.react.svg";
|
||||
|
||||
import { tablet, mobile } from "@docspace/shared/utils";
|
||||
import { Base } from "@docspace/shared/themes";
|
||||
|
||||
import { ColorTheme, ThemeId } from "@docspace/shared/components/color-theme";
|
||||
import { DeviceType } from "@docspace/shared/enums";
|
||||
|
||||
const StyledItem = styled.div`
|
||||
height: auto;
|
||||
width: auto !important;
|
||||
position: relative;
|
||||
display: grid;
|
||||
align-items: ${(props) => (props.isRoot ? "baseline" : "end")};
|
||||
grid-template-columns: 17px auto;
|
||||
cursor: pointer;
|
||||
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl" ? `margin-right: 0;` : `margin-left: 0;`}
|
||||
|
||||
@media ${tablet} {
|
||||
${({ withLogo }) =>
|
||||
withLogo &&
|
||||
css`
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: 44px;
|
||||
`
|
||||
: css`
|
||||
margin-left: 44px;
|
||||
`}
|
||||
`};
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: 0;
|
||||
`
|
||||
: css`
|
||||
margin-left: 0;
|
||||
`}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledText = styled(Text)`
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: 10px;
|
||||
`
|
||||
: css`
|
||||
margin-left: 10px;
|
||||
`}
|
||||
position: relative;
|
||||
bottom: ${(props) => (props.isRoot ? "2px" : "-1px")};
|
||||
`;
|
||||
|
||||
const Item = ({
|
||||
id,
|
||||
title,
|
||||
isRoot,
|
||||
isRootRoom,
|
||||
onClick,
|
||||
withLogo,
|
||||
currentDeviceType,
|
||||
...rest
|
||||
}) => {
|
||||
const onClickAvailable = () => {
|
||||
onClick && onClick(id, isRootRoom);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledItem
|
||||
id={id}
|
||||
isRoot={isRoot}
|
||||
onClick={onClickAvailable}
|
||||
withLogo={withLogo}
|
||||
{...rest}
|
||||
>
|
||||
<ColorTheme isRoot={isRoot} themeId={ThemeId.IconWrapper}>
|
||||
{currentDeviceType !== DeviceType.desktop ? (
|
||||
isRoot ? (
|
||||
<RootTabletIcon />
|
||||
) : (
|
||||
<DefaultTabletIcon />
|
||||
)
|
||||
) : isRoot ? (
|
||||
<RootIcon />
|
||||
) : (
|
||||
<DefaultIcon />
|
||||
)}
|
||||
</ColorTheme>
|
||||
|
||||
<StyledText
|
||||
isRoot={isRoot}
|
||||
fontWeight={isRoot ? "600" : "400"}
|
||||
fontSize={"15px"}
|
||||
truncate={true}
|
||||
title={title}
|
||||
>
|
||||
{title}
|
||||
</StyledText>
|
||||
</StyledItem>
|
||||
);
|
||||
};
|
||||
|
||||
Item.propTypes = {
|
||||
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
title: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
isRoot: PropTypes.bool,
|
||||
onClick: PropTypes.func,
|
||||
};
|
||||
|
||||
export default React.memo(Item);
|
@ -1,15 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
const NavigationLogo = ({ logo, burgerLogo, ...rest }) => {
|
||||
return (
|
||||
<div {...rest}>
|
||||
<img className="logo-icon_svg" src={logo} />
|
||||
<div className="header-burger">
|
||||
<img src={burgerLogo} /* onClick={onLogoClick} */ />
|
||||
</div>
|
||||
<div className="header_separator" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavigationLogo;
|
@ -1,65 +0,0 @@
|
||||
import React, { useState, useRef } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import PlusReactSvgUrl from "PUBLIC_DIR/images/icons/17/plus.svg?url";
|
||||
|
||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
import { ContextMenu } from "@docspace/shared/components/context-menu";
|
||||
|
||||
const PlusButton = (props) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const ref = useRef(null);
|
||||
const menuRef = useRef(null);
|
||||
|
||||
const { className, getData, withMenu, onPlusClick, isFrame, ...rest } = props;
|
||||
|
||||
const toggle = (e, isOpen) => {
|
||||
isOpen ? menuRef.current.show(e) : menuRef.current.hide(e);
|
||||
setIsOpen(isOpen);
|
||||
};
|
||||
|
||||
const onClick = (e) => {
|
||||
if (withMenu) toggle(e, !isOpen);
|
||||
else onPlusClick && onPlusClick();
|
||||
};
|
||||
|
||||
const onHide = () => {
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const model = getData();
|
||||
|
||||
return (
|
||||
<div ref={ref} className={className} {...rest}>
|
||||
<IconButton
|
||||
onClick={onClick}
|
||||
iconName={PlusReactSvgUrl}
|
||||
id={props.id}
|
||||
size={17}
|
||||
isFill
|
||||
/>
|
||||
<ContextMenu
|
||||
model={model}
|
||||
containerRef={ref}
|
||||
ref={menuRef}
|
||||
onHide={onHide}
|
||||
scaled={false}
|
||||
directionX="right"
|
||||
leftOffset={isFrame ? 190 : 150}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
PlusButton.propTypes = {
|
||||
className: PropTypes.string,
|
||||
getData: PropTypes.func.isRequired,
|
||||
onPlusClick: PropTypes.func,
|
||||
id: PropTypes.string,
|
||||
};
|
||||
|
||||
PlusButton.defaultProps = {
|
||||
withMenu: true,
|
||||
};
|
||||
|
||||
export default PlusButton;
|
@ -1,169 +0,0 @@
|
||||
import React from "react";
|
||||
import styled, { css } from "styled-components";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import ExpanderDownIcon from "PUBLIC_DIR/images/expander-down.react.svg";
|
||||
import ArrowIcon from "PUBLIC_DIR/images/arrow.react.svg";
|
||||
|
||||
import { Heading } from "@docspace/shared/components/heading";
|
||||
|
||||
import { tablet, mobile, commonIconsStyles } from "@docspace/shared/utils";
|
||||
|
||||
import { Base } from "@docspace/shared/themes";
|
||||
|
||||
const StyledTextContainer = styled.div`
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
|
||||
flex-direction: row;
|
||||
|
||||
position: relative;
|
||||
|
||||
${(props) =>
|
||||
!props.isRootFolder && !props.isRootFolderTitle && "cursor: pointer"};
|
||||
${(props) =>
|
||||
props.isRootFolderTitle &&
|
||||
(props.theme.interfaceDirection === "rtl"
|
||||
? "padding-left: 3px;"
|
||||
: "padding-right: 3px;")};
|
||||
|
||||
${(props) =>
|
||||
!props.isRootFolderTitle &&
|
||||
css`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
`};
|
||||
`;
|
||||
|
||||
const StyledHeading = styled(Heading)`
|
||||
font-weight: 700;
|
||||
font-size: ${(props) => props.theme.getCorrectFontSize("18px")};
|
||||
line-height: 24px;
|
||||
|
||||
margin: 0;
|
||||
|
||||
${(props) =>
|
||||
props.isRootFolderTitle &&
|
||||
`color: ${props.theme.navigation.rootFolderTitleColor}`};
|
||||
|
||||
@media ${tablet} {
|
||||
font-size: ${(props) => props.theme.getCorrectFontSize("21px")};
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
font-size: ${(props) => props.theme.getCorrectFontSize("18px")};
|
||||
line-height: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledExpanderDownIcon = styled(ExpanderDownIcon)`
|
||||
min-width: 8px !important;
|
||||
width: 8px !important;
|
||||
min-height: 18px !important;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
padding: 0 4px 0 2px;
|
||||
`
|
||||
: css`
|
||||
padding: 0 2px 0 4px;
|
||||
`}
|
||||
path {
|
||||
fill: ${(props) => props.theme.navigation.expanderColor};
|
||||
}
|
||||
|
||||
${commonIconsStyles};
|
||||
`;
|
||||
|
||||
const StyledArrowIcon = styled(ArrowIcon)`
|
||||
height: 12px;
|
||||
min-width: 12px;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
padding-right: 6px;
|
||||
`
|
||||
: css`
|
||||
padding-left: 6px;
|
||||
`}
|
||||
path {
|
||||
fill: ${(props) => props.theme.navigation.rootFolderTitleColor};
|
||||
}
|
||||
`;
|
||||
|
||||
StyledExpanderDownIcon.defaultProps = { theme: Base };
|
||||
|
||||
const StyledExpanderDownIconRotate = styled(ExpanderDownIcon)`
|
||||
min-width: 8px !important;
|
||||
width: 8px !important;
|
||||
min-height: 18px !important;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
padding: 0 2px 0 4px;
|
||||
`
|
||||
: css`
|
||||
padding: 0 4px 0 2px;
|
||||
`}
|
||||
transform: rotate(-180deg);
|
||||
|
||||
path {
|
||||
fill: ${(props) => props.theme.navigation.expanderColor};
|
||||
}
|
||||
|
||||
${commonIconsStyles};
|
||||
`;
|
||||
|
||||
StyledExpanderDownIconRotate.defaultProps = { theme: Base };
|
||||
|
||||
const Text = ({
|
||||
title,
|
||||
isRootFolder,
|
||||
isOpen,
|
||||
isRootFolderTitle,
|
||||
onClick,
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
<StyledTextContainer
|
||||
isRootFolder={isRootFolder}
|
||||
onClick={onClick}
|
||||
isOpen={isOpen}
|
||||
isRootFolderTitle={isRootFolderTitle}
|
||||
{...rest}
|
||||
>
|
||||
<StyledHeading
|
||||
type="content"
|
||||
title={title}
|
||||
truncate={true}
|
||||
isRootFolderTitle={isRootFolderTitle}
|
||||
>
|
||||
{title}
|
||||
</StyledHeading>
|
||||
|
||||
{isRootFolderTitle && <StyledArrowIcon />}
|
||||
|
||||
{!isRootFolderTitle && !isRootFolder ? (
|
||||
isOpen ? (
|
||||
<StyledExpanderDownIconRotate />
|
||||
) : (
|
||||
<StyledExpanderDownIcon />
|
||||
)
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</StyledTextContainer>
|
||||
);
|
||||
};
|
||||
|
||||
Text.propTypes = {
|
||||
title: PropTypes.string,
|
||||
isOpen: PropTypes.bool,
|
||||
isRootFolder: PropTypes.bool,
|
||||
onCLick: PropTypes.func,
|
||||
};
|
||||
|
||||
export default React.memo(Text);
|
@ -1,87 +0,0 @@
|
||||
import React from "react";
|
||||
import styled, { css } from "styled-components";
|
||||
import PanelReactSvgUrl from "PUBLIC_DIR/images/panel.react.svg?url";
|
||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
import { tablet } from "@docspace/shared/utils";
|
||||
import { Base } from "@docspace/shared/themes";
|
||||
import { ColorTheme, ThemeId } from "@docspace/shared/components/color-theme";
|
||||
|
||||
const StyledInfoPanelToggleColorThemeWrapper = styled(ColorTheme)`
|
||||
align-self: center;
|
||||
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: auto;
|
||||
transform: scaleX(-1);
|
||||
`
|
||||
: css`
|
||||
margin-left: auto;
|
||||
`}
|
||||
|
||||
margin-bottom: 1px;
|
||||
padding: 0;
|
||||
|
||||
.info-panel-toggle {
|
||||
margin-inline-end: 8px;
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
props.isInfoPanelVisible &&
|
||||
css`
|
||||
.info-panel-toggle-bg {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
background: ${props.theme.backgroundAndSubstrateColor};
|
||||
border: 1px solid ${props.theme.backgroundAndSubstrateColor};
|
||||
border-radius: 50%;
|
||||
.info-panel-toggle {
|
||||
margin: auto;
|
||||
margin-top: 25%;
|
||||
}
|
||||
}
|
||||
`}
|
||||
|
||||
@media ${tablet} {
|
||||
display: none;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: ${props.isRootFolder ? "auto" : "0"};
|
||||
`
|
||||
: css`
|
||||
margin-left: ${props.isRootFolder ? "auto" : "0"};
|
||||
`}
|
||||
}
|
||||
`;
|
||||
StyledInfoPanelToggleColorThemeWrapper.defaultProps = { theme: Base };
|
||||
|
||||
const ToggleInfoPanelButton = ({
|
||||
isRootFolder,
|
||||
isInfoPanelVisible,
|
||||
toggleInfoPanel,
|
||||
id,
|
||||
titles,
|
||||
}) => {
|
||||
return (
|
||||
<StyledInfoPanelToggleColorThemeWrapper
|
||||
isRootFolder={isRootFolder}
|
||||
themeId={ThemeId.InfoPanelToggle}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
>
|
||||
<div className="info-panel-toggle-bg">
|
||||
<IconButton
|
||||
id={id}
|
||||
className="info-panel-toggle"
|
||||
iconName={PanelReactSvgUrl}
|
||||
size="16"
|
||||
isFill={true}
|
||||
title={titles?.infoPanel}
|
||||
onClick={toggleInfoPanel}
|
||||
/>
|
||||
</div>
|
||||
</StyledInfoPanelToggleColorThemeWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ToggleInfoPanelButton;
|
@ -1,35 +0,0 @@
|
||||
import React from "react";
|
||||
import styled, { css } from "styled-components";
|
||||
import { tablet } from "@docspace/shared/utils";
|
||||
|
||||
const StyledTrashWarning = styled.div`
|
||||
box-sizing: border-box;
|
||||
height: 32px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: ${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl" ? `right` : `left`};
|
||||
|
||||
font-weight: 400;
|
||||
font-size: ${(props) => props.theme.getCorrectFontSize("12px")};
|
||||
line-height: 16px;
|
||||
|
||||
color: ${({ theme }) => theme.section.header.trashErasureLabelText};
|
||||
background: ${({ theme }) =>
|
||||
theme.section.header.trashErasureLabelBackground};
|
||||
|
||||
@media ${tablet} {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
const TrashWarning = ({ title }) => {
|
||||
return (
|
||||
<StyledTrashWarning className="trash-warning">{title}</StyledTrashWarning>
|
||||
);
|
||||
};
|
||||
|
||||
export default TrashWarning;
|
@ -52,6 +52,8 @@ export type HeaderType = {
|
||||
|
||||
export type ContextMenuModel = ContextMenuType | SeparatorType;
|
||||
|
||||
export type TGetContextMenuModel = () => ContextMenuModel[];
|
||||
|
||||
export interface ContextMenuProps {
|
||||
/** Unique identifier of the element */
|
||||
id?: string;
|
||||
@ -98,7 +100,7 @@ export interface ContextMenuProps {
|
||||
/** Fills the icons with default colors */
|
||||
fillIcon?: boolean;
|
||||
/** Function that returns an object containing the elements of the context menu */
|
||||
getContextModel?: () => ContextMenuModel[];
|
||||
getContextModel?: TGetContextMenuModel;
|
||||
/** Specifies the offset */
|
||||
leftOffset?: number;
|
||||
rightOffset?: number;
|
||||
@ -106,3 +108,8 @@ export interface ContextMenuProps {
|
||||
isArchive?: boolean;
|
||||
ref?: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
export type TContextMenuRef = {
|
||||
show: (e: React.MouseEvent) => void;
|
||||
hide: (e: React.MouseEvent) => {};
|
||||
};
|
||||
|
@ -2,8 +2,16 @@ import {
|
||||
ContextMenuModel,
|
||||
ContextMenuType,
|
||||
SeparatorType,
|
||||
TGetContextMenuModel,
|
||||
TContextMenuRef,
|
||||
} from "./ContextMenu.types";
|
||||
|
||||
export type { ContextMenuModel, ContextMenuType, SeparatorType };
|
||||
export type {
|
||||
TContextMenuRef,
|
||||
TGetContextMenuModel,
|
||||
ContextMenuModel,
|
||||
ContextMenuType,
|
||||
SeparatorType,
|
||||
};
|
||||
|
||||
export { ContextMenu } from "./ContextMenu";
|
||||
|
657
packages/shared/components/navigation/Navigation.styled.ts
Normal file
657
packages/shared/components/navigation/Navigation.styled.ts
Normal file
@ -0,0 +1,657 @@
|
||||
import styled, { css } from "styled-components";
|
||||
|
||||
import ExpanderDownIcon from "PUBLIC_DIR/images/expander-down.react.svg";
|
||||
import ArrowIcon from "PUBLIC_DIR/images/arrow.react.svg";
|
||||
|
||||
import { tablet, mobile, commonIconsStyles } from "../../utils";
|
||||
import { Base } from "../../themes";
|
||||
|
||||
import { ColorTheme } from "../color-theme";
|
||||
import { Heading } from "../heading";
|
||||
import { Text } from "../text";
|
||||
|
||||
const StyledContainer = styled.div<{
|
||||
isDropBoxComponent?: boolean;
|
||||
isDesktop: boolean;
|
||||
isInfoPanelVisible: boolean;
|
||||
isTrashFolder?: boolean;
|
||||
isRootFolder?: boolean;
|
||||
withLogo: boolean;
|
||||
isDesktopClient?: boolean;
|
||||
width?: number;
|
||||
}>`
|
||||
${(props) =>
|
||||
!props.isDropBoxComponent &&
|
||||
props.isDesktop &&
|
||||
css`
|
||||
width: fit-content;
|
||||
max-width: ${props.isInfoPanelVisible
|
||||
? `calc(100%)`
|
||||
: `calc(100% - 72px)`};
|
||||
`}
|
||||
|
||||
display: grid;
|
||||
align-items: center;
|
||||
|
||||
margin-right: ${(props) => (props.isTrashFolder ? "16px" : 0)};
|
||||
|
||||
grid-template-columns: ${({ isRootFolder, withLogo }) =>
|
||||
isRootFolder
|
||||
? withLogo
|
||||
? "1fr auto 1fr"
|
||||
: "auto 1fr"
|
||||
: withLogo
|
||||
? "1fr 49px auto 1fr"
|
||||
: "49px auto 1fr"};
|
||||
|
||||
.navigation-logo {
|
||||
display: flex;
|
||||
height: 24px;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 16px;
|
||||
`
|
||||
: css`
|
||||
margin-right: 16px;
|
||||
`}
|
||||
|
||||
@media ${tablet} {
|
||||
.logo-icon_svg {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header_separator {
|
||||
display: ${({ isRootFolder }) => (isRootFolder ? "block" : "none")};
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
border-right: 1px solid #dfe2e3;
|
||||
margin: 0 15px 0 0;
|
||||
`
|
||||
: css`
|
||||
border-left: 1px solid #dfe2e3;
|
||||
margin: 0 0 0 15px;
|
||||
`}
|
||||
|
||||
height: 21px;
|
||||
}
|
||||
|
||||
.header-burger {
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
margin-top: -2px;
|
||||
|
||||
img {
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drop-box-logo {
|
||||
display: none;
|
||||
|
||||
@media ${tablet} {
|
||||
display: grid;
|
||||
}
|
||||
}
|
||||
|
||||
height: 100%;
|
||||
${(props) =>
|
||||
props.isDesktopClient &&
|
||||
props.isDropBoxComponent &&
|
||||
css`
|
||||
max-height: 32px;
|
||||
`}
|
||||
|
||||
.navigation-arrow-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.arrow-button {
|
||||
padding-top: 2px;
|
||||
width: 17px;
|
||||
min-width: 17px;
|
||||
|
||||
svg {
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl" && `transform: scaleX(-1);`}
|
||||
}
|
||||
}
|
||||
|
||||
.title-container {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(1px, max-content) auto;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
.room-title {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.navigation-header-separator {
|
||||
display: block;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
padding-right: 16px;
|
||||
border-left: ${`1px solid ${props.theme.navigation.icon.stroke}`};
|
||||
`
|
||||
: css`
|
||||
padding-left: 16px;
|
||||
border-right: ${`1px solid ${props.theme.navigation.icon.stroke}`};
|
||||
`}
|
||||
|
||||
height: 21px;
|
||||
@media ${mobile} {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.headline-heading {
|
||||
display: flex;
|
||||
height: 32px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title-block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
gap: 8px;
|
||||
|
||||
.title-icon {
|
||||
min-width: 17px;
|
||||
min-height: 17px;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
|
||||
svg {
|
||||
path,
|
||||
rect {
|
||||
fill: ${({ theme }) => theme.navigation.publicIcon};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
width: 100%;
|
||||
grid-template-columns: ${({ isRootFolder, withLogo }) =>
|
||||
isRootFolder
|
||||
? withLogo
|
||||
? "59px 1fr auto"
|
||||
: "1fr auto"
|
||||
: withLogo
|
||||
? "43px 49px 1fr auto"
|
||||
: "49px 1fr auto"};
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
.navigation-logo {
|
||||
display: none;
|
||||
}
|
||||
|
||||
grid-template-columns: ${(props) =>
|
||||
props.isRootFolder ? "1fr auto" : "29px 1fr auto"};
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledInfoPanelToggleColorThemeWrapper = styled(ColorTheme)<{
|
||||
isInfoPanelVisible?: boolean;
|
||||
isRootFolder?: boolean;
|
||||
}>`
|
||||
align-self: center;
|
||||
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: auto;
|
||||
transform: scaleX(-1);
|
||||
`
|
||||
: css`
|
||||
margin-left: auto;
|
||||
`}
|
||||
|
||||
margin-bottom: 1px;
|
||||
padding: 0;
|
||||
|
||||
.info-panel-toggle {
|
||||
margin-inline-end: 8px;
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
props.isInfoPanelVisible &&
|
||||
css`
|
||||
.info-panel-toggle-bg {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
background: ${props.theme.backgroundAndSubstrateColor};
|
||||
border: 1px solid ${props.theme.backgroundAndSubstrateColor};
|
||||
border-radius: 50%;
|
||||
.info-panel-toggle {
|
||||
margin: auto;
|
||||
margin-top: 25%;
|
||||
}
|
||||
}
|
||||
`}
|
||||
|
||||
@media ${tablet} {
|
||||
display: none;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: ${props.isRootFolder ? "auto" : "0"};
|
||||
`
|
||||
: css`
|
||||
margin-left: ${props.isRootFolder ? "auto" : "0"};
|
||||
`}
|
||||
}
|
||||
`;
|
||||
StyledInfoPanelToggleColorThemeWrapper.defaultProps = { theme: Base };
|
||||
|
||||
const StyledControlButtonContainer = styled.div<{ isFrame?: boolean }>`
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: 16px;
|
||||
`
|
||||
: css`
|
||||
margin-left: 16px;
|
||||
`}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
height: 32px;
|
||||
|
||||
.add-button {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 16px;
|
||||
`
|
||||
: css`
|
||||
margin-right: 16px;
|
||||
`}
|
||||
min-width: 15px;
|
||||
|
||||
@media ${tablet} {
|
||||
display: ${(props) => (props.isFrame ? "flex" : "none")};
|
||||
}
|
||||
}
|
||||
|
||||
.add-drop-down {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.option-button {
|
||||
min-width: 17px;
|
||||
|
||||
/* ${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 16px;
|
||||
`
|
||||
: css`
|
||||
margin-right: 16px;
|
||||
`} */
|
||||
|
||||
/* @media ${tablet} {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 9px;
|
||||
`
|
||||
: css`
|
||||
margin-right: 9px;
|
||||
`}
|
||||
} */
|
||||
}
|
||||
|
||||
.trash-button {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 16px;
|
||||
`
|
||||
: css`
|
||||
margin-right: 16px;
|
||||
`}
|
||||
min-width: 15px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledInfoPanelToggleWrapper = styled.div<{
|
||||
isRootFolder: boolean;
|
||||
isInfoPanelVisible: boolean;
|
||||
}>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-self: center;
|
||||
justify-content: center;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: auto;
|
||||
`
|
||||
: css`
|
||||
margin-left: auto;
|
||||
`}
|
||||
|
||||
@media ${tablet} {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: ${props.isRootFolder ? "auto" : "0"};
|
||||
`
|
||||
: css`
|
||||
margin-left: ${props.isRootFolder ? "auto" : "0"};
|
||||
`}
|
||||
}
|
||||
|
||||
.info-panel-toggle-bg {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background-color: ${(props) =>
|
||||
props.isInfoPanelVisible
|
||||
? props.theme.infoPanel.sectionHeaderToggleBgActive
|
||||
: props.theme.infoPanel.sectionHeaderToggleBg};
|
||||
|
||||
path {
|
||||
fill: ${(props) =>
|
||||
props.isInfoPanelVisible
|
||||
? props.theme.infoPanel.sectionHeaderToggleIconActive
|
||||
: props.theme.infoPanel.sectionHeaderToggleIcon};
|
||||
}
|
||||
}
|
||||
`;
|
||||
StyledInfoPanelToggleWrapper.defaultProps = { theme: Base };
|
||||
|
||||
const StyledTrashWarning = styled.div`
|
||||
box-sizing: border-box;
|
||||
height: 32px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: ${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl" ? `right` : `left`};
|
||||
|
||||
font-weight: 400;
|
||||
font-size: ${(props) => props.theme.getCorrectFontSize("12px")};
|
||||
line-height: 16px;
|
||||
|
||||
color: ${({ theme }) => theme.section.header.trashErasureLabelText};
|
||||
background: ${({ theme }) =>
|
||||
theme.section.header.trashErasureLabelBackground};
|
||||
|
||||
@media ${tablet} {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledTrashWarning.defaultProps = { theme: Base };
|
||||
|
||||
const StyledTextContainer = styled.div<{
|
||||
isRootFolder: boolean;
|
||||
isRootFolderTitle: boolean;
|
||||
}>`
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
|
||||
flex-direction: row;
|
||||
|
||||
position: relative;
|
||||
|
||||
${(props) =>
|
||||
!props.isRootFolder && !props.isRootFolderTitle && "cursor: pointer"};
|
||||
${(props) =>
|
||||
props.isRootFolderTitle &&
|
||||
(props.theme.interfaceDirection === "rtl"
|
||||
? "padding-left: 3px;"
|
||||
: "padding-right: 3px;")};
|
||||
|
||||
${(props) =>
|
||||
!props.isRootFolderTitle &&
|
||||
css`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
`};
|
||||
`;
|
||||
|
||||
const StyledHeading = styled(Heading)<{ isRootFolderTitle: boolean }>`
|
||||
font-weight: 700;
|
||||
font-size: ${(props) => props.theme.getCorrectFontSize("18px")};
|
||||
line-height: 24px;
|
||||
|
||||
margin: 0;
|
||||
|
||||
${(props) =>
|
||||
props.isRootFolderTitle &&
|
||||
`color: ${props.theme.navigation.rootFolderTitleColor}`};
|
||||
|
||||
@media ${tablet} {
|
||||
font-size: ${(props) => props.theme.getCorrectFontSize("21px")};
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
font-size: ${(props) => props.theme.getCorrectFontSize("18px")};
|
||||
line-height: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledExpanderDownIcon = styled(ExpanderDownIcon)`
|
||||
min-width: 8px !important;
|
||||
width: 8px !important;
|
||||
min-height: 18px !important;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
padding: 0 4px 0 2px;
|
||||
`
|
||||
: css`
|
||||
padding: 0 2px 0 4px;
|
||||
`}
|
||||
path {
|
||||
fill: ${(props) => props.theme.navigation.expanderColor};
|
||||
}
|
||||
|
||||
${commonIconsStyles};
|
||||
`;
|
||||
|
||||
const StyledArrowIcon = styled(ArrowIcon)`
|
||||
height: 12px;
|
||||
min-width: 12px;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
padding-right: 6px;
|
||||
`
|
||||
: css`
|
||||
padding-left: 6px;
|
||||
`}
|
||||
path {
|
||||
fill: ${(props) => props.theme.navigation.rootFolderTitleColor};
|
||||
}
|
||||
`;
|
||||
|
||||
StyledExpanderDownIcon.defaultProps = { theme: Base };
|
||||
|
||||
const StyledExpanderDownIconRotate = styled(ExpanderDownIcon)`
|
||||
min-width: 8px !important;
|
||||
width: 8px !important;
|
||||
min-height: 18px !important;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
padding: 0 2px 0 4px;
|
||||
`
|
||||
: css`
|
||||
padding: 0 4px 0 2px;
|
||||
`}
|
||||
transform: rotate(-180deg);
|
||||
|
||||
path {
|
||||
fill: ${(props) => props.theme.navigation.expanderColor};
|
||||
}
|
||||
|
||||
${commonIconsStyles};
|
||||
`;
|
||||
|
||||
StyledExpanderDownIconRotate.defaultProps = { theme: Base };
|
||||
|
||||
const StyledItem = styled.div<{ isRoot: boolean; withLogo: boolean }>`
|
||||
height: auto;
|
||||
width: auto !important;
|
||||
position: relative;
|
||||
display: grid;
|
||||
align-items: ${(props) => (props.isRoot ? "baseline" : "end")};
|
||||
grid-template-columns: 17px auto;
|
||||
cursor: pointer;
|
||||
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl" ? `margin-right: 0;` : `margin-left: 0;`}
|
||||
|
||||
@media ${tablet} {
|
||||
${({ withLogo }) =>
|
||||
withLogo &&
|
||||
css`
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: 44px;
|
||||
`
|
||||
: css`
|
||||
margin-left: 44px;
|
||||
`}
|
||||
`};
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: 0;
|
||||
`
|
||||
: css`
|
||||
margin-left: 0;
|
||||
`}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledText = styled(Text)<{ isRoot: boolean }>`
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: 10px;
|
||||
`
|
||||
: css`
|
||||
margin-left: 10px;
|
||||
`}
|
||||
position: relative;
|
||||
bottom: ${(props) => (props.isRoot ? "2px" : "-1px")};
|
||||
`;
|
||||
|
||||
const StyledBox = styled.div<{
|
||||
withLogo: boolean;
|
||||
height: number | null;
|
||||
dropBoxWidth: number;
|
||||
}>`
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
right: -20px;
|
||||
${props.withLogo && `right: 207px;`};
|
||||
`
|
||||
: css`
|
||||
left: -20px;
|
||||
${props.withLogo && `left: 207px;`};
|
||||
`}
|
||||
padding: 0 20px;
|
||||
padding-top: 18px;
|
||||
|
||||
width: unset;
|
||||
|
||||
height: ${(props) => (props.height ? `${props.height}px` : "fit-content")};
|
||||
max-height: calc(100vh - 48px);
|
||||
|
||||
z-index: 401;
|
||||
display: table;
|
||||
margin: auto;
|
||||
flex-direction: column;
|
||||
|
||||
background: ${(props) => props.theme.navigation.background};
|
||||
|
||||
box-shadow: ${(props) => props.theme.navigation.boxShadow};
|
||||
border-radius: 0px 0px 6px 6px;
|
||||
|
||||
.title-container {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(1px, max-content) auto;
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
width: ${({ dropBoxWidth }) => `${dropBoxWidth}px`};
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
right: -16px;
|
||||
`
|
||||
: css`
|
||||
left: -16px;
|
||||
`}
|
||||
padding: 0 16px;
|
||||
padding-top: 14px;
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
width: ${({ dropBoxWidth }) => `${dropBoxWidth}px`};
|
||||
padding-top: 10px !important;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledBox.defaultProps = { theme: Base };
|
||||
|
||||
export {
|
||||
StyledContainer,
|
||||
StyledInfoPanelToggleColorThemeWrapper,
|
||||
StyledControlButtonContainer,
|
||||
StyledInfoPanelToggleWrapper,
|
||||
StyledTrashWarning,
|
||||
StyledTextContainer,
|
||||
StyledArrowIcon,
|
||||
StyledExpanderDownIcon,
|
||||
StyledExpanderDownIconRotate,
|
||||
StyledHeading,
|
||||
StyledText,
|
||||
StyledItem,
|
||||
StyledBox,
|
||||
};
|
@ -1,22 +1,21 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import StyledContainer from "./StyledNavigation";
|
||||
import ArrowButton from "./sub-components/arrow-btn";
|
||||
import Text from "./sub-components/text";
|
||||
import ControlButtons from "./sub-components/control-btn";
|
||||
import DropBox from "./sub-components/drop-box";
|
||||
|
||||
import { Consumer, DomHelpers } from "@docspace/shared/utils";
|
||||
|
||||
import { Backdrop } from "@docspace/shared/components/backdrop";
|
||||
|
||||
import React, { useCallback } from "react";
|
||||
import { ReactSVG } from "react-svg";
|
||||
|
||||
import ToggleInfoPanelButton from "./sub-components/toggle-infopanel-btn";
|
||||
import TrashWarning from "./sub-components/trash-warning";
|
||||
import NavigationLogo from "./sub-components/logo-block";
|
||||
import { DeviceType } from "@docspace/shared/enums";
|
||||
import { Consumer, DomHelpers } from "../../utils";
|
||||
import { DeviceType } from "../../enums";
|
||||
|
||||
import { Backdrop } from "../backdrop";
|
||||
|
||||
import ArrowButton from "./sub-components/ArrowBtn";
|
||||
import Text from "./sub-components/Text";
|
||||
import ControlButtons from "./sub-components/ControlBtn";
|
||||
import ToggleInfoPanelButton from "./sub-components/ToggleInfoPanelBtn";
|
||||
import TrashWarning from "./sub-components/TrashWarning";
|
||||
import NavigationLogo from "./sub-components/LogoBlock";
|
||||
import DropBox from "./sub-components/DropBox";
|
||||
|
||||
import { StyledContainer } from "./Navigation.styled";
|
||||
import { INavigationProps } from "./Navigation.types";
|
||||
|
||||
const Navigation = ({
|
||||
tReady,
|
||||
@ -25,7 +24,7 @@ const Navigation = ({
|
||||
title,
|
||||
canCreate,
|
||||
isTabletView,
|
||||
personal,
|
||||
|
||||
onClickFolder,
|
||||
navigationItems,
|
||||
getContextOptionsPlus,
|
||||
@ -55,61 +54,64 @@ const Navigation = ({
|
||||
rootRoomTitle,
|
||||
|
||||
...rest
|
||||
}) => {
|
||||
}: INavigationProps) => {
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
const [firstClick, setFirstClick] = React.useState(true);
|
||||
const [dropBoxWidth, setDropBoxWidth] = React.useState(0);
|
||||
const [maxHeight, setMaxHeight] = React.useState(false);
|
||||
// const [maxHeight, setMaxHeight] = React.useState("");
|
||||
|
||||
const dropBoxRef = React.useRef(null);
|
||||
const containerRef = React.useRef(null);
|
||||
const dropBoxRef = React.useRef<HTMLDivElement | null>(null);
|
||||
const containerRef = React.useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const isDesktop = currentDeviceType === DeviceType.desktop;
|
||||
|
||||
const infoPanelIsVisible = React.useMemo(
|
||||
() => isDesktop && (!isEmptyPage || (isEmptyPage && isRoom)),
|
||||
[isDesktop, isEmptyPage, isRoom]
|
||||
[isDesktop, isEmptyPage, isRoom],
|
||||
);
|
||||
|
||||
const onMissClick = React.useCallback(
|
||||
(e) => {
|
||||
e.preventDefault;
|
||||
const path = e.path || (e.composedPath && e.composedPath());
|
||||
|
||||
if (!firstClick) {
|
||||
!path.includes(dropBoxRef.current) ? toggleDropBox() : null;
|
||||
} else {
|
||||
setFirstClick((prev) => !prev);
|
||||
}
|
||||
},
|
||||
[firstClick, toggleDropBox, setFirstClick]
|
||||
);
|
||||
|
||||
const onClickAvailable = React.useCallback(
|
||||
(id, isRootRoom) => {
|
||||
onClickFolder && onClickFolder(id, isRootRoom);
|
||||
toggleDropBox();
|
||||
},
|
||||
[onClickFolder, toggleDropBox]
|
||||
);
|
||||
|
||||
const toggleDropBox = () => {
|
||||
const toggleDropBox = useCallback(() => {
|
||||
if (navigationItems.length === 0) return;
|
||||
if (isRootFolder) return setIsOpen(false);
|
||||
setIsOpen((prev) => !prev);
|
||||
|
||||
setDropBoxWidth(DomHelpers.getOuterWidth(containerRef.current));
|
||||
if (containerRef.current)
|
||||
setDropBoxWidth(DomHelpers.getOuterWidth(containerRef.current));
|
||||
|
||||
const { top } = DomHelpers.getOffset(containerRef.current);
|
||||
// const { top } = DomHelpers.getOffset(containerRef.current);
|
||||
|
||||
setMaxHeight(`calc(100vh - ${top}px)`);
|
||||
// setMaxHeight(`calc(100vh - ${top}px)`);
|
||||
|
||||
setFirstClick(true);
|
||||
};
|
||||
}, [isRootFolder, navigationItems?.length]);
|
||||
|
||||
const onMissClick = React.useCallback(
|
||||
(e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
const path = e.composedPath && e.composedPath();
|
||||
|
||||
if (!firstClick) {
|
||||
if (dropBoxRef.current && !path.includes(dropBoxRef.current))
|
||||
toggleDropBox();
|
||||
} else {
|
||||
setFirstClick((prev) => !prev);
|
||||
}
|
||||
},
|
||||
[firstClick, toggleDropBox, setFirstClick],
|
||||
);
|
||||
|
||||
const onClickAvailable = React.useCallback(
|
||||
(id: number | string, isRootRoom: boolean) => {
|
||||
onClickFolder?.(id, isRootRoom);
|
||||
toggleDropBox();
|
||||
},
|
||||
[onClickFolder, toggleDropBox],
|
||||
);
|
||||
|
||||
const onResize = React.useCallback(() => {
|
||||
setDropBoxWidth(DomHelpers.getOuterWidth(containerRef.current));
|
||||
}, [containerRef.current]);
|
||||
if (containerRef.current)
|
||||
setDropBoxWidth(DomHelpers.getOuterWidth(containerRef.current));
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isOpen) {
|
||||
@ -129,7 +131,7 @@ const Navigation = ({
|
||||
|
||||
const onBackToParentFolderAction = React.useCallback(() => {
|
||||
setIsOpen((val) => !val);
|
||||
onBackToParentFolder && onBackToParentFolder();
|
||||
onBackToParentFolder?.();
|
||||
}, [onBackToParentFolder]);
|
||||
|
||||
const showRootFolderNavigation =
|
||||
@ -146,10 +148,16 @@ const Navigation = ({
|
||||
isOpen={isOpen}
|
||||
isRootFolder={isRootFolder}
|
||||
onClick={toggleDropBox}
|
||||
isRootFolderTitle={false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
const onTextClick = React.useCallback(() => {
|
||||
onClickFolder(navigationItems[navigationItems.length - 2].id, false);
|
||||
setIsOpen(false);
|
||||
}, [navigationItems, onClickFolder]);
|
||||
|
||||
const navigationTitleContainerNode = showRootFolderNavigation ? (
|
||||
<div className="title-container">
|
||||
<Text
|
||||
@ -160,15 +168,7 @@ const Navigation = ({
|
||||
isOpen={isOpen}
|
||||
isRootFolder={isRootFolder}
|
||||
isRootFolderTitle
|
||||
onClick={() => {
|
||||
{
|
||||
onClickFolder(
|
||||
navigationItems[navigationItems.length - 2].id,
|
||||
false
|
||||
);
|
||||
setIsOpen(false);
|
||||
}
|
||||
}}
|
||||
onClick={onTextClick}
|
||||
/>
|
||||
{navigationTitleNode}
|
||||
</div>
|
||||
@ -185,7 +185,7 @@ const Navigation = ({
|
||||
<Backdrop
|
||||
visible={isOpen}
|
||||
withBackground={false}
|
||||
withoutBlur={true}
|
||||
withoutBlur
|
||||
zIndex={400}
|
||||
/>
|
||||
|
||||
@ -193,14 +193,10 @@ const Navigation = ({
|
||||
{...rest}
|
||||
isDesktop={isDesktop}
|
||||
ref={dropBoxRef}
|
||||
maxHeight={maxHeight}
|
||||
dropBoxWidth={dropBoxWidth}
|
||||
sectionHeight={context.sectionHeight}
|
||||
showText={showText}
|
||||
sectionHeight={context.sectionHeight || 0}
|
||||
isRootFolder={isRootFolder}
|
||||
onBackToParentFolder={onBackToParentFolderAction}
|
||||
title={title}
|
||||
personal={personal}
|
||||
canCreate={canCreate}
|
||||
navigationItems={navigationItems}
|
||||
getContextOptionsFolder={getContextOptionsFolder}
|
||||
@ -210,10 +206,8 @@ const Navigation = ({
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
onClickAvailable={onClickAvailable}
|
||||
isDesktopClient={isDesktopClient}
|
||||
showRootFolderNavigation={showRootFolderNavigation}
|
||||
withLogo={withLogo}
|
||||
burgerLogo={burgerLogo}
|
||||
titleIcon={titleIcon}
|
||||
currentDeviceType={currentDeviceType}
|
||||
navigationTitleContainerNode={navigationTitleContainerNode}
|
||||
/>
|
||||
@ -221,10 +215,8 @@ const Navigation = ({
|
||||
)}
|
||||
<StyledContainer
|
||||
ref={containerRef}
|
||||
width={context.sectionWidth}
|
||||
width={context.sectionWidth || 0}
|
||||
isRootFolder={isRootFolder}
|
||||
canCreate={canCreate}
|
||||
isTabletView={isTabletView}
|
||||
isTrashFolder={isTrashFolder}
|
||||
isDesktop={isDesktop}
|
||||
isDesktopClient={isDesktopClient}
|
||||
@ -235,7 +227,6 @@ const Navigation = ({
|
||||
{withLogo && (
|
||||
<NavigationLogo
|
||||
className="navigation-logo"
|
||||
logo={withLogo}
|
||||
burgerLogo={burgerLogo}
|
||||
/>
|
||||
)}
|
||||
@ -247,13 +238,11 @@ const Navigation = ({
|
||||
{navigationTitleContainerNode}
|
||||
|
||||
<ControlButtons
|
||||
personal={personal}
|
||||
isRootFolder={isRootFolder}
|
||||
canCreate={canCreate}
|
||||
getContextOptionsFolder={getContextOptionsFolder}
|
||||
getContextOptionsPlus={getContextOptionsPlus}
|
||||
isEmptyFilesList={isEmptyFilesList}
|
||||
clearTrash={clearTrash}
|
||||
toggleInfoPanel={toggleInfoPanel}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
isDesktop={isDesktop}
|
||||
@ -266,10 +255,7 @@ const Navigation = ({
|
||||
/>
|
||||
</StyledContainer>
|
||||
{isDesktop && isTrashFolder && !isEmptyPage && (
|
||||
<TrashWarning
|
||||
title={titles.trashWarning}
|
||||
isTabletView={isTabletView}
|
||||
/>
|
||||
<TrashWarning title={titles.trashWarning} />
|
||||
)}
|
||||
{infoPanelIsVisible && !hideInfoPanel && (
|
||||
<ToggleInfoPanelButton
|
||||
@ -286,22 +272,4 @@ const Navigation = ({
|
||||
);
|
||||
};
|
||||
|
||||
Navigation.propTypes = {
|
||||
tReady: PropTypes.bool,
|
||||
isRootFolder: PropTypes.bool,
|
||||
title: PropTypes.string,
|
||||
canCreate: PropTypes.bool,
|
||||
isDesktop: PropTypes.bool,
|
||||
isTabletView: PropTypes.bool,
|
||||
personal: PropTypes.bool,
|
||||
onClickFolder: PropTypes.func,
|
||||
navigationItems: PropTypes.arrayOf(PropTypes.object),
|
||||
getContextOptionsPlus: PropTypes.func,
|
||||
getContextOptionsFolder: PropTypes.func,
|
||||
onBackToParentFolder: PropTypes.func,
|
||||
titles: PropTypes.object,
|
||||
isEmptyPage: PropTypes.bool,
|
||||
isRoom: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default React.memo(Navigation);
|
163
packages/shared/components/navigation/Navigation.types.ts
Normal file
163
packages/shared/components/navigation/Navigation.types.ts
Normal file
@ -0,0 +1,163 @@
|
||||
import { DeviceType } from "../../enums";
|
||||
import { TGetContextMenuModel } from "../context-menu";
|
||||
|
||||
export type TOnBackToParenFolder = () => void;
|
||||
|
||||
export type TTitles = {
|
||||
infoPanel?: string;
|
||||
actions?: string;
|
||||
contextMenu?: string;
|
||||
trashWarning?: string;
|
||||
};
|
||||
|
||||
export interface IArrowButtonProps {
|
||||
isRootFolder: boolean;
|
||||
onBackToParentFolder: TOnBackToParenFolder;
|
||||
}
|
||||
|
||||
export interface IContextButtonProps {
|
||||
className: string;
|
||||
getData: TGetContextMenuModel;
|
||||
withMenu?: boolean;
|
||||
isTrashFolder?: boolean;
|
||||
isMobile: boolean;
|
||||
id: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface IPlusButtonProps {
|
||||
className: string;
|
||||
getData: TGetContextMenuModel;
|
||||
withMenu?: boolean;
|
||||
id?: string;
|
||||
title?: string;
|
||||
onPlusClick?: () => void;
|
||||
isFrame?: boolean;
|
||||
}
|
||||
|
||||
export interface IToggleInfoPanelButtonProps {
|
||||
isRootFolder: boolean;
|
||||
isInfoPanelVisible: boolean;
|
||||
toggleInfoPanel: (e: React.MouseEvent) => void;
|
||||
id?: string;
|
||||
titles?: TTitles;
|
||||
}
|
||||
|
||||
export interface IControlButtonProps {
|
||||
isRootFolder: boolean;
|
||||
canCreate: boolean;
|
||||
getContextOptionsFolder: TGetContextMenuModel;
|
||||
getContextOptionsPlus: TGetContextMenuModel;
|
||||
isEmptyFilesList?: boolean;
|
||||
isInfoPanelVisible: boolean;
|
||||
toggleInfoPanel: () => void;
|
||||
toggleDropBox?: () => void;
|
||||
isDesktop: boolean;
|
||||
titles?: TTitles;
|
||||
withMenu?: boolean;
|
||||
onPlusClick?: () => void;
|
||||
isFrame?: boolean;
|
||||
isPublicRoom?: boolean;
|
||||
isTrashFolder?: boolean;
|
||||
isMobile?: boolean;
|
||||
}
|
||||
|
||||
export interface ITextProps {
|
||||
title: string;
|
||||
isOpen: boolean;
|
||||
isRootFolder: boolean;
|
||||
isRootFolderTitle: boolean;
|
||||
onClick: () => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export interface INavigationLogoProps {
|
||||
logo?: string;
|
||||
burgerLogo: string;
|
||||
className: string;
|
||||
}
|
||||
|
||||
export type TOnNavigationItemClick = (
|
||||
id: string | number,
|
||||
isRootRoom: boolean,
|
||||
) => void;
|
||||
|
||||
export interface INavigationItemProps {
|
||||
id: string | number;
|
||||
title: string;
|
||||
isRoot: boolean;
|
||||
isRootRoom: boolean;
|
||||
onClick: TOnNavigationItemClick;
|
||||
withLogo: boolean;
|
||||
currentDeviceType: DeviceType;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export type TNavigationItem = {
|
||||
id: string | number;
|
||||
title: string;
|
||||
isRootRoom: boolean;
|
||||
};
|
||||
|
||||
export type TRowData = [
|
||||
TNavigationItem[],
|
||||
TOnNavigationItemClick,
|
||||
{ withLogo: boolean; currentDeviceType: DeviceType },
|
||||
];
|
||||
|
||||
export interface IDropBoxProps {
|
||||
sectionHeight: number;
|
||||
dropBoxWidth: number;
|
||||
isRootFolder: boolean;
|
||||
onBackToParentFolder: TOnBackToParenFolder;
|
||||
canCreate: boolean;
|
||||
navigationItems: TNavigationItem[];
|
||||
getContextOptionsFolder: TGetContextMenuModel;
|
||||
getContextOptionsPlus: TGetContextMenuModel;
|
||||
toggleInfoPanel: () => void;
|
||||
toggleDropBox: () => void;
|
||||
onClickAvailable: TOnNavigationItemClick;
|
||||
isInfoPanelVisible: boolean;
|
||||
isDesktop: boolean;
|
||||
isDesktopClient: boolean;
|
||||
withLogo: boolean;
|
||||
burgerLogo: string;
|
||||
currentDeviceType: DeviceType;
|
||||
navigationTitleContainerNode: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface INavigationProps {
|
||||
tReady: boolean;
|
||||
showText: boolean;
|
||||
isRootFolder: boolean;
|
||||
title: string;
|
||||
canCreate: boolean;
|
||||
isTabletView: boolean;
|
||||
onClickFolder: TOnNavigationItemClick;
|
||||
navigationItems: TNavigationItem[];
|
||||
onBackToParentFolder: TOnBackToParenFolder;
|
||||
getContextOptionsFolder: TGetContextMenuModel;
|
||||
getContextOptionsPlus: TGetContextMenuModel;
|
||||
isTrashFolder: boolean;
|
||||
isEmptyFilesList: boolean;
|
||||
clearTrash: () => void;
|
||||
showFolderInfo: () => void;
|
||||
isCurrentFolderInfo: boolean;
|
||||
toggleInfoPanel: () => void;
|
||||
isInfoPanelVisible: boolean;
|
||||
titles: TTitles;
|
||||
withMenu: boolean;
|
||||
onPlusClick: () => void;
|
||||
isEmptyPage: boolean;
|
||||
isDesktop: boolean;
|
||||
isRoom: boolean;
|
||||
isFrame: boolean;
|
||||
hideInfoPanel: () => void;
|
||||
withLogo: boolean;
|
||||
burgerLogo: string;
|
||||
showRootFolderTitle: boolean;
|
||||
isPublicRoom: boolean;
|
||||
titleIcon: string;
|
||||
currentDeviceType: DeviceType;
|
||||
rootRoomTitle: string;
|
||||
}
|
7
packages/shared/components/navigation/index.ts
Normal file
7
packages/shared/components/navigation/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import Navigation from "./Navigation";
|
||||
|
||||
import { TTitles, TNavigationItem } from "./Navigation.types";
|
||||
|
||||
export type { TTitles, TNavigationItem };
|
||||
|
||||
export default Navigation;
|
@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
|
||||
import ArrowPathReactSvgUrl from "PUBLIC_DIR/images/arrow.path.react.svg?url";
|
||||
|
||||
import { IconButton } from "../../icon-button";
|
||||
|
||||
import { IArrowButtonProps } from "../Navigation.types";
|
||||
|
||||
const ArrowButton = ({
|
||||
isRootFolder,
|
||||
onBackToParentFolder,
|
||||
}: IArrowButtonProps) => {
|
||||
return !isRootFolder ? (
|
||||
<div className="navigation-arrow-container">
|
||||
<IconButton
|
||||
iconName={ArrowPathReactSvgUrl}
|
||||
size={17}
|
||||
isFill
|
||||
onClick={onBackToParentFolder}
|
||||
className="arrow-button"
|
||||
/>
|
||||
<div className="navigation-header-separator" />
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default React.memo(ArrowButton);
|
@ -1,23 +1,36 @@
|
||||
import React, { useState, useRef } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import VerticalDotsReactSvgUrl from "PUBLIC_DIR/images/icons/17/vertical-dots.react.svg?url";
|
||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
import { ContextMenu } from "@docspace/shared/components/context-menu";
|
||||
|
||||
const ContextButton = (props) => {
|
||||
import { IconButton } from "../../icon-button";
|
||||
import { ContextMenu, TContextMenuRef } from "../../context-menu";
|
||||
|
||||
import { IContextButtonProps } from "../Navigation.types";
|
||||
|
||||
const ContextButton = ({
|
||||
className,
|
||||
getData,
|
||||
withMenu = true,
|
||||
isTrashFolder,
|
||||
isMobile,
|
||||
id,
|
||||
...rest
|
||||
}: IContextButtonProps) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const ref = useRef(null);
|
||||
const menuRef = useRef(null);
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
const menuRef = useRef<TContextMenuRef | null>(null);
|
||||
|
||||
const { className, getData, withMenu, isTrashFolder, isMobile, ...rest } =
|
||||
props;
|
||||
const toggle = (e: React.MouseEvent<HTMLDivElement>, open: boolean) => {
|
||||
if (open) {
|
||||
menuRef.current?.show(e);
|
||||
} else {
|
||||
menuRef.current?.hide(e);
|
||||
}
|
||||
|
||||
const toggle = (e, isOpen) => {
|
||||
isOpen ? menuRef.current.show(e) : menuRef.current.hide(e);
|
||||
setIsOpen(isOpen);
|
||||
setIsOpen(open);
|
||||
};
|
||||
|
||||
const onClick = (e) => {
|
||||
const onClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (withMenu) toggle(e, !isOpen);
|
||||
};
|
||||
|
||||
@ -32,7 +45,7 @@ const ContextButton = (props) => {
|
||||
<IconButton
|
||||
onClick={onClick}
|
||||
iconName={VerticalDotsReactSvgUrl}
|
||||
id={props.id}
|
||||
id={id}
|
||||
size={17}
|
||||
isFill
|
||||
/>
|
||||
@ -48,14 +61,4 @@ const ContextButton = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
ContextButton.propTypes = {
|
||||
className: PropTypes.string,
|
||||
getData: PropTypes.func.isRequired,
|
||||
id: PropTypes.string,
|
||||
};
|
||||
|
||||
ContextButton.defaultProps = {
|
||||
withMenu: true,
|
||||
};
|
||||
|
||||
export default ContextButton;
|
@ -0,0 +1,131 @@
|
||||
import React from "react";
|
||||
|
||||
import { StyledControlButtonContainer } from "../Navigation.styled";
|
||||
import { IControlButtonProps } from "../Navigation.types";
|
||||
|
||||
import ToggleInfoPanelButton from "./ToggleInfoPanelBtn";
|
||||
import PlusButton from "./PlusBtn";
|
||||
import ContextButton from "./ContextBtn";
|
||||
|
||||
const ControlButtons = ({
|
||||
isRootFolder,
|
||||
canCreate,
|
||||
getContextOptionsFolder,
|
||||
getContextOptionsPlus,
|
||||
isEmptyFilesList,
|
||||
isInfoPanelVisible,
|
||||
toggleInfoPanel,
|
||||
toggleDropBox,
|
||||
isDesktop,
|
||||
titles,
|
||||
withMenu,
|
||||
onPlusClick,
|
||||
isFrame,
|
||||
isPublicRoom,
|
||||
isTrashFolder,
|
||||
isMobile,
|
||||
}: IControlButtonProps) => {
|
||||
const toggleInfoPanelAction = () => {
|
||||
toggleInfoPanel?.();
|
||||
toggleDropBox?.();
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledControlButtonContainer isFrame={isFrame}>
|
||||
{!isRootFolder || (isTrashFolder && !isEmptyFilesList) ? (
|
||||
<>
|
||||
{!isMobile && canCreate && (
|
||||
<PlusButton
|
||||
className="add-button"
|
||||
getData={getContextOptionsPlus}
|
||||
withMenu={withMenu}
|
||||
onPlusClick={onPlusClick}
|
||||
isFrame={isFrame}
|
||||
title={titles?.actions}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* <ContextMenuButton
|
||||
id="header_optional-button"
|
||||
zIndex={402}
|
||||
className="option-button"
|
||||
directionX="right"
|
||||
iconName={VerticalDotsReactSvgUrl}
|
||||
size={15}
|
||||
isFill
|
||||
getData={getContextOptionsFolder}
|
||||
isDisabled={false}
|
||||
title={titles?.contextMenu}
|
||||
/> */}
|
||||
|
||||
<ContextButton
|
||||
id="header_optional-button"
|
||||
className="option-button"
|
||||
getData={getContextOptionsFolder}
|
||||
withMenu={withMenu}
|
||||
// onPlusClick={onPlusClick}
|
||||
title={titles?.actions}
|
||||
isTrashFolder={isTrashFolder}
|
||||
isMobile={isMobile || false}
|
||||
/>
|
||||
|
||||
{!isDesktop && (
|
||||
<ToggleInfoPanelButton
|
||||
isRootFolder={isRootFolder}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
toggleInfoPanel={toggleInfoPanelAction}
|
||||
titles={titles}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : canCreate ? (
|
||||
<>
|
||||
{!isMobile && (
|
||||
<PlusButton
|
||||
id="header_add-button"
|
||||
className="add-button"
|
||||
getData={getContextOptionsPlus}
|
||||
withMenu={withMenu}
|
||||
onPlusClick={onPlusClick}
|
||||
isFrame={isFrame}
|
||||
title={titles?.actions}
|
||||
/>
|
||||
)}
|
||||
{!isDesktop && (
|
||||
<ToggleInfoPanelButton
|
||||
isRootFolder={isRootFolder}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
toggleInfoPanel={toggleInfoPanelAction}
|
||||
titles={titles}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{!isDesktop && (
|
||||
<ToggleInfoPanelButton
|
||||
isRootFolder={isRootFolder}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
toggleInfoPanel={toggleInfoPanelAction}
|
||||
titles={titles}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isPublicRoom && (
|
||||
<ContextButton
|
||||
id="header_optional-button"
|
||||
className="option-button"
|
||||
getData={getContextOptionsFolder}
|
||||
withMenu={withMenu}
|
||||
title={titles?.contextMenu}
|
||||
isTrashFolder={isTrashFolder}
|
||||
isMobile={isMobile || false}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</StyledControlButtonContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ControlButtons);
|
146
packages/shared/components/navigation/sub-components/DropBox.tsx
Normal file
146
packages/shared/components/navigation/sub-components/DropBox.tsx
Normal file
@ -0,0 +1,146 @@
|
||||
import React, { useCallback } from "react";
|
||||
import { useTheme } from "styled-components";
|
||||
import { Direction, VariableSizeList } from "react-window";
|
||||
|
||||
import { DeviceType } from "../../../enums";
|
||||
|
||||
import { CustomScrollbarsVirtualList } from "../../scrollbar";
|
||||
|
||||
import { StyledBox, StyledContainer } from "../Navigation.styled";
|
||||
import { IDropBoxProps } from "../Navigation.types";
|
||||
|
||||
import NavigationLogo from "./LogoBlock";
|
||||
import ArrowButton from "./ArrowBtn";
|
||||
import ControlButtons from "./ControlBtn";
|
||||
import Row from "./Row";
|
||||
|
||||
const DropBox = React.forwardRef<HTMLDivElement, IDropBoxProps>(
|
||||
(
|
||||
{
|
||||
sectionHeight,
|
||||
|
||||
dropBoxWidth,
|
||||
isRootFolder,
|
||||
onBackToParentFolder,
|
||||
|
||||
canCreate,
|
||||
navigationItems,
|
||||
getContextOptionsFolder,
|
||||
getContextOptionsPlus,
|
||||
toggleDropBox,
|
||||
toggleInfoPanel,
|
||||
onClickAvailable,
|
||||
isInfoPanelVisible,
|
||||
|
||||
isDesktop,
|
||||
isDesktopClient,
|
||||
|
||||
withLogo,
|
||||
burgerLogo,
|
||||
|
||||
currentDeviceType,
|
||||
navigationTitleContainerNode,
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const [dropBoxHeight, setDropBoxHeight] = React.useState(0);
|
||||
const countItems = navigationItems.length;
|
||||
|
||||
const getItemSize = useCallback(
|
||||
(index: number): number => {
|
||||
if (index === countItems - 1) return 51;
|
||||
return currentDeviceType !== DeviceType.desktop ? 36 : 30;
|
||||
},
|
||||
[countItems, currentDeviceType],
|
||||
);
|
||||
|
||||
const { interfaceDirection } = useTheme();
|
||||
React.useEffect(() => {
|
||||
const itemsHeight = navigationItems.map((item, index) =>
|
||||
getItemSize(index),
|
||||
);
|
||||
|
||||
const currentHeight = itemsHeight.reduce((a, b) => a + b);
|
||||
|
||||
let navHeight = 41;
|
||||
|
||||
if (currentDeviceType === DeviceType.tablet) {
|
||||
navHeight = 49;
|
||||
}
|
||||
|
||||
if (currentDeviceType === DeviceType.mobile) {
|
||||
navHeight = 45;
|
||||
}
|
||||
|
||||
setDropBoxHeight(
|
||||
currentHeight + navHeight > sectionHeight
|
||||
? sectionHeight - navHeight - 20
|
||||
: currentHeight,
|
||||
);
|
||||
}, [sectionHeight, currentDeviceType, navigationItems, getItemSize]);
|
||||
|
||||
const isTabletView = currentDeviceType === DeviceType.tablet;
|
||||
|
||||
return (
|
||||
<StyledBox
|
||||
ref={ref}
|
||||
height={sectionHeight < dropBoxHeight ? sectionHeight : null}
|
||||
dropBoxWidth={dropBoxWidth}
|
||||
withLogo={withLogo}
|
||||
>
|
||||
<StyledContainer
|
||||
isDropBoxComponent
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
isDesktopClient={isDesktopClient}
|
||||
withLogo={!!withLogo && isTabletView}
|
||||
isDesktop={isDesktop}
|
||||
>
|
||||
{withLogo && (
|
||||
<NavigationLogo
|
||||
burgerLogo={burgerLogo}
|
||||
className="navigation-logo drop-box-logo"
|
||||
/>
|
||||
)}
|
||||
<ArrowButton
|
||||
isRootFolder={isRootFolder}
|
||||
onBackToParentFolder={onBackToParentFolder}
|
||||
/>
|
||||
|
||||
{navigationTitleContainerNode}
|
||||
|
||||
<ControlButtons
|
||||
isDesktop={isDesktop}
|
||||
isMobile={currentDeviceType !== DeviceType.desktop}
|
||||
isRootFolder={isRootFolder}
|
||||
canCreate={canCreate}
|
||||
getContextOptionsFolder={getContextOptionsFolder}
|
||||
getContextOptionsPlus={getContextOptionsPlus}
|
||||
toggleInfoPanel={toggleInfoPanel}
|
||||
toggleDropBox={toggleDropBox}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
/>
|
||||
</StyledContainer>
|
||||
|
||||
<VariableSizeList
|
||||
direction={interfaceDirection as Direction}
|
||||
height={dropBoxHeight}
|
||||
width="auto"
|
||||
itemCount={countItems}
|
||||
itemSize={getItemSize}
|
||||
itemData={[
|
||||
navigationItems,
|
||||
onClickAvailable,
|
||||
{ withLogo: !!withLogo, currentDeviceType },
|
||||
]}
|
||||
outerElementType={CustomScrollbarsVirtualList}
|
||||
>
|
||||
{Row}
|
||||
</VariableSizeList>
|
||||
</StyledBox>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
DropBox.displayName = "DropBox";
|
||||
|
||||
export default React.memo(DropBox);
|
@ -0,0 +1,63 @@
|
||||
import React from "react";
|
||||
|
||||
import DefaultIcon from "PUBLIC_DIR/images/default.react.svg";
|
||||
import RootIcon from "PUBLIC_DIR/images/root.react.svg";
|
||||
import DefaultTabletIcon from "PUBLIC_DIR/images/default.tablet.react.svg";
|
||||
import RootTabletIcon from "PUBLIC_DIR/images/root.tablet.react.svg";
|
||||
|
||||
import { DeviceType } from "../../../enums";
|
||||
|
||||
import { ColorTheme, ThemeId } from "../../color-theme";
|
||||
import { StyledItem, StyledText } from "../Navigation.styled";
|
||||
import { INavigationItemProps } from "../Navigation.types";
|
||||
|
||||
const Item = ({
|
||||
id,
|
||||
title,
|
||||
isRoot,
|
||||
isRootRoom,
|
||||
onClick,
|
||||
withLogo,
|
||||
currentDeviceType,
|
||||
...rest
|
||||
}: INavigationItemProps) => {
|
||||
const onClickAvailable = () => {
|
||||
onClick?.(id, isRootRoom);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledItem
|
||||
id={`${id}`}
|
||||
isRoot={isRoot}
|
||||
onClick={onClickAvailable}
|
||||
withLogo={withLogo}
|
||||
{...rest}
|
||||
>
|
||||
<ColorTheme isRoot={isRoot} themeId={ThemeId.IconWrapper}>
|
||||
{currentDeviceType !== DeviceType.desktop ? (
|
||||
isRoot ? (
|
||||
<RootTabletIcon />
|
||||
) : (
|
||||
<DefaultTabletIcon />
|
||||
)
|
||||
) : isRoot ? (
|
||||
<RootIcon />
|
||||
) : (
|
||||
<DefaultIcon />
|
||||
)}
|
||||
</ColorTheme>
|
||||
|
||||
<StyledText
|
||||
isRoot={isRoot}
|
||||
fontWeight={isRoot ? "600" : "400"}
|
||||
fontSize="15px"
|
||||
truncate
|
||||
title={title}
|
||||
>
|
||||
{title}
|
||||
</StyledText>
|
||||
</StyledItem>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Item);
|
@ -0,0 +1,20 @@
|
||||
import React from "react";
|
||||
import { INavigationLogoProps } from "../Navigation.types";
|
||||
|
||||
const NavigationLogo = ({
|
||||
logo,
|
||||
burgerLogo,
|
||||
...rest
|
||||
}: INavigationLogoProps) => {
|
||||
return (
|
||||
<div {...rest}>
|
||||
<img className="logo-icon_svg" alt="logo" src={logo} />
|
||||
<div className="header-burger">
|
||||
<img src={burgerLogo} alt="burger logo" /* onClick={onLogoClick} */ />
|
||||
</div>
|
||||
<div className="header_separator" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavigationLogo;
|
@ -0,0 +1,65 @@
|
||||
import React, { useState, useRef } from "react";
|
||||
|
||||
import PlusReactSvgUrl from "PUBLIC_DIR/images/icons/17/plus.svg?url";
|
||||
|
||||
import { IconButton } from "../../icon-button";
|
||||
import { ContextMenu, TContextMenuRef } from "../../context-menu";
|
||||
import { IPlusButtonProps } from "../Navigation.types";
|
||||
|
||||
const PlusButton = ({
|
||||
className,
|
||||
getData,
|
||||
withMenu = true,
|
||||
onPlusClick,
|
||||
isFrame,
|
||||
id,
|
||||
...rest
|
||||
}: IPlusButtonProps) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
const menuRef = useRef<TContextMenuRef | null>(null);
|
||||
|
||||
const toggle = (e: React.MouseEvent<HTMLDivElement>, open: boolean) => {
|
||||
if (open) {
|
||||
menuRef.current?.show(e);
|
||||
} else {
|
||||
menuRef.current?.hide(e);
|
||||
}
|
||||
|
||||
setIsOpen(open);
|
||||
};
|
||||
|
||||
const onClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (withMenu) toggle(e, !isOpen);
|
||||
else onPlusClick?.();
|
||||
};
|
||||
|
||||
const onHide = () => {
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const model = getData();
|
||||
|
||||
return (
|
||||
<div ref={ref} className={className} {...rest}>
|
||||
<IconButton
|
||||
onClick={onClick}
|
||||
iconName={PlusReactSvgUrl}
|
||||
id={id}
|
||||
size={17}
|
||||
isFill
|
||||
/>
|
||||
<ContextMenu
|
||||
model={model}
|
||||
containerRef={ref}
|
||||
ref={menuRef}
|
||||
onHide={onHide}
|
||||
scaled={false}
|
||||
// directionX="right"
|
||||
leftOffset={isFrame ? 190 : 150}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlusButton;
|
35
packages/shared/components/navigation/sub-components/Row.tsx
Normal file
35
packages/shared/components/navigation/sub-components/Row.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import React from "react";
|
||||
import Item from "./Item";
|
||||
|
||||
import { TRowData } from "../Navigation.types";
|
||||
|
||||
const Row = React.memo(
|
||||
({
|
||||
data,
|
||||
index,
|
||||
style,
|
||||
}: {
|
||||
data: TRowData;
|
||||
index: number;
|
||||
style: React.CSSProperties;
|
||||
}) => {
|
||||
const isRoot = index === data[0].length - 1;
|
||||
return (
|
||||
<Item
|
||||
key={data[0][index].id}
|
||||
id={data[0][index].id}
|
||||
title={data[0][index].title}
|
||||
isRootRoom={data[0][index].isRootRoom}
|
||||
isRoot={isRoot}
|
||||
onClick={data[1]}
|
||||
withLogo={data[2].withLogo}
|
||||
currentDeviceType={data[2].currentDeviceType}
|
||||
style={{ ...style }}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Row.displayName = "Row";
|
||||
|
||||
export default Row;
|
@ -0,0 +1,49 @@
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
StyledArrowIcon,
|
||||
StyledExpanderDownIcon,
|
||||
StyledExpanderDownIconRotate,
|
||||
StyledHeading,
|
||||
StyledTextContainer,
|
||||
} from "../Navigation.styled";
|
||||
|
||||
import { ITextProps } from "../Navigation.types";
|
||||
|
||||
const Text = ({
|
||||
title,
|
||||
isRootFolder,
|
||||
isOpen,
|
||||
isRootFolderTitle,
|
||||
onClick,
|
||||
...rest
|
||||
}: ITextProps) => {
|
||||
return (
|
||||
<StyledTextContainer
|
||||
isRootFolder={isRootFolder}
|
||||
onClick={onClick}
|
||||
isRootFolderTitle={isRootFolderTitle}
|
||||
{...rest}
|
||||
>
|
||||
<StyledHeading
|
||||
title={title}
|
||||
truncate
|
||||
isRootFolderTitle={isRootFolderTitle}
|
||||
>
|
||||
{title}
|
||||
</StyledHeading>
|
||||
|
||||
{isRootFolderTitle && <StyledArrowIcon />}
|
||||
|
||||
{!isRootFolderTitle && !isRootFolder ? (
|
||||
isOpen ? (
|
||||
<StyledExpanderDownIconRotate />
|
||||
) : (
|
||||
<StyledExpanderDownIcon />
|
||||
)
|
||||
) : null}
|
||||
</StyledTextContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Text);
|
@ -0,0 +1,38 @@
|
||||
import React from "react";
|
||||
|
||||
import PanelReactSvgUrl from "PUBLIC_DIR/images/panel.react.svg?url";
|
||||
|
||||
import { IconButton } from "../../icon-button";
|
||||
import { ThemeId } from "../../color-theme";
|
||||
import { IToggleInfoPanelButtonProps } from "../Navigation.types";
|
||||
import { StyledInfoPanelToggleColorThemeWrapper } from "../Navigation.styled";
|
||||
|
||||
const ToggleInfoPanelButton = ({
|
||||
isRootFolder,
|
||||
isInfoPanelVisible,
|
||||
toggleInfoPanel,
|
||||
id,
|
||||
titles,
|
||||
}: IToggleInfoPanelButtonProps) => {
|
||||
return (
|
||||
<StyledInfoPanelToggleColorThemeWrapper
|
||||
isRootFolder={isRootFolder}
|
||||
themeId={ThemeId.InfoPanelToggle}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
>
|
||||
<div className="info-panel-toggle-bg">
|
||||
<IconButton
|
||||
id={id}
|
||||
className="info-panel-toggle"
|
||||
iconName={PanelReactSvgUrl}
|
||||
size={16}
|
||||
isFill
|
||||
title={titles?.infoPanel}
|
||||
onClick={toggleInfoPanel}
|
||||
/>
|
||||
</div>
|
||||
</StyledInfoPanelToggleColorThemeWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ToggleInfoPanelButton;
|
@ -0,0 +1,10 @@
|
||||
import React from "react";
|
||||
import { StyledTrashWarning } from "../Navigation.styled";
|
||||
|
||||
const TrashWarning = ({ title }: { title?: string }) => {
|
||||
return (
|
||||
<StyledTrashWarning className="trash-warning">{title}</StyledTrashWarning>
|
||||
);
|
||||
};
|
||||
|
||||
export default TrashWarning;
|
@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
|
||||
const defaultValue = {};
|
||||
const defaultValue: { sectionWidth?: number; sectionHeight?: number } = {};
|
||||
|
||||
export const Context = React.createContext(defaultValue);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user