mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-06 11:59:51 +08:00
feat: add ui component Table & add initial workspace style
This commit is contained in:
@@ -0,0 +1,127 @@
|
|||||||
|
import React, { PropsWithChildren, useEffect, useState } from 'react';
|
||||||
|
import {
|
||||||
|
LogoIcon,
|
||||||
|
MoreIcon,
|
||||||
|
ExportIcon,
|
||||||
|
Export2Markdown,
|
||||||
|
Export2HTML,
|
||||||
|
RightArrow,
|
||||||
|
} from './icons';
|
||||||
|
import {
|
||||||
|
StyledHeader,
|
||||||
|
StyledTitle,
|
||||||
|
StyledTitleWrapper,
|
||||||
|
StyledLogo,
|
||||||
|
StyledHeaderRightSide,
|
||||||
|
IconButton,
|
||||||
|
StyledHeaderContainer,
|
||||||
|
StyledBrowserWarning,
|
||||||
|
StyledCloseButton,
|
||||||
|
StyledMenuItemWrapper,
|
||||||
|
} from './styles';
|
||||||
|
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 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 (
|
||||||
|
<>
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
setMode(mode === 'page' ? 'edgeless' : 'page');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MenuItem>
|
||||||
|
<StyledMenuItemWrapper>
|
||||||
|
<ExportIcon />
|
||||||
|
Export
|
||||||
|
<RightArrow />
|
||||||
|
</StyledMenuItemWrapper>
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const BrowserWarning = ({
|
||||||
|
show,
|
||||||
|
onClose,
|
||||||
|
}: {
|
||||||
|
show: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<StyledBrowserWarning show={show}>
|
||||||
|
{getWarningMessage()}
|
||||||
|
<StyledCloseButton onClick={onClose}>
|
||||||
|
<CloseIcon />
|
||||||
|
</StyledCloseButton>
|
||||||
|
</StyledBrowserWarning>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Header = ({ children }: PropsWithChildren<{}>) => {
|
||||||
|
const [showWarning, setShowWarning] = useState(shouldShowWarning());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledHeaderContainer hasWarning={showWarning}>
|
||||||
|
<BrowserWarning
|
||||||
|
show={showWarning}
|
||||||
|
onClose={() => {
|
||||||
|
setShowWarning(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<StyledHeader hasWarning={showWarning}>
|
||||||
|
{children}
|
||||||
|
<StyledHeaderRightSide>
|
||||||
|
<ThemeModeSwitch />
|
||||||
|
<Menu content={<PopoverContent />} placement="bottom-end">
|
||||||
|
<IconButton>
|
||||||
|
<MoreIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Menu>
|
||||||
|
</StyledHeaderRightSide>
|
||||||
|
</StyledHeader>
|
||||||
|
</StyledHeaderContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Header;
|
||||||
@@ -1,165 +1,2 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
export * from './header';
|
||||||
import {
|
export * from './page-header';
|
||||||
LogoIcon,
|
|
||||||
MoreIcon,
|
|
||||||
ExportIcon,
|
|
||||||
Export2Markdown,
|
|
||||||
Export2HTML,
|
|
||||||
RightArrow,
|
|
||||||
} from './icons';
|
|
||||||
import {
|
|
||||||
StyledHeader,
|
|
||||||
StyledTitle,
|
|
||||||
StyledTitleWrapper,
|
|
||||||
StyledLogo,
|
|
||||||
StyledHeaderRightSide,
|
|
||||||
IconButton,
|
|
||||||
StyledHeaderContainer,
|
|
||||||
StyledBrowserWarning,
|
|
||||||
StyledCloseButton,
|
|
||||||
StyledMenuItemWrapper,
|
|
||||||
} from './styles';
|
|
||||||
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 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 (
|
|
||||||
<>
|
|
||||||
<MenuItem
|
|
||||||
onClick={() => {
|
|
||||||
setMode(mode === 'page' ? 'edgeless' : 'page');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<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>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<MenuItem>
|
|
||||||
<StyledMenuItemWrapper>
|
|
||||||
<ExportIcon />
|
|
||||||
Export
|
|
||||||
<RightArrow />
|
|
||||||
</StyledMenuItemWrapper>
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const BrowserWarning = ({
|
|
||||||
show,
|
|
||||||
onClose,
|
|
||||||
}: {
|
|
||||||
show: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<StyledBrowserWarning show={show}>
|
|
||||||
{getWarningMessage()}
|
|
||||||
<StyledCloseButton onClick={onClose}>
|
|
||||||
<CloseIcon />
|
|
||||||
</StyledCloseButton>
|
|
||||||
</StyledBrowserWarning>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Header = () => {
|
|
||||||
const [title, setTitle] = useState('');
|
|
||||||
const [isHover, setIsHover] = useState(false);
|
|
||||||
const [showWarning, setShowWarning] = useState(shouldShowWarning());
|
|
||||||
|
|
||||||
const { contactModalHandler } = useModal();
|
|
||||||
const { editor } = useEditor();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log('header', editor);
|
|
||||||
|
|
||||||
if (editor?.model) {
|
|
||||||
setTitle(editor.model.title ?? '');
|
|
||||||
editor.model.propsUpdated.on(() => {
|
|
||||||
setTitle(editor.model.title);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [editor]);
|
|
||||||
return (
|
|
||||||
<StyledHeaderContainer hasWarning={showWarning}>
|
|
||||||
<BrowserWarning
|
|
||||||
show={showWarning}
|
|
||||||
onClose={() => {
|
|
||||||
setShowWarning(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<StyledHeader hasWarning={showWarning}>
|
|
||||||
{/*<StyledLogo*/}
|
|
||||||
{/* onClick={() => {*/}
|
|
||||||
{/* contactModalHandler(true);*/}
|
|
||||||
{/* }}*/}
|
|
||||||
{/*>*/}
|
|
||||||
{/* <LogoIcon />*/}
|
|
||||||
{/*</StyledLogo>*/}
|
|
||||||
{title ? (
|
|
||||||
<StyledTitle
|
|
||||||
onMouseEnter={() => {
|
|
||||||
setIsHover(true);
|
|
||||||
}}
|
|
||||||
onMouseLeave={() => {
|
|
||||||
setIsHover(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<EditorModeSwitch
|
|
||||||
isHover={isHover}
|
|
||||||
style={{
|
|
||||||
marginRight: '12px',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<StyledTitleWrapper>{title}</StyledTitleWrapper>
|
|
||||||
</StyledTitle>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<StyledHeaderRightSide>
|
|
||||||
<ThemeModeSwitch />
|
|
||||||
<Menu content={<PopoverContent />} placement="bottom-end">
|
|
||||||
<IconButton>
|
|
||||||
<MoreIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Menu>
|
|
||||||
</StyledHeaderRightSide>
|
|
||||||
</StyledHeader>
|
|
||||||
</StyledHeaderContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { StyledTitle, StyledTitleWrapper } from './styles';
|
||||||
|
import { useEditor } from '@/providers/editor-provider';
|
||||||
|
import EditorModeSwitch from '@/components/editor-mode-switch';
|
||||||
|
|
||||||
|
import Header from './header';
|
||||||
|
|
||||||
|
export const PageHeader = () => {
|
||||||
|
const [title, setTitle] = useState('');
|
||||||
|
const [isHover, setIsHover] = useState(false);
|
||||||
|
|
||||||
|
const { editor } = useEditor();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (editor?.model) {
|
||||||
|
setTitle(editor.model.title ?? '');
|
||||||
|
editor.model.propsUpdated.on(() => {
|
||||||
|
setTitle(editor.model.title);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [editor]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Header>
|
||||||
|
{title ? (
|
||||||
|
<StyledTitle
|
||||||
|
onMouseEnter={() => {
|
||||||
|
setIsHover(true);
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
setIsHover(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<EditorModeSwitch
|
||||||
|
isHover={isHover}
|
||||||
|
style={{
|
||||||
|
marginRight: '12px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<StyledTitleWrapper>{title}</StyledTitleWrapper>
|
||||||
|
</StyledTitle>
|
||||||
|
) : null}
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PageHeader;
|
||||||
@@ -1,22 +1,26 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import Router from 'next/router';
|
||||||
import {
|
import {
|
||||||
StyledArrowButton,
|
StyledArrowButton,
|
||||||
StyledListItem,
|
StyledListItem,
|
||||||
|
StyledNewPageButton,
|
||||||
StyledSliderBar,
|
StyledSliderBar,
|
||||||
StyledSubListItem,
|
StyledSubListItem,
|
||||||
StyledWrapper,
|
|
||||||
} from './style';
|
} from './style';
|
||||||
import { Arrow } from './icons';
|
import { Arrow } from './icons';
|
||||||
|
|
||||||
export const WorkSpaceSliderBar = () => {
|
export const WorkSpaceSliderBar = () => {
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<StyledSliderBar show={show}>
|
<StyledSliderBar show={show}>
|
||||||
|
|
||||||
<StyledListItem>Quick search</StyledListItem>
|
<StyledListItem>Quick search</StyledListItem>
|
||||||
<StyledListItem>All pages</StyledListItem>
|
<StyledListItem
|
||||||
|
onClick={() => {
|
||||||
|
Router.push('/all-page');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
All pages
|
||||||
|
</StyledListItem>
|
||||||
<StyledListItem>Favourites</StyledListItem>
|
<StyledListItem>Favourites</StyledListItem>
|
||||||
<StyledSubListItem>
|
<StyledSubListItem>
|
||||||
document 1, this is a paper icondocument 1
|
document 1, this is a paper icondocument 1
|
||||||
@@ -25,6 +29,8 @@ export const WorkSpaceSliderBar = () => {
|
|||||||
<StyledSubListItem>document 4</StyledSubListItem>
|
<StyledSubListItem>document 4</StyledSubListItem>
|
||||||
<StyledListItem>Import</StyledListItem>
|
<StyledListItem>Import</StyledListItem>
|
||||||
<StyledListItem>Bin</StyledListItem>
|
<StyledListItem>Bin</StyledListItem>
|
||||||
|
|
||||||
|
<StyledNewPageButton>New Page</StyledNewPageButton>
|
||||||
</StyledSliderBar>
|
</StyledSliderBar>
|
||||||
<StyledArrowButton
|
<StyledArrowButton
|
||||||
isShow={show}
|
isShow={show}
|
||||||
|
|||||||
@@ -12,16 +12,11 @@ export const StyledSliderBar = styled.div<{ show: boolean }>(
|
|||||||
zIndex: theme.zIndex.modal,
|
zIndex: theme.zIndex.modal,
|
||||||
padding: show ? '24px 12px' : '24px 0',
|
padding: show ? '24px 12px' : '24px 0',
|
||||||
overflowX: 'hidden',
|
overflowX: 'hidden',
|
||||||
|
flexShrink: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
export const StyledWrapper = styled.div(() => {
|
|
||||||
return {
|
|
||||||
// padding: '24px 12px',
|
|
||||||
// height: '100%',
|
|
||||||
// overflowY: 'auto',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
export const StyledArrowButton = styled.button<{ isShow: boolean }>(
|
export const StyledArrowButton = styled.button<{ isShow: boolean }>(
|
||||||
({ theme, isShow }) => {
|
({ theme, isShow }) => {
|
||||||
return {
|
return {
|
||||||
@@ -54,6 +49,8 @@ export const StyledListItem = styled.button(({ theme }) => {
|
|||||||
marginTop: '12px',
|
marginTop: '12px',
|
||||||
fontSize: theme.font.sm,
|
fontSize: theme.font.sm,
|
||||||
color: theme.colors.popoverColor,
|
color: theme.colors.popoverColor,
|
||||||
|
padding: '0 12px',
|
||||||
|
borderRadius: '5px',
|
||||||
...displayFlex('flex-start', 'center'),
|
...displayFlex('flex-start', 'center'),
|
||||||
':hover': {
|
':hover': {
|
||||||
color: theme.colors.primaryColor,
|
color: theme.colors.primaryColor,
|
||||||
@@ -62,13 +59,22 @@ export const StyledListItem = styled.button(({ theme }) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const StyledNewPageButton = styled(StyledListItem)(({ theme }) => {
|
||||||
|
return {
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: '24px',
|
||||||
|
left: '0',
|
||||||
|
right: '0',
|
||||||
|
margin: 'auto',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const StyledSubListItem = styled.button(({ theme }) => {
|
export const StyledSubListItem = styled.button(({ theme }) => {
|
||||||
return {
|
return {
|
||||||
width: '296px',
|
width: '296px',
|
||||||
height: '32px',
|
height: '32px',
|
||||||
marginTop: '4px',
|
marginTop: '4px',
|
||||||
fontSize: theme.font.sm,
|
fontSize: theme.font.sm,
|
||||||
fontWeight: 400,
|
|
||||||
color: theme.colors.popoverColor,
|
color: theme.colors.popoverColor,
|
||||||
paddingLeft: '45px',
|
paddingLeft: '45px',
|
||||||
lineHeight: '32px',
|
lineHeight: '32px',
|
||||||
@@ -77,7 +83,6 @@ export const StyledSubListItem = styled.button(({ theme }) => {
|
|||||||
':hover': {
|
':hover': {
|
||||||
color: theme.colors.primaryColor,
|
color: theme.colors.primaryColor,
|
||||||
backgroundColor: theme.colors.hoverBackground,
|
backgroundColor: theme.colors.hoverBackground,
|
||||||
fontWeight: 500,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,9 +11,8 @@ import '@fontsource/space-mono';
|
|||||||
import '@fontsource/poppins';
|
import '@fontsource/poppins';
|
||||||
import '../utils/print-build-info';
|
import '../utils/print-build-info';
|
||||||
import { styled } from '@/styles';
|
import { styled } from '@/styles';
|
||||||
import type { ReactNode, PropsWithChildren, FC } from 'react';
|
import ProviderComposer from '@/components/provider-composer';
|
||||||
import { cloneElement } from 'react';
|
import ConfirmProvider from '@/providers/confirm-provider';
|
||||||
|
|
||||||
const ThemeProvider = dynamic(() => import('@/providers/themeProvider'), {
|
const ThemeProvider = dynamic(() => import('@/providers/themeProvider'), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
});
|
});
|
||||||
@@ -24,21 +23,15 @@ const StyledPage = styled('div')(({ theme }) => {
|
|||||||
backgroundColor: theme.colors.pageBackground,
|
backgroundColor: theme.colors.pageBackground,
|
||||||
transition: 'background-color .5s',
|
transition: 'background-color .5s',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
flexGrow: '1',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const ProviderComposer: FC<
|
const StyledWrapper = styled('div')(({ theme }) => {
|
||||||
PropsWithChildren<{
|
return {
|
||||||
contexts: any;
|
flexGrow: 1,
|
||||||
}>
|
};
|
||||||
> = ({ contexts, children }) =>
|
});
|
||||||
contexts.reduceRight(
|
|
||||||
(kids: ReactNode, parent: any) =>
|
|
||||||
cloneElement(parent, {
|
|
||||||
children: kids,
|
|
||||||
}),
|
|
||||||
children
|
|
||||||
);
|
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
function MyApp({ Component, pageProps }: AppProps) {
|
||||||
return (
|
return (
|
||||||
@@ -49,11 +42,14 @@ function MyApp({ Component, pageProps }: AppProps) {
|
|||||||
<EditorProvider key="EditorProvider" />,
|
<EditorProvider key="EditorProvider" />,
|
||||||
<ThemeProvider key="ThemeProvider" />,
|
<ThemeProvider key="ThemeProvider" />,
|
||||||
<ModalProvider key="ModalProvider" />,
|
<ModalProvider key="ModalProvider" />,
|
||||||
|
<ConfirmProvider key="ConfirmProvider" />,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<StyledPage>
|
<StyledPage>
|
||||||
<WorkSpaceSliderBar />
|
<WorkSpaceSliderBar />
|
||||||
<Component {...pageProps} />
|
<StyledWrapper>
|
||||||
|
<Component {...pageProps} />
|
||||||
|
</StyledWrapper>
|
||||||
</StyledPage>
|
</StyledPage>
|
||||||
</ProviderComposer>
|
</ProviderComposer>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Header } from '@/components/Header';
|
||||||
|
import { styled } from '@/styles';
|
||||||
|
import { Table, TableCell, TableHead, TableRow, TableBody } from '../ui/table';
|
||||||
|
import { useConfirm } from '@/providers/confirm-provider';
|
||||||
|
const StyledTableContainer = styled.div(() => {
|
||||||
|
return {
|
||||||
|
height: 'calc(100vh - 60px)',
|
||||||
|
padding: '78px 72px',
|
||||||
|
overflowY: 'auto',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
export const AllPage = () => {
|
||||||
|
const { confirm } = useConfirm();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
confirm({
|
||||||
|
title: 'Permanently delete',
|
||||||
|
content: "Once deleted, you can't undo this action.Do you confirm?",
|
||||||
|
confirmText: 'Delete',
|
||||||
|
confirmType: 'danger',
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
click to show confirm
|
||||||
|
</button>
|
||||||
|
<StyledTableContainer>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell proportion={0.5}>Documents</TableCell>
|
||||||
|
<TableCell proportion={0.2}>Created</TableCell>
|
||||||
|
<TableCell proportion={0.2}>Uploaded</TableCell>
|
||||||
|
<TableCell proportion={0.1}></TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{new Array(100).fill(0).map((_, index) => {
|
||||||
|
return (
|
||||||
|
<TableRow key={index}>
|
||||||
|
<TableCell ellipsis={true}>
|
||||||
|
This is a long, very long, extremely long, incredibly long,
|
||||||
|
exceedingly long, very long document title
|
||||||
|
</TableCell>
|
||||||
|
<TableCell ellipsis={true}>2022-11-02 18:30</TableCell>
|
||||||
|
<TableCell ellipsis={true}>2022-11-02 18:30</TableCell>
|
||||||
|
<TableCell>...</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</StyledTableContainer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AllPage;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { NextPage } from 'next';
|
import type { NextPage } from 'next';
|
||||||
import { styled } from '@/styles';
|
import { styled } from '@/styles';
|
||||||
import { Header } from '@/components/Header';
|
import { PageHeader } from '@/components/Header';
|
||||||
import { FAQ } from '@/components/faq';
|
import { FAQ } from '@/components/faq';
|
||||||
import EdgelessToolbar from '@/components/edgeless-toolbar';
|
import EdgelessToolbar from '@/components/edgeless-toolbar';
|
||||||
import MobileModal from '@/components/mobile-modal';
|
import MobileModal from '@/components/mobile-modal';
|
||||||
@@ -14,26 +14,17 @@ const StyledEditorContainer = styled('div')(({ theme }) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const StyledWrapper = styled('div')(({ theme }) => {
|
|
||||||
return {
|
|
||||||
height: '100vh',
|
|
||||||
backgroundColor: theme.colors.pageBackground,
|
|
||||||
transition: 'background-color .5s',
|
|
||||||
flexGrow: 1,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const Home: NextPage = () => {
|
const Home: NextPage = () => {
|
||||||
return (
|
return (
|
||||||
<StyledWrapper>
|
<>
|
||||||
<Header />
|
<PageHeader />
|
||||||
<MobileModal />
|
<MobileModal />
|
||||||
<StyledEditorContainer>
|
<StyledEditorContainer>
|
||||||
<Editor />
|
<Editor />
|
||||||
</StyledEditorContainer>
|
</StyledEditorContainer>
|
||||||
<FAQ />
|
<FAQ />
|
||||||
<EdgelessToolbar />
|
<EdgelessToolbar />
|
||||||
</StyledWrapper>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { createContext, useContext, useState, ReactNode } from 'react';
|
||||||
|
import type { PropsWithChildren } from 'react';
|
||||||
|
import { Confirm, ConfirmProps } from '@/ui/confirm';
|
||||||
|
|
||||||
|
type ConfirmContextValue = {
|
||||||
|
confirm: (props: ConfirmProps) => void;
|
||||||
|
};
|
||||||
|
type ConfirmContextProps = PropsWithChildren<{}>;
|
||||||
|
|
||||||
|
export const ConfirmContext = createContext<ConfirmContextValue>({
|
||||||
|
confirm: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const useConfirm = () => useContext(ConfirmContext);
|
||||||
|
|
||||||
|
export const ConfirmProvider = ({
|
||||||
|
children,
|
||||||
|
}: PropsWithChildren<ConfirmContextProps>) => {
|
||||||
|
const [confirmRecord, setConfirmRecord] = useState<Record<string, ReactNode>>(
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<ConfirmContext.Provider
|
||||||
|
value={{
|
||||||
|
confirm: (props: ConfirmProps) => {
|
||||||
|
const confirmId = String(Date.now());
|
||||||
|
setConfirmRecord(oldConfirmRecord => {
|
||||||
|
return {
|
||||||
|
...oldConfirmRecord,
|
||||||
|
[confirmId]: (
|
||||||
|
<Confirm
|
||||||
|
{...props}
|
||||||
|
onClose={() => {
|
||||||
|
delete confirmRecord[confirmId];
|
||||||
|
setConfirmRecord({ ...confirmRecord });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{Object.entries(confirmRecord).map(([confirmId, confirmNode]) => {
|
||||||
|
return <div key={confirmId}>{confirmNode}</div>;
|
||||||
|
})}
|
||||||
|
</ConfirmContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ConfirmProvider;
|
||||||
@@ -20,6 +20,7 @@ export const getLightTheme = (
|
|||||||
tooltipBackground: '#6880FF',
|
tooltipBackground: '#6880FF',
|
||||||
codeBackground: '#f2f5f9',
|
codeBackground: '#f2f5f9',
|
||||||
warningBackground: '#FFF9C7',
|
warningBackground: '#FFF9C7',
|
||||||
|
errorBackground: '#FFDED8',
|
||||||
|
|
||||||
textColor: '#3A4C5C',
|
textColor: '#3A4C5C',
|
||||||
edgelessTextColor: '#3A4C5C',
|
edgelessTextColor: '#3A4C5C',
|
||||||
@@ -36,11 +37,19 @@ export const getLightTheme = (
|
|||||||
borderColor: '#D0D7E3',
|
borderColor: '#D0D7E3',
|
||||||
disableColor: '#C0C0C0',
|
disableColor: '#C0C0C0',
|
||||||
warningColor: '#906616',
|
warningColor: '#906616',
|
||||||
|
errorColor: '#EB4335',
|
||||||
},
|
},
|
||||||
font: {
|
font: {
|
||||||
xs: '12px',
|
xs: '12px',
|
||||||
sm: '16px',
|
sm: '16px',
|
||||||
base: '18px',
|
base: '18px',
|
||||||
|
h1: '30px',
|
||||||
|
h2: '28px',
|
||||||
|
h3: '26px',
|
||||||
|
h4: '24px',
|
||||||
|
h5: '22px',
|
||||||
|
h6: '20px',
|
||||||
|
|
||||||
family: `Avenir Next, Poppins, ${basicFontFamily}`,
|
family: `Avenir Next, Poppins, ${basicFontFamily}`,
|
||||||
family2: `Space Mono, ${basicFontFamily}`,
|
family2: `Space Mono, ${basicFontFamily}`,
|
||||||
lineHeightBase: '26px',
|
lineHeightBase: '26px',
|
||||||
@@ -85,6 +94,7 @@ export const getDarkTheme = (
|
|||||||
? lightTheme.colors.codeBackground
|
? lightTheme.colors.codeBackground
|
||||||
: '#505662',
|
: '#505662',
|
||||||
warningBackground: '#FFF9C7',
|
warningBackground: '#FFF9C7',
|
||||||
|
errorBackground: '#FFDED8',
|
||||||
|
|
||||||
textColor: '#fff',
|
textColor: '#fff',
|
||||||
edgelessTextColor: '#3A4C5C',
|
edgelessTextColor: '#3A4C5C',
|
||||||
@@ -102,6 +112,7 @@ export const getDarkTheme = (
|
|||||||
borderColor: '#4D4C53',
|
borderColor: '#4D4C53',
|
||||||
disableColor: '#4b4b4b',
|
disableColor: '#4b4b4b',
|
||||||
warningColor: '#906616',
|
warningColor: '#906616',
|
||||||
|
errorColor: '#EB4335',
|
||||||
},
|
},
|
||||||
shadow: {
|
shadow: {
|
||||||
popover:
|
popover:
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export interface AffineTheme {
|
|||||||
hoverBackground: string;
|
hoverBackground: string;
|
||||||
codeBackground: string;
|
codeBackground: string;
|
||||||
warningBackground: string;
|
warningBackground: string;
|
||||||
|
errorBackground: string;
|
||||||
// Use for the page`s text
|
// Use for the page`s text
|
||||||
textColor: string;
|
textColor: string;
|
||||||
// Use for the editor`s text, because in edgeless mode text is different form other
|
// Use for the editor`s text, because in edgeless mode text is different form other
|
||||||
@@ -43,11 +44,18 @@ export interface AffineTheme {
|
|||||||
borderColor: string;
|
borderColor: string;
|
||||||
disableColor: string;
|
disableColor: string;
|
||||||
warningColor: string;
|
warningColor: string;
|
||||||
|
errorColor: string;
|
||||||
};
|
};
|
||||||
font: {
|
font: {
|
||||||
xs: string; // tiny
|
xs: string; // tiny
|
||||||
sm: string; // small
|
sm: string; // small
|
||||||
base: string;
|
base: string;
|
||||||
|
h1: string;
|
||||||
|
h2: string;
|
||||||
|
h3: string;
|
||||||
|
h4: string;
|
||||||
|
h5: string;
|
||||||
|
h6: string;
|
||||||
|
|
||||||
family: string;
|
family: string;
|
||||||
family2: string;
|
family2: string;
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { Modal, ModalCloseButton, ModalProps } from '../modal';
|
||||||
|
import {
|
||||||
|
StyledButtonWrapper,
|
||||||
|
StyledConfirmContent,
|
||||||
|
StyledConfirmTitle,
|
||||||
|
StyledModalWrapper,
|
||||||
|
StyledButton,
|
||||||
|
} from '@/ui/confirm/styles';
|
||||||
|
|
||||||
|
export type ConfirmProps = {
|
||||||
|
title?: string;
|
||||||
|
content?: string;
|
||||||
|
confirmText?: string;
|
||||||
|
// TODO: Confirm button's color should depend on confirm type
|
||||||
|
confirmType?: 'primary' | 'warning' | 'danger';
|
||||||
|
onConfirm?: () => void;
|
||||||
|
onCancel?: () => void;
|
||||||
|
} & Omit<ModalProps, 'open' | 'children'>;
|
||||||
|
|
||||||
|
export const Confirm = ({
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
confirmText,
|
||||||
|
confirmType,
|
||||||
|
onConfirm,
|
||||||
|
onCancel,
|
||||||
|
}: ConfirmProps) => {
|
||||||
|
const [open, setOpen] = useState(true);
|
||||||
|
return (
|
||||||
|
<Modal open={open}>
|
||||||
|
<StyledModalWrapper>
|
||||||
|
<ModalCloseButton
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(false);
|
||||||
|
onCancel?.();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<StyledConfirmTitle>{title}</StyledConfirmTitle>
|
||||||
|
<StyledConfirmContent>{content}</StyledConfirmContent>
|
||||||
|
|
||||||
|
<StyledButtonWrapper>
|
||||||
|
<StyledButton
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(false);
|
||||||
|
onCancel?.();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</StyledButton>
|
||||||
|
<StyledButton
|
||||||
|
confirmType={confirmType}
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(false);
|
||||||
|
onConfirm?.();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{confirmText}
|
||||||
|
</StyledButton>
|
||||||
|
</StyledButtonWrapper>
|
||||||
|
</StyledModalWrapper>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Confirm;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './confirm';
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import { displayFlex, styled, AffineTheme } from '@/styles';
|
||||||
|
import { ConfirmProps } from '@/ui/confirm/confirm';
|
||||||
|
|
||||||
|
export const StyledModalWrapper = styled.div(({ theme }) => {
|
||||||
|
return {
|
||||||
|
width: '460px',
|
||||||
|
height: '240px',
|
||||||
|
padding: '0 60px',
|
||||||
|
background: theme.colors.popoverBackground,
|
||||||
|
borderRadius: '28px',
|
||||||
|
position: 'relative',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const StyledConfirmTitle = styled.div(({ theme }) => {
|
||||||
|
return {
|
||||||
|
fontSize: theme.font.h6,
|
||||||
|
fontWeight: 600,
|
||||||
|
textAlign: 'center',
|
||||||
|
marginTop: '45px',
|
||||||
|
color: theme.colors.popoverColor,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const StyledConfirmContent = styled.div(({ theme }) => {
|
||||||
|
return {
|
||||||
|
fontSize: theme.font.base,
|
||||||
|
textAlign: 'center',
|
||||||
|
marginTop: '12px',
|
||||||
|
color: theme.colors.textColor,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const StyledButtonWrapper = styled.div(() => {
|
||||||
|
return {
|
||||||
|
...displayFlex('center', 'center'),
|
||||||
|
marginTop: '32px',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const getButtonColors = (
|
||||||
|
theme: AffineTheme,
|
||||||
|
confirmType: ConfirmProps['confirmType']
|
||||||
|
) => {
|
||||||
|
switch (confirmType) {
|
||||||
|
case 'primary':
|
||||||
|
return {
|
||||||
|
background: theme.colors.primaryColor,
|
||||||
|
color: '#fff',
|
||||||
|
borderColor: theme.colors.primaryColor,
|
||||||
|
};
|
||||||
|
case 'warning':
|
||||||
|
return {
|
||||||
|
background: theme.colors.warningBackground,
|
||||||
|
color: theme.colors.warningColor,
|
||||||
|
borderColor: theme.colors.warningBackground,
|
||||||
|
':hover': {
|
||||||
|
borderColor: theme.colors.warningColor,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case 'danger':
|
||||||
|
return {
|
||||||
|
background: theme.colors.errorBackground,
|
||||||
|
color: theme.colors.errorColor,
|
||||||
|
borderColor: theme.colors.errorBackground,
|
||||||
|
':hover': {
|
||||||
|
borderColor: theme.colors.errorColor,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return {
|
||||||
|
color: theme.colors.popoverColor,
|
||||||
|
borderColor: theme.colors.borderColor,
|
||||||
|
':hover': {
|
||||||
|
borderColor: theme.colors.primaryColor,
|
||||||
|
color: theme.colors.primaryColor,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StyledButton = styled.button<Pick<ConfirmProps, 'confirmType'>>(
|
||||||
|
({ theme, confirmType }) => {
|
||||||
|
return {
|
||||||
|
width: '100px',
|
||||||
|
height: '38px',
|
||||||
|
borderRadius: '19px',
|
||||||
|
border: '1px solid',
|
||||||
|
...getButtonColors(theme, confirmType),
|
||||||
|
fontSize: theme.font.sm,
|
||||||
|
fontWeight: 500,
|
||||||
|
|
||||||
|
'&:first-of-type': {
|
||||||
|
marginRight: '24px',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import Modal from './modal';
|
import Modal from './modal';
|
||||||
|
|
||||||
|
export * from './modal-close-button';
|
||||||
export * from './modal';
|
export * from './modal';
|
||||||
|
|
||||||
export default Modal;
|
export default Modal;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { HTMLAttributes } from 'react';
|
||||||
|
import { StyledCloseButton } from './style';
|
||||||
|
import { CloseIcon } from '@blocksuite/icons';
|
||||||
|
|
||||||
|
export type ModalCloseButtonProps = {
|
||||||
|
top?: number;
|
||||||
|
right?: number;
|
||||||
|
triggerSize?: [number, number];
|
||||||
|
size?: [number, number];
|
||||||
|
iconSize?: [number, number];
|
||||||
|
} & HTMLAttributes<HTMLButtonElement>;
|
||||||
|
|
||||||
|
export const ModalCloseButton = ({
|
||||||
|
iconSize = [24, 24],
|
||||||
|
...props
|
||||||
|
}: ModalCloseButtonProps) => {
|
||||||
|
const [iconWidth, iconHeight] = iconSize;
|
||||||
|
return (
|
||||||
|
<StyledCloseButton {...props}>
|
||||||
|
<CloseIcon width={iconWidth} height={iconHeight} />
|
||||||
|
</StyledCloseButton>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ModalCloseButton;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { displayFlex, fixedCenter, styled } from '@/styles';
|
import { absoluteCenter, displayFlex, fixedCenter, styled } from '@/styles';
|
||||||
import ModalUnstyled from '@mui/base/ModalUnstyled';
|
import ModalUnstyled from '@mui/base/ModalUnstyled';
|
||||||
|
import { ModalCloseButtonProps } from '@/ui/modal/modal-close-button';
|
||||||
|
|
||||||
export const StyledBackdrop = styled.div<{ open?: boolean }>(({ open }) => {
|
export const StyledBackdrop = styled.div<{ open?: boolean }>(({ open }) => {
|
||||||
return {
|
return {
|
||||||
@@ -28,3 +29,40 @@ export const StyledModal = styled(ModalUnstyled)(({ theme }) => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const StyledCloseButton = styled.button<
|
||||||
|
Pick<ModalCloseButtonProps, 'size' | 'triggerSize' | 'top' | 'right'>
|
||||||
|
>(({ theme, triggerSize = [], size = [32, 32], top, right }) => {
|
||||||
|
const [triggerWidth, triggerHeight] = triggerSize;
|
||||||
|
const [width, height] = size;
|
||||||
|
|
||||||
|
return {
|
||||||
|
width: triggerWidth ?? width * 2,
|
||||||
|
height: triggerHeight ?? height * 2,
|
||||||
|
color: theme.colors.iconColor,
|
||||||
|
cursor: 'pointer',
|
||||||
|
...displayFlex('center', 'center'),
|
||||||
|
position: 'absolute',
|
||||||
|
top: top ?? 0,
|
||||||
|
right: right ?? 0,
|
||||||
|
|
||||||
|
// TODO: we need to add @emotion/babel-plugin
|
||||||
|
'::after': {
|
||||||
|
content: '""',
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
borderRadius: '6px',
|
||||||
|
...absoluteCenter({ horizontal: true, vertical: true }),
|
||||||
|
},
|
||||||
|
':hover': {
|
||||||
|
color: theme.colors.primaryColor,
|
||||||
|
'::after': {
|
||||||
|
background: theme.colors.hoverBackground,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
svg: {
|
||||||
|
position: 'relative',
|
||||||
|
zIndex: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// import Table from '@mui/material/Table';
|
||||||
|
// import TableBody from '@mui/material/TableBody';
|
||||||
|
import TableCell from '@mui/material/TableCell';
|
||||||
|
// import TableHead from '@mui/material/TableHead';
|
||||||
|
// import TableRow from '@mui/material/TableRow';
|
||||||
|
//
|
||||||
|
|
||||||
|
export * from './table';
|
||||||
|
export * from './table-body';
|
||||||
|
export * from './table-cell';
|
||||||
|
export * from './table-head';
|
||||||
|
export * from './table-row';
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { CSSProperties } from 'react';
|
||||||
|
|
||||||
|
export type TableCellProps = {
|
||||||
|
align?: 'left' | 'right' | 'center';
|
||||||
|
ellipsis?: boolean;
|
||||||
|
proportion?: number;
|
||||||
|
style?: CSSProperties;
|
||||||
|
};
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import { styled, textEllipsis } from '@/styles';
|
||||||
|
import { TableCellProps } from './interface';
|
||||||
|
|
||||||
|
export const StyledTable = styled.table<{ tableLayout: 'auto' | 'fixed' }>(
|
||||||
|
({ theme, tableLayout }) => {
|
||||||
|
return {
|
||||||
|
fontSize: theme.font.base,
|
||||||
|
color: theme.colors.textColor,
|
||||||
|
tableLayout,
|
||||||
|
width: '100%',
|
||||||
|
borderCollapse: 'separate',
|
||||||
|
borderSpacing: '0 25px',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const StyledTableBody = styled.tbody(({ theme }) => {
|
||||||
|
return {
|
||||||
|
fontWeight: 400,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const StyledTableCell = styled.td<
|
||||||
|
Pick<TableCellProps, 'ellipsis' | 'align' | 'proportion'>
|
||||||
|
>(({ theme, align = 'left', ellipsis = false, proportion }) => {
|
||||||
|
const width = proportion ? `${proportion * 100}%` : 'auto';
|
||||||
|
return {
|
||||||
|
width,
|
||||||
|
height: '54px',
|
||||||
|
lineHeight: '54px',
|
||||||
|
padding: '0 30px',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
textAlign: align,
|
||||||
|
...(ellipsis ? textEllipsis(1) : {}),
|
||||||
|
overflowWrap: 'break-word',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const StyledTableHead = styled.thead(({ theme }) => {
|
||||||
|
return {
|
||||||
|
fontWeight: 500,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const StyledTableRow = styled.tr(({ theme }) => {
|
||||||
|
return {
|
||||||
|
marginBottom: '25px',
|
||||||
|
td: {
|
||||||
|
transition: 'background .15s',
|
||||||
|
},
|
||||||
|
'td:first-child': {
|
||||||
|
borderTopLeftRadius: '10px',
|
||||||
|
borderBottomLeftRadius: '10px',
|
||||||
|
},
|
||||||
|
'td:last-child': {
|
||||||
|
borderTopRightRadius: '10px',
|
||||||
|
borderBottomRightRadius: '10px',
|
||||||
|
},
|
||||||
|
|
||||||
|
':hover': {
|
||||||
|
td: {
|
||||||
|
background: theme.colors.hoverBackground,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { PropsWithChildren } from 'react';
|
||||||
|
import { StyledTableBody } from '@/ui/table/styles';
|
||||||
|
|
||||||
|
export const TableBody = ({ children }: PropsWithChildren<{}>) => {
|
||||||
|
return <StyledTableBody>{children}</StyledTableBody>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableBody;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { PropsWithChildren, useLayoutEffect } from 'react';
|
||||||
|
import { TableCellProps } from './interface';
|
||||||
|
import { StyledTableCell } from './styles';
|
||||||
|
|
||||||
|
export const TableCell = ({
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: PropsWithChildren<TableCellProps>) => {
|
||||||
|
return <StyledTableCell {...props}>{children}</StyledTableCell>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableCell;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { PropsWithChildren } from 'react';
|
||||||
|
import { StyledTableHead } from './styles';
|
||||||
|
|
||||||
|
export const TableHead = ({ children }: PropsWithChildren<{}>) => {
|
||||||
|
return <StyledTableHead>{children}</StyledTableHead>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableHead;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { PropsWithChildren } from 'react';
|
||||||
|
import { StyledTableRow } from './styles';
|
||||||
|
|
||||||
|
export const TableRow = ({ children }: PropsWithChildren<{}>) => {
|
||||||
|
return <StyledTableRow>{children}</StyledTableRow>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableRow;
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { PropsWithChildren, Children, ReactNode } from 'react';
|
||||||
|
import { StyledTable } from './styles';
|
||||||
|
|
||||||
|
const childrenHasEllipsis = (children: ReactNode | ReactNode[]): boolean => {
|
||||||
|
return Children.toArray(children).some(child => {
|
||||||
|
if (typeof child === 'object' && 'props' in child) {
|
||||||
|
if (!child.props.ellipsis && child.props.children) {
|
||||||
|
return childrenHasEllipsis(child.props.children);
|
||||||
|
}
|
||||||
|
return child.props.ellipsis ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Table = ({ children }: PropsWithChildren<{}>) => {
|
||||||
|
const tableLayout = childrenHasEllipsis(children) ? 'fixed' : 'auto';
|
||||||
|
|
||||||
|
return <StyledTable tableLayout={tableLayout}>{children}</StyledTable>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Table;
|
||||||
Reference in New Issue
Block a user