fix(editor): add recent open doc with mode button (#11419)
Closes: [BS-3013](https://linear.app/affine-design/issue/BS-3013/open-doc-分开两个按钮:一个快捷按钮和一个菜单) Split into two buttons: `recent open doc with mode button` and `open doc with dropdown menu`.
This commit is contained in:
@@ -6,7 +6,7 @@ import {
|
|||||||
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
|
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
|
||||||
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
|
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
|
||||||
import { PropTypes, requiredProperties } from '@blocksuite/std';
|
import { PropTypes, requiredProperties } from '@blocksuite/std';
|
||||||
import type { ReadonlySignal } from '@preact/signals-core';
|
import { computed, type ReadonlySignal } from '@preact/signals-core';
|
||||||
import { css, html, LitElement } from 'lit';
|
import { css, html, LitElement } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
||||||
@@ -24,6 +24,17 @@ export class OpenDocDropdownMenu extends SignalWatcher(
|
|||||||
WithDisposable(LitElement)
|
WithDisposable(LitElement)
|
||||||
) {
|
) {
|
||||||
static override styles = css`
|
static override styles = css`
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
gap: unset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
editor-icon-button {
|
||||||
|
.label {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
div[data-orientation] {
|
div[data-orientation] {
|
||||||
width: 264px;
|
width: 264px;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
@@ -59,31 +70,36 @@ export class OpenDocDropdownMenu extends SignalWatcher(
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor updateOpenDocMode!: (mode: OpenDocMode) => void;
|
accessor updateOpenDocMode!: (mode: OpenDocMode) => void;
|
||||||
|
|
||||||
|
currentAction$ = computed(() => {
|
||||||
|
const currentOpenDocMode = this.openDocMode$.value;
|
||||||
|
return (
|
||||||
|
this.actions.find(a => a.mode === currentOpenDocMode) ?? this.actions[0]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
override render() {
|
override render() {
|
||||||
const {
|
const {
|
||||||
actions,
|
actions,
|
||||||
context,
|
context,
|
||||||
openDocMode$: { value: openDocMode },
|
|
||||||
updateOpenDocMode,
|
updateOpenDocMode,
|
||||||
|
currentAction$: { value: currentAction },
|
||||||
} = this;
|
} = this;
|
||||||
const currentAction =
|
|
||||||
actions.find(a => a.mode === openDocMode) ?? actions[0];
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
|
<editor-icon-button
|
||||||
|
aria-label="${currentAction.label}"
|
||||||
|
.tooltip="${currentAction.label}"
|
||||||
|
@click=${() => currentAction.run?.(context)}
|
||||||
|
>
|
||||||
|
${currentAction.icon}
|
||||||
|
<span class="label">Open</span>
|
||||||
|
</editor-icon-button>
|
||||||
<editor-menu-button
|
<editor-menu-button
|
||||||
aria-label="Open doc menu"
|
aria-label="Open doc menu"
|
||||||
.contentPadding="${'8px'}"
|
.contentPadding="${'8px'}"
|
||||||
.button=${html`
|
.button=${html`
|
||||||
<editor-icon-button
|
<editor-icon-button aria-label="Open doc with">
|
||||||
data-open-doc-mode="${currentAction.label}"
|
${EditorChevronDown}
|
||||||
aria-label="Open doc"
|
|
||||||
.tooltip="${'Open doc'}"
|
|
||||||
.justify="${'space-between'}"
|
|
||||||
.labelHeight="${'20px'}"
|
|
||||||
.iconContainerWidth="${'84px'}"
|
|
||||||
>
|
|
||||||
${currentAction.icon}
|
|
||||||
<span class="label">Open</span> ${EditorChevronDown}
|
|
||||||
</editor-icon-button>
|
</editor-icon-button>
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -716,18 +716,20 @@ function renderOpenDocMenu(
|
|||||||
}));
|
}));
|
||||||
if (!actions.length) return null;
|
if (!actions.length) return null;
|
||||||
|
|
||||||
|
const openDocMode = computed(
|
||||||
|
() => settings.settingSignal.value.openDocMode ?? 'open-in-active-view'
|
||||||
|
);
|
||||||
|
const updateOpenDocMode = (mode: OpenDocMode) =>
|
||||||
|
settings.openDocMode.set(mode);
|
||||||
|
|
||||||
return html`${keyed(
|
return html`${keyed(
|
||||||
target,
|
target,
|
||||||
html`
|
html`
|
||||||
<affine-open-doc-dropdown-menu
|
<affine-open-doc-dropdown-menu
|
||||||
.actions=${actions}
|
.actions=${actions}
|
||||||
.context=${ctx}
|
.context=${ctx}
|
||||||
.openDocMode$=${computed(
|
.openDocMode$=${openDocMode}
|
||||||
() =>
|
.updateOpenDocMode=${updateOpenDocMode}
|
||||||
settings.settingSignal.value.openDocMode ?? 'open-in-active-view'
|
|
||||||
)}
|
|
||||||
.updateOpenDocMode=${(mode: OpenDocMode) =>
|
|
||||||
settings.openDocMode.set(mode)}
|
|
||||||
>
|
>
|
||||||
</affine-open-doc-dropdown-menu>
|
</affine-open-doc-dropdown-menu>
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ test('outline viewer should be useable in doc peek preview', async ({
|
|||||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||||
await expect(toolbar).toBeVisible();
|
await expect(toolbar).toBeVisible();
|
||||||
|
|
||||||
await toolbar.getByLabel(/^Open doc$/).click();
|
await toolbar.getByLabel(/^Open doc with$/).click();
|
||||||
await toolbar
|
await toolbar
|
||||||
.getByLabel('Open doc menu')
|
.getByLabel('Open doc menu')
|
||||||
.getByLabel('Open in center peek')
|
.getByLabel('Open in center peek')
|
||||||
|
|||||||
@@ -1054,11 +1054,18 @@ test('should save open doc mode of internal links', async ({ page }) => {
|
|||||||
const inlineLink = page.locator('affine-reference');
|
const inlineLink = page.locator('affine-reference');
|
||||||
await inlineLink.hover();
|
await inlineLink.hover();
|
||||||
|
|
||||||
const openDocBtn = toolbar.getByLabel(/^Open doc$/);
|
const recentOpenModeBtn = toolbar.locator(
|
||||||
await expect(openDocBtn).toHaveAttribute(
|
'editor-icon-button:has-text("Open")'
|
||||||
'data-open-doc-mode',
|
);
|
||||||
|
await expect(recentOpenModeBtn).toHaveAttribute(
|
||||||
|
'aria-label',
|
||||||
'Open this doc'
|
'Open this doc'
|
||||||
);
|
);
|
||||||
|
await expect(
|
||||||
|
recentOpenModeBtn.locator('span.label:has-text("Open")')
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
const openDocBtn = toolbar.getByLabel(/^Open doc with$/);
|
||||||
await openDocBtn.click();
|
await openDocBtn.click();
|
||||||
|
|
||||||
const openDocMenu = toolbar.getByLabel('Open doc menu');
|
const openDocMenu = toolbar.getByLabel('Open doc menu');
|
||||||
@@ -1081,8 +1088,8 @@ test('should save open doc mode of internal links', async ({ page }) => {
|
|||||||
await inlineLink.hover();
|
await inlineLink.hover();
|
||||||
|
|
||||||
await expect(toolbar).toBeVisible();
|
await expect(toolbar).toBeVisible();
|
||||||
await expect(openDocBtn).toHaveAttribute(
|
await expect(recentOpenModeBtn).toHaveAttribute(
|
||||||
'data-open-doc-mode',
|
'aria-label',
|
||||||
'Open in center peek'
|
'Open in center peek'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1090,8 +1097,8 @@ test('should save open doc mode of internal links', async ({ page }) => {
|
|||||||
await cardViewBtn.click();
|
await cardViewBtn.click();
|
||||||
|
|
||||||
await expect(toolbar).toBeVisible();
|
await expect(toolbar).toBeVisible();
|
||||||
await expect(openDocBtn).toHaveAttribute(
|
await expect(recentOpenModeBtn).toHaveAttribute(
|
||||||
'data-open-doc-mode',
|
'aria-label',
|
||||||
'Open in center peek'
|
'Open in center peek'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1099,8 +1106,8 @@ test('should save open doc mode of internal links', async ({ page }) => {
|
|||||||
await embedViewBtn.click();
|
await embedViewBtn.click();
|
||||||
|
|
||||||
await expect(toolbar).toBeVisible();
|
await expect(toolbar).toBeVisible();
|
||||||
await expect(openDocBtn).toHaveAttribute(
|
await expect(recentOpenModeBtn).toHaveAttribute(
|
||||||
'data-open-doc-mode',
|
'aria-label',
|
||||||
'Open in center peek'
|
'Open in center peek'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1112,8 +1119,8 @@ test('should save open doc mode of internal links', async ({ page }) => {
|
|||||||
await page.waitForTimeout(250);
|
await page.waitForTimeout(250);
|
||||||
|
|
||||||
await expect(toolbar).toBeVisible();
|
await expect(toolbar).toBeVisible();
|
||||||
await expect(openDocBtn).toHaveAttribute(
|
await expect(recentOpenModeBtn).toHaveAttribute(
|
||||||
'data-open-doc-mode',
|
'aria-label',
|
||||||
'Open in center peek'
|
'Open in center peek'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ test('can open peek view via link popover', async ({ page }) => {
|
|||||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||||
await expect(toolbar).toBeVisible();
|
await expect(toolbar).toBeVisible();
|
||||||
|
|
||||||
await toolbar.getByLabel(/^Open doc$/).click();
|
await toolbar.getByLabel(/^Open doc with$/).click();
|
||||||
await toolbar
|
await toolbar
|
||||||
.getByLabel('Open doc menu')
|
.getByLabel('Open doc menu')
|
||||||
.getByLabel('Open in center peek')
|
.getByLabel('Open in center peek')
|
||||||
|
|||||||
Reference in New Issue
Block a user