diff --git a/packages/app/src/components/Header/header.tsx b/packages/app/src/components/Header/header.tsx
index 3be73a1413..c4675ed222 100644
--- a/packages/app/src/components/Header/header.tsx
+++ b/packages/app/src/components/Header/header.tsx
@@ -1,29 +1,22 @@
-import React, { PropsWithChildren, useEffect, useState } from 'react';
-import {
- LogoIcon,
- MoreIcon,
- ExportIcon,
- Export2Markdown,
- Export2HTML,
- RightArrow,
-} from './icons';
+import React, { PropsWithChildren, useState } from 'react';
import {
StyledHeader,
- StyledTitle,
- StyledTitleWrapper,
- StyledLogo,
StyledHeaderRightSide,
- IconButton,
StyledHeaderContainer,
StyledBrowserWarning,
StyledCloseButton,
- StyledMenuItemWrapper,
} from './styles';
+import {
+ MiddleExportIcon,
+ EdgelessIcon,
+ PaperIcon,
+ MiddleExportToHtmlIcon,
+ MiddleExportToMarkdownIcon,
+ MoreVerticalIcon,
+} from '@blocksuite/icons';
import { useEditor } from '@/providers/editor-provider';
-import EditorModeSwitch from '@/components/editor-mode-switch';
-import { EdgelessIcon, PaperIcon } from '../editor-mode-switch/icons';
import ThemeModeSwitch from '@/components/theme-mode-switch';
-import { useModal } from '@/providers/global-modal-provider';
+import { IconButton } from '@/ui/button';
import CloseIcon from '@mui/icons-material/Close';
import { getWarningMessage, shouldShowWarning } from './utils';
import { Menu, MenuItem } from '@/ui/menu';
@@ -33,14 +26,12 @@ const PopoverContent = () => {
return (
<>
: }
onClick={() => {
setMode(mode === 'page' ? 'edgeless' : 'page');
}}
>
-
- {mode === 'page' ? : }
- Convert to {mode === 'page' ? 'Edgeless' : 'Page'}
-
+ Convert to {mode === 'page' ? 'Edgeless' : 'Page'}
>
@@ -115,7 +98,7 @@ export const Header = ({ children }: PropsWithChildren<{}>) => {
} placement="bottom-end">
-
+
diff --git a/packages/app/src/components/Header/icons.tsx b/packages/app/src/components/Header/icons.tsx
deleted file mode 100644
index 57a4134d6e..0000000000
--- a/packages/app/src/components/Header/icons.tsx
+++ /dev/null
@@ -1,119 +0,0 @@
-import type { DOMAttributes, CSSProperties } from 'react';
-type IconProps = {
- style?: CSSProperties;
-} & DOMAttributes;
-
-export const RightArrow = ({ style = {}, ...props }: IconProps) => {
- return (
-
- );
-};
-export const Export2Markdown = ({ style = {}, ...props }: IconProps) => {
- return (
-
- );
-};
-export const Export2HTML = ({ style = {}, ...props }: IconProps) => {
- return (
-
- );
-};
-export const LogoIcon = ({ style = {}, ...props }: IconProps) => {
- return (
-
- );
-};
-
-export const MoreIcon = ({ style = {}, ...props }: IconProps) => {
- return (
-
- );
-};
-export const ExportIcon = ({ style = {}, ...props }: IconProps) => {
- return (
-
- );
-};
diff --git a/packages/app/src/components/Header/styles.ts b/packages/app/src/components/Header/styles.ts
index b5ca7561da..399ac197a7 100644
--- a/packages/app/src/components/Header/styles.ts
+++ b/packages/app/src/components/Header/styles.ts
@@ -1,5 +1,4 @@
import { displayFlex, styled } from '@/styles';
-import { MenuItem } from '@/ui/menu';
export const StyledHeaderContainer = styled.div<{ hasWarning: boolean }>(
({ hasWarning }) => {
@@ -47,56 +46,12 @@ export const StyledTitleWrapper = styled('div')({
position: 'relative',
});
-export const StyledLogo = styled('div')(({ theme }) => ({
- color: theme.colors.primaryColor,
- width: '60px',
- height: '60px',
- cursor: 'pointer',
- marginLeft: '-22px',
- ...displayFlex('center', 'center'),
-}));
-
export const StyledHeaderRightSide = styled('div')({
height: '100%',
display: 'flex',
alignItems: 'center',
});
-export const StyledMenuItemWrapper = styled.div(({ theme }) => {
- return {
- height: '32px',
- position: 'relative',
- cursor: 'pointer',
- ...displayFlex('flex-start', 'center'),
- svg: {
- width: '16px',
- height: '16px',
- marginRight: '14px',
- },
- 'svg:nth-child(2)': {
- position: 'absolute',
- right: 0,
- top: 0,
- bottom: 0,
- margin: 'auto',
- },
- };
-});
-
-export const IconButton = styled('div')(({ theme }) => {
- return {
- width: '32px',
- height: '32px',
- ...displayFlex('center', 'center'),
- color: theme.colors.iconColor,
- borderRadius: '5px',
- ':hover': {
- color: theme.colors.primaryColor,
- background: theme.colors.hoverBackground,
- },
- };
-});
-
export const StyledBrowserWarning = styled.div<{ show: boolean }>(
({ theme, show }) => {
return {
diff --git a/packages/app/src/pages/all-page.tsx b/packages/app/src/pages/all-page.tsx
index dd40b8188f..447a271d18 100644
--- a/packages/app/src/pages/all-page.tsx
+++ b/packages/app/src/pages/all-page.tsx
@@ -3,6 +3,10 @@ import { Header } from '@/components/Header';
import { styled } from '@/styles';
import { Table, TableCell, TableHead, TableRow, TableBody } from '../ui/table';
import { useConfirm } from '@/providers/confirm-provider';
+import { IconButton } from '@/ui/button';
+import { MoreVerticalIcon } from '@blocksuite/icons';
+import { Menu, MenuItem } from '@/ui/menu';
+
const StyledTableContainer = styled.div(() => {
return {
height: 'calc(100vh - 60px)',
@@ -10,6 +14,17 @@ const StyledTableContainer = styled.div(() => {
overflowY: 'auto',
};
});
+
+const OperationMenu = () => {
+ return (
+ <>
+
+
+
+ >
+ );
+};
+
export const AllPage = () => {
const { confirm } = useConfirm();
return (
@@ -47,7 +62,17 @@ export const AllPage = () => {
2022-11-02 18:30
2022-11-02 18:30
- ...
+
+ }
+ placement="bottom-end"
+ disablePortal={true}
+ >
+
+
+
+
+
);
})}
diff --git a/packages/app/src/ui/button/icon-button.tsx b/packages/app/src/ui/button/icon-button.tsx
new file mode 100644
index 0000000000..922f838425
--- /dev/null
+++ b/packages/app/src/ui/button/icon-button.tsx
@@ -0,0 +1,85 @@
+import {
+ HTMLAttributes,
+ cloneElement,
+ ReactElement,
+ Children,
+ CSSProperties,
+ forwardRef,
+} from 'react';
+import { StyledIconButton } from './styles';
+
+const SIZE_SMALL = 'small' as const;
+const SIZE_MIDDLE = 'middle' as const;
+const SIZE_NORMAL = 'normal' as const;
+// TODO: Designer is not sure about the size of the icon button
+const SIZE_CONFIG = {
+ [SIZE_SMALL]: {
+ iconSize: 16,
+ areaSize: 24,
+ },
+ [SIZE_MIDDLE]: {
+ iconSize: 20,
+ areaSize: 28,
+ },
+ [SIZE_NORMAL]: {
+ iconSize: 24,
+ areaSize: 32,
+ },
+} as const;
+
+export type IconButtonProps = {
+ size?:
+ | typeof SIZE_SMALL
+ | typeof SIZE_MIDDLE
+ | typeof SIZE_NORMAL
+ | [number, number];
+ iconSize?:
+ | typeof SIZE_SMALL
+ | typeof SIZE_MIDDLE
+ | typeof SIZE_NORMAL
+ | [number, number];
+ disabled?: boolean;
+ hoverBackground?: string;
+ hoverColor?: string;
+ hoverStyle?: CSSProperties;
+ children: ReactElement, 'svg'>;
+} & HTMLAttributes;
+
+export const IconButton = forwardRef(
+ (
+ {
+ size = 'normal',
+ iconSize = 'normal',
+ disabled = false,
+ children,
+ ...props
+ },
+ ref
+ ) => {
+ const [width, height] = Array.isArray(size)
+ ? size
+ : [SIZE_CONFIG[size]['areaSize'], SIZE_CONFIG[size]['areaSize']];
+ const [iconWidth, iconHeight] = Array.isArray(iconSize)
+ ? iconSize
+ : [SIZE_CONFIG[iconSize]['iconSize'], SIZE_CONFIG[iconSize]['iconSize']];
+
+ return (
+
+ {cloneElement(Children.only(children), {
+ width: iconWidth,
+ height: iconHeight,
+ })}
+
+ );
+ }
+);
+IconButton.displayName = 'IconButton';
+
+export default IconButton;
diff --git a/packages/app/src/ui/button/index.ts b/packages/app/src/ui/button/index.ts
new file mode 100644
index 0000000000..51688a7c80
--- /dev/null
+++ b/packages/app/src/ui/button/index.ts
@@ -0,0 +1 @@
+export * from './icon-button';
diff --git a/packages/app/src/ui/button/styles.ts b/packages/app/src/ui/button/styles.ts
new file mode 100644
index 0000000000..90cd0a8f0a
--- /dev/null
+++ b/packages/app/src/ui/button/styles.ts
@@ -0,0 +1,55 @@
+import { absoluteCenter, displayFlex, styled } from '@/styles';
+import { CSSProperties } from 'react';
+
+export const StyledIconButton = styled.button<{
+ width: number;
+ height: number;
+ borderRadius: number;
+ disabled?: boolean;
+ hoverBackground?: string;
+ hoverColor?: string;
+ hoverStyle?: CSSProperties;
+}>(
+ ({
+ theme,
+ width,
+ height,
+ disabled,
+ hoverBackground,
+ hoverColor,
+ hoverStyle,
+ }) => {
+ return {
+ width,
+ height,
+ color: theme.colors.iconColor,
+ ...displayFlex('center', 'center'),
+ position: 'relative',
+ ...(disabled ? { cursor: 'not-allowed', pointerEvents: 'none' } : {}),
+ transition: 'background .15s',
+
+ // TODO: we need to add @emotion/babel-plugin
+ '::after': {
+ content: '""',
+ width,
+ height,
+ borderRadius: width / 5,
+ transition: 'background .15s',
+ ...absoluteCenter({ horizontal: true, vertical: true }),
+ },
+
+ svg: {
+ position: 'relative',
+ zIndex: 1,
+ },
+
+ ':hover': {
+ color: hoverColor ?? theme.colors.primaryColor,
+ '::after': {
+ background: hoverBackground ?? theme.colors.hoverBackground,
+ },
+ ...(hoverStyle ?? {}),
+ },
+ };
+ }
+);
diff --git a/packages/app/src/ui/menu/index.ts b/packages/app/src/ui/menu/index.ts
index 8dde85f113..d56e8d1489 100644
--- a/packages/app/src/ui/menu/index.ts
+++ b/packages/app/src/ui/menu/index.ts
@@ -1,2 +1,3 @@
export * from './menu';
-export { StyledMenuItem as MenuItem } from './styles';
+// export { StyledMenuItem as MenuItem } from './styles';
+export * from './menu-item';
diff --git a/packages/app/src/ui/menu/menu-item.tsx b/packages/app/src/ui/menu/menu-item.tsx
new file mode 100644
index 0000000000..45e40fb649
--- /dev/null
+++ b/packages/app/src/ui/menu/menu-item.tsx
@@ -0,0 +1,35 @@
+import {
+ cloneElement,
+ forwardRef,
+ HTMLAttributes,
+ PropsWithChildren,
+ ReactElement,
+} from 'react';
+import { StyledMenuItem, StyledArrow } from './styles';
+
+export type IconMenuProps = PropsWithChildren<{
+ isDir?: boolean;
+ icon?: ReactElement;
+}> &
+ HTMLAttributes;
+
+export const MenuItem = forwardRef(
+ ({ isDir = false, icon, children, ...props }, ref) => {
+ return (
+
+ {icon &&
+ cloneElement(icon, {
+ width: 16,
+ height: 16,
+ style: {
+ marginRight: 14,
+ },
+ })}
+ {children}
+ {isDir ? : null}
+
+ );
+ }
+);
+MenuItem.displayName = 'MenuItem';
+export default MenuItem;
diff --git a/packages/app/src/ui/menu/styles.ts b/packages/app/src/ui/menu/styles.ts
index 1b426217d6..4321a17722 100644
--- a/packages/app/src/ui/menu/styles.ts
+++ b/packages/app/src/ui/menu/styles.ts
@@ -1,5 +1,6 @@
-import { styled } from '@/styles';
+import { displayFlex, styled } from '@/styles';
import StyledPopperContainer from '../shared/Container';
+import { MiddleArrowRightIcon } from '@blocksuite/icons';
export const StyledMenuWrapper = styled(StyledPopperContainer)(({ theme }) => {
return {
@@ -12,23 +13,39 @@ export const StyledMenuWrapper = styled(StyledPopperContainer)(({ theme }) => {
};
});
-export const StyledMenuItem = styled('div')<{ popperVisible?: boolean }>(
- ({ theme, popperVisible }) => {
- return {
- borderRadius: '5px',
- padding: '0 14px',
+export const StyledArrow = styled(MiddleArrowRightIcon)(({ theme }) => {
+ return {
+ position: 'absolute',
+ right: 0,
+ top: 0,
+ bottom: 0,
+ margin: 'auto',
+ };
+});
- color: popperVisible
- ? theme.colors.primaryColor
- : theme.colors.popoverColor,
- backgroundColor: popperVisible
- ? theme.colors.hoverBackground
- : 'transparent',
+export const StyledMenuItem = styled.button<{
+ popperVisible?: boolean;
+ isDir?: boolean;
+}>(({ theme, popperVisible, isDir = false }) => {
+ return {
+ width: '100%',
+ borderRadius: '5px',
+ padding: '0 14px',
+ fontSize: '14px',
+ height: '32px',
+ ...displayFlex('flex-start', 'center'),
+ cursor: isDir ? 'pointer' : '',
+ position: 'relative',
+ color: popperVisible
+ ? theme.colors.primaryColor
+ : theme.colors.popoverColor,
+ backgroundColor: popperVisible
+ ? theme.colors.hoverBackground
+ : 'transparent',
- ':hover': {
- color: theme.colors.primaryColor,
- backgroundColor: theme.colors.hoverBackground,
- },
- };
- }
-);
+ ':hover': {
+ color: theme.colors.primaryColor,
+ backgroundColor: theme.colors.hoverBackground,
+ },
+ };
+});
diff --git a/packages/app/src/ui/table/styles.ts b/packages/app/src/ui/table/styles.ts
index 39d16aa5db..5c14236737 100644
--- a/packages/app/src/ui/table/styles.ts
+++ b/packages/app/src/ui/table/styles.ts
@@ -48,11 +48,11 @@ export const StyledTableRow = styled.tr(({ theme }) => {
td: {
transition: 'background .15s',
},
- 'td:first-child': {
+ 'td:first-of-type': {
borderTopLeftRadius: '10px',
borderBottomLeftRadius: '10px',
},
- 'td:last-child': {
+ 'td:last-of-type': {
borderTopRightRadius: '10px',
borderBottomRightRadius: '10px',
},