feat: add Menu component

This commit is contained in:
QiShaoXuan 2022-11-03 19:00:17 +08:00
parent 75f05cb399
commit 523f3f273c
6 changed files with 185 additions and 39 deletions

View File

@ -2,6 +2,69 @@ import type { DOMAttributes, CSSProperties } from 'react';
type IconProps = {
style?: CSSProperties;
} & DOMAttributes<SVGElement>;
export const RightArrow = ({ style = {}, ...props }: IconProps) => {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
style={style}
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M11.667 10.0007L8.33366 6.66732L8.33366 13.334L11.667 10.0007Z"
/>
</svg>
);
};
export const Export2Markdown = ({ style = {}, ...props }: IconProps) => {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
style={style}
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.99963 1.66707V1.66699H10.833L16.6663 7.50033V7.50037L16.6663 7.50041V15.8337C16.6663 17.2145 15.5471 18.3337 14.1663 18.3337H5.83301C4.4523 18.3337 3.33301 17.2145 3.33301 15.8337V4.16707C3.33301 2.78636 4.4523 1.66707 5.83301 1.66707H9.99963ZM9.99963 3.00041H5.83301C5.18868 3.00041 4.66634 3.52274 4.66634 4.16707V15.8337C4.66634 16.4781 5.18868 17.0004 5.83301 17.0004H14.1663C14.8107 17.0004 15.333 16.4781 15.333 15.8337V8.33366H12.4996C11.1189 8.33366 9.99963 7.21437 9.99963 5.83366V3.00041ZM11.333 4.05265L14.2806 7.00033H12.4996C11.8553 7.00033 11.333 6.47799 11.333 5.83366V4.05265Z"
/>
<path d="M11.245 14.1671L11.2683 11.2446H11.2508L10.1775 14.1671H9.4775L8.43333 11.2446H8.41583L8.43917 14.1671H7.5V10.0371H8.9175L9.85667 12.6854H9.88L10.7783 10.0371H12.2192V14.1671H11.245Z" />
</svg>
);
};
export const Export2HTML = ({ style = {}, ...props }: IconProps) => {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
style={style}
{...props}
>
<path d="M5.35987 18.3335V16.7055H3.84187V18.3335H2.90137V14.4395H3.84187V15.9135H5.35987V14.4395H6.30037V18.3335H5.35987Z" />
<path d="M8.76806 15.2425V18.3335H7.82756V15.2425H6.72756V14.4395H9.86806V15.2425H8.76806Z" />
<path d="M13.8284 18.3335L13.8504 15.578H13.8339L12.8219 18.3335H12.1619L11.1774 15.578H11.1609L11.1829 18.3335H10.2974V14.4395H11.6339L12.5194 16.9365H12.5414L13.3884 14.4395H14.7469V18.3335H13.8284Z" />
<path d="M15.5503 18.3335V14.4395H16.4963V17.514H18.0033V18.3335H15.5503Z" />
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.99963 1.66707V1.66699H10.833L11.333 2.16699L16.1663 7.00032L16.6663 7.50033V7.50037L16.6663 7.50041V13.3337H15.333V8.33366H15.333H12.4996C11.1189 8.33366 9.99963 7.21437 9.99963 5.83366V3.00041H5.83301C5.18868 3.00041 4.66634 3.52274 4.66634 4.16707V13.3337H3.33301V4.16707C3.33301 2.78636 4.4523 1.66707 5.83301 1.66707H9.99963ZM11.333 4.05265V5.83366C11.333 6.47799 11.8553 7.00032 12.4996 7.00032H14.2806L11.333 4.05265Z"
/>
</svg>
);
};
export const LogoIcon = ({ style = {}, ...props }: IconProps) => {
return (
<svg

View File

@ -1,18 +1,24 @@
import React, { useEffect, useState } from 'react';
import { LogoIcon, MoreIcon, ExportIcon } from './icons';
import {
LogoIcon,
MoreIcon,
ExportIcon,
Export2Markdown,
Export2HTML,
RightArrow,
} from './icons';
import {
StyledHeader,
StyledTitle,
StyledTitleWrapper,
StyledLogo,
StyledHeaderRightSide,
StyledMoreMenuItem,
IconButton,
StyledHeaderContainer,
StyledBrowserWarning,
StyledCloseButton,
StyledMenuItemWrapper,
} from './styles';
import { Popover } from '@/ui/popover';
import { useEditor } from '@/components/editor-provider';
import EditorModeSwitch from '@/components/editor-mode-switch';
import { EdgelessIcon, PaperIcon } from '../editor-mode-switch/icons';
@ -20,34 +26,57 @@ import ThemeModeSwitch from '@/components/theme-mode-switch';
import { useModal } from '@/components/global-modal-provider';
import CloseIcon from '@mui/icons-material/Close';
import { getWarningMessage, shouldShowWarning } from './utils';
import { Menu, MenuItem } from '@/ui/menu';
const PopoverContent = () => {
const { editor, mode, setMode } = useEditor();
return (
<>
<StyledMoreMenuItem
<MenuItem
onClick={() => {
setMode(mode === 'page' ? 'edgeless' : 'page');
}}
>
{mode === 'page' ? <EdgelessIcon /> : <PaperIcon />}
Convert to {mode === 'page' ? 'Edgeless' : 'Page'}
</StyledMoreMenuItem>
<StyledMoreMenuItem
onClick={() => {
editor && editor.contentParser.onExportHtml();
}}
<StyledMenuItemWrapper>
{mode === 'page' ? <EdgelessIcon /> : <PaperIcon />}
Convert to {mode === 'page' ? 'Edgeless' : 'Page'}
</StyledMenuItemWrapper>
</MenuItem>
<Menu
placement="left-start"
content={
<>
<MenuItem
onClick={() => {
editor && editor.contentParser.onExportHtml();
}}
>
<StyledMenuItemWrapper>
<Export2HTML />
Export to HTML
</StyledMenuItemWrapper>
</MenuItem>
<MenuItem
onClick={() => {
editor && editor.contentParser.onExportMarkdown();
}}
>
<StyledMenuItemWrapper>
<Export2Markdown />
Export to Markdown
</StyledMenuItemWrapper>
</MenuItem>
</>
}
>
<ExportIcon />
Export to HTML
</StyledMoreMenuItem>
<StyledMoreMenuItem
onClick={() => {
editor && editor.contentParser.onExportMarkdown();
}}
>
<ExportIcon />
Export to Markdown
</StyledMoreMenuItem>
<MenuItem>
<StyledMenuItemWrapper>
<ExportIcon />
Export
<RightArrow />
</StyledMenuItemWrapper>
</MenuItem>
</Menu>
</>
);
};
@ -115,14 +144,11 @@ export const Header = () => {
<StyledHeaderRightSide>
<ThemeModeSwitch />
<Popover
popoverContent={<PopoverContent />}
style={{ marginLeft: '20px' }}
>
<Menu content={<PopoverContent />} placement="bottom-end">
<IconButton>
<MoreIcon />
</IconButton>
</Popover>
</Menu>
</StyledHeaderRightSide>
</StyledHeader>
</StyledHeaderContainer>

View File

@ -1,4 +1,5 @@
import { absoluteCenter, displayFlex, styled } from '@/styles';
import { displayFlex, styled } from '@/styles';
import { MenuItem } from '@/ui/menu';
export const StyledHeaderContainer = styled.div<{ hasWarning: boolean }>(
({ hasWarning }) => {
@ -20,7 +21,7 @@ export const StyledHeader = styled.div<{ hasWarning: boolean }>(
left: '0',
top: hasWarning ? '36px' : '0',
padding: '0 22px',
zIndex: theme.zIndex.modal,
zIndex: 99,
};
}
);
@ -61,23 +62,23 @@ export const StyledHeaderRightSide = styled('div')({
alignItems: 'center',
});
export const StyledMoreMenuItem = styled('div')(({ theme }) => {
export const StyledMenuItemWrapper = styled.div(({ theme }) => {
return {
height: '32px',
display: 'flex',
alignItems: 'center',
borderRadius: '5px',
fontSize: '14px',
color: theme.colors.popoverColor,
padding: '0 14px',
position: 'relative',
cursor: 'pointer',
...displayFlex('flex-start', 'center'),
svg: {
width: '16px',
height: '16px',
marginRight: '14px',
},
':hover': {
color: theme.colors.primaryColor,
background: theme.colors.hoverBackground,
'svg:nth-child(2)': {
position: 'absolute',
right: 0,
top: 0,
bottom: 0,
margin: 'auto',
},
};
});

View File

@ -0,0 +1,2 @@
export * from './menu';
export { StyledMenuItem as MenuItem } from './styles';

View File

@ -0,0 +1,20 @@
import { Popper, type PopperProps } from '../popper';
import { TooltipProps } from '@mui/material';
import { StyledMenuWrapper } from '@/ui/menu/styles';
export const Menu = (props: PopperProps & Omit<TooltipProps, 'title'>) => {
const { content, placement = 'bottom-start', children } = props;
return content ? (
<Popper
{...props}
showArrow={false}
content={
<StyledMenuWrapper placement={placement}>{content}</StyledMenuWrapper>
}
>
{children}
</Popper>
) : null;
};
export default Menu;

View File

@ -0,0 +1,34 @@
import { styled } from '@/styles';
import StyledPopperContainer from '../shared/Container';
export const StyledMenuWrapper = styled(StyledPopperContainer)(({ theme }) => {
return {
background: theme.colors.popoverBackground,
padding: '8px 4px',
fontSize: '14px',
backgroundColor: theme.colors.popoverBackground,
boxShadow: theme.shadow.popover,
color: theme.colors.popoverColor,
};
});
export const StyledMenuItem = styled('div')<{ popperVisible?: boolean }>(
({ theme, popperVisible }) => {
return {
borderRadius: '5px',
padding: '0 14px',
color: popperVisible
? theme.colors.primaryColor
: theme.colors.popoverColor,
backgroundColor: popperVisible
? theme.colors.hoverBackground
: 'transparent',
':hover': {
color: theme.colors.primaryColor,
backgroundColor: theme.colors.hoverBackground,
},
};
}
);