mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 21:05:19 +00:00
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`.
138 lines
3.5 KiB
TypeScript
138 lines
3.5 KiB
TypeScript
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 { computed, 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`
|
|
:host {
|
|
display: flex;
|
|
gap: unset !important;
|
|
}
|
|
|
|
editor-icon-button {
|
|
.label {
|
|
font-weight: 400;
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
currentAction$ = computed(() => {
|
|
const currentOpenDocMode = this.openDocMode$.value;
|
|
return (
|
|
this.actions.find(a => a.mode === currentOpenDocMode) ?? this.actions[0]
|
|
);
|
|
});
|
|
|
|
override render() {
|
|
const {
|
|
actions,
|
|
context,
|
|
updateOpenDocMode,
|
|
currentAction$: { value: currentAction },
|
|
} = this;
|
|
|
|
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
|
|
aria-label="Open doc menu"
|
|
.contentPadding="${'8px'}"
|
|
.button=${html`
|
|
<editor-icon-button aria-label="Open doc with">
|
|
${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;
|
|
}
|
|
}
|