diff --git a/frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts b/frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts
index afb82f32b0c0..6f3f2b705684 100644
--- a/frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts
+++ b/frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts
@@ -2,8 +2,6 @@ import { YjsEditor } from '@/application/slate-yjs/plugins/withYjs';
import { EditorMarkFormat } from '@/application/slate-yjs/types';
import {
beforePasted,
- findIndentPath,
- findLiftPath,
findSlateEntryByBlockId,
} from '@/application/slate-yjs/utils/slateUtils';
@@ -166,12 +164,12 @@ export const CustomEditor = {
const block = getBlock(node.blockId as string, sharedRoot);
const blockType = block.get(YjsEditorKey.block_type) as BlockType;
- if (blockType !== BlockType.Paragraph) {
- handleNonParagraphBlockBackspaceAndEnterWithTxn(editor, sharedRoot, block, point);
+ if (path.length > 1 && handleLiftBlockOnBackspaceAndEnterWithTxn(editor, sharedRoot, block, point)) {
return;
}
- if (path.length > 1 && handleLiftBlockOnBackspaceAndEnterWithTxn(editor, sharedRoot, block, point)) {
+ if (blockType !== BlockType.Paragraph) {
+ handleNonParagraphBlockBackspaceAndEnterWithTxn(editor, sharedRoot, block, point);
return;
}
@@ -232,6 +230,7 @@ export const CustomEditor = {
const endBlockPath = endNode[1];
const startAtPath = point.path.slice(startBlockPath.length);
const startAtOffset = point.offset;
+
const endAtPath = endPoint.path.slice(endBlockPath.length);
const endAtOffset = endPoint.offset;
let newStartBlockPath: Path = [];
@@ -239,6 +238,7 @@ export const CustomEditor = {
const isSameBlock = node[0].blockId === endNode[0].blockId;
+ editor.deselect();
if (isSameBlock) {
const block = getBlock(node[0].blockId as string, sharedRoot);
let newBlockId: string | undefined;
@@ -272,9 +272,10 @@ export const CustomEditor = {
});
if (newBlockIds.length === 0) return;
const newStartBlockEntry = findSlateEntryByBlockId(editor, newBlockIds[0]);
+ const newEndBlockEntry = findSlateEntryByBlockId(editor, newBlockIds[newBlockIds.length - 1]);
newStartBlockPath = newStartBlockEntry[1];
- newEndBlockPath = type === 'tabForward' ? findIndentPath(startBlockPath, endBlockPath, newStartBlockPath) : findLiftPath(startBlockPath, endBlockPath, newStartBlockPath);
+ newEndBlockPath = newEndBlockEntry[1];
}
const newStartPath = [...newStartBlockPath, ...startAtPath];
diff --git a/frontend/appflowy_web_app/src/application/slate-yjs/utils/slateUtils.tsx b/frontend/appflowy_web_app/src/application/slate-yjs/utils/slateUtils.tsx
index db491ad56440..5bbd992b6357 100644
--- a/frontend/appflowy_web_app/src/application/slate-yjs/utils/slateUtils.tsx
+++ b/frontend/appflowy_web_app/src/application/slate-yjs/utils/slateUtils.tsx
@@ -1,31 +1,6 @@
import { Editor, Element, NodeEntry, Path, Range, Transforms, Node, Point, BasePoint } from 'slate';
import { ReactEditor } from 'slate-react';
-export function findIndentPath (originalStart: Path, originalEnd: Path, newStart: Path): Path {
- // Find the common ancestor path
- const commonPath = Path.common(originalStart, originalEnd);
-
- // Calculate end's path relative to common ancestor
- const endRelativePath = originalEnd.slice(commonPath.length);
-
- // Calculate new common ancestor path by maintaining the same level difference
- const startToCommonLevels = originalStart.length - commonPath.length;
- const newCommonAncestor = newStart.slice(0, newStart.length - startToCommonLevels);
-
- // Append the relative path to new common ancestor
- return [...newCommonAncestor, ...endRelativePath];
-}
-
-export function findLiftPath (originalStart: Path, originalEnd: Path, newStart: Path): Path {
- // Same logic as findIndentPath
- const commonPath = Path.common(originalStart, originalEnd);
- const endRelativePath = originalEnd.slice(commonPath.length);
- const startToCommonLevels = originalStart.length - commonPath.length;
- const newCommonAncestor = newStart.slice(0, newStart.length - startToCommonLevels);
-
- return [...newCommonAncestor, ...endRelativePath];
-}
-
export function findSlateEntryByBlockId (editor: Editor, blockId: string) {
const [node] = Editor.nodes(editor, {
match: (n) => !Editor.isEditor(n) && Element.isElement(n) && n.blockId === blockId,
diff --git a/frontend/appflowy_web_app/src/application/slate-yjs/utils/yjsOperations.ts b/frontend/appflowy_web_app/src/application/slate-yjs/utils/yjsOperations.ts
index 790fce46f377..b8037945f36f 100644
--- a/frontend/appflowy_web_app/src/application/slate-yjs/utils/yjsOperations.ts
+++ b/frontend/appflowy_web_app/src/application/slate-yjs/utils/yjsOperations.ts
@@ -276,14 +276,15 @@ export function handleCollapsedBreakWithTxn (editor: YjsEditor, sharedRoot: YSha
if (yText.length === 0) {
const point = Editor.start(editor, at);
- if (blockType !== BlockType.Paragraph) {
- handleNonParagraphBlockBackspaceAndEnterWithTxn(editor, sharedRoot, block, point);
+ if (path.length > 1 && handleLiftBlockOnBackspaceAndEnterWithTxn(editor, sharedRoot, block, point)) {
return;
}
- if (path.length > 1 && handleLiftBlockOnBackspaceAndEnterWithTxn(editor, sharedRoot, block, point)) {
+ if (blockType !== BlockType.Paragraph) {
+ handleNonParagraphBlockBackspaceAndEnterWithTxn(editor, sharedRoot, block, point);
return;
}
+
}
const { operations, select } = getSplitBlockOperations(sharedRoot, block, startOffset);
diff --git a/frontend/appflowy_web_app/src/components/_shared/image-upload/Unsplash.tsx b/frontend/appflowy_web_app/src/components/_shared/image-upload/Unsplash.tsx
index 3db40cc6df42..e0c47c84e840 100644
--- a/frontend/appflowy_web_app/src/components/_shared/image-upload/Unsplash.tsx
+++ b/frontend/appflowy_web_app/src/components/_shared/image-upload/Unsplash.tsx
@@ -89,7 +89,7 @@ export function Unsplash ({ onDone, onEscape }: { onDone?: (value: string) => vo
boolean): View[] {
+ const filter = (views: View[]): View[] => {
+ let result: View[] = [];
+
+ for (const view of views) {
+ if (condition(view)) {
+ result.push(view);
+ }
+
+ if (view.children) {
+ const filteredChildren = filter(view.children);
+
+ result = result.concat(filteredChildren);
+ }
+ }
+
+ return result;
+ };
+
+ return filter(views);
+}
+
export function filterOutByCondition (views: View[], condition: (view: View) => {
remove: boolean;
}): View[] {
diff --git a/frontend/appflowy_web_app/src/components/app/ViewModal.tsx b/frontend/appflowy_web_app/src/components/app/ViewModal.tsx
index fe56ea6fd2a7..7346a7b7f392 100644
--- a/frontend/appflowy_web_app/src/components/app/ViewModal.tsx
+++ b/frontend/appflowy_web_app/src/components/app/ViewModal.tsx
@@ -133,7 +133,12 @@ function ViewModal ({
-
+
{
+ onClose();
+ }}
+ viewId={viewId}
+ />
void;
}) {
const [anchorEl, setAnchorEl] = React.useState(null);
@@ -56,6 +58,7 @@ function MoreActions ({
itemClicked={() => {
handleClose();
}}
+ onDeleted={onDeleted}
viewId={viewId}
movePopoverOrigins={{
transformOrigin: {
diff --git a/frontend/appflowy_web_app/src/components/app/header/MoreActionsContent.tsx b/frontend/appflowy_web_app/src/components/app/header/MoreActionsContent.tsx
index 549a9b5cfeee..926f7acfd54f 100644
--- a/frontend/appflowy_web_app/src/components/app/header/MoreActionsContent.tsx
+++ b/frontend/appflowy_web_app/src/components/app/header/MoreActionsContent.tsx
@@ -8,8 +8,9 @@ import { ReactComponent as DeleteIcon } from '@/assets/trash.svg';
import { ReactComponent as DuplicateIcon } from '@/assets/duplicate.svg';
import { ReactComponent as MoveToIcon } from '@/assets/move_to.svg';
-function MoreActionsContent ({ itemClicked, viewId, movePopoverOrigins }: {
+function MoreActionsContent ({ itemClicked, viewId, movePopoverOrigins, onDeleted }: {
itemClicked?: () => void;
+ onDeleted?: () => void;
viewId: string;
movePopoverOrigins: Origins
}) {
@@ -51,9 +52,15 @@ function MoreActionsContent ({ itemClicked, viewId, movePopoverOrigins }: {
>{t('button.delete')}
setDeleteModalOpen(false)}
+ onClose={() => {
+ setDeleteModalOpen(false);
+ itemClicked?.();
+ }}
viewId={viewId}
- onDeleted={itemClicked}
+ onDeleted={() => {
+ onDeleted?.();
+ itemClicked?.();
+ }}
/>
setHovered(true)}
onMouseLeave={() => setHovered(false)}
diff --git a/frontend/appflowy_web_app/src/components/app/view-actions/AddPageActions.tsx b/frontend/appflowy_web_app/src/components/app/view-actions/AddPageActions.tsx
index e813d4235a41..d67f5b3cb654 100644
--- a/frontend/appflowy_web_app/src/components/app/view-actions/AddPageActions.tsx
+++ b/frontend/appflowy_web_app/src/components/app/view-actions/AddPageActions.tsx
@@ -7,8 +7,9 @@ import CircularProgress from '@mui/material/CircularProgress';
import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
-function AddPageActions ({ view }: {
- view: View
+function AddPageActions ({ view, onClose }: {
+ view: View;
+ onClose: () => void;
}) {
const { t } = useTranslation();
const {
@@ -36,7 +37,11 @@ function AddPageActions ({ view }: {
}
}, [addPage, openPageModal, t, view.view_id]);
- const actions = useMemo(() => [
+ const actions: {
+ label: string;
+ icon: React.ReactNode;
+ onClick: (e: React.MouseEvent) => void;
+ }[] = useMemo(() => [
{
label: t('document.menuName'),
icon: {
+ action.onClick(e);
+ onClose();
+ }}
className={'px-3 py-1 justify-start'}
color={'inherit'}
startIcon={action.icon}
diff --git a/frontend/appflowy_web_app/src/components/app/view-actions/DeletePageConfirm.tsx b/frontend/appflowy_web_app/src/components/app/view-actions/DeletePageConfirm.tsx
index bffbfc9040aa..a0c5ef8f2762 100644
--- a/frontend/appflowy_web_app/src/components/app/view-actions/DeletePageConfirm.tsx
+++ b/frontend/appflowy_web_app/src/components/app/view-actions/DeletePageConfirm.tsx
@@ -1,7 +1,8 @@
import { NormalModal } from '@/components/_shared/modal';
import { notify } from '@/components/_shared/notify';
+import { filterViewsByCondition } from '@/components/_shared/outline/utils';
import { useAppHandlers, useAppView } from '@/components/app/app.hooks';
-import React from 'react';
+import React, { useCallback, useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
function DeletePageConfirm ({ open, onClose, viewId, onDeleted }: {
@@ -17,7 +18,7 @@ function DeletePageConfirm ({ open, onClose, viewId, onDeleted }: {
} = useAppHandlers();
const { t } = useTranslation();
- const handleOk = async () => {
+ const handleOk = useCallback(async () => {
if (!view) return;
setLoading(true);
try {
@@ -30,12 +31,27 @@ function DeletePageConfirm ({ open, onClose, viewId, onDeleted }: {
} finally {
setLoading(false);
}
- };
+ }, [deletePage, onClose, onDeleted, view, viewId]);
+
+ const hasPublished = useMemo(() => {
+ const publishedView = filterViewsByCondition(view?.children || [], v => v.is_published);
+
+ return view?.is_published || !!publishedView.length;
+ }, [view]);
+
+ useEffect(() => {
+ if (!hasPublished && open) {
+ void handleOk();
+ }
+ }, [handleOk, hasPublished, open]);
+
+ if (!hasPublished) return null;
return (
;
+ return {
+ handleClosePopover();
+ }}
+ view={view}
+ />;
}
if (popoverType.category === 'space') {
diff --git a/frontend/appflowy_web_app/src/components/editor/Editable.tsx b/frontend/appflowy_web_app/src/components/editor/Editable.tsx
index 1fc2426bd6db..ec0bfe63f474 100644
--- a/frontend/appflowy_web_app/src/components/editor/Editable.tsx
+++ b/frontend/appflowy_web_app/src/components/editor/Editable.tsx
@@ -1,18 +1,20 @@
import { YjsEditor } from '@/application/slate-yjs';
+import { CustomEditor } from '@/application/slate-yjs/command';
import { ensureBlockText } from '@/application/slate-yjs/utils/yjsOperations';
+import { BlockType } from '@/application/types';
import { BlockPopoverProvider } from '@/components/editor/components/block-popover/BlockPopoverContext';
import { useDecorate } from '@/components/editor/components/blocks/code/useDecorate';
import { Leaf } from '@/components/editor/components/leaf';
+import { PanelProvider } from '@/components/editor/components/panels/PanelsContext';
import { useEditorContext } from '@/components/editor/EditorContext';
import { useShortcuts } from '@/components/editor/shortcut.hooks';
import { getTextCount } from '@/utils/word';
+import { Skeleton } from '@mui/material';
import { debounce } from 'lodash-es';
import React, { lazy, Suspense, useCallback, useEffect, useMemo } from 'react';
-import { BaseRange, Editor, NodeEntry, Range } from 'slate';
+import { BaseRange, Editor, NodeEntry, Range, Element as SlateElement } from 'slate';
import { Editable, RenderElementProps, useSlate } from 'slate-react';
import { Element } from './components/element';
-import { Skeleton } from '@mui/material';
-import { PanelProvider } from '@/components/editor/components/panels/PanelsContext';
const EditorOverlay = lazy(() => import('@/components/editor/EditorOverlay'));
@@ -107,7 +109,7 @@ const EditorEditable = () => {
return [...codeDecoration, ...decoration];
}}
- className={'outline-none scroll-mb-[100px] scroll-mt-[300px] mb-36 min-w-0 max-w-full w-[988px] max-sm:px-6 px-24 focus:outline-none'}
+ className={'outline-none scroll-mb-[100px] scroll-mt-[300px] pb-36 min-w-0 max-w-full w-[988px] max-sm:px-6 px-24 focus:outline-none'}
renderLeaf={Leaf}
renderElement={renderElement}
readOnly={readOnly}
@@ -116,6 +118,17 @@ const EditorEditable = () => {
autoComplete={'off'}
onCompositionStart={onCompositionStart}
onKeyDown={onKeyDown}
+ onClick={e => {
+ const currentTarget = e.currentTarget as HTMLElement;
+ const bottomArea = currentTarget.getBoundingClientRect().bottom - 36 * 4;
+
+ if (e.clientY > bottomArea) {
+ const lastBlockId = (editor.children[editor.children.length - 1] as SlateElement).blockId as string;
+
+ if (!lastBlockId) return;
+ CustomEditor.addBelowBlock(editor as YjsEditor, lastBlockId, BlockType.Paragraph, {});
+ }
+ }}
/>
{!readOnly &&
diff --git a/frontend/appflowy_web_app/src/components/editor/components/block-popover/ImageBlockPopoverContent.tsx b/frontend/appflowy_web_app/src/components/editor/components/block-popover/ImageBlockPopoverContent.tsx
index 2fc41c698c7c..bbb53ed79c6c 100644
--- a/frontend/appflowy_web_app/src/components/editor/components/block-popover/ImageBlockPopoverContent.tsx
+++ b/frontend/appflowy_web_app/src/components/editor/components/block-popover/ImageBlockPopoverContent.tsx
@@ -93,7 +93,7 @@ function ImageBlockPopoverContent ({
/>;
})}
-
+
{tabOptions.map((tab, index) => {
const { key, panel } = tab;
diff --git a/frontend/appflowy_web_app/src/components/editor/components/blocks/text/Placeholder.tsx b/frontend/appflowy_web_app/src/components/editor/components/blocks/text/Placeholder.tsx
index dea3703d228b..d597b1ea65ab 100644
--- a/frontend/appflowy_web_app/src/components/editor/components/blocks/text/Placeholder.tsx
+++ b/frontend/appflowy_web_app/src/components/editor/components/blocks/text/Placeholder.tsx
@@ -28,7 +28,11 @@ function Placeholder ({ node, ...attributes }: { node: Element; className?: stri
}, [editor, node]);
const className = useMemo(() => {
- return `text-placeholder select-none ${attributes.className ?? ''}`;
+ const classList = attributes.className?.split(' ') ?? [];
+
+ classList.push('text-placeholder select-none');
+
+ return classList.join(' ');
}, [attributes.className]);
const unSelectedPlaceholder = useMemo(() => {
@@ -79,7 +83,6 @@ function Placeholder ({ node, ...attributes }: { node: Element; className?: stri
}
}
- case BlockType.CalloutBlock:
case BlockType.CodeBlock:
return t('editor.typeSomething');
default:
diff --git a/frontend/appflowy_web_app/src/components/editor/components/blocks/text/Text.tsx b/frontend/appflowy_web_app/src/components/editor/components/blocks/text/Text.tsx
index 7fe1cb83ce72..87966df4c806 100644
--- a/frontend/appflowy_web_app/src/components/editor/components/blocks/text/Text.tsx
+++ b/frontend/appflowy_web_app/src/components/editor/components/blocks/text/Text.tsx
@@ -24,8 +24,9 @@ export const Text = forwardRef
>(
const content = useMemo(() => {
return <>
- {placeholder}
- {children}
+
+
+ {placeholder}{children}
>;
}, [placeholder, isEmpty, children]);
diff --git a/frontend/appflowy_web_app/src/components/editor/components/panels/slash-panel/SlashPanel.tsx b/frontend/appflowy_web_app/src/components/editor/components/panels/slash-panel/SlashPanel.tsx
index f99ca5699186..1705a0286759 100644
--- a/frontend/appflowy_web_app/src/components/editor/components/panels/slash-panel/SlashPanel.tsx
+++ b/frontend/appflowy_web_app/src/components/editor/components/panels/slash-panel/SlashPanel.tsx
@@ -1,5 +1,6 @@
import { YjsEditor } from '@/application/slate-yjs';
import { CustomEditor } from '@/application/slate-yjs/command';
+import { isEmbedBlockTypes } from '@/application/slate-yjs/command/const';
import { findSlateEntryByBlockId } from '@/application/slate-yjs/utils/slateUtils';
import { getBlockEntry } from '@/application/slate-yjs/utils/yjsOperations';
import {
@@ -91,6 +92,12 @@ export function SlashPanel ({
newBlockId = CustomEditor.addBelowBlock(editor, blockId, type, data);
}
+ if (newBlockId && isEmbedBlockTypes(type)) {
+ const [, path] = findSlateEntryByBlockId(editor, newBlockId);
+
+ editor.select(editor.start(path));
+ }
+
if ([BlockType.FileBlock, BlockType.ImageBlock, BlockType.EquationBlock].includes(type)) {
setTimeout(() => {
if (!newBlockId) return;
@@ -422,6 +429,7 @@ export function SlashPanel ({
break;
case 'ArrowUp':
case 'ArrowDown': {
+ e.stopPropagation();
e.preventDefault();
const index = options.findIndex((option) => option.key === selectedOptionRef.current);
const nextIndex = key === 'ArrowDown' ? (index + 1) % options.length : (index - 1 + options.length) % options.length;
diff --git a/frontend/appflowy_web_app/src/components/editor/components/toolbar/block-controls/utils.ts b/frontend/appflowy_web_app/src/components/editor/components/toolbar/block-controls/utils.ts
index d910c9e01a91..a646212a2047 100644
--- a/frontend/appflowy_web_app/src/components/editor/components/toolbar/block-controls/utils.ts
+++ b/frontend/appflowy_web_app/src/components/editor/components/toolbar/block-controls/utils.ts
@@ -8,9 +8,14 @@ export function getBlockActionsPosition (editor: ReactEditor, blockElement: HTML
const editorDom = ReactEditor.toDOMNode(editor, editor);
const editorDomRect = editorDom.getBoundingClientRect();
const blockDomRect = blockElement.getBoundingClientRect();
+ const parentBlockDom = blockElement.parentElement?.closest('[data-block-type]');
const relativeTop = blockDomRect.top - editorDomRect.top;
- const relativeLeft = blockDomRect.left - editorDomRect.left;
+ let relativeLeft = blockDomRect.left - editorDomRect.left;
+
+ if (parentBlockDom?.getAttribute('data-block-type') === BlockType.QuoteBlock) {
+ relativeLeft -= 16;
+ }
return {
top: relativeTop,
diff --git a/frontend/appflowy_web_app/src/components/editor/components/toolbar/selection-toolbar/actions/Color.tsx b/frontend/appflowy_web_app/src/components/editor/components/toolbar/selection-toolbar/actions/Color.tsx
index 8ad413b97289..320469295e89 100644
--- a/frontend/appflowy_web_app/src/components/editor/components/toolbar/selection-toolbar/actions/Color.tsx
+++ b/frontend/appflowy_web_app/src/components/editor/components/toolbar/selection-toolbar/actions/Color.tsx
@@ -6,6 +6,7 @@ import {
useSelectionToolbarContext,
} from '@/components/editor/components/toolbar/selection-toolbar/SelectionToolbar.hooks';
import { ColorEnum, renderColor } from '@/utils/color';
+import { Tooltip } from '@mui/material';
import React, { useCallback, useEffect, useMemo } from 'react';
import ActionButton from './ActionButton';
import { useTranslation } from 'react-i18next';
@@ -124,23 +125,29 @@ function Color () {
{t('editor.textColor')}
{editorTextColors.map((color, index) => {
- return
handlePickedColor(EditorMarkFormat.FontColor, color.color)}
- style={{
- color: color.color || 'var(--text-title)',
- }}
+ title={color.label}
+ placement={'top'}
>
handlePickedColor(EditorMarkFormat.FontColor, color.color)}
style={{
- borderColor: color.color || 'var(--text-title)',
- opacity: color.color ? undefined : 1,
+ color: color.color || 'var(--text-title)',
}}
- />
-
-
;
+ >
+
+
+
+ ;
})}
@@ -148,24 +155,31 @@ function Color () {
{t('editor.backgroundColor')}
{editorBgColors.map((color, index) => {
- return
handlePickedColor(EditorMarkFormat.BgColor, color.color)}
+ title={color.label}
+ placement={'top'}
>
-
-
;
+ key={index}
+ className={'h-6 relative w-6 overflow-hidden flex items-center rounded-[6px] cursor-pointer justify-center'}
+ onClick={() => handlePickedColor(EditorMarkFormat.BgColor, color.color)}
+ >
+
+
+
+ ;
})}
diff --git a/frontend/appflowy_web_app/src/components/editor/editor.scss b/frontend/appflowy_web_app/src/components/editor/editor.scss
index 0bc81fb93ca1..f224b58c691f 100644
--- a/frontend/appflowy_web_app/src/components/editor/editor.scss
+++ b/frontend/appflowy_web_app/src/components/editor/editor.scss
@@ -55,9 +55,10 @@
.block-element[data-block-type="quote"] {
- .block-element {
+ .border-l-4 > .block-element {
margin-left: 0 !important;
}
+
}
.block-element[data-block-type="callout"] {
@@ -198,7 +199,7 @@ span[data-slate-placeholder="true"]:not(.inline-block-content) {
}
.text-placeholder {
- @apply absolute left-[5px] transform -translate-y-1/2 pointer-events-none select-none whitespace-nowrap;
+ @apply absolute left-0 transform -translate-y-1/2 pointer-events-none select-none whitespace-nowrap;
&:after {
@apply text-text-placeholder absolute top-0;
content: (attr(data-placeholder));
@@ -211,11 +212,6 @@ span[data-slate-placeholder="true"]:not(.inline-block-content) {
}
}
-.has-start-icon .text-placeholder {
- &:after {
- @apply left-[24px];
- }
-}
.block-align-center {
.text-placeholder {
@@ -225,13 +221,6 @@ span[data-slate-placeholder="true"]:not(.inline-block-content) {
}
}
- .has-start-icon .text-placeholder {
- @apply left-[calc(50%+13px)];
- &:after {
- @apply left-0;
- }
- }
-
}
@@ -239,9 +228,9 @@ span[data-slate-placeholder="true"]:not(.inline-block-content) {
.text-placeholder {
- @apply relative w-fit h-0 order-2;
+ @apply hidden;
&:after {
- @apply relative w-fit top-1/2 left-[-6px];
+ @apply relative w-fit;
}
}
@@ -249,11 +238,6 @@ span[data-slate-placeholder="true"]:not(.inline-block-content) {
@apply order-1;
}
- .has-start-icon .text-placeholder {
- &:after {
- @apply left-[-6px];
- }
- }
}
diff --git a/frontend/appflowy_web_app/src/components/editor/shortcut.hooks.ts b/frontend/appflowy_web_app/src/components/editor/shortcut.hooks.ts
index f93b5476689b..f66575b44e9a 100644
--- a/frontend/appflowy_web_app/src/components/editor/shortcut.hooks.ts
+++ b/frontend/appflowy_web_app/src/components/editor/shortcut.hooks.ts
@@ -20,7 +20,7 @@ export function useShortcuts (editor: ReactEditor) {
const title = document.getElementById('editor-title');
if (!title) return;
-
+
const selection = window.getSelection();
const range = document.createRange();
@@ -51,15 +51,16 @@ export function useShortcuts (editor: ReactEditor) {
if (selection && Range.isCollapsed(selection)) {
switch (true) {
case createHotkey(HOT_KEY_NAME.UP)(e): {
- const before = Editor.before(editor, selection, { unit: 'offset' });
- const beforeText = findInlineTextNode(editor, before);
const path = editor.start(selection).path;
- if (!Path.hasPrevious(path)) {
+ if (Path.isAncestor([0, 0], path)) {
focusedFocusableElement(false);
break;
}
+ const before = Editor.before(editor, selection, { unit: 'offset' });
+ const beforeText = findInlineTextNode(editor, before);
+
if (before && beforeText) {
e.preventDefault();
Transforms.move(editor, { unit: 'line', reverse: true, distance: 2 });
@@ -69,11 +70,30 @@ export function useShortcuts (editor: ReactEditor) {
break;
}
- case createHotkey(HOT_KEY_NAME.BACKSPACE)(e):
+ case createHotkey(HOT_KEY_NAME.BACKSPACE)(e): {
+ const [node] = getBlockEntry(yjsEditor);
+ const type = node.type as BlockType;
+
+ if (type !== BlockType.Paragraph) {
+ break;
+ }
+
+ const path = editor.start(selection).path;
+
+ const before = Editor.before(editor, selection, { unit: 'offset' });
+
+ if (!before && Path.isAncestor([0, 0], path)) {
+ focusedFocusableElement(true);
+ }
+
+ break;
+ }
+
case createHotkey(HOT_KEY_NAME.LEFT)(e): {
+ const path = editor.start(selection).path;
const before = Editor.before(editor, selection, { unit: 'offset' });
- if (!before) {
+ if (!before && Path.isAncestor([0, 0], path)) {
focusedFocusableElement(true);
}
diff --git a/frontend/appflowy_web_app/src/components/view-meta/ViewMetaPreview.tsx b/frontend/appflowy_web_app/src/components/view-meta/ViewMetaPreview.tsx
index 64f4a0342fda..a8a1c3fa05f0 100644
--- a/frontend/appflowy_web_app/src/components/view-meta/ViewMetaPreview.tsx
+++ b/frontend/appflowy_web_app/src/components/view-meta/ViewMetaPreview.tsx
@@ -135,7 +135,7 @@ export function ViewMetaPreview ({
setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
- className={'flex mt-2 flex-col relative'}
+ className={'flex mt-2 flex-col relative w-full overflow-hidden'}
>
{isHover && !readOnly &&
}
{icon?.value ?
diff --git a/frontend/appflowy_web_app/src/pages/TrashPage.tsx b/frontend/appflowy_web_app/src/pages/TrashPage.tsx
index 85b525a2bbdb..23477b372f42 100644
--- a/frontend/appflowy_web_app/src/pages/TrashPage.tsx
+++ b/frontend/appflowy_web_app/src/pages/TrashPage.tsx
@@ -105,16 +105,20 @@ function TrashPage () {
;
} else if (column.id === 'created_at' || column.id === 'last_edited_time') {
- content = dayjs(value).format('MMM D, YYYY h:mm A');
+ content =
{dayjs(value).format('MMM D, YYYY h:mm A')}
;
} else {
- content = value || t('menuAppHeader.defaultNewPageName');
+ content =
+
+ {value}
+
+
|| t('menuAppHeader.defaultNewPageName');
}
return (
{content}
@@ -133,7 +137,7 @@ function TrashPage () {
className={'flex items-center justify-between px-4'}
>
{t('trash.text')}
-
+ {trashList?.length &&
-
+
}
+
{!trashList ?
{columns.map((column) => {
return renderCell(column, row);