fix(core): new no children status for explorer (#7686)

close AF-1140
This commit is contained in:
CatsJuice
2024-08-01 09:41:12 +00:00
parent 8816d2a639
commit e60b2d64e5
17 changed files with 71 additions and 104 deletions

View File

@@ -0,0 +1,25 @@
import { cssVar } from '@toeverything/theme';
import { cssVarV2 } from '@toeverything/theme/v2';
import { fallbackVar, style } from '@vanilla-extract/css';
import { levelIndent } from '../tree/node.css';
export const emptyChildren = style({
fontSize: cssVar('fontSm'),
color: cssVarV2('text/disable'),
textAlign: 'left',
userSelect: 'none',
lineHeight: '22px',
padding: '4px 0px',
marginTop: 2,
// 48 = node.paddingLeft + node.collapsable.width + node.icon.width + node.icon.marginRight
// = 4 + 16 + 20 + 8
// to align with node's content
paddingLeft: `calc(${fallbackVar(levelIndent, '20px')} + 48px)`,
selectors: {
'&[data-dragged-over="true"]': {
background: cssVarV2('layer/background/hoverOverlay'),
borderRadius: '4px',
},
},
});

View File

@@ -0,0 +1,15 @@
import clsx from 'clsx';
import { forwardRef, type HTMLAttributes, type Ref } from 'react';
import { emptyChildren } from './empty-node-children.css';
export const EmptyNodeChildren = forwardRef(function EmptyNodeChildren(
{ children, className, ...attrs }: HTMLAttributes<HTMLDivElement>,
ref: Ref<HTMLDivElement>
) {
return (
<div className={clsx(emptyChildren, className)} ref={ref} {...attrs}>
{children}
</div>
);
});

View File

@@ -7,9 +7,9 @@ import {
type SVGProps,
} from 'react';
import * as styles from './empty-layout.css';
import * as styles from './empty-section.css';
interface ExplorerGroupEmptyProps extends HTMLAttributes<HTMLDivElement> {
interface ExplorerEmptySectionProps extends HTMLAttributes<HTMLDivElement> {
icon: (props: SVGProps<SVGSVGElement>) => JSX.Element;
message: string;
messageTestId?: string;
@@ -17,7 +17,7 @@ interface ExplorerGroupEmptyProps extends HTMLAttributes<HTMLDivElement> {
onActionClick?: () => void;
}
export const ExplorerGroupEmpty = forwardRef(function ExplorerGroupEmpty(
export const ExplorerEmptySection = forwardRef(function ExplorerEmptySection(
{
icon: Icon,
message,
@@ -27,7 +27,7 @@ export const ExplorerGroupEmpty = forwardRef(function ExplorerGroupEmpty(
className,
onActionClick,
...attrs
}: ExplorerGroupEmptyProps,
}: ExplorerEmptySectionProps,
ref: Ref<HTMLDivElement>
) {
return (

View File

@@ -1,19 +0,0 @@
import { cssVar } from '@toeverything/theme';
import { fallbackVar, style } from '@vanilla-extract/css';
import { levelIndent } from '../../tree/node.css';
export const noReferences = style({
fontSize: cssVar('fontSm'),
textAlign: 'left',
padding: '4px 0 4px 32px',
color: cssVar('black30'),
userSelect: 'none',
paddingLeft: `calc(${fallbackVar(levelIndent, '20px')} + 32px)`,
selectors: {
'&[data-dragged-over="true"]': {
background: cssVar('--affine-hover-color'),
borderRadius: '4px',
},
},
});

View File

@@ -2,7 +2,7 @@ import { type DropTargetDropEvent, useDropTarget } from '@affine/component';
import type { AffineDNDData } from '@affine/core/types/dnd';
import { useI18n } from '@affine/i18n';
import * as styles from './empty.css';
import { EmptyNodeChildren } from '../../layouts/empty-node-children';
export const Empty = ({
onDrop,
@@ -17,8 +17,8 @@ export const Empty = ({
);
const t = useI18n();
return (
<div className={styles.noReferences} ref={dropTargetRef}>
<EmptyNodeChildren ref={dropTargetRef}>
{t['com.affine.collection.emptyCollection']()}
</div>
</EmptyNodeChildren>
);
};

View File

@@ -1,19 +0,0 @@
import { cssVar } from '@toeverything/theme';
import { fallbackVar, style } from '@vanilla-extract/css';
import { levelIndent } from '../../tree/node.css';
export const noReferences = style({
fontSize: cssVar('fontSm'),
textAlign: 'left',
padding: '4px 0 4px 32px',
color: cssVar('black30'),
userSelect: 'none',
paddingLeft: `calc(${fallbackVar(levelIndent, '20px')} + 32px)`,
selectors: {
'&[data-dragged-over="true"]': {
background: cssVar('--affine-hover-color'),
borderRadius: '4px',
},
},
});

View File

@@ -2,7 +2,7 @@ import { type DropTargetDropEvent, useDropTarget } from '@affine/component';
import type { AffineDNDData } from '@affine/core/types/dnd';
import { useI18n } from '@affine/i18n';
import * as styles from './empty.css';
import { EmptyNodeChildren } from '../../layouts/empty-node-children';
export const Empty = ({
onDrop,
@@ -16,9 +16,10 @@ export const Empty = ({
[onDrop]
);
const t = useI18n();
return (
<div className={styles.noReferences} ref={dropTargetRef}>
<EmptyNodeChildren ref={dropTargetRef}>
{t['com.affine.rootAppSidebar.docs.no-subdoc']()}
</div>
</EmptyNodeChildren>
);
};

View File

@@ -5,22 +5,16 @@ import {
} from '@affine/component';
import type { AffineDNDData } from '@affine/core/types/dnd';
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';
import { EmptyNodeChildren } from '../../layouts/empty-node-children';
import { draggedOverHighlight } from './empty.css';
export const FolderEmpty = ({
onClickCreate,
className,
canDrop,
onDrop,
}: {
onClickCreate?: () => void;
onDrop?: (data: DropTargetDropEvent<AffineDNDData>) => void;
canDrop?: DropTargetOptions<AffineDNDData>['canDrop'];
className?: string;
}) => {
const { dropTargetRef } = useDropTarget(
() => ({
@@ -32,16 +26,8 @@ export const FolderEmpty = ({
const t = useI18n();
return (
<ExplorerGroupEmpty
className={clsx(styles.draggedOverHighlight, className)}
ref={dropTargetRef}
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}
/>
<EmptyNodeChildren ref={dropTargetRef} className={draggedOverHighlight}>
{t['com.affine.rootAppSidebar.organize.empty-folder']()}
</EmptyNodeChildren>
);
};

View File

@@ -814,11 +814,7 @@ export const ExplorerFolderNodeFolder = ({
operations={finalOperations}
canDrop={handleCanDrop}
childrenPlaceholder={
<FolderEmpty
canDrop={handleCanDrop}
onDrop={handleDropOnPlaceholder}
onClickCreate={() => handleAddToFolder('doc')}
/>
<FolderEmpty canDrop={handleCanDrop} onDrop={handleDropOnPlaceholder} />
}
dropEffect={handleDropEffect}
data-testid={`explorer-folder-${node.id}`}

View File

@@ -1,19 +0,0 @@
import { cssVar } from '@toeverything/theme';
import { fallbackVar, style } from '@vanilla-extract/css';
import { levelIndent } from '../../tree/node.css';
export const noReferences = style({
fontSize: cssVar('fontSm'),
textAlign: 'left',
padding: '4px 0 4px 32px',
color: cssVar('black30'),
userSelect: 'none',
paddingLeft: `calc(${fallbackVar(levelIndent, '20px')} + 32px)`,
selectors: {
'&[data-dragged-over="true"]': {
background: cssVar('--affine-hover-color'),
borderRadius: '4px',
},
},
});

View File

@@ -2,7 +2,7 @@ import { type DropTargetDropEvent, useDropTarget } from '@affine/component';
import type { AffineDNDData } from '@affine/core/types/dnd';
import { useI18n } from '@affine/i18n';
import * as styles from './empty.css';
import { EmptyNodeChildren } from '../../layouts/empty-node-children';
export const Empty = ({
onDrop,
@@ -17,8 +17,8 @@ export const Empty = ({
);
const t = useI18n();
return (
<div className={styles.noReferences} ref={dropTargetRef}>
<EmptyNodeChildren ref={dropTargetRef}>
{t['com.affine.rootAppSidebar.tags.no-doc']()}
</div>
</EmptyNodeChildren>
);
};

View File

@@ -1,7 +1,7 @@
import { useI18n } from '@affine/i18n';
import { ViewLayersIcon } from '@blocksuite/icons/rc';
import { ExplorerGroupEmpty } from '../../layouts/empty-layout';
import { ExplorerEmptySection } from '../../layouts/empty-section';
export const RootEmpty = ({
onClickCreate,
@@ -11,7 +11,7 @@ export const RootEmpty = ({
const t = useI18n();
return (
<ExplorerGroupEmpty
<ExplorerEmptySection
icon={ViewLayersIcon}
message={t['com.affine.collections.empty.message']()}
messageTestId="slider-bar-collection-empty-message"

View File

@@ -7,7 +7,7 @@ import type { AffineDNDData } from '@affine/core/types/dnd';
import { useI18n } from '@affine/i18n';
import { FavoriteIcon } from '@blocksuite/icons/rc';
import { ExplorerGroupEmpty } from '../../layouts/empty-layout';
import { ExplorerEmptySection } from '../../layouts/empty-section';
import { DropEffect, type ExplorerTreeNodeDropEffect } from '../../tree';
export const RootEmpty = ({
@@ -34,7 +34,7 @@ export const RootEmpty = ({
);
return (
<ExplorerGroupEmpty
<ExplorerEmptySection
ref={dropTargetRef}
icon={FavoriteIcon}
message={t['com.affine.rootAppSidebar.favorites.empty']()}
@@ -52,6 +52,6 @@ export const RootEmpty = ({
})}
/>
)}
</ExplorerGroupEmpty>
</ExplorerEmptySection>
);
};

View File

@@ -1,7 +1,7 @@
import { useI18n } from '@affine/i18n';
import { FolderIcon } from '@blocksuite/icons/rc';
import { ExplorerGroupEmpty } from '../../layouts/empty-layout';
import { ExplorerEmptySection } from '../../layouts/empty-section';
export const RootEmpty = ({
onClickCreate,
@@ -11,7 +11,7 @@ export const RootEmpty = ({
const t = useI18n();
return (
<ExplorerGroupEmpty
<ExplorerEmptySection
icon={FolderIcon}
message={t['com.affine.rootAppSidebar.organize.empty']()}
messageTestId="slider-bar-organize-empty-message"

View File

@@ -1,13 +1,13 @@
import { useI18n } from '@affine/i18n';
import { TagIcon } from '@blocksuite/icons/rc';
import { ExplorerGroupEmpty } from '../../layouts/empty-layout';
import { ExplorerEmptySection } from '../../layouts/empty-section';
export const RootEmpty = () => {
const t = useI18n();
return (
<ExplorerGroupEmpty
<ExplorerEmptySection
icon={TagIcon}
message={t['com.affine.rootAppSidebar.tags.empty']()}
messageTestId="slider-bar-tags-empty-message"