feat(core): save recent open mode of internal links (#11086)
Closes: [BS-2865](https://linear.app/affine-design/issue/BS-2865/internal-links-保存用户最近的打开方式) Added `openDocMode` in settings. https://github.com/user-attachments/assets/a452da73-83e4-4ef5-9b57-58291fc22785
This commit is contained in:
@@ -57,7 +57,7 @@ export class EditorIconButton extends LitElement {
|
|||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
line-height: var(--label-height, inherit);
|
line-height: var(--label-height, var(--icon-size, 20px));
|
||||||
}
|
}
|
||||||
::slotted(.label.padding0) {
|
::slotted(.label.padding0) {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ export function renderToolbar(
|
|||||||
`${flavour}:${key}`,
|
`${flavour}:${key}`,
|
||||||
html`
|
html`
|
||||||
<editor-menu-button
|
<editor-menu-button
|
||||||
aria-label="more-menu"
|
aria-label="More menu"
|
||||||
.contentPadding="${'8px'}"
|
.contentPadding="${'8px'}"
|
||||||
.button=${html`
|
.button=${html`
|
||||||
<editor-icon-button aria-label="More" .tooltip="${'More'}">
|
<editor-icon-button aria-label="More" .tooltip="${'More'}">
|
||||||
|
|||||||
@@ -29,6 +29,6 @@ export function getEditorConfigExtension(
|
|||||||
}),
|
}),
|
||||||
ToolbarMoreMenuConfigExtension(createToolbarMoreMenuConfig(framework)),
|
ToolbarMoreMenuConfigExtension(createToolbarMoreMenuConfig(framework)),
|
||||||
|
|
||||||
createCustomToolbarExtension(baseUrl),
|
createCustomToolbarExtension(editorSettingService.editorSetting, baseUrl),
|
||||||
].flat();
|
].flat();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
} from '@affine/core/components/hooks/affine/use-share-url';
|
} from '@affine/core/components/hooks/affine/use-share-url';
|
||||||
import { WorkspaceServerService } from '@affine/core/modules/cloud';
|
import { WorkspaceServerService } from '@affine/core/modules/cloud';
|
||||||
import { EditorService } from '@affine/core/modules/editor';
|
import { EditorService } from '@affine/core/modules/editor';
|
||||||
|
import type { EditorSettingExt } from '@affine/core/modules/editor-setting/entities/editor-setting';
|
||||||
import { copyLinkToBlockStdScopeClipboard } from '@affine/core/utils/clipboard';
|
import { copyLinkToBlockStdScopeClipboard } from '@affine/core/utils/clipboard';
|
||||||
import { I18n, i18nTime } from '@affine/i18n';
|
import { I18n, i18nTime } from '@affine/i18n';
|
||||||
import { track } from '@affine/track';
|
import { track } from '@affine/track';
|
||||||
@@ -57,7 +58,6 @@ import {
|
|||||||
GenerateDocUrlProvider,
|
GenerateDocUrlProvider,
|
||||||
isRemovedUserInfo,
|
isRemovedUserInfo,
|
||||||
OpenDocExtensionIdentifier,
|
OpenDocExtensionIdentifier,
|
||||||
type OpenDocMode,
|
|
||||||
type ToolbarAction,
|
type ToolbarAction,
|
||||||
type ToolbarActionGenerator,
|
type ToolbarActionGenerator,
|
||||||
type ToolbarActionGroupGenerator,
|
type ToolbarActionGroupGenerator,
|
||||||
@@ -69,14 +69,11 @@ import {
|
|||||||
import { matchModels } from '@blocksuite/affine/shared/utils';
|
import { matchModels } from '@blocksuite/affine/shared/utils';
|
||||||
import type { ExtensionType } from '@blocksuite/affine/store';
|
import type { ExtensionType } from '@blocksuite/affine/store';
|
||||||
import {
|
import {
|
||||||
CenterPeekIcon,
|
|
||||||
CopyAsImgaeIcon,
|
CopyAsImgaeIcon,
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
EditIcon,
|
EditIcon,
|
||||||
ExpandFullIcon,
|
|
||||||
LinkIcon,
|
LinkIcon,
|
||||||
OpenInNewIcon,
|
OpenInNewIcon,
|
||||||
SplitViewIcon,
|
|
||||||
} from '@blocksuite/icons/lit';
|
} from '@blocksuite/icons/lit';
|
||||||
import { computed } from '@preact/signals-core';
|
import { computed } from '@preact/signals-core';
|
||||||
import type { FrameworkProvider } from '@toeverything/infra';
|
import type { FrameworkProvider } from '@toeverything/infra';
|
||||||
@@ -86,6 +83,7 @@ import { keyed } from 'lit/directives/keyed.js';
|
|||||||
import { repeat } from 'lit/directives/repeat.js';
|
import { repeat } from 'lit/directives/repeat.js';
|
||||||
import { styleMap } from 'lit/directives/style-map.js';
|
import { styleMap } from 'lit/directives/style-map.js';
|
||||||
|
|
||||||
|
import { openDocActions } from '../../open-doc';
|
||||||
import { createCopyAsPngMenuItem } from './copy-as-image';
|
import { createCopyAsPngMenuItem } from './copy-as-image';
|
||||||
|
|
||||||
export function createToolbarMoreMenuConfig(framework: FrameworkProvider) {
|
export function createToolbarMoreMenuConfig(framework: FrameworkProvider) {
|
||||||
@@ -477,39 +475,6 @@ function createExternalLinkableToolbarConfig(
|
|||||||
} as const satisfies ToolbarModuleConfig;
|
} as const satisfies ToolbarModuleConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
const openDocActions = [
|
|
||||||
{
|
|
||||||
mode: 'open-in-active-view',
|
|
||||||
id: 'a.open-in-active-view',
|
|
||||||
label: I18n['com.affine.peek-view-controls.open-doc'](),
|
|
||||||
icon: ExpandFullIcon(),
|
|
||||||
when: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mode: 'open-in-new-view',
|
|
||||||
id: 'b.open-in-new-view',
|
|
||||||
label: I18n['com.affine.peek-view-controls.open-doc-in-split-view'](),
|
|
||||||
icon: SplitViewIcon(),
|
|
||||||
when: BUILD_CONFIG.isElectron,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mode: 'open-in-new-tab',
|
|
||||||
id: 'c.open-in-new-tab',
|
|
||||||
label: I18n['com.affine.peek-view-controls.open-doc-in-new-tab'](),
|
|
||||||
icon: OpenInNewIcon(),
|
|
||||||
when: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mode: 'open-in-center-peek',
|
|
||||||
id: 'd.open-in-center-peek',
|
|
||||||
label: I18n['com.affine.peek-view-controls.open-doc-in-center-peek'](),
|
|
||||||
icon: CenterPeekIcon(),
|
|
||||||
when: true,
|
|
||||||
},
|
|
||||||
] as const satisfies (Pick<ToolbarAction, 'id' | 'label' | 'icon' | 'when'> & {
|
|
||||||
mode: OpenDocMode;
|
|
||||||
})[];
|
|
||||||
|
|
||||||
function createOpenDocActions(
|
function createOpenDocActions(
|
||||||
ctx: ToolbarContext,
|
ctx: ToolbarContext,
|
||||||
target:
|
target:
|
||||||
@@ -517,7 +482,15 @@ function createOpenDocActions(
|
|||||||
| EmbedSyncedDocBlockComponent
|
| EmbedSyncedDocBlockComponent
|
||||||
| AffineReference,
|
| AffineReference,
|
||||||
isSameDoc: boolean,
|
isSameDoc: boolean,
|
||||||
actions = openDocActions
|
actions = openDocActions.map(
|
||||||
|
({ type: mode, label, icon, enabled: when }, i) => ({
|
||||||
|
mode,
|
||||||
|
id: `${i}.${mode}`,
|
||||||
|
label,
|
||||||
|
icon,
|
||||||
|
when,
|
||||||
|
})
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
return actions
|
return actions
|
||||||
.filter(action => action.when)
|
.filter(action => action.when)
|
||||||
@@ -552,7 +525,8 @@ function createOpenDocActions(
|
|||||||
function createOpenDocActionGroup(
|
function createOpenDocActionGroup(
|
||||||
klass:
|
klass:
|
||||||
| typeof EmbedLinkedDocBlockComponent
|
| typeof EmbedLinkedDocBlockComponent
|
||||||
| typeof EmbedSyncedDocBlockComponent
|
| typeof EmbedSyncedDocBlockComponent,
|
||||||
|
settings: EditorSettingExt
|
||||||
): ToolbarAction {
|
): ToolbarAction {
|
||||||
return {
|
return {
|
||||||
placement: ActionPlacement.Start,
|
placement: ActionPlacement.Start,
|
||||||
@@ -562,6 +536,7 @@ function createOpenDocActionGroup(
|
|||||||
if (!block) return null;
|
if (!block) return null;
|
||||||
|
|
||||||
return renderOpenDocMenu(
|
return renderOpenDocMenu(
|
||||||
|
settings,
|
||||||
ctx,
|
ctx,
|
||||||
block,
|
block,
|
||||||
block.model.props.pageId === ctx.store.id
|
block.model.props.pageId === ctx.store.id
|
||||||
@@ -594,6 +569,7 @@ function createEdgelessOpenDocActionGroup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderOpenDocMenu(
|
function renderOpenDocMenu(
|
||||||
|
settings: EditorSettingExt,
|
||||||
ctx: ToolbarContext,
|
ctx: ToolbarContext,
|
||||||
target:
|
target:
|
||||||
| EmbedLinkedDocBlockComponent
|
| EmbedLinkedDocBlockComponent
|
||||||
@@ -607,42 +583,64 @@ function renderOpenDocMenu(
|
|||||||
}));
|
}));
|
||||||
if (!actions.length) return null;
|
if (!actions.length) return null;
|
||||||
|
|
||||||
return html`
|
const currentOpenMode =
|
||||||
${keyed(
|
settings.settingSignal.value.openDocMode ?? 'open-in-active-view';
|
||||||
target,
|
const currentIcon =
|
||||||
html`
|
openDocActions.find(a => a.type === currentOpenMode)?.icon ??
|
||||||
<editor-menu-button
|
OpenInNewIcon();
|
||||||
.contentPadding="${'8px'}"
|
const currentAction = actions.find(a => a.icon === currentIcon) ?? actions[0];
|
||||||
.button=${html`
|
|
||||||
<editor-icon-button aria-label="Open doc" .tooltip=${'Open doc'}>
|
return html`${keyed(
|
||||||
${OpenInNewIcon()} ${EditorChevronDown}
|
target,
|
||||||
</editor-icon-button>
|
html`
|
||||||
`}
|
<editor-icon-button
|
||||||
>
|
aria-label="${currentAction.label}"
|
||||||
<div data-size="small" data-orientation="vertical">
|
.tooltip="${currentAction.label}"
|
||||||
${repeat(
|
@click=${() => currentAction.run?.(ctx)}
|
||||||
actions,
|
>
|
||||||
action => action.id,
|
${currentAction.icon} <span class="label">Open</span>
|
||||||
({ label, icon, run, disabled }) => html`
|
</editor-icon-button>
|
||||||
<editor-menu-action
|
<editor-menu-button
|
||||||
aria-label=${ifDefined(label)}
|
aria-label="Open doc menu"
|
||||||
?disabled=${ifDefined(disabled)}
|
.contentPadding="${'8px'}"
|
||||||
@click=${() => run?.(ctx)}
|
.button=${html`
|
||||||
>
|
<editor-icon-button
|
||||||
${icon}<span class="label">${label}</span>
|
aria-label="Open doc"
|
||||||
</editor-menu-action>
|
.tooltip="${'Open doc'}"
|
||||||
`
|
.iconContainerPadding="${'4'}"
|
||||||
)}
|
>
|
||||||
</div>
|
${EditorChevronDown}
|
||||||
</editor-menu-button>
|
</editor-icon-button>
|
||||||
`
|
`}
|
||||||
)}
|
>
|
||||||
`;
|
<div data-size="small" data-orientation="vertical">
|
||||||
|
${repeat(
|
||||||
|
actions,
|
||||||
|
action => action.id,
|
||||||
|
({ label, icon, run, disabled }) => html`
|
||||||
|
<editor-menu-action
|
||||||
|
aria-label=${ifDefined(label)}
|
||||||
|
?disabled=${ifDefined(disabled)}
|
||||||
|
@click=${() => {
|
||||||
|
run?.(ctx);
|
||||||
|
settings.openDocMode.set(
|
||||||
|
openDocActions.find(a => a.icon === icon)?.type ??
|
||||||
|
'open-in-active-view'
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${icon}<span class="label">${label}</span>
|
||||||
|
</editor-menu-action>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</editor-menu-button>
|
||||||
|
`
|
||||||
|
)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const embedLinkedDocToolbarConfig = {
|
const embedLinkedDocToolbarConfig = {
|
||||||
actions: [
|
actions: [
|
||||||
createOpenDocActionGroup(EmbedLinkedDocBlockComponent),
|
|
||||||
{
|
{
|
||||||
id: 'a.doc-title.after.copy-link-and-edit',
|
id: 'a.doc-title.after.copy-link-and-edit',
|
||||||
actions: [
|
actions: [
|
||||||
@@ -724,7 +722,6 @@ const embedLinkedDocToolbarConfig = {
|
|||||||
|
|
||||||
const embedSyncedDocToolbarConfig = {
|
const embedSyncedDocToolbarConfig = {
|
||||||
actions: [
|
actions: [
|
||||||
createOpenDocActionGroup(EmbedSyncedDocBlockComponent),
|
|
||||||
{
|
{
|
||||||
placement: ActionPlacement.Start,
|
placement: ActionPlacement.Start,
|
||||||
id: 'B.copy-link-and-edit',
|
id: 'B.copy-link-and-edit',
|
||||||
@@ -800,20 +797,6 @@ const embedSyncedDocToolbarConfig = {
|
|||||||
|
|
||||||
const inlineReferenceToolbarConfig = {
|
const inlineReferenceToolbarConfig = {
|
||||||
actions: [
|
actions: [
|
||||||
{
|
|
||||||
placement: ActionPlacement.Start,
|
|
||||||
id: 'A.open-doc',
|
|
||||||
content(ctx) {
|
|
||||||
const target = ctx.message$.peek()?.element;
|
|
||||||
if (!(target instanceof AffineReference)) return null;
|
|
||||||
|
|
||||||
return renderOpenDocMenu(
|
|
||||||
ctx,
|
|
||||||
target,
|
|
||||||
target.referenceInfo.pageId === ctx.store.id
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'b.copy-link-and-edit',
|
id: 'b.copy-link-and-edit',
|
||||||
actions: [
|
actions: [
|
||||||
@@ -957,6 +940,7 @@ const embedIframeToolbarConfig = {
|
|||||||
} as const satisfies ToolbarModuleConfig;
|
} as const satisfies ToolbarModuleConfig;
|
||||||
|
|
||||||
export const createCustomToolbarExtension = (
|
export const createCustomToolbarExtension = (
|
||||||
|
settings: EditorSettingExt,
|
||||||
baseUrl: string
|
baseUrl: string
|
||||||
): ExtensionType[] => {
|
): ExtensionType[] => {
|
||||||
return [
|
return [
|
||||||
@@ -1017,7 +1001,12 @@ export const createCustomToolbarExtension = (
|
|||||||
|
|
||||||
ToolbarModuleExtension({
|
ToolbarModuleExtension({
|
||||||
id: BlockFlavourIdentifier('custom:affine:embed-linked-doc'),
|
id: BlockFlavourIdentifier('custom:affine:embed-linked-doc'),
|
||||||
config: embedLinkedDocToolbarConfig,
|
config: {
|
||||||
|
actions: [
|
||||||
|
embedLinkedDocToolbarConfig.actions,
|
||||||
|
createOpenDocActionGroup(EmbedLinkedDocBlockComponent, settings),
|
||||||
|
].flat(),
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
ToolbarModuleExtension({
|
ToolbarModuleExtension({
|
||||||
@@ -1025,6 +1014,7 @@ export const createCustomToolbarExtension = (
|
|||||||
config: {
|
config: {
|
||||||
actions: [
|
actions: [
|
||||||
embedLinkedDocToolbarConfig.actions,
|
embedLinkedDocToolbarConfig.actions,
|
||||||
|
createOpenDocActionGroup(EmbedLinkedDocBlockComponent, settings),
|
||||||
createEdgelessOpenDocActionGroup(EmbedLinkedDocBlockComponent),
|
createEdgelessOpenDocActionGroup(EmbedLinkedDocBlockComponent),
|
||||||
].flat(),
|
].flat(),
|
||||||
|
|
||||||
@@ -1034,7 +1024,13 @@ export const createCustomToolbarExtension = (
|
|||||||
|
|
||||||
ToolbarModuleExtension({
|
ToolbarModuleExtension({
|
||||||
id: BlockFlavourIdentifier('custom:affine:embed-synced-doc'),
|
id: BlockFlavourIdentifier('custom:affine:embed-synced-doc'),
|
||||||
config: embedSyncedDocToolbarConfig,
|
config: {
|
||||||
|
actions: [
|
||||||
|
embedSyncedDocToolbarConfig.actions,
|
||||||
|
createOpenDocActionGroup(EmbedSyncedDocBlockComponent, settings),
|
||||||
|
createEdgelessOpenDocActionGroup(EmbedSyncedDocBlockComponent),
|
||||||
|
].flat(),
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
ToolbarModuleExtension({
|
ToolbarModuleExtension({
|
||||||
@@ -1042,6 +1038,7 @@ export const createCustomToolbarExtension = (
|
|||||||
config: {
|
config: {
|
||||||
actions: [
|
actions: [
|
||||||
embedSyncedDocToolbarConfig.actions,
|
embedSyncedDocToolbarConfig.actions,
|
||||||
|
createOpenDocActionGroup(EmbedSyncedDocBlockComponent, settings),
|
||||||
createEdgelessOpenDocActionGroup(EmbedSyncedDocBlockComponent),
|
createEdgelessOpenDocActionGroup(EmbedSyncedDocBlockComponent),
|
||||||
].flat(),
|
].flat(),
|
||||||
|
|
||||||
@@ -1051,7 +1048,26 @@ export const createCustomToolbarExtension = (
|
|||||||
|
|
||||||
ToolbarModuleExtension({
|
ToolbarModuleExtension({
|
||||||
id: BlockFlavourIdentifier('custom:affine:reference'),
|
id: BlockFlavourIdentifier('custom:affine:reference'),
|
||||||
config: inlineReferenceToolbarConfig,
|
config: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
placement: ActionPlacement.Start,
|
||||||
|
id: 'A.open-doc',
|
||||||
|
content(ctx) {
|
||||||
|
const target = ctx.message$.peek()?.element;
|
||||||
|
if (!(target instanceof AffineReference)) return null;
|
||||||
|
|
||||||
|
return renderOpenDocMenu(
|
||||||
|
settings,
|
||||||
|
ctx,
|
||||||
|
target,
|
||||||
|
target.referenceInfo.pageId === ctx.store.id
|
||||||
|
);
|
||||||
|
},
|
||||||
|
} as const satisfies ToolbarAction,
|
||||||
|
inlineReferenceToolbarConfig.actions,
|
||||||
|
].flat(),
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
ToolbarModuleExtension({
|
ToolbarModuleExtension({
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { EditorSettingSchema } from '@affine/core/modules/editor-setting';
|
||||||
import { I18n } from '@affine/i18n';
|
import { I18n } from '@affine/i18n';
|
||||||
import {
|
import {
|
||||||
type OpenDocConfig,
|
type OpenDocConfig,
|
||||||
@@ -11,33 +12,45 @@ import {
|
|||||||
SplitViewIcon,
|
SplitViewIcon,
|
||||||
} from '@blocksuite/icons/lit';
|
} from '@blocksuite/icons/lit';
|
||||||
|
|
||||||
|
type OpenDocAction = OpenDocConfigItem & { enabled: boolean };
|
||||||
|
|
||||||
|
export const openDocActions: Array<OpenDocAction> = [
|
||||||
|
{
|
||||||
|
type: 'open-in-active-view',
|
||||||
|
label: I18n['com.affine.peek-view-controls.open-doc'](),
|
||||||
|
icon: ExpandFullIcon(),
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'open-in-new-view',
|
||||||
|
label: I18n['com.affine.peek-view-controls.open-doc-in-split-view'](),
|
||||||
|
icon: SplitViewIcon(),
|
||||||
|
enabled: BUILD_CONFIG.isElectron,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'open-in-new-tab',
|
||||||
|
label: I18n['com.affine.peek-view-controls.open-doc-in-new-tab'](),
|
||||||
|
icon: OpenInNewIcon(),
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'open-in-center-peek',
|
||||||
|
label: I18n['com.affine.peek-view-controls.open-doc-in-center-peek'](),
|
||||||
|
icon: CenterPeekIcon(),
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
].filter(
|
||||||
|
(a): a is OpenDocAction =>
|
||||||
|
a.enabled && EditorSettingSchema.shape.openDocMode.safeParse(a.type).success
|
||||||
|
);
|
||||||
|
|
||||||
export function patchOpenDocExtension() {
|
export function patchOpenDocExtension() {
|
||||||
const openDocConfig: OpenDocConfig = {
|
const openDocConfig: OpenDocConfig = {
|
||||||
items: [
|
items: openDocActions.map<OpenDocConfigItem>(({ type, label, icon }) => ({
|
||||||
{
|
type,
|
||||||
type: 'open-in-active-view',
|
label,
|
||||||
label: I18n['com.affine.peek-view-controls.open-doc'](),
|
icon,
|
||||||
icon: ExpandFullIcon(),
|
})),
|
||||||
},
|
|
||||||
BUILD_CONFIG.isElectron
|
|
||||||
? {
|
|
||||||
type: 'open-in-new-view',
|
|
||||||
label:
|
|
||||||
I18n['com.affine.peek-view-controls.open-doc-in-split-view'](),
|
|
||||||
icon: SplitViewIcon(),
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
{
|
|
||||||
type: 'open-in-new-tab',
|
|
||||||
label: I18n['com.affine.peek-view-controls.open-doc-in-new-tab'](),
|
|
||||||
icon: OpenInNewIcon(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'open-in-center-peek',
|
|
||||||
label: I18n['com.affine.peek-view-controls.open-doc-in-center-peek'](),
|
|
||||||
icon: CenterPeekIcon(),
|
|
||||||
},
|
|
||||||
].filter((item): item is OpenDocConfigItem => item !== null),
|
|
||||||
};
|
};
|
||||||
return OpenDocExtension(openDocConfig);
|
return OpenDocExtension(openDocConfig);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,14 @@ const AffineEditorSettingSchema = z.object({
|
|||||||
edgelessDefaultTheme: z
|
edgelessDefaultTheme: z
|
||||||
.enum(['specified', 'dark', 'light', 'auto'])
|
.enum(['specified', 'dark', 'light', 'auto'])
|
||||||
.default('specified'),
|
.default('specified'),
|
||||||
|
openDocMode: z
|
||||||
|
.enum([
|
||||||
|
'open-in-active-view',
|
||||||
|
'open-in-new-view',
|
||||||
|
'open-in-new-tab',
|
||||||
|
'open-in-center-peek',
|
||||||
|
])
|
||||||
|
.default('open-in-active-view'),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const EditorSettingSchema = BSEditorSettingSchema.merge(
|
export const EditorSettingSchema = BSEditorSettingSchema.merge(
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ test('should update zindex of element when moving it into frame', async ({
|
|||||||
await createEdgelessNoteBlock(page, [500, 500]);
|
await createEdgelessNoteBlock(page, [500, 500]);
|
||||||
await clickView(page, [0, 100]);
|
await clickView(page, [0, 100]);
|
||||||
await clickView(page, [500, 500]);
|
await clickView(page, [500, 500]);
|
||||||
await toolbar.getByLabel('more-menu').click();
|
await toolbar.getByLabel('More menu').click();
|
||||||
await toolbar.getByLabel('Send to Back').click();
|
await toolbar.getByLabel('Send to Back').click();
|
||||||
await pressEscape(page);
|
await pressEscape(page);
|
||||||
|
|
||||||
|
|||||||
@@ -190,8 +190,11 @@ 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$/).click();
|
||||||
await toolbar.getByLabel('Open in center peek').click();
|
await toolbar
|
||||||
|
.getByLabel('Open doc menu')
|
||||||
|
.getByLabel('Open in center peek')
|
||||||
|
.click();
|
||||||
|
|
||||||
const peekView = page.getByTestId('peek-view-modal');
|
const peekView = page.getByTestId('peek-view-modal');
|
||||||
await expect(peekView).toBeVisible();
|
await expect(peekView).toBeVisible();
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ test('not allowed to switch to embed view when linking to block', async ({
|
|||||||
|
|
||||||
await cardLink.click();
|
await cardLink.click();
|
||||||
|
|
||||||
await toolbar.getByLabel('more-menu').click();
|
await toolbar.getByLabel('More menu').click();
|
||||||
await toolbar.getByLabel('Copy link to block').click();
|
await toolbar.getByLabel('Copy link to block').click();
|
||||||
|
|
||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
@@ -1035,3 +1035,89 @@ test.describe('Customize linked doc title and description', () => {
|
|||||||
await expect(a.locator('.affine-reference-title')).toContainText(year);
|
await expect(a.locator('.affine-reference-title')).toContainText(year);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should save open doc mode of internal links', async ({ page }) => {
|
||||||
|
await waitForEditorLoad(page);
|
||||||
|
await enableEmojiDocIcon(page);
|
||||||
|
|
||||||
|
await clickNewPageButton(page);
|
||||||
|
const title = getBlockSuiteEditorTitle(page);
|
||||||
|
await title.click();
|
||||||
|
|
||||||
|
await page.keyboard.press('Enter');
|
||||||
|
await createLinkedPage(page, 'Test Page');
|
||||||
|
|
||||||
|
const { toolbar, switchViewBtn, inlineViewBtn, cardViewBtn, embedViewBtn } =
|
||||||
|
toolbarButtons(page);
|
||||||
|
|
||||||
|
const inlineLink = page.locator('affine-reference');
|
||||||
|
await inlineLink.hover();
|
||||||
|
|
||||||
|
const recentOpenModeBtn = toolbar.getByLabel(/^Open/).nth(0);
|
||||||
|
await expect(recentOpenModeBtn).toHaveAttribute(
|
||||||
|
'aria-label',
|
||||||
|
'Open this doc'
|
||||||
|
);
|
||||||
|
await expect(
|
||||||
|
recentOpenModeBtn.locator('span.label:has-text("Open")')
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
const openDocBtn = toolbar.getByLabel(/^Open doc$/);
|
||||||
|
await openDocBtn.click();
|
||||||
|
|
||||||
|
const openDocMenu = toolbar.getByLabel('Open doc menu');
|
||||||
|
|
||||||
|
const openThisDocBtn = openDocMenu.getByLabel('Open this doc');
|
||||||
|
// In Desktop
|
||||||
|
const openInSplitViewBtn = openDocMenu.getByLabel('Open in split view');
|
||||||
|
const openInNewTabBtn = openDocMenu.getByLabel('Open in new tab');
|
||||||
|
const openInCenterPeekBtn = openDocMenu.getByLabel('Open in center peek');
|
||||||
|
|
||||||
|
await expect(openThisDocBtn).toBeVisible();
|
||||||
|
await expect(openInSplitViewBtn).toBeHidden();
|
||||||
|
await expect(openInNewTabBtn).toBeVisible();
|
||||||
|
await expect(openInCenterPeekBtn).toBeVisible();
|
||||||
|
|
||||||
|
await openInCenterPeekBtn.click();
|
||||||
|
|
||||||
|
await page.keyboard.press('Escape');
|
||||||
|
|
||||||
|
await inlineLink.hover();
|
||||||
|
|
||||||
|
await expect(toolbar).toBeVisible();
|
||||||
|
await expect(recentOpenModeBtn).toHaveAttribute(
|
||||||
|
'aria-label',
|
||||||
|
'Open in center peek'
|
||||||
|
);
|
||||||
|
|
||||||
|
await switchViewBtn.click();
|
||||||
|
await cardViewBtn.click();
|
||||||
|
|
||||||
|
await expect(toolbar).toBeVisible();
|
||||||
|
await expect(recentOpenModeBtn).toHaveAttribute(
|
||||||
|
'aria-label',
|
||||||
|
'Open in center peek'
|
||||||
|
);
|
||||||
|
|
||||||
|
await switchViewBtn.click();
|
||||||
|
await embedViewBtn.click();
|
||||||
|
|
||||||
|
await expect(toolbar).toBeVisible();
|
||||||
|
await expect(recentOpenModeBtn).toHaveAttribute(
|
||||||
|
'aria-label',
|
||||||
|
'Open in center peek'
|
||||||
|
);
|
||||||
|
|
||||||
|
await switchViewBtn.click();
|
||||||
|
await inlineViewBtn.click();
|
||||||
|
|
||||||
|
await inlineLink.hover();
|
||||||
|
|
||||||
|
await page.waitForTimeout(250);
|
||||||
|
|
||||||
|
await expect(toolbar).toBeVisible();
|
||||||
|
await expect(recentOpenModeBtn).toHaveAttribute(
|
||||||
|
'aria-label',
|
||||||
|
'Open in center peek'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -26,9 +26,11 @@ 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();
|
||||||
|
|
||||||
// click more button
|
await toolbar.getByLabel(/^Open doc$/).click();
|
||||||
await toolbar.getByLabel('Open doc').click();
|
await toolbar
|
||||||
await toolbar.getByLabel('Open in center peek').click();
|
.getByLabel('Open doc menu')
|
||||||
|
.getByLabel('Open in center peek')
|
||||||
|
.click();
|
||||||
|
|
||||||
// verify peek view is opened
|
// verify peek view is opened
|
||||||
await expect(page.getByTestId('peek-view-modal')).toBeVisible();
|
await expect(page.getByTestId('peek-view-modal')).toBeVisible();
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ test.describe('frame copy and paste', () => {
|
|||||||
|
|
||||||
await frameTitles.nth(0).click();
|
await frameTitles.nth(0).click();
|
||||||
|
|
||||||
const moreMenu = page.getByLabel('more-menu');
|
const moreMenu = page.getByLabel('More menu');
|
||||||
|
|
||||||
await moreMenu.click();
|
await moreMenu.click();
|
||||||
await moreMenu
|
await moreMenu
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ test('duplicate note should work correctly', async ({ page }) => {
|
|||||||
|
|
||||||
await triggerComponentToolbarAction(page, 'duplicate');
|
await triggerComponentToolbarAction(page, 'duplicate');
|
||||||
await waitNextFrame(page, 200); // wait viewport fit animation
|
await waitNextFrame(page, 200); // wait viewport fit animation
|
||||||
const moreActionsContainer = page.getByLabel('more-menu').getByRole('menu');
|
const moreActionsContainer = page.getByLabel('More menu').getByRole('menu');
|
||||||
await expect(moreActionsContainer).toBeHidden();
|
await expect(moreActionsContainer).toBeHidden();
|
||||||
|
|
||||||
const noteLocator = page.locator('affine-edgeless-note');
|
const noteLocator = page.locator('affine-edgeless-note');
|
||||||
|
|||||||
@@ -797,7 +797,7 @@ export async function updateExistedBrushElementSize(
|
|||||||
export async function openComponentToolbarMoreMenu(page: Page) {
|
export async function openComponentToolbarMoreMenu(page: Page) {
|
||||||
const btn = page
|
const btn = page
|
||||||
.locator('affine-toolbar-widget editor-toolbar')
|
.locator('affine-toolbar-widget editor-toolbar')
|
||||||
.getByLabel('more-menu');
|
.getByLabel('More menu');
|
||||||
|
|
||||||
await btn.click();
|
await btn.click();
|
||||||
}
|
}
|
||||||
@@ -1023,7 +1023,7 @@ export function locatorComponentToolbar(page: Page) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function locatorComponentToolbarMoreButton(page: Page) {
|
export function locatorComponentToolbarMoreButton(page: Page) {
|
||||||
const moreButton = locatorComponentToolbar(page).getByLabel('more-menu');
|
const moreButton = locatorComponentToolbar(page).getByLabel('More menu');
|
||||||
return moreButton;
|
return moreButton;
|
||||||
}
|
}
|
||||||
type Action =
|
type Action =
|
||||||
|
|||||||
Reference in New Issue
Block a user