fix(core): add shortcuts to open doc dropdown menu (#11358)

Closes: [BS-2992](https://linear.app/affine-design/issue/BS-2992/走查toolbar上的open-in-button)

[Screen Recording 2025-04-01 at 16.37.57.mov <span class="graphite__hidden">(uploaded via Graphite)</span> <img class="graphite__hidden" src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/8ypiIKZXudF5a0tIgIzf/cf4b1baf-aa2c-4f37-9c62-f7202d0f7c42.mov" />](https://app.graphite.dev/media/video/8ypiIKZXudF5a0tIgIzf/cf4b1baf-aa2c-4f37-9c62-f7202d0f7c42.mov)
This commit is contained in:
fundon
2025-04-01 12:39:13 +00:00
parent bd30a73db8
commit f374f2695f
8 changed files with 184 additions and 86 deletions

View File

@@ -0,0 +1,121 @@
import {
type OpenDocMode,
type ToolbarAction,
ToolbarContext,
} from '@blocksuite/affine-shared/services';
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
import { PropTypes, requiredProperties } from '@blocksuite/std';
import type { ReadonlySignal } from '@preact/signals-core';
import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import { ifDefined } from 'lit-html/directives/if-defined.js';
import { repeat } from 'lit-html/directives/repeat.js';
import { EditorChevronDown } from '../toolbar';
@requiredProperties({
actions: PropTypes.array,
context: PropTypes.instanceOf(ToolbarContext),
openDocMode$: PropTypes.object,
updateOpenDocMode: PropTypes.instanceOf(Function),
})
export class OpenDocDropdownMenu extends SignalWatcher(
WithDisposable(LitElement)
) {
static override styles = css`
div[data-orientation] {
width: 264px;
gap: 4px;
min-width: unset;
overflow: unset;
}
editor-menu-action {
.label {
display: flex;
flex: 1;
justify-content: space-between;
}
.shortcut {
color: ${unsafeCSSVarV2('text/secondary')};
}
}
`;
@property({ attribute: false })
accessor actions!: (ToolbarAction & {
mode: OpenDocMode;
shortcut?: string;
})[];
@property({ attribute: false })
accessor context!: ToolbarContext;
@property({ attribute: false })
accessor openDocMode$!: ReadonlySignal<OpenDocMode>;
@property({ attribute: false })
accessor updateOpenDocMode!: (mode: OpenDocMode) => void;
override render() {
const {
actions,
context,
openDocMode$: { value: openDocMode },
updateOpenDocMode,
} = this;
const currentAction =
actions.find(a => a.mode === openDocMode) ?? actions[0];
return html`
<editor-menu-button
aria-label="Open doc menu"
.contentPadding="${'8px'}"
.button=${html`
<editor-icon-button
data-open-doc-mode="${currentAction.label}"
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>
`}
>
<div data-orientation="vertical">
${repeat(
actions,
action => action.id,
({ label, icon, run, disabled, mode, shortcut }) => html`
<editor-menu-action
aria-label=${ifDefined(label)}
?disabled=${ifDefined(disabled)}
@click=${() => {
run?.(context);
updateOpenDocMode(mode);
}}
>
${icon}
<div class="label">
${label}
<span class="shortcut">${shortcut}</span>
</div>
</editor-menu-action>
`
)}
</div>
</editor-menu-button>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'affine-open-doc-dropdown-menu': OpenDocDropdownMenu;
}
}

View File

@@ -0,0 +1,7 @@
import { OpenDocDropdownMenu } from './dropdown-menu';
export * from './dropdown-menu';
export function effects() {
customElements.define('affine-open-doc-dropdown-menu', OpenDocDropdownMenu);
}