Merge remote-tracking branch 'origin/develop' into feature/new-grid-drop

This commit is contained in:
SaikaSakura
2022-08-10 18:14:17 +08:00
13 changed files with 262 additions and 78 deletions
@@ -36,6 +36,9 @@ export class GridBlock extends BaseView {
}
return block.remove();
}
if (block.childrenIds.length === 0) {
return block.remove();
}
return true;
}
}
@@ -156,7 +156,13 @@ export const CardContainer = (props: CardContainerProps) => {
const { kanban } = useKanban();
const { containerIds, items: dataSource, activeId } = props;
return (
<KanbanContainer>
<KanbanContainer
onMouseDown={e => {
// Fix https://github.com/toeverything/AFFiNE/issues/29
// Prevent active selection when dragging kanban card
e.stopPropagation();
}}
>
{containerIds.map((containerId, idx) => {
const items = dataSource[containerId];
@@ -128,8 +128,12 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => {
if (clientHeight - rectTop <= COMMAND_MENU_HEIGHT) {
setCommandMenuPosition({
left: rect.left - left,
bottom: rectTop - top + 10,
top: 'initial',
top:
rectTop -
top -
COMMAND_MENU_HEIGHT +
20,
bottom: 'initial',
});
} else {
setCommandMenuPosition({
@@ -17,16 +17,20 @@ export const StatusIcon = ({ mode }: StatusIconProps) => {
const IconWrapper = styled('div')<Pick<StatusIconProps, 'mode'>>(
({ theme, mode }) => {
return {
width: '20px',
height: '20px',
width: '24px',
height: '24px',
borderRadius: '5px',
boxShadow: theme.affine.shadows.shadow1,
color: theme.affine.palette.primary,
cursor: 'pointer',
backgroundColor: theme.affine.palette.white,
transform: `translateX(${mode === DocMode.doc ? 0 : 20}px)`,
transform: `translateX(${mode === DocMode.doc ? 0 : 30}px)`,
transition: 'transform 300ms ease',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
'& > svg': {
fontSize: '20px',
},
@@ -2,26 +2,37 @@ import { styled } from '@toeverything/components/ui';
type StatusTextProps = {
children: string;
width?: string;
active?: boolean;
onClick?: () => void;
};
export const StatusText = ({ children, active, onClick }: StatusTextProps) => {
export const StatusText = ({
children,
width,
active,
onClick,
}: StatusTextProps) => {
return (
<StyledText active={active} onClick={onClick}>
<StyledText width={width} active={active} onClick={onClick}>
{children}
</StyledText>
);
};
const StyledText = styled('div')<StatusTextProps>(({ theme, active }) => {
return {
display: 'inline-flex',
alignItems: 'center',
color: theme.affine.palette.primary,
fontWeight: active ? '500' : '300',
fontSize: '15px',
cursor: 'pointer',
padding: '0 6px',
};
});
const StyledText = styled('div')<StatusTextProps>(
({ theme, width, active }) => {
return {
display: 'inline-flex',
alignItems: 'center',
color: active
? theme.affine.palette.primary
: 'rgba(62, 111, 219, 0.6)',
fontWeight: active ? '600' : '400',
fontSize: '16px',
lineHeight: '22px',
cursor: 'pointer',
...(!!width && { width }),
};
}
);
@@ -18,11 +18,15 @@ export const StatusTrack: FC<StatusTrackProps> = ({ mode, onClick }) => {
const Container = styled('div')(({ theme }) => {
return {
width: '64px',
height: '32px',
backgroundColor: theme.affine.palette.textHover,
borderRadius: '5px',
height: '30px',
width: '50px',
border: '1px solid #ECF1FB',
borderRadius: '8px',
cursor: 'pointer',
padding: '5px',
margin: '0 8px',
display: 'flex',
alignItems: 'center',
padding: '0 4px',
};
});
@@ -32,6 +32,7 @@ export const Switcher = () => {
return (
<StyledContainerForSwitcher>
<StatusText
width={'44px'}
active={pageViewMode === DocMode.doc}
onClick={() => switchToPageView(DocMode.doc)}
>
@@ -48,6 +49,7 @@ export const Switcher = () => {
}}
/>
<StatusText
width={'56px'}
active={pageViewMode === DocMode.board}
onClick={() => switchToPageView(DocMode.board)}
>
@@ -1,4 +1,4 @@
import { IconButton, styled } from '@toeverything/components/ui';
import { IconButton, styled, MuiButton } from '@toeverything/components/ui';
import {
LogoIcon,
SideBarViewIcon,
@@ -24,9 +24,13 @@ export const LayoutHeader = () => {
</FlexContainer>
<FlexContainer>
<StyledHelper>
<StyledShare>Share</StyledShare>
<StyledShare disabled={true}>Share</StyledShare>
<div style={{ margin: '0px 12px' }}>
<IconButton size="large">
<IconButton
size="large"
hoverColor={'transparent'}
disabled={true}
>
<SearchIcon />
</IconButton>
</div>
@@ -119,17 +123,19 @@ const StyledHelper = styled('div')({
alignItems: 'center',
});
const StyledShare = styled('div')({
const StyledShare = styled(MuiButton)<{ disabled?: boolean }>({
padding: '10px 12px',
fontWeight: 600,
fontSize: '14px',
color: '#3E6FDB',
cursor: 'pointer',
'&:hover': {
background: '#F5F7F8',
borderRadius: '5px',
},
color: '#98ACBD',
textTransform: 'none',
/* disabled for current time */
// color: '#3E6FDB',
// '&:hover': {
// background: '#F5F7F8',
// borderRadius: '5px',
// },
});
const StyledLogoIcon = styled(LogoIcon)(({ theme }) => {
@@ -141,9 +147,7 @@ const StyledLogoIcon = styled(LogoIcon)(({ theme }) => {
const StyledContainerForEditorBoardSwitcher = styled('div')(({ theme }) => {
return {
width: '100%',
position: 'absolute',
display: 'flex',
justifyContent: 'center',
left: '50%',
};
});
@@ -67,8 +67,12 @@ export function ChildrenListenerHandler(
const keys = Array.from(event.keys.entries()).map(
([key, { action }]) => [key, action] as [string, ChangedStateKeys]
);
const deleted = Array.from(event.changes.deleted.values())
.flatMap(val => val.content.getContent() as string[])
.filter(v => v)
.map(k => [k, 'delete'] as [string, ChangedStateKeys]);
for (const listener of listeners.values()) {
EmitEvents(keys, listener);
EmitEvents([...keys, ...deleted], listener);
}
}
}
+44 -39
View File
@@ -27,12 +27,13 @@ export class AbstractBlock<
C extends ContentOperation
> {
private readonly _id: string;
readonly #block: BlockInstance<C>;
private readonly _block: BlockInstance<C>;
private readonly _history: HistoryManager;
private readonly _root?: AbstractBlock<B, C>;
private readonly _parentListener: Map<string, BlockListener>;
_parent?: AbstractBlock<B, C>;
private _parent?: AbstractBlock<B, C>;
private _changeParent?: () => void;
constructor(
block: B,
@@ -40,20 +41,14 @@ export class AbstractBlock<
parent?: AbstractBlock<B, C>
) {
this._id = block.id;
this.#block = block;
this._history = this.#block.scopedHistory([this._id]);
this._block = block;
this._history = this._block.scopedHistory([this._id]);
this._root = root;
this._parentListener = new Map();
this._parent = parent;
JWT_DEV && logger_debug(`init: exists ${this._id}`);
if (parent) {
parent.addChildrenListener(this._id, states => {
if (states.get(this._id) === 'delete') {
this._emitParent(parent._id, 'delete');
}
});
}
if (parent) this._refreshParent(parent);
}
public get root() {
@@ -66,7 +61,7 @@ export class AbstractBlock<
protected _getParentPage(warning = true): string | undefined {
if (this.flavor === 'page') {
return this.#block.id;
return this._block.id;
} else if (!this._parent) {
if (warning && this.flavor !== 'workspace') {
console.warn('parent not found');
@@ -89,7 +84,7 @@ export class AbstractBlock<
if (event === 'parent') {
this._parentListener.set(name, callback);
} else {
this.#block.on(event, name, callback);
this._block.on(event, name, callback);
}
}
@@ -97,42 +92,40 @@ export class AbstractBlock<
if (event === 'parent') {
this._parentListener.delete(name);
} else {
this.#block.off(event, name);
this._block.off(event, name);
}
}
public addChildrenListener(name: string, listener: BlockListener) {
this.#block.addChildrenListener(name, listener);
this._block.addChildrenListener(name, listener);
}
public removeChildrenListener(name: string) {
this.#block.removeChildrenListener(name);
this._block.removeChildrenListener(name);
}
public addContentListener(name: string, listener: BlockListener) {
this.#block.addContentListener(name, listener);
this._block.addContentListener(name, listener);
}
public removeContentListener(name: string) {
this.#block.removeContentListener(name);
this._block.removeContentListener(name);
}
public getContent<
T extends ContentTypes = ContentOperation
>(): MapOperation<T> {
if (this.#block.type === BlockTypes.block) {
return this.#block.content.asMap() as MapOperation<T>;
if (this._block.type === BlockTypes.block) {
return this._block.content.asMap() as MapOperation<T>;
}
throw new Error(
`this block not a structured block: ${this._id}, ${
this.#block.type
}`
`this block not a structured block: ${this._id}, ${this._block.type}`
);
}
public getBinary(): ArrayBuffer | undefined {
if (this.#block.type === BlockTypes.binary) {
return this.#block.content.asArray<ArrayBuffer>()?.get(0);
if (this._block.type === BlockTypes.binary) {
return this._block.content.asArray<ArrayBuffer>()?.get(0);
}
throw new Error('this block not a binary block');
}
@@ -162,7 +155,7 @@ export class AbstractBlock<
// Last update UTC time
public get lastUpdated(): number {
return this.#block.updated || this.#block.created;
return this._block.updated || this._block.created;
}
private get last_updated_date(): string | undefined {
@@ -171,7 +164,7 @@ export class AbstractBlock<
// create UTC time
public get created(): number {
return this.#block.created;
return this._block.created;
}
private get created_date(): string | undefined {
@@ -180,11 +173,11 @@ export class AbstractBlock<
// creator id
public get creator(): string | undefined {
return this.#block.creator;
return this._block.creator;
}
[_GET_BLOCK]() {
return this.#block;
return this._block;
}
private _emitParent(
@@ -199,8 +192,20 @@ export class AbstractBlock<
}
}
[_SET_PARENT](parent: AbstractBlock<B, C>) {
private _refreshParent(parent: AbstractBlock<B, C>) {
this._changeParent?.();
parent.addChildrenListener(this._id, states => {
if (states.get(this._id) === 'delete') {
this._emitParent(parent._id, 'delete');
}
});
this._parent = parent;
this._changeParent = () => parent.removeChildrenListener(this._id);
}
[_SET_PARENT](parent: AbstractBlock<B, C>) {
this._refreshParent(parent);
this._emitParent(parent.id);
}
@@ -234,23 +239,23 @@ export class AbstractBlock<
* current block type
*/
public get type(): typeof BlockTypes[BlockTypeKeys] {
return this.#block.type;
return this._block.type;
}
/**
* current block flavor
*/
public get flavor(): typeof BlockFlavors[BlockFlavorKeys] {
return this.#block.flavor;
return this._block.flavor;
}
// TODO: flavor needs optimization
setFlavor(flavor: typeof BlockFlavors[BlockFlavorKeys]) {
this.#block.setFlavor(flavor);
this._block.setFlavor(flavor);
}
public get children(): string[] {
return this.#block.children;
return this._block.children;
}
/**
@@ -274,12 +279,12 @@ export class AbstractBlock<
throw new Error('insertChildren: binary not allow insert children');
}
this.#block.insertChildren(block[_GET_BLOCK](), position);
this._block.insertChildren(block[_GET_BLOCK](), position);
block[_SET_PARENT](this);
}
public hasChildren(id: string): boolean {
return this.#block.hasChildren(id);
return this._block.hasChildren(id);
}
/**
@@ -289,11 +294,11 @@ export class AbstractBlock<
*/
protected get_children(blockId?: string): BlockInstance<C>[] {
JWT_DEV && logger(`get children: ${blockId}`);
return this.#block.getChildren([blockId]);
return this._block.getChildren([blockId]);
}
public removeChildren(blockId?: string) {
this.#block.removeChildren([blockId]);
this._block.removeChildren([blockId]);
}
public remove() {