mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
fix(core): adjust sidebar explorer empty status (#7657)
Close AF-1126,AF-1132
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { globalStyle, style } from '@vanilla-extract/css';
|
||||
export const dropdownBtn = style({
|
||||
display: 'inline-flex',
|
||||
@@ -124,8 +125,8 @@ export const button = style({
|
||||
// changeable
|
||||
height: '28px',
|
||||
background: cssVar('white'),
|
||||
borderColor: cssVar('borderColor'),
|
||||
color: cssVar('textPrimaryColor'),
|
||||
borderColor: cssVarV2('layer/border'),
|
||||
color: cssVarV2('text/primary'),
|
||||
selectors: {
|
||||
'&.text-bold': {
|
||||
fontWeight: 600,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const content = style({
|
||||
@@ -6,8 +7,8 @@ export const content = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
padding: '9px 20px 25px 21px',
|
||||
gap: 4,
|
||||
padding: '12px 0px',
|
||||
});
|
||||
export const iconWrapper = style({
|
||||
width: 36,
|
||||
@@ -16,21 +17,24 @@ export const iconWrapper = style({
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: cssVar('hoverColor'),
|
||||
backgroundColor: cssVarV2('button/emptyIconBackground'),
|
||||
});
|
||||
export const icon = style({
|
||||
fontSize: 20,
|
||||
color: cssVar('iconSecondary'),
|
||||
color: cssVarV2('icon/secondary'),
|
||||
});
|
||||
export const message = style({
|
||||
fontSize: cssVar('fontSm'),
|
||||
textAlign: 'center',
|
||||
color: cssVar('black30'),
|
||||
color: cssVarV2('text/tertiary'),
|
||||
userSelect: 'none',
|
||||
fontWeight: 400,
|
||||
lineHeight: '22px',
|
||||
});
|
||||
|
||||
export const newButton = style({
|
||||
padding: '0 8px',
|
||||
height: '28px',
|
||||
fontSize: cssVar('fontXs'),
|
||||
marginTop: 8,
|
||||
padding: '4px 8px',
|
||||
height: '30px',
|
||||
fontSize: cssVar('fontSm'),
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Button } from '@affine/component';
|
||||
import clsx from 'clsx';
|
||||
import {
|
||||
forwardRef,
|
||||
type HTMLAttributes,
|
||||
type Ref,
|
||||
type SVGProps,
|
||||
} from 'react';
|
||||
|
||||
import * as styles from './empty-layout.css';
|
||||
|
||||
interface ExplorerGroupEmptyProps extends HTMLAttributes<HTMLDivElement> {
|
||||
icon: (props: SVGProps<SVGSVGElement>) => JSX.Element;
|
||||
message: string;
|
||||
messageTestId?: string;
|
||||
actionText?: string;
|
||||
onActionClick?: () => void;
|
||||
}
|
||||
|
||||
export const ExplorerGroupEmpty = forwardRef(function ExplorerGroupEmpty(
|
||||
{
|
||||
icon: Icon,
|
||||
message,
|
||||
messageTestId,
|
||||
actionText,
|
||||
children,
|
||||
className,
|
||||
onActionClick,
|
||||
...attrs
|
||||
}: ExplorerGroupEmptyProps,
|
||||
ref: Ref<HTMLDivElement>
|
||||
) {
|
||||
return (
|
||||
<div className={clsx(styles.content, className)} ref={ref} {...attrs}>
|
||||
<div className={styles.iconWrapper}>
|
||||
<Icon className={styles.icon} />
|
||||
</div>
|
||||
<div data-testid={messageTestId} className={styles.message}>
|
||||
{message}
|
||||
</div>
|
||||
{actionText ? (
|
||||
<Button className={styles.newButton} onClick={onActionClick}>
|
||||
{actionText}
|
||||
</Button>
|
||||
) : null}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@@ -1,39 +1,6 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const content = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
padding: '9px 20px 25px 21px',
|
||||
});
|
||||
export const iconWrapper = style({
|
||||
width: 36,
|
||||
height: 36,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: cssVar('hoverColor'),
|
||||
});
|
||||
export const icon = style({
|
||||
fontSize: 20,
|
||||
color: cssVar('iconSecondary'),
|
||||
});
|
||||
export const message = style({
|
||||
fontSize: cssVar('fontSm'),
|
||||
textAlign: 'center',
|
||||
color: cssVar('black30'),
|
||||
userSelect: 'none',
|
||||
});
|
||||
|
||||
export const newButton = style({
|
||||
padding: '0 8px',
|
||||
height: '28px',
|
||||
fontSize: cssVar('fontXs'),
|
||||
});
|
||||
|
||||
export const draggedOverHighlight = style({
|
||||
selectors: {
|
||||
'&[data-dragged-over="true"]': {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
Button,
|
||||
type DropTargetDropEvent,
|
||||
type DropTargetOptions,
|
||||
useDropTarget,
|
||||
@@ -9,6 +8,7 @@ import { useI18n } from '@affine/i18n';
|
||||
import { FolderIcon } from '@blocksuite/icons/rc';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import { ExplorerGroupEmpty } from '../../layouts/empty-layout';
|
||||
import * as styles from './empty.css';
|
||||
|
||||
export const FolderEmpty = ({
|
||||
@@ -32,22 +32,16 @@ export const FolderEmpty = ({
|
||||
|
||||
const t = useI18n();
|
||||
return (
|
||||
<div
|
||||
className={clsx(styles.content, styles.draggedOverHighlight, className)}
|
||||
<ExplorerGroupEmpty
|
||||
className={clsx(styles.draggedOverHighlight, className)}
|
||||
ref={dropTargetRef}
|
||||
>
|
||||
<div className={styles.iconWrapper}>
|
||||
<FolderIcon className={styles.icon} />
|
||||
</div>
|
||||
<div
|
||||
data-testid="slider-bar-organize-empty-message"
|
||||
className={styles.message}
|
||||
>
|
||||
{t['com.affine.rootAppSidebar.organize.empty-folder']()}
|
||||
</div>
|
||||
<Button className={styles.newButton} onClick={onClickCreate}>
|
||||
{t['com.affine.rootAppSidebar.organize.empty-folder.add-pages']()}
|
||||
</Button>
|
||||
</div>
|
||||
icon={FolderIcon}
|
||||
message={t['com.affine.rootAppSidebar.organize.empty-folder']()}
|
||||
messageTestId="slider-bar-organize-empty-message"
|
||||
actionText={t[
|
||||
'com.affine.rootAppSidebar.organize.empty-folder.add-pages'
|
||||
]()}
|
||||
onActionClick={onClickCreate}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -814,7 +814,11 @@ export const ExplorerFolderNodeFolder = ({
|
||||
operations={finalOperations}
|
||||
canDrop={handleCanDrop}
|
||||
childrenPlaceholder={
|
||||
<FolderEmpty canDrop={handleCanDrop} onDrop={handleDropOnPlaceholder} />
|
||||
<FolderEmpty
|
||||
canDrop={handleCanDrop}
|
||||
onDrop={handleDropOnPlaceholder}
|
||||
onClickCreate={() => handleAddToFolder('doc')}
|
||||
/>
|
||||
}
|
||||
dropEffect={handleDropEffect}
|
||||
data-testid={`explorer-folder-${node.id}`}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const content = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
padding: '9px 20px 25px 21px',
|
||||
});
|
||||
export const iconWrapper = style({
|
||||
width: 36,
|
||||
height: 36,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: cssVar('hoverColor'),
|
||||
});
|
||||
export const icon = style({
|
||||
fontSize: 20,
|
||||
color: cssVar('iconSecondary'),
|
||||
});
|
||||
export const message = style({
|
||||
fontSize: cssVar('fontSm'),
|
||||
textAlign: 'center',
|
||||
color: cssVar('black30'),
|
||||
userSelect: 'none',
|
||||
});
|
||||
|
||||
export const newButton = style({
|
||||
padding: '0 8px',
|
||||
height: '28px',
|
||||
fontSize: cssVar('fontXs'),
|
||||
});
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Button } from '@affine/component';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { ViewLayersIcon } from '@blocksuite/icons/rc';
|
||||
|
||||
import * as styles from './empty.css';
|
||||
import { ExplorerGroupEmpty } from '../../layouts/empty-layout';
|
||||
|
||||
export const RootEmpty = ({
|
||||
onClickCreate,
|
||||
@@ -12,19 +11,12 @@ export const RootEmpty = ({
|
||||
const t = useI18n();
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
<div className={styles.iconWrapper}>
|
||||
<ViewLayersIcon className={styles.icon} />
|
||||
</div>
|
||||
<div
|
||||
data-testid="slider-bar-collection-empty-message"
|
||||
className={styles.message}
|
||||
>
|
||||
{t['com.affine.collections.empty.message']()}
|
||||
</div>
|
||||
<Button className={styles.newButton} onClick={onClickCreate}>
|
||||
{t['com.affine.collections.empty.new-collection-button']()}
|
||||
</Button>
|
||||
</div>
|
||||
<ExplorerGroupEmpty
|
||||
icon={ViewLayersIcon}
|
||||
message={t['com.affine.collections.empty.message']()}
|
||||
messageTestId="slider-bar-collection-empty-message"
|
||||
actionText={t['com.affine.collections.empty.new-collection-button']()}
|
||||
onActionClick={onClickCreate}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,10 +5,10 @@ import {
|
||||
} from '@affine/component';
|
||||
import type { AffineDNDData } from '@affine/core/types/dnd';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { FolderIcon } from '@blocksuite/icons/rc';
|
||||
import { FavoriteIcon } from '@blocksuite/icons/rc';
|
||||
|
||||
import { ExplorerGroupEmpty } from '../../layouts/empty-layout';
|
||||
import { DropEffect, type ExplorerTreeNodeDropEffect } from '../../tree';
|
||||
import * as styles from './empty.css';
|
||||
|
||||
export const RootEmpty = ({
|
||||
onDrop,
|
||||
@@ -34,16 +34,12 @@ export const RootEmpty = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.content} ref={dropTargetRef}>
|
||||
<div className={styles.iconWrapper}>
|
||||
<FolderIcon className={styles.icon} />
|
||||
</div>
|
||||
<div
|
||||
data-testid="slider-bar-favorites-empty-message"
|
||||
className={styles.message}
|
||||
>
|
||||
{t['com.affine.rootAppSidebar.favorites.empty']()}
|
||||
</div>
|
||||
<ExplorerGroupEmpty
|
||||
ref={dropTargetRef}
|
||||
icon={FavoriteIcon}
|
||||
message={t['com.affine.rootAppSidebar.favorites.empty']()}
|
||||
messageTestId="slider-bar-favorites-empty-message"
|
||||
>
|
||||
{dropEffect && draggedOverDraggable && (
|
||||
<DropEffect
|
||||
position={{
|
||||
@@ -56,6 +52,6 @@ export const RootEmpty = ({
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</ExplorerGroupEmpty>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const content = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
padding: '9px 20px 25px 21px',
|
||||
position: 'relative',
|
||||
});
|
||||
export const iconWrapper = style({
|
||||
width: 36,
|
||||
height: 36,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: cssVar('hoverColor'),
|
||||
});
|
||||
export const icon = style({
|
||||
fontSize: 20,
|
||||
color: cssVar('iconSecondary'),
|
||||
});
|
||||
export const message = style({
|
||||
fontSize: cssVar('fontSm'),
|
||||
textAlign: 'center',
|
||||
color: cssVar('black30'),
|
||||
userSelect: 'none',
|
||||
});
|
||||
|
||||
export const newButton = style({
|
||||
padding: '0 8px',
|
||||
height: '28px',
|
||||
fontSize: cssVar('fontXs'),
|
||||
});
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Button } from '@affine/component';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { FolderIcon } from '@blocksuite/icons/rc';
|
||||
|
||||
import * as styles from './empty.css';
|
||||
import { ExplorerGroupEmpty } from '../../layouts/empty-layout';
|
||||
|
||||
export const RootEmpty = ({
|
||||
onClickCreate,
|
||||
@@ -12,19 +11,14 @@ export const RootEmpty = ({
|
||||
const t = useI18n();
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
<div className={styles.iconWrapper}>
|
||||
<FolderIcon className={styles.icon} />
|
||||
</div>
|
||||
<div
|
||||
data-testid="slider-bar-organize-empty-message"
|
||||
className={styles.message}
|
||||
>
|
||||
{t['com.affine.rootAppSidebar.organize.empty']()}
|
||||
</div>
|
||||
<Button className={styles.newButton} onClick={onClickCreate}>
|
||||
{t['com.affine.rootAppSidebar.organize.empty.new-folders-button']()}
|
||||
</Button>
|
||||
</div>
|
||||
<ExplorerGroupEmpty
|
||||
icon={FolderIcon}
|
||||
message={t['com.affine.rootAppSidebar.organize.empty']()}
|
||||
messageTestId="slider-bar-organize-empty-message"
|
||||
actionText={t[
|
||||
'com.affine.rootAppSidebar.organize.empty.new-folders-button'
|
||||
]()}
|
||||
onActionClick={onClickCreate}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const content = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
padding: '9px 20px 25px 21px',
|
||||
position: 'relative',
|
||||
});
|
||||
export const iconWrapper = style({
|
||||
width: 36,
|
||||
height: 36,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: cssVar('hoverColor'),
|
||||
});
|
||||
export const icon = style({
|
||||
fontSize: 20,
|
||||
color: cssVar('iconSecondary'),
|
||||
});
|
||||
export const message = style({
|
||||
fontSize: cssVar('fontSm'),
|
||||
textAlign: 'center',
|
||||
color: cssVar('black30'),
|
||||
userSelect: 'none',
|
||||
});
|
||||
|
||||
export const newButton = style({
|
||||
padding: '0 8px',
|
||||
height: '28px',
|
||||
fontSize: cssVar('fontXs'),
|
||||
});
|
||||
@@ -1,30 +1,16 @@
|
||||
import { Button } from '@affine/component';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { TagIcon } from '@blocksuite/icons/rc';
|
||||
|
||||
import * as styles from './empty.css';
|
||||
import { ExplorerGroupEmpty } from '../../layouts/empty-layout';
|
||||
|
||||
export const RootEmpty = ({
|
||||
onClickCreate,
|
||||
}: {
|
||||
onClickCreate?: () => void;
|
||||
}) => {
|
||||
export const RootEmpty = () => {
|
||||
const t = useI18n();
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
<div className={styles.iconWrapper}>
|
||||
<TagIcon className={styles.icon} />
|
||||
</div>
|
||||
<div
|
||||
data-testid="slider-bar-tags-empty-message"
|
||||
className={styles.message}
|
||||
>
|
||||
{t['com.affine.rootAppSidebar.tags.empty']()}
|
||||
</div>
|
||||
<Button className={styles.newButton} onClick={onClickCreate}>
|
||||
{t['com.affine.rootAppSidebar.tags.empty.new-tag-button']()}
|
||||
</Button>
|
||||
</div>
|
||||
<ExplorerGroupEmpty
|
||||
icon={TagIcon}
|
||||
message={t['com.affine.rootAppSidebar.tags.empty']()}
|
||||
messageTestId="slider-bar-tags-empty-message"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -69,9 +69,7 @@ export const ExplorerTags = ({
|
||||
</IconButton>
|
||||
</CategoryDivider>
|
||||
<Collapsible.Content>
|
||||
<ExplorerTreeRoot
|
||||
placeholder={<RootEmpty onClickCreate={handleCreateNewFavoriteDoc} />}
|
||||
>
|
||||
<ExplorerTreeRoot placeholder={<RootEmpty />}>
|
||||
{tags.map(tag => (
|
||||
<ExplorerTagNode
|
||||
key={tag.id}
|
||||
|
||||
@@ -1149,7 +1149,7 @@
|
||||
"com.affine.rootAppSidebar.explorer.drop-effect.move": "Move",
|
||||
"com.affine.rootAppSidebar.explorer.drop-effect.copy": "Copy",
|
||||
"com.affine.rootAppSidebar.docs.no-subdoc": "No linked docs",
|
||||
"com.affine.rootAppSidebar.favorites.empty": "You can add documents to your favourites",
|
||||
"com.affine.rootAppSidebar.favorites.empty": "No Favorites",
|
||||
"com.affine.rootAppSidebar.others": "Others",
|
||||
"com.affine.rootAppSidebar.docs.references-loading": "Loading linked docs...",
|
||||
"com.affine.search-tags.placeholder": "Type here ...",
|
||||
|
||||
Reference in New Issue
Block a user