mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-22 04:26:23 +08:00
feat(editor): append note to page button (#9762)
Close [BS-2310](https://linear.app/affine-design/issue/BS-2310/note-display-in-page-%E7%9A%84%E8%A1%8C%E4%B8%BA), [BS-2312](https://linear.app/affine-design/issue/BS-2312/edgeless-note-%E7%9A%84-element-toolbar-%E6%B7%BB%E5%8A%A0display-in-page%E6%8C%89%E9%92%AE) and [BS-2313](https://linear.app/affine-design/issue/BS-2313/添加display-in-page的toast提示,以及打开toc的按钮)
This commit is contained in:
@@ -29,6 +29,7 @@ export interface NotificationService {
|
|||||||
notify(options: {
|
notify(options: {
|
||||||
title: string | TemplateResult;
|
title: string | TemplateResult;
|
||||||
message?: string | TemplateResult;
|
message?: string | TemplateResult;
|
||||||
|
footer?: string | TemplateResult;
|
||||||
accent?: 'info' | 'success' | 'warning' | 'error';
|
accent?: 'info' | 'success' | 'warning' | 'error';
|
||||||
duration?: number; // unit ms, give 0 to disable auto dismiss
|
duration?: number; // unit ms, give 0 to disable auto dismiss
|
||||||
abort?: AbortSignal;
|
abort?: AbortSignal;
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
"@lit/context": "^1.1.2",
|
"@lit/context": "^1.1.2",
|
||||||
"@preact/signals-core": "^1.8.0",
|
"@preact/signals-core": "^1.8.0",
|
||||||
"@toeverything/theme": "^1.1.6",
|
"@toeverything/theme": "^1.1.6",
|
||||||
|
"@vanilla-extract/css": "^1.17.0",
|
||||||
"date-fns": "^4.0.0",
|
"date-fns": "^4.0.0",
|
||||||
"dompurify": "^3.1.6",
|
"dompurify": "^3.1.6",
|
||||||
"fflate": "^0.8.2",
|
"fflate": "^0.8.2",
|
||||||
|
|||||||
@@ -30,16 +30,18 @@ import {
|
|||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
FeatureFlagService,
|
FeatureFlagService,
|
||||||
|
NotificationProvider,
|
||||||
|
SidebarExtensionIdentifier,
|
||||||
ThemeProvider,
|
ThemeProvider,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { matchFlavours } from '@blocksuite/affine-shared/utils';
|
import { matchFlavours } from '@blocksuite/affine-shared/utils';
|
||||||
import {
|
import {
|
||||||
assertExists,
|
|
||||||
Bound,
|
Bound,
|
||||||
countBy,
|
countBy,
|
||||||
maxBy,
|
maxBy,
|
||||||
WithDisposable,
|
WithDisposable,
|
||||||
} from '@blocksuite/global/utils';
|
} from '@blocksuite/global/utils';
|
||||||
|
import { LinkedPageIcon } from '@blocksuite/icons/lit';
|
||||||
import { html, LitElement, nothing, type TemplateResult } from 'lit';
|
import { html, LitElement, nothing, type TemplateResult } from 'lit';
|
||||||
import { property, query } from 'lit/decorators.js';
|
import { property, query } from 'lit/decorators.js';
|
||||||
import { join } from 'lit/directives/join.js';
|
import { join } from 'lit/directives/join.js';
|
||||||
@@ -52,6 +54,7 @@ import {
|
|||||||
} from '../../edgeless/components/panel/line-styles-panel.js';
|
} from '../../edgeless/components/panel/line-styles-panel.js';
|
||||||
import { getTooltipWithShortcut } from '../../edgeless/components/utils.js';
|
import { getTooltipWithShortcut } from '../../edgeless/components/utils.js';
|
||||||
import type { EdgelessRootBlockComponent } from '../../edgeless/edgeless-root-block.js';
|
import type { EdgelessRootBlockComponent } from '../../edgeless/edgeless-root-block.js';
|
||||||
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
const SIZE_LIST = [
|
const SIZE_LIST = [
|
||||||
{ name: 'None', value: 0 },
|
{ name: 'None', value: 0 },
|
||||||
@@ -141,15 +144,17 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
|||||||
.getFlag('enable_advanced_block_visibility');
|
.getFlag('enable_advanced_block_visibility');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get _pageBlockHeaderEnabled() {
|
||||||
|
return this.doc.get(FeatureFlagService).getFlag('enable_page_block_header');
|
||||||
|
}
|
||||||
|
|
||||||
private get doc() {
|
private get doc() {
|
||||||
return this.edgeless.doc;
|
return this.edgeless.doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _enableAutoHeight() {
|
private get _enableAutoHeight() {
|
||||||
return !(
|
return !(
|
||||||
this.edgeless.doc
|
this._pageBlockHeaderEnabled &&
|
||||||
.get(FeatureFlagService)
|
|
||||||
.getFlag('enable_page_block_header') &&
|
|
||||||
this.notes.length === 1 &&
|
this.notes.length === 1 &&
|
||||||
this.notes[0].parent?.children.find(child =>
|
this.notes[0].parent?.children.find(child =>
|
||||||
matchFlavours(child, ['affine:note'])
|
matchFlavours(child, ['affine:note'])
|
||||||
@@ -195,13 +200,16 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.doc.captureSync();
|
||||||
|
|
||||||
this.crud.updateElement(note.id, { displayMode: newMode });
|
this.crud.updateElement(note.id, { displayMode: newMode });
|
||||||
|
|
||||||
const noteParent = this.doc.getParent(note);
|
const noteParent = this.doc.getParent(note);
|
||||||
assertExists(noteParent);
|
if (!noteParent) return;
|
||||||
|
|
||||||
const noteParentChildNotes = noteParent.children.filter(block =>
|
const noteParentChildNotes = noteParent.children.filter(block =>
|
||||||
matchFlavours(block, ['affine:note'])
|
matchFlavours(block, ['affine:note'])
|
||||||
) as NoteBlockModel[];
|
);
|
||||||
const noteParentLastNote =
|
const noteParentLastNote =
|
||||||
noteParentChildNotes[noteParentChildNotes.length - 1];
|
noteParentChildNotes[noteParentChildNotes.length - 1];
|
||||||
|
|
||||||
@@ -218,6 +226,61 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
|||||||
if (newMode === NoteDisplayMode.DocOnly) {
|
if (newMode === NoteDisplayMode.DocOnly) {
|
||||||
this.edgeless.service.selection.clear();
|
this.edgeless.service.selection.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const abortController = new AbortController();
|
||||||
|
const clear = () => {
|
||||||
|
this.doc.history.off('stack-item-added', addHandler);
|
||||||
|
this.doc.history.off('stack-item-popped', popHandler);
|
||||||
|
disposable.dispose();
|
||||||
|
};
|
||||||
|
const closeNotify = () => {
|
||||||
|
abortController.abort();
|
||||||
|
clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
const addHandler = this.doc.history.on('stack-item-added', closeNotify);
|
||||||
|
const popHandler = this.doc.history.on('stack-item-popped', closeNotify);
|
||||||
|
const disposable = this.edgeless.std.host.slots.unmounted.on(closeNotify);
|
||||||
|
|
||||||
|
const undo = () => {
|
||||||
|
this.doc.undo();
|
||||||
|
closeNotify();
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewInToc = () => {
|
||||||
|
const sidebar = this.edgeless.std.getOptional(SidebarExtensionIdentifier);
|
||||||
|
sidebar?.open('outline');
|
||||||
|
closeNotify();
|
||||||
|
};
|
||||||
|
|
||||||
|
const notification = this.edgeless.std.getOptional(NotificationProvider);
|
||||||
|
notification?.notify({
|
||||||
|
title: 'Note displayed in Page Mode',
|
||||||
|
message:
|
||||||
|
'Content added to your page. Find it in the TOC for quick navigation.',
|
||||||
|
accent: 'success',
|
||||||
|
duration: 1000 * 1000,
|
||||||
|
footer: html`<div class=${styles.viewInPageNotifyFooter}>
|
||||||
|
<button
|
||||||
|
class=${styles.viewInPageNotifyFooterButton}
|
||||||
|
@click=${undo}
|
||||||
|
data-testid="undo-display-in-page"
|
||||||
|
>
|
||||||
|
Undo
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class=${styles.viewInPageNotifyFooterButton}
|
||||||
|
@click=${viewInToc}
|
||||||
|
data-testid="view-in-toc"
|
||||||
|
>
|
||||||
|
View in Toc
|
||||||
|
</button>
|
||||||
|
</div>`,
|
||||||
|
abort: abortController.signal,
|
||||||
|
onClose: () => {
|
||||||
|
clear();
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _setShadowType(shadowType: string) {
|
private _setShadowType(shadowType: string) {
|
||||||
@@ -286,6 +349,11 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
|||||||
const currentMode = DisplayModeMap[displayMode];
|
const currentMode = DisplayModeMap[displayMode];
|
||||||
const onlyOne = len === 1;
|
const onlyOne = len === 1;
|
||||||
const isDocOnly = displayMode === NoteDisplayMode.DocOnly;
|
const isDocOnly = displayMode === NoteDisplayMode.DocOnly;
|
||||||
|
const isFirstNote =
|
||||||
|
onlyOne &&
|
||||||
|
note.parent?.children.find(child =>
|
||||||
|
matchFlavours(child, ['affine:note'])
|
||||||
|
) === note;
|
||||||
const theme = this.edgeless.std.get(ThemeProvider).theme;
|
const theme = this.edgeless.std.get(ThemeProvider).theme;
|
||||||
const buttons = [
|
const buttons = [
|
||||||
onlyOne && this._advancedVisibilityEnabled
|
onlyOne && this._advancedVisibilityEnabled
|
||||||
@@ -315,6 +383,32 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
|||||||
`
|
`
|
||||||
: nothing,
|
: nothing,
|
||||||
|
|
||||||
|
onlyOne &&
|
||||||
|
!isFirstNote &&
|
||||||
|
this._pageBlockHeaderEnabled &&
|
||||||
|
!this._advancedVisibilityEnabled
|
||||||
|
? html`<editor-icon-button
|
||||||
|
aria-label="Display In Page"
|
||||||
|
.showTooltip=${displayMode === NoteDisplayMode.DocAndEdgeless}
|
||||||
|
.tooltip=${'This note is part of Page Mode. Click to remove it from the page.'}
|
||||||
|
data-testid="display-in-page"
|
||||||
|
@click=${() =>
|
||||||
|
this._setDisplayMode(
|
||||||
|
note,
|
||||||
|
displayMode === NoteDisplayMode.EdgelessOnly
|
||||||
|
? NoteDisplayMode.DocAndEdgeless
|
||||||
|
: NoteDisplayMode.EdgelessOnly
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
${LinkedPageIcon({ width: '20px', height: '20px' })}
|
||||||
|
<span class="label"
|
||||||
|
>${displayMode === NoteDisplayMode.EdgelessOnly
|
||||||
|
? 'Display In Page'
|
||||||
|
: 'Displayed In Page'}</span
|
||||||
|
>
|
||||||
|
</editor-icon-button>`
|
||||||
|
: nothing,
|
||||||
|
|
||||||
isDocOnly
|
isDocOnly
|
||||||
? nothing
|
? nothing
|
||||||
: when(
|
: when(
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { cssVar } from '@toeverything/theme';
|
||||||
|
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||||
|
import { style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
|
export const viewInPageNotifyFooter = style({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
gap: '12px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const viewInPageNotifyFooterButton = style({
|
||||||
|
padding: '0px 6px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
color: cssVarV2('text/primary'),
|
||||||
|
|
||||||
|
fontSize: cssVar('fontSm'),
|
||||||
|
lineHeight: '22px',
|
||||||
|
fontWeight: '500',
|
||||||
|
textAlign: 'center',
|
||||||
|
|
||||||
|
':hover': {
|
||||||
|
background: cssVarV2('layer/background/hoverOverlay'),
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tweakpane/core": "^2.0.4",
|
"@tweakpane/core": "^2.0.4",
|
||||||
"@types/micromatch": "^4.0.9",
|
"@types/micromatch": "^4.0.9",
|
||||||
|
"@vanilla-extract/vite-plugin": "^4.0.19",
|
||||||
"graphql": "^16.9.0",
|
"graphql": "^16.9.0",
|
||||||
"magic-string": "^0.30.11",
|
"magic-string": "^0.30.11",
|
||||||
"vite": "^6.0.3",
|
"vite": "^6.0.3",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { cpus } from 'node:os';
|
|||||||
import path, { resolve } from 'node:path';
|
import path, { resolve } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
|
||||||
import type { GetManualChunk } from 'rollup';
|
import type { GetManualChunk } from 'rollup';
|
||||||
import type { Plugin } from 'vite';
|
import type { Plugin } from 'vite';
|
||||||
import { defineConfig, loadEnv } from 'vite';
|
import { defineConfig, loadEnv } from 'vite';
|
||||||
@@ -187,6 +188,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
forceBuildInstrument: true,
|
forceBuildInstrument: true,
|
||||||
}),
|
}),
|
||||||
wasm(),
|
wasm(),
|
||||||
|
vanillaExtractPlugin(),
|
||||||
clearSiteDataPlugin(),
|
clearSiteDataPlugin(),
|
||||||
],
|
],
|
||||||
esbuild: {
|
esbuild: {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
"!dist/__tests__"
|
"!dist/__tests__"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@vanilla-extract/vite-plugin": "^4.0.19",
|
||||||
"vitest": "^3.0.0"
|
"vitest": "^3.0.0"
|
||||||
},
|
},
|
||||||
"version": "0.19.0"
|
"version": "0.19.0"
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ async function createEditor(collection: TestWorkspace, mode: DocMode = 'page') {
|
|||||||
|
|
||||||
app.style.width = '100%';
|
app.style.width = '100%';
|
||||||
app.style.height = '1280px';
|
app.style.height = '1280px';
|
||||||
|
app.style.overflowY = 'auto';
|
||||||
|
|
||||||
document.body.append(app);
|
document.body.append(app);
|
||||||
await editor.updateComplete;
|
await editor.updateComplete;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
|
||||||
import { defineConfig } from 'vitest/config';
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
export default defineConfig(_configEnv =>
|
export default defineConfig(_configEnv =>
|
||||||
@@ -14,6 +15,7 @@ export default defineConfig(_configEnv =>
|
|||||||
target: 'es2022',
|
target: 'es2022',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
plugins: [vanillaExtractPlugin()],
|
||||||
test: {
|
test: {
|
||||||
include: ['src/__tests__/**/*.spec.ts'],
|
include: ['src/__tests__/**/*.spec.ts'],
|
||||||
browser: {
|
browser: {
|
||||||
|
|||||||
+1
@@ -225,6 +225,7 @@ export function patchNotificationService({
|
|||||||
{
|
{
|
||||||
title: toReactNode(notification.title),
|
title: toReactNode(notification.title),
|
||||||
message: toReactNode(notification.message),
|
message: toReactNode(notification.message),
|
||||||
|
footer: toReactNode(notification.footer),
|
||||||
action: notification.action?.onClick
|
action: notification.action?.onClick
|
||||||
? {
|
? {
|
||||||
label: toReactNode(notification.action?.label),
|
label: toReactNode(notification.action?.label),
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
import { test } from '@affine-test/kit/playwright';
|
import { test } from '@affine-test/kit/playwright';
|
||||||
import {
|
import {
|
||||||
clickEdgelessModeButton,
|
clickEdgelessModeButton,
|
||||||
|
clickView,
|
||||||
createEdgelessNoteBlock,
|
createEdgelessNoteBlock,
|
||||||
getEdgelessSelectedIds,
|
getEdgelessSelectedIds,
|
||||||
getPageMode,
|
getPageMode,
|
||||||
locateEditorContainer,
|
locateEditorContainer,
|
||||||
locateElementToolbar,
|
locateElementToolbar,
|
||||||
|
locateModeSwitchButton,
|
||||||
} from '@affine-test/kit/utils/editor';
|
} from '@affine-test/kit/utils/editor';
|
||||||
import {
|
import {
|
||||||
pasteByKeyboard,
|
pasteByKeyboard,
|
||||||
selectAllByKeyboard,
|
selectAllByKeyboard,
|
||||||
|
undoByKeyboard,
|
||||||
} from '@affine-test/kit/utils/keyboard';
|
} from '@affine-test/kit/utils/keyboard';
|
||||||
import { openHomePage } from '@affine-test/kit/utils/load-page';
|
import { openHomePage } from '@affine-test/kit/utils/load-page';
|
||||||
import {
|
import {
|
||||||
@@ -143,14 +146,90 @@ test.describe('edgeless page header toolbar', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test.describe('edgeless note element toolbar', () => {
|
test.describe('edgeless note element toolbar', () => {
|
||||||
test('the toolbar of page block should not contains auto-height', async ({
|
test('the toolbar of page block should not contains auto-height button and display in page button', async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
await selectAllByKeyboard(page);
|
await selectAllByKeyboard(page);
|
||||||
const toolbar = locateElementToolbar(page);
|
const toolbar = locateElementToolbar(page);
|
||||||
const autoHeight = toolbar.getByTestId('edgeless-note-auto-height');
|
const autoHeight = toolbar.getByTestId('edgeless-note-auto-height');
|
||||||
|
const displayInPage = toolbar.getByTestId('display-in-page');
|
||||||
|
|
||||||
await expect(toolbar).toBeVisible();
|
await expect(toolbar).toBeVisible();
|
||||||
await expect(autoHeight).toHaveCount(0);
|
await expect(autoHeight).toHaveCount(0);
|
||||||
|
await expect(displayInPage).toHaveCount(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the toolbar of note block should contains auto-height button and display in page button', async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
await createEdgelessNoteBlock(page, [100, 100]);
|
||||||
|
await page.waitForSelector('.affine-paragraph-placeholder.visible');
|
||||||
|
await clickView(page, [0, 0]);
|
||||||
|
await clickView(page, [100, 100]);
|
||||||
|
|
||||||
|
const toolbar = locateElementToolbar(page);
|
||||||
|
const autoHeight = toolbar.getByTestId('edgeless-note-auto-height');
|
||||||
|
const displayInPage = toolbar.getByTestId('display-in-page');
|
||||||
|
|
||||||
|
await expect(toolbar).toBeVisible();
|
||||||
|
await expect(autoHeight).toBeVisible();
|
||||||
|
await expect(displayInPage).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('display in page button', async ({ page }) => {
|
||||||
|
const editorContainer = locateEditorContainer(page);
|
||||||
|
const notes = editorContainer.locator('affine-note');
|
||||||
|
|
||||||
|
await createEdgelessNoteBlock(page, [100, 100]);
|
||||||
|
await page.waitForSelector('.affine-paragraph-placeholder.visible');
|
||||||
|
await page.keyboard.type('Note 2');
|
||||||
|
await clickView(page, [0, 0]);
|
||||||
|
await clickView(page, [100, 100]);
|
||||||
|
|
||||||
|
const toolbar = locateElementToolbar(page);
|
||||||
|
const displayInPage = toolbar.getByTestId('display-in-page');
|
||||||
|
|
||||||
|
await displayInPage.click();
|
||||||
|
await locateModeSwitchButton(page, 'page').click();
|
||||||
|
expect(notes).toHaveCount(2);
|
||||||
|
|
||||||
|
await locateModeSwitchButton(page, 'edgeless').click();
|
||||||
|
await clickView(page, [100, 100]);
|
||||||
|
await displayInPage.click();
|
||||||
|
await locateModeSwitchButton(page, 'page').click();
|
||||||
|
await waitForEditorLoad(page);
|
||||||
|
expect(notes).toHaveCount(1);
|
||||||
|
|
||||||
|
const undoButton = page.getByTestId('undo-display-in-page');
|
||||||
|
const viewTocButton = page.getByTestId('view-in-toc');
|
||||||
|
|
||||||
|
await locateModeSwitchButton(page, 'edgeless').click();
|
||||||
|
await waitForEditorLoad(page);
|
||||||
|
await clickView(page, [100, 100]);
|
||||||
|
await displayInPage.click();
|
||||||
|
expect(undoButton).toBeVisible();
|
||||||
|
expect(viewTocButton).toBeVisible();
|
||||||
|
|
||||||
|
await undoButton.click();
|
||||||
|
await expect(undoButton).toBeHidden();
|
||||||
|
await locateModeSwitchButton(page, 'page').click();
|
||||||
|
await waitForEditorLoad(page);
|
||||||
|
expect(notes).toHaveCount(1);
|
||||||
|
|
||||||
|
await locateModeSwitchButton(page, 'edgeless').click();
|
||||||
|
await waitForEditorLoad(page);
|
||||||
|
await clickView(page, [100, 100]);
|
||||||
|
await displayInPage.click();
|
||||||
|
await undoByKeyboard(page);
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
expect(
|
||||||
|
undoButton,
|
||||||
|
'the toast should be hidden immediately when undo by keyboard'
|
||||||
|
).toBeHidden();
|
||||||
|
|
||||||
|
await displayInPage.click();
|
||||||
|
await viewTocButton.click();
|
||||||
|
await page.waitForSelector('affine-outline-panel');
|
||||||
|
expect(page.locator('affine-outline-panel')).toBeVisible();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -70,6 +70,12 @@ export async function selectAllByKeyboard(page: Page) {
|
|||||||
await keyUpCtrlOrMeta(page);
|
await keyUpCtrlOrMeta(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function undoByKeyboard(page: Page) {
|
||||||
|
await keyDownCtrlOrMeta(page);
|
||||||
|
await page.keyboard.press('z', { delay: 50 });
|
||||||
|
await keyUpCtrlOrMeta(page);
|
||||||
|
}
|
||||||
|
|
||||||
export async function writeTextToClipboard(page: Page, text: string) {
|
export async function writeTextToClipboard(page: Page, text: string) {
|
||||||
// paste the url
|
// paste the url
|
||||||
await page.evaluate(
|
await page.evaluate(
|
||||||
|
|||||||
@@ -3910,6 +3910,7 @@ __metadata:
|
|||||||
"@toeverything/theme": "npm:^1.1.6"
|
"@toeverything/theme": "npm:^1.1.6"
|
||||||
"@types/katex": "npm:^0.16.7"
|
"@types/katex": "npm:^0.16.7"
|
||||||
"@types/lodash.isequal": "npm:^4.5.8"
|
"@types/lodash.isequal": "npm:^4.5.8"
|
||||||
|
"@vanilla-extract/css": "npm:^1.17.0"
|
||||||
date-fns: "npm:^4.0.0"
|
date-fns: "npm:^4.0.0"
|
||||||
dompurify: "npm:^3.1.6"
|
dompurify: "npm:^3.1.6"
|
||||||
fflate: "npm:^0.8.2"
|
fflate: "npm:^0.8.2"
|
||||||
@@ -4034,6 +4035,7 @@ __metadata:
|
|||||||
"@tweakpane/core": "npm:^2.0.4"
|
"@tweakpane/core": "npm:^2.0.4"
|
||||||
"@types/katex": "npm:^0.16.7"
|
"@types/katex": "npm:^0.16.7"
|
||||||
"@types/micromatch": "npm:^4.0.9"
|
"@types/micromatch": "npm:^4.0.9"
|
||||||
|
"@vanilla-extract/vite-plugin": "npm:^4.0.19"
|
||||||
browser-fs-access: "npm:^0.35.0"
|
browser-fs-access: "npm:^0.35.0"
|
||||||
graphql: "npm:^16.9.0"
|
graphql: "npm:^16.9.0"
|
||||||
jszip: "npm:^3.10.1"
|
jszip: "npm:^3.10.1"
|
||||||
@@ -4068,6 +4070,7 @@ __metadata:
|
|||||||
"@lottiefiles/dotlottie-wc": "npm:^0.4.0"
|
"@lottiefiles/dotlottie-wc": "npm:^0.4.0"
|
||||||
"@preact/signals-core": "npm:^1.8.0"
|
"@preact/signals-core": "npm:^1.8.0"
|
||||||
"@toeverything/theme": "npm:^1.1.6"
|
"@toeverything/theme": "npm:^1.1.6"
|
||||||
|
"@vanilla-extract/vite-plugin": "npm:^4.0.19"
|
||||||
lit: "npm:^3.2.0"
|
lit: "npm:^3.2.0"
|
||||||
vitest: "npm:^3.0.0"
|
vitest: "npm:^3.0.0"
|
||||||
yjs: "npm:^13.6.21"
|
yjs: "npm:^13.6.21"
|
||||||
@@ -15530,7 +15533,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@vanilla-extract/vite-plugin@npm:^4.0.18":
|
"@vanilla-extract/vite-plugin@npm:^4.0.18, @vanilla-extract/vite-plugin@npm:^4.0.19":
|
||||||
version: 4.0.19
|
version: 4.0.19
|
||||||
resolution: "@vanilla-extract/vite-plugin@npm:4.0.19"
|
resolution: "@vanilla-extract/vite-plugin@npm:4.0.19"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
Reference in New Issue
Block a user