mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-22 12:36:24 +08:00
fix: a series of bugs
This commit is contained in:
@@ -66,7 +66,9 @@ export const EditorModeSwitch = ({
|
||||
style = {},
|
||||
}: AnimateRadioProps) => {
|
||||
const { mode: themeMode } = useTheme();
|
||||
const { mode, setMode } = useEditor();
|
||||
const { mode, setMode, getPageMeta } = useEditor();
|
||||
const pageMeta = getPageMeta();
|
||||
|
||||
const modifyRadioItemStatus = (): RadioItemStatus => {
|
||||
return {
|
||||
left: isHover
|
||||
@@ -99,6 +101,7 @@ export const EditorModeSwitch = ({
|
||||
data-testid="editor-mode-switcher"
|
||||
shrink={!isHover}
|
||||
style={style}
|
||||
disabled={!!pageMeta?.trash}
|
||||
>
|
||||
<AnimateRadioItem
|
||||
isLeft={true}
|
||||
|
||||
@@ -5,41 +5,42 @@ import type { ItemStatus } from './type';
|
||||
|
||||
const ANIMATE_DURATION = 500;
|
||||
|
||||
export const StyledAnimateRadioContainer = styled('div')<{ shrink: boolean }>(
|
||||
({ shrink, theme }) => {
|
||||
const animateScaleStretch = keyframes`${toString(
|
||||
spring({ width: '36px' }, { width: '160px' }, { preset: 'gentle' })
|
||||
)}`;
|
||||
const animateScaleShrink = keyframes(
|
||||
`${toString(
|
||||
spring({ width: '160px' }, { width: '36px' }, { preset: 'gentle' })
|
||||
)}`
|
||||
);
|
||||
const shrinkStyle = shrink
|
||||
? {
|
||||
animation: `${animateScaleShrink} ${ANIMATE_DURATION}ms forwards`,
|
||||
background: 'transparent',
|
||||
}
|
||||
: {
|
||||
animation: `${animateScaleStretch} ${ANIMATE_DURATION}ms forwards`,
|
||||
};
|
||||
export const StyledAnimateRadioContainer = styled('div')<{
|
||||
shrink: boolean;
|
||||
disabled: boolean;
|
||||
}>(({ shrink, theme, disabled }) => {
|
||||
const animateScaleStretch = keyframes`${toString(
|
||||
spring({ width: '36px' }, { width: '160px' }, { preset: 'gentle' })
|
||||
)}`;
|
||||
const animateScaleShrink = keyframes(
|
||||
`${toString(
|
||||
spring({ width: '160px' }, { width: '36px' }, { preset: 'gentle' })
|
||||
)}`
|
||||
);
|
||||
const shrinkStyle = shrink
|
||||
? {
|
||||
animation: `${animateScaleShrink} ${ANIMATE_DURATION}ms forwards`,
|
||||
background: 'transparent',
|
||||
}
|
||||
: {
|
||||
animation: `${animateScaleStretch} ${ANIMATE_DURATION}ms forwards`,
|
||||
};
|
||||
|
||||
return {
|
||||
height: '36px',
|
||||
borderRadius: '18px',
|
||||
background: theme.colors.hoverBackground,
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
transition: `background ${ANIMATE_DURATION}ms, border ${ANIMATE_DURATION}ms`,
|
||||
border: '1px solid transparent',
|
||||
return {
|
||||
height: '36px',
|
||||
borderRadius: '18px',
|
||||
background: disabled ? 'transparent' : theme.colors.hoverBackground,
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
transition: `background ${ANIMATE_DURATION}ms, border ${ANIMATE_DURATION}ms`,
|
||||
border: '1px solid transparent',
|
||||
|
||||
...shrinkStyle,
|
||||
':hover': {
|
||||
border: `1px solid ${theme.colors.primaryColor}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
...(disabled ? { pointerEvents: 'none' } : shrinkStyle),
|
||||
':hover': {
|
||||
border: disabled ? '' : `1px solid ${theme.colors.primaryColor}`,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledMiddleLine = styled('div')<{
|
||||
hidden: boolean;
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
StyledFAQ,
|
||||
StyledIconWrapper,
|
||||
StyledFAQWrapper,
|
||||
StyledTransformIcon,
|
||||
} from './style';
|
||||
import { CloseIcon, ContactIcon, HelpIcon, KeyboardIcon } from './icons';
|
||||
import Grow from '@mui/material/Grow';
|
||||
import { Tooltip } from '@/ui/tooltip';
|
||||
import { useEditor } from '@/providers/editor-provider';
|
||||
import { useModal } from '@/providers/global-modal-provider';
|
||||
import { useTheme } from '@/providers/themeProvider';
|
||||
|
||||
export const FAQ = () => {
|
||||
const [showContent, setShowContent] = useState(false);
|
||||
const { mode } = useTheme();
|
||||
const { mode: editorMode } = useEditor();
|
||||
const { triggerShortcutsModal, triggerContactModal } = useModal();
|
||||
const isEdgelessDark = mode === 'dark' && editorMode === 'edgeless';
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledFAQ
|
||||
className=""
|
||||
onMouseEnter={() => {
|
||||
setShowContent(true);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setShowContent(false);
|
||||
}}
|
||||
>
|
||||
<Grow in={showContent}>
|
||||
<StyledFAQWrapper>
|
||||
<Tooltip content="Contact Us" placement="left-end">
|
||||
<StyledIconWrapper
|
||||
data-testid="right-bottom-contact-us-icon"
|
||||
isEdgelessDark={isEdgelessDark}
|
||||
onClick={() => {
|
||||
setShowContent(false);
|
||||
triggerContactModal();
|
||||
}}
|
||||
>
|
||||
<ContactIcon />
|
||||
</StyledIconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip content="Keyboard Shortcuts" placement="left-end">
|
||||
<StyledIconWrapper
|
||||
data-testid="shortcuts-icon"
|
||||
isEdgelessDark={isEdgelessDark}
|
||||
onClick={() => {
|
||||
setShowContent(false);
|
||||
triggerShortcutsModal();
|
||||
}}
|
||||
>
|
||||
<KeyboardIcon />
|
||||
</StyledIconWrapper>
|
||||
</Tooltip>
|
||||
</StyledFAQWrapper>
|
||||
</Grow>
|
||||
|
||||
<div style={{ position: 'relative' }}>
|
||||
<StyledIconWrapper
|
||||
data-testid="faq-icon"
|
||||
isEdgelessDark={isEdgelessDark}
|
||||
>
|
||||
<HelpIcon />
|
||||
</StyledIconWrapper>
|
||||
<StyledTransformIcon in={showContent}>
|
||||
<CloseIcon />
|
||||
</StyledTransformIcon>
|
||||
</div>
|
||||
</StyledFAQ>
|
||||
</>
|
||||
);
|
||||
};
|
||||
+12
-16
@@ -5,25 +5,21 @@ import {
|
||||
StyledTitle,
|
||||
StyledTitleWrapper,
|
||||
} from './styles';
|
||||
import { IconButton } from '@/ui/button';
|
||||
import { Content } from '@/ui/layout';
|
||||
import { useEditor } from '@/providers/editor-provider';
|
||||
import EditorModeSwitch from '@/components/editor-mode-switch';
|
||||
import { ArrowDownIcon } from '@blocksuite/icons';
|
||||
import { useModal } from '@/providers/global-modal-provider';
|
||||
|
||||
import QuickSearchButton from './quick-search-button';
|
||||
import Header from './header';
|
||||
|
||||
export const PageHeader = () => {
|
||||
export const EditorHeader = () => {
|
||||
const [title, setTitle] = useState('');
|
||||
const [isHover, setIsHover] = useState(false);
|
||||
|
||||
const { editor, onPropsUpdated } = useEditor();
|
||||
const { triggerQuickSearchModal } = useModal();
|
||||
const { editor, onPropsUpdated, getPageMeta } = useEditor();
|
||||
|
||||
useEffect(() => {
|
||||
onPropsUpdated(editor => {
|
||||
setTitle(editor.model.title);
|
||||
setTitle(editor.model.title || 'Untitled');
|
||||
});
|
||||
}, [onPropsUpdated]);
|
||||
|
||||
@@ -31,14 +27,20 @@ export const PageHeader = () => {
|
||||
setTitle(editor?.model.title || 'Untitled');
|
||||
}, [editor]);
|
||||
|
||||
const pageMeta = getPageMeta();
|
||||
|
||||
return (
|
||||
<Header>
|
||||
{title && (
|
||||
<StyledTitle
|
||||
onMouseEnter={() => {
|
||||
if (pageMeta?.trash) return;
|
||||
|
||||
setIsHover(true);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
if (pageMeta?.trash) return;
|
||||
|
||||
setIsHover(false);
|
||||
}}
|
||||
>
|
||||
@@ -53,13 +55,7 @@ export const PageHeader = () => {
|
||||
</StyledSwitchWrapper>
|
||||
<Content ellipsis={true}>{title}</Content>
|
||||
<StyledSearchArrowWrapper>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
triggerQuickSearchModal();
|
||||
}}
|
||||
>
|
||||
<ArrowDownIcon />
|
||||
</IconButton>
|
||||
<QuickSearchButton />
|
||||
</StyledSearchArrowWrapper>
|
||||
</StyledTitleWrapper>
|
||||
</StyledTitle>
|
||||
@@ -68,4 +64,4 @@ export const PageHeader = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default PageHeader;
|
||||
export default EditorHeader;
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from './header';
|
||||
export * from './page-header';
|
||||
export { StyledTitle as HeaderWrapper } from './styles';
|
||||
export * from './editor-header';
|
||||
export * from './page-list-header';
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { PropsWithChildren, ReactNode } from 'react';
|
||||
import Header from './header';
|
||||
import { StyledPageListTittleWrapper } from './styles';
|
||||
import QuickSearchButton from './quick-search-button';
|
||||
|
||||
export type PageListHeaderProps = PropsWithChildren<{
|
||||
icon?: ReactNode;
|
||||
}>;
|
||||
export const PageListHeader = ({ icon, children }: PageListHeaderProps) => {
|
||||
return (
|
||||
<Header>
|
||||
<StyledPageListTittleWrapper>
|
||||
{icon}
|
||||
{children}
|
||||
<QuickSearchButton style={{ marginLeft: '5px' }} />
|
||||
</StyledPageListTittleWrapper>
|
||||
</Header>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageListHeader;
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import { IconButton, IconButtonProps } from '@/ui/button';
|
||||
import { ArrowDownIcon } from '@blocksuite/icons';
|
||||
import { useModal } from '@/providers/global-modal-provider';
|
||||
|
||||
export const QuickSearchButton = ({
|
||||
onClick,
|
||||
...props
|
||||
}: Omit<IconButtonProps, 'children'>) => {
|
||||
const { triggerQuickSearchModal } = useModal();
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
{...props}
|
||||
onClick={e => {
|
||||
onClick?.(e);
|
||||
triggerQuickSearchModal();
|
||||
}}
|
||||
>
|
||||
<ArrowDownIcon />
|
||||
</IconButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuickSearchButton;
|
||||
@@ -110,3 +110,14 @@ export const StyledSearchArrowWrapper = styled.div(() => {
|
||||
...displayFlex('center', 'center'),
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledPageListTittleWrapper = styled(StyledTitle)(({ theme }) => {
|
||||
return {
|
||||
fontSize: theme.font.sm,
|
||||
color: theme.colors.textColor,
|
||||
'>svg': {
|
||||
fontSize: '20px',
|
||||
marginRight: '12px',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
StyledIsland,
|
||||
StyledIconWrapper,
|
||||
StyledIslandWrapper,
|
||||
StyledTransformIcon,
|
||||
} from './style';
|
||||
import { CloseIcon, ContactIcon, HelpIcon, KeyboardIcon } from './icons';
|
||||
import Grow from '@mui/material/Grow';
|
||||
import { Tooltip } from '@/ui/tooltip';
|
||||
import { useEditor } from '@/providers/editor-provider';
|
||||
import { useModal } from '@/providers/global-modal-provider';
|
||||
import { useTheme } from '@/providers/themeProvider';
|
||||
|
||||
export type IslandItemNames = 'contact' | 'shortcuts';
|
||||
// export type IslandShowMap = Record<IslandItemNames, boolean>;
|
||||
|
||||
export const HelpIsland = ({
|
||||
showList = ['contact', 'shortcuts'],
|
||||
}: {
|
||||
showList?: IslandItemNames[];
|
||||
}) => {
|
||||
const [showContent, setShowContent] = useState(false);
|
||||
const { mode } = useTheme();
|
||||
const { mode: editorMode } = useEditor();
|
||||
const { triggerShortcutsModal, triggerContactModal } = useModal();
|
||||
const isEdgelessDark = mode === 'dark' && editorMode === 'edgeless';
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledIsland
|
||||
className=""
|
||||
onMouseEnter={() => {
|
||||
setShowContent(true);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setShowContent(false);
|
||||
}}
|
||||
>
|
||||
<Grow in={showContent}>
|
||||
<StyledIslandWrapper>
|
||||
{showList.includes('contact') && (
|
||||
<Tooltip content="Contact Us" placement="left-end">
|
||||
<StyledIconWrapper
|
||||
data-testid="right-bottom-contact-us-icon"
|
||||
isEdgelessDark={isEdgelessDark}
|
||||
onClick={() => {
|
||||
setShowContent(false);
|
||||
triggerContactModal();
|
||||
}}
|
||||
>
|
||||
<ContactIcon />
|
||||
</StyledIconWrapper>
|
||||
</Tooltip>
|
||||
)}
|
||||
{showList.includes('shortcuts') && (
|
||||
<Tooltip content="Keyboard Shortcuts" placement="left-end">
|
||||
<StyledIconWrapper
|
||||
data-testid="shortcuts-icon"
|
||||
isEdgelessDark={isEdgelessDark}
|
||||
onClick={() => {
|
||||
setShowContent(false);
|
||||
triggerShortcutsModal();
|
||||
}}
|
||||
>
|
||||
<KeyboardIcon />
|
||||
</StyledIconWrapper>
|
||||
</Tooltip>
|
||||
)}
|
||||
</StyledIslandWrapper>
|
||||
</Grow>
|
||||
|
||||
<div style={{ position: 'relative' }}>
|
||||
<StyledIconWrapper isEdgelessDark={isEdgelessDark}>
|
||||
<HelpIcon />
|
||||
</StyledIconWrapper>
|
||||
<StyledTransformIcon in={showContent}>
|
||||
<CloseIcon />
|
||||
</StyledTransformIcon>
|
||||
</div>
|
||||
</StyledIsland>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default HelpIsland;
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { displayFlex, styled } from '@/styles';
|
||||
|
||||
export const StyledFAQ = styled('div')(({ theme }) => {
|
||||
export const StyledIsland = styled('div')(({ theme }) => {
|
||||
return {
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
@@ -57,7 +57,7 @@ export const StyledIconWrapper = styled('div')<{ isEdgelessDark: boolean }>(
|
||||
}
|
||||
);
|
||||
|
||||
export const StyledFAQWrapper = styled('div')(({ theme }) => {
|
||||
export const StyledIslandWrapper = styled('div')(({ theme }) => {
|
||||
return {
|
||||
position: 'absolute',
|
||||
bottom: '100%',
|
||||
@@ -9,16 +9,17 @@ dayjs.extend(localizedFormat);
|
||||
export const DateCell = ({
|
||||
pageMeta,
|
||||
dateKey,
|
||||
backupKey = '',
|
||||
}: {
|
||||
pageMeta: PageMeta;
|
||||
dateKey: keyof PageMeta;
|
||||
backupKey?: keyof PageMeta;
|
||||
}) => {
|
||||
// dayjs().format('L LT');
|
||||
const value = pageMeta[dateKey] ?? pageMeta[backupKey];
|
||||
return (
|
||||
<TableCell ellipsis={true}>
|
||||
{pageMeta[dateKey] === undefined
|
||||
? '--'
|
||||
: dayjs(pageMeta[dateKey] as string).format('YYYY-MM-DD HH:mm')}
|
||||
{value ? dayjs(value as string).format('YYYY-MM-DD HH:mm') : '--'}
|
||||
</TableCell>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -85,6 +85,7 @@ export const PageList = ({
|
||||
<DateCell
|
||||
pageMeta={pageMeta}
|
||||
dateKey={isTrash ? 'trashDate' : 'updatedDate'}
|
||||
backupKey={isTrash ? 'trashDate' : 'createDate'}
|
||||
/>
|
||||
<TableCell style={{ padding: 0 }}>
|
||||
{isTrash ? (
|
||||
|
||||
@@ -40,9 +40,8 @@ export const OperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => {
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
confirm({
|
||||
title: 'Delete',
|
||||
content:
|
||||
'Deleted items will be moved to Trash Bin. Do you confirm?',
|
||||
title: 'Delete page?',
|
||||
content: `${pageMeta.title} will be moved to Trash`,
|
||||
confirmText: 'Delete',
|
||||
confirmType: 'danger',
|
||||
}).then(confirm => {
|
||||
|
||||
@@ -20,10 +20,12 @@ import {
|
||||
AddIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import Link from 'next/link';
|
||||
import { Tooltip } from '@/ui/tooltip';
|
||||
import { useEditor } from '@/providers/editor-provider';
|
||||
import { useModal } from '@/providers/global-modal-provider';
|
||||
|
||||
import { IconButton } from '@/ui/button';
|
||||
import useLocalStorage from '@/hooks/use-local-storage';
|
||||
|
||||
const FavoriteList = ({ showList }: { showList: boolean }) => {
|
||||
const { pageList, openPage } = useEditor();
|
||||
@@ -45,7 +47,7 @@ const FavoriteList = ({ showList }: { showList: boolean }) => {
|
||||
openPage(pageMeta.id);
|
||||
}}
|
||||
>
|
||||
{pageMeta.title || pageMeta.id}
|
||||
{pageMeta.title || 'Untitled'}
|
||||
</StyledSubListItem>
|
||||
);
|
||||
})}
|
||||
@@ -57,11 +59,13 @@ const FavoriteList = ({ showList }: { showList: boolean }) => {
|
||||
};
|
||||
export const WorkSpaceSliderBar = () => {
|
||||
const { triggerQuickSearchModal, triggerImportModal } = useModal();
|
||||
const [show, setShow] = useState(false);
|
||||
const [showSubFavorite, setShowSubFavorite] = useState(true);
|
||||
const { createPage, getPageMeta, openPage } = useEditor();
|
||||
const router = useRouter();
|
||||
|
||||
const [showTip, setShowTip] = useState(false);
|
||||
const [show, setShow] = useLocalStorage('AFFINE_SLIDE_BAR', false, true);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledSliderBar show={show}>
|
||||
@@ -120,14 +124,27 @@ export const WorkSpaceSliderBar = () => {
|
||||
<AddIcon /> New Page
|
||||
</StyledNewPageButton>
|
||||
</StyledSliderBar>
|
||||
<StyledArrowButton
|
||||
isShow={show}
|
||||
onClick={() => {
|
||||
setShow(!show);
|
||||
}}
|
||||
<Tooltip
|
||||
content={show ? 'Collapse sidebar' : 'Expand sidebar'}
|
||||
placement="right"
|
||||
visible={showTip}
|
||||
>
|
||||
<Arrow />
|
||||
</StyledArrowButton>
|
||||
<StyledArrowButton
|
||||
isShow={show}
|
||||
onClick={() => {
|
||||
setShow(!show);
|
||||
setShowTip(false);
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
setShowTip(true);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setShowTip(false);
|
||||
}}
|
||||
>
|
||||
<Arrow />
|
||||
</StyledArrowButton>
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user