mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
style: move trash button group to page bottom (#3352)
This commit is contained in:
@@ -43,6 +43,9 @@ export const EditorModeSwitch = ({
|
||||
assertExists(pageMeta);
|
||||
const { trash } = pageMeta;
|
||||
useEffect(() => {
|
||||
if (trash) {
|
||||
return;
|
||||
}
|
||||
const keydown = (e: KeyboardEvent) => {
|
||||
if (
|
||||
!environment.isServer && environment.isMacOs
|
||||
@@ -64,7 +67,7 @@ export const EditorModeSwitch = ({
|
||||
document.addEventListener('keydown', keydown, { capture: true });
|
||||
return () =>
|
||||
document.removeEventListener('keydown', keydown, { capture: true });
|
||||
}, [setSetting, t]);
|
||||
}, [setSetting, t, trash]);
|
||||
|
||||
return (
|
||||
<Tooltip content={<TooltipContent />}>
|
||||
@@ -77,6 +80,7 @@ export const EditorModeSwitch = ({
|
||||
data-testid="switch-page-mode-button"
|
||||
active={currentMode === 'page'}
|
||||
hide={trash && currentMode !== 'page'}
|
||||
trash={trash}
|
||||
onClick={() => {
|
||||
setSetting(setting => {
|
||||
if (setting?.mode !== 'page') {
|
||||
@@ -90,6 +94,7 @@ export const EditorModeSwitch = ({
|
||||
data-testid="switch-edgeless-mode-button"
|
||||
active={currentMode === 'edgeless'}
|
||||
hide={trash && currentMode !== 'edgeless'}
|
||||
trash={trash}
|
||||
onClick={() => {
|
||||
setSetting(setting => {
|
||||
if (setting?.mode !== 'edgeless') {
|
||||
|
||||
@@ -34,14 +34,19 @@ export const StyledEditorModeSwitch = styled('div')<{
|
||||
export const StyledSwitchItem = styled('button')<{
|
||||
active?: boolean;
|
||||
hide?: boolean;
|
||||
}>(({ active = false, hide = false }) => {
|
||||
trash?: boolean;
|
||||
}>(({ active = false, hide = false, trash = false }) => {
|
||||
return {
|
||||
width: '24px',
|
||||
height: '24px',
|
||||
borderRadius: '8px',
|
||||
WebkitAppRegion: 'no-drag',
|
||||
boxShadow: active ? 'var(--affine-shadow-1)' : 'none',
|
||||
color: active ? 'var(--affine-primary-color)' : 'var(--affine-icon-color)',
|
||||
color: active
|
||||
? trash
|
||||
? 'var(--affine-error-color)'
|
||||
: 'var(--affine-primary-color)'
|
||||
: 'var(--affine-icon-color)',
|
||||
display: hide ? 'none' : 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
|
||||
@@ -8,12 +8,14 @@ import { StyledSwitchItem } from './style';
|
||||
type HoverAnimateControllerProps = {
|
||||
active?: boolean;
|
||||
hide?: boolean;
|
||||
trash?: boolean;
|
||||
children: React.ReactElement;
|
||||
} & HTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
const HoverAnimateController = ({
|
||||
active,
|
||||
hide,
|
||||
trash,
|
||||
children,
|
||||
...props
|
||||
}: HoverAnimateControllerProps) => {
|
||||
@@ -22,6 +24,7 @@ const HoverAnimateController = ({
|
||||
<StyledSwitchItem
|
||||
hide={hide}
|
||||
active={active}
|
||||
trash={trash}
|
||||
onMouseEnter={() => {
|
||||
setStartAnimate(true);
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const group = style({
|
||||
width: '100%',
|
||||
position: 'absolute',
|
||||
bottom: '100px',
|
||||
left: '0',
|
||||
display: 'flex',
|
||||
gap: '24px',
|
||||
justifyContent: 'center',
|
||||
});
|
||||
export const buttonContainer = style({
|
||||
boxShadow: 'var(--affine-float-button-shadow-2)',
|
||||
borderRadius: '8px',
|
||||
});
|
||||
@@ -10,7 +10,7 @@ import { useCallback, useState } from 'react';
|
||||
import { useBlockSuiteMetaHelper } from '../../../../hooks/affine/use-block-suite-meta-helper';
|
||||
import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace';
|
||||
import { useNavigateHelper } from '../../../../hooks/use-navigate-helper';
|
||||
|
||||
import { buttonContainer, group } from './styles.css';
|
||||
export const TrashButtonGroup = () => {
|
||||
// fixme(himself65): remove these hooks ASAP
|
||||
const [workspace] = useCurrentWorkspace();
|
||||
@@ -29,25 +29,29 @@ export const TrashButtonGroup = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
shape="round"
|
||||
style={{ marginRight: '24px' }}
|
||||
onClick={() => {
|
||||
restoreFromTrash(pageId);
|
||||
}}
|
||||
>
|
||||
{t['Restore it']()}
|
||||
</Button>
|
||||
<Button
|
||||
shape="round"
|
||||
type="error"
|
||||
onClick={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
{t['Delete permanently']()}
|
||||
</Button>
|
||||
<div className={group}>
|
||||
<div className={buttonContainer}>
|
||||
<Button
|
||||
type="processing"
|
||||
onClick={() => {
|
||||
restoreFromTrash(pageId);
|
||||
}}
|
||||
size="large"
|
||||
>
|
||||
{t['Restore it']()}
|
||||
</Button>
|
||||
</div>
|
||||
<div className={buttonContainer}>
|
||||
<Button
|
||||
type="error"
|
||||
onClick={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
size="large"
|
||||
>
|
||||
{t['Delete permanently']()}
|
||||
</Button>
|
||||
</div>
|
||||
<Confirm
|
||||
title={t['TrashButtonGroupTitle']()}
|
||||
content={t['TrashButtonGroupDescription']()}
|
||||
@@ -65,7 +69,7 @@ export const TrashButtonGroup = () => {
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import { currentModeAtom } from '../../../atoms/mode';
|
||||
import type { AffineOfficialWorkspace } from '../../../shared';
|
||||
import DownloadClientTip from './download-tips';
|
||||
import { EditorOptionMenu } from './header-right-items/editor-option-menu';
|
||||
import TrashButtonGroup from './header-right-items/trash-button-group';
|
||||
import * as styles from './styles.css';
|
||||
import { OSWarningMessage, shouldShowWarning } from './utils';
|
||||
|
||||
@@ -38,7 +37,6 @@ export type BaseHeaderProps<
|
||||
|
||||
export enum HeaderRightItemName {
|
||||
EditorOptionMenu = 'editorOptionMenu',
|
||||
TrashButtonGroup = 'trashButtonGroup',
|
||||
// some windows only items
|
||||
WindowsAppControls = 'windowsAppControls',
|
||||
}
|
||||
@@ -56,16 +54,10 @@ type HeaderItem = {
|
||||
};
|
||||
|
||||
const HeaderRightItems: Record<HeaderRightItemName, HeaderItem> = {
|
||||
[HeaderRightItemName.TrashButtonGroup]: {
|
||||
Component: TrashButtonGroup,
|
||||
availableWhen: (_, currentPage) => {
|
||||
return currentPage?.meta.trash === true;
|
||||
},
|
||||
},
|
||||
[HeaderRightItemName.EditorOptionMenu]: {
|
||||
Component: EditorOptionMenu,
|
||||
availableWhen: (_, currentPage, { isPublic }) => {
|
||||
return !isPublic;
|
||||
return !isPublic && currentPage?.meta.trash !== true;
|
||||
},
|
||||
},
|
||||
[HeaderRightItemName.WindowsAppControls]: {
|
||||
|
||||
@@ -25,6 +25,7 @@ import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
|
||||
import { pageSettingFamily } from '../atoms';
|
||||
import { fontStyleOptions, useAppSetting } from '../atoms/settings';
|
||||
import { BlockSuiteEditor as Editor } from './blocksuite/block-suite-editor';
|
||||
import TrashButtonGroup from './blocksuite/workspace-header/header-right-items/trash-button-group';
|
||||
import * as styles from './page-detail-editor.css';
|
||||
import { pluginContainer } from './page-detail-editor.css';
|
||||
|
||||
@@ -67,62 +68,65 @@ const EditorWrapper = memo(function EditorWrapper({
|
||||
}, [appSettings.fontStyle]);
|
||||
|
||||
return (
|
||||
<Editor
|
||||
className={clsx(styles.editor, {
|
||||
'full-screen': appSettings.fullWidthLayout,
|
||||
})}
|
||||
style={
|
||||
{
|
||||
'--affine-font-family': value,
|
||||
} as CSSProperties
|
||||
}
|
||||
key={`${workspace.id}-${pageId}`}
|
||||
mode={isPublic ? 'page' : currentMode}
|
||||
page={page}
|
||||
onInit={useCallback(
|
||||
(page: Page, editor: Readonly<EditorContainer>) => {
|
||||
onInit(page, editor);
|
||||
},
|
||||
[onInit]
|
||||
)}
|
||||
setBlockHub={setBlockHub}
|
||||
onLoad={useCallback(
|
||||
(page: Page, editor: EditorContainer) => {
|
||||
page.workspace.setPageMeta(page.id, {
|
||||
updatedDate: Date.now(),
|
||||
});
|
||||
localStorage.setItem('last_page_id', page.id);
|
||||
let dispose = () => {};
|
||||
if (onLoad) {
|
||||
dispose = onLoad(page, editor);
|
||||
}
|
||||
const editorItems = rootStore.get(editorItemsAtom);
|
||||
let disposes: (() => void)[] = [];
|
||||
const renderTimeout = setTimeout(() => {
|
||||
disposes = Object.entries(editorItems).map(([id, editorItem]) => {
|
||||
const div = document.createElement('div');
|
||||
div.setAttribute('plugin-id', id);
|
||||
const cleanup = editorItem(div, editor);
|
||||
assertExists(parent);
|
||||
document.body.appendChild(div);
|
||||
return () => {
|
||||
cleanup();
|
||||
document.body.removeChild(div);
|
||||
};
|
||||
<>
|
||||
<Editor
|
||||
className={clsx(styles.editor, {
|
||||
'full-screen': appSettings.fullWidthLayout,
|
||||
})}
|
||||
style={
|
||||
{
|
||||
'--affine-font-family': value,
|
||||
} as CSSProperties
|
||||
}
|
||||
key={`${workspace.id}-${pageId}`}
|
||||
mode={isPublic ? 'page' : currentMode}
|
||||
page={page}
|
||||
onInit={useCallback(
|
||||
(page: Page, editor: Readonly<EditorContainer>) => {
|
||||
onInit(page, editor);
|
||||
},
|
||||
[onInit]
|
||||
)}
|
||||
setBlockHub={setBlockHub}
|
||||
onLoad={useCallback(
|
||||
(page: Page, editor: EditorContainer) => {
|
||||
page.workspace.setPageMeta(page.id, {
|
||||
updatedDate: Date.now(),
|
||||
});
|
||||
localStorage.setItem('last_page_id', page.id);
|
||||
let dispose = () => {};
|
||||
if (onLoad) {
|
||||
dispose = onLoad(page, editor);
|
||||
}
|
||||
const editorItems = rootStore.get(editorItemsAtom);
|
||||
let disposes: (() => void)[] = [];
|
||||
const renderTimeout = setTimeout(() => {
|
||||
disposes = Object.entries(editorItems).map(([id, editorItem]) => {
|
||||
const div = document.createElement('div');
|
||||
div.setAttribute('plugin-id', id);
|
||||
const cleanup = editorItem(div, editor);
|
||||
assertExists(parent);
|
||||
document.body.appendChild(div);
|
||||
return () => {
|
||||
cleanup();
|
||||
document.body.removeChild(div);
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
dispose();
|
||||
clearTimeout(renderTimeout);
|
||||
setTimeout(() => {
|
||||
disposes.forEach(dispose => dispose());
|
||||
});
|
||||
};
|
||||
},
|
||||
[onLoad]
|
||||
)}
|
||||
/>
|
||||
return () => {
|
||||
dispose();
|
||||
clearTimeout(renderTimeout);
|
||||
setTimeout(() => {
|
||||
disposes.forEach(dispose => dispose());
|
||||
});
|
||||
};
|
||||
},
|
||||
[onLoad]
|
||||
)}
|
||||
/>
|
||||
{meta.trash && <TrashButtonGroup />}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"@radix-ui/react-toast": "^1.1.4",
|
||||
"@toeverything/hooks": "workspace:*",
|
||||
"@toeverything/plugin-infra": "workspace:*",
|
||||
"@toeverything/theme": "^0.7.7",
|
||||
"@toeverything/theme": "^0.7.9",
|
||||
"@vanilla-extract/dynamic": "^2.0.3",
|
||||
"clsx": "^2.0.0",
|
||||
"dayjs": "^1.11.9",
|
||||
|
||||
@@ -70,7 +70,7 @@ export const button = style({
|
||||
color: 'var(--affine-white)',
|
||||
background: 'var(--affine-primary-color)',
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset',
|
||||
boxShadow: 'var(--affine-button-inner-shadow)',
|
||||
},
|
||||
'&.primary:hover': {
|
||||
background:
|
||||
@@ -85,10 +85,10 @@ export const button = style({
|
||||
},
|
||||
|
||||
'&.error': {
|
||||
color: 'var(--affine-white)',
|
||||
color: 'var(--affine-pure-white)',
|
||||
background: 'var(--affine-error-color)',
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset',
|
||||
boxShadow: 'var(--affine-button-inner-shadow)',
|
||||
},
|
||||
'&.error:hover': {
|
||||
background:
|
||||
@@ -106,7 +106,7 @@ export const button = style({
|
||||
color: 'var(--affine-white)',
|
||||
background: 'var(--affine-warning-color)',
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset',
|
||||
boxShadow: 'var(--affine-button-inner-shadow)',
|
||||
},
|
||||
'&.warning:hover': {
|
||||
background:
|
||||
@@ -121,10 +121,10 @@ export const button = style({
|
||||
},
|
||||
|
||||
'&.success': {
|
||||
color: 'var(--affine-white)',
|
||||
color: 'var(--affine-pure-white)',
|
||||
background: 'var(--affine-success-color)',
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset',
|
||||
boxShadow: 'var(--affine-button-inner-shadow)',
|
||||
},
|
||||
'&.success:hover': {
|
||||
background:
|
||||
@@ -139,10 +139,10 @@ export const button = style({
|
||||
},
|
||||
|
||||
'&.processing': {
|
||||
color: 'var(--affine-white)',
|
||||
color: 'var(--affine-pure-white)',
|
||||
background: 'var(--affine-processing-color)',
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset',
|
||||
boxShadow: 'var(--affine-button-inner-shadow)',
|
||||
},
|
||||
'&.processing:hover': {
|
||||
background:
|
||||
|
||||
@@ -52,10 +52,10 @@ export const Confirm = ({
|
||||
{buttonDirection === 'row' ? (
|
||||
<StyledRowButtonWrapper>
|
||||
<Button
|
||||
shape="round"
|
||||
onClick={() => {
|
||||
onCancel?.();
|
||||
}}
|
||||
size="large"
|
||||
style={{ marginRight: '24px' }}
|
||||
data-testid={cancelButtonTestId}
|
||||
>
|
||||
@@ -63,10 +63,10 @@ export const Confirm = ({
|
||||
</Button>
|
||||
<Button
|
||||
type={confirmType}
|
||||
shape="round"
|
||||
onClick={() => {
|
||||
onConfirm?.();
|
||||
}}
|
||||
size="large"
|
||||
data-testid={confirmButtonTestId}
|
||||
>
|
||||
{confirmText}
|
||||
@@ -76,7 +76,6 @@ export const Confirm = ({
|
||||
<StyledColumnButtonWrapper>
|
||||
<Button
|
||||
type={confirmType}
|
||||
shape="round"
|
||||
onClick={() => {
|
||||
onConfirm?.();
|
||||
}}
|
||||
@@ -86,7 +85,6 @@ export const Confirm = ({
|
||||
{confirmText}
|
||||
</Button>
|
||||
<Button
|
||||
shape="round"
|
||||
onClick={() => {
|
||||
onCancel?.();
|
||||
}}
|
||||
|
||||
@@ -11,7 +11,7 @@ export const ModalWrapper = styled('div')<{
|
||||
width,
|
||||
height,
|
||||
minHeight,
|
||||
backgroundColor: 'var(--affine-background-secondary-color)',
|
||||
backgroundColor: 'var(--affine-background-overlay-panel-color)',
|
||||
boxShadow: 'var(--affine-shadow-3)',
|
||||
borderRadius: '12px',
|
||||
position: 'relative',
|
||||
|
||||
11
yarn.lock
11
yarn.lock
@@ -132,7 +132,7 @@ __metadata:
|
||||
"@radix-ui/react-toast": ^1.1.4
|
||||
"@toeverything/hooks": "workspace:*"
|
||||
"@toeverything/plugin-infra": "workspace:*"
|
||||
"@toeverything/theme": ^0.7.7
|
||||
"@toeverything/theme": ^0.7.9
|
||||
"@types/react": ^18.2.15
|
||||
"@types/react-datepicker": ^4.11.2
|
||||
"@types/react-dnd": ^3.0.2
|
||||
@@ -10977,13 +10977,20 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@toeverything/theme@npm:0.7.7, @toeverything/theme@npm:^0.7.7":
|
||||
"@toeverything/theme@npm:0.7.7":
|
||||
version: 0.7.7
|
||||
resolution: "@toeverything/theme@npm:0.7.7"
|
||||
checksum: 5a449eb440c49c712069203d85acc73613a000324807ce2e42c3b441b74b74e54ba76292144b60e3900d54bf41a13f98923174fee527c20303ad6c68e26e6176
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@toeverything/theme@npm:^0.7.9":
|
||||
version: 0.7.9
|
||||
resolution: "@toeverything/theme@npm:0.7.9"
|
||||
checksum: ac7eeea49f9099e34e8aacbd327ef5e48cc9fc02c32a20309da3dbcb4363c8dda3d2c887cf0e8eb8bb0fa2c50e73f123332f7009d2926961ef7ecbbb921a856d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@toeverything/y-indexeddb@workspace:*, @toeverything/y-indexeddb@workspace:packages/y-indexeddb":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@toeverything/y-indexeddb@workspace:packages/y-indexeddb"
|
||||
|
||||
Reference in New Issue
Block a user