import { ShadowlessElement, WithDisposable } from '@blockeditor/lit'; import { css, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { repeat } from 'lit/directives/repeat.js'; import { popFilterableSimpleMenu, popMenu, } from '../../../_common/components/menu/index.js'; import { renderUniLit } from '../../../_common/components/uni-component/uni-component.js'; import { AddCursorIcon, DeleteIcon, DuplicateIcon, MoveLeftIcon, MoveRightIcon, } from '../../../_common/icons/index.js'; import { viewManager, viewRendererManager } from '../data-view.js'; import type { ViewSource } from '../view-source.js'; @customElement('data-view-header-views') export class DataViewHeaderViews extends WithDisposable(ShadowlessElement) { static override styles = css` data-view-header-views { height: 32px; display: flex; user-select: none; gap: 4px; } data-view-header-views::-webkit-scrollbar-thumb { width: 1px; } .database-view-button { cursor: pointer; padding: 4px 8px; border-radius: 4px; font-size: 14px; display: flex; align-items: center; color: var(--affine-text-secondary-color); white-space: nowrap; } .database-view-button .name { display: flex; align-items: center; height: 22px; max-width: 100px; overflow: hidden; text-overflow: ellipsis; } .database-view-button .icon { margin-right: 6px; display: block; } .database-view-button .icon svg { width: 16px; height: 16px; } .database-view-button.active { color: var(--affine-text-primary-color); background-color: var(--affine-hover-color-filled); } `; @property({ attribute: false }) viewSource!: ViewSource; get readonly() { return this.viewSource.readonly; } _addViewMenu(event: MouseEvent) { popFilterableSimpleMenu( event.target as HTMLElement, viewManager.all.map(v => { return { type: 'action', name: v.defaultName, icon: html``, select: () => { const id = this.viewSource.viewAdd(v.type); this.viewSource.selectView(id); }, }; }) ); } _showMore(event: MouseEvent) { const views = this.viewSource.views; popFilterableSimpleMenu(event.target as HTMLElement, [ ...views.map(v => ({ type: 'action' as const, icon: html``, name: v.view.name, isSelected: this.viewSource.currentViewId === v.view.id, select: () => { this.viewSource.selectView(v.view.id); }, })), { type: 'group', name: '', hide: () => this.readonly, children: () => viewManager.all.map(v => { return { type: 'action', name: `Create ${v.defaultName}`, icon: html``, select: () => { const id = this.viewSource.viewAdd(v.type); this.viewSource.selectView(id); }, }; }), }, ]); } _clickView(event: MouseEvent, id: string) { if (this.viewSource.currentViewId !== id) { this.viewSource.selectView(id); return; } if (this.readonly) { return; } const views = this.viewSource.views; const index = views.findIndex(v => v.view.id === id); const view = views[index]; if (!view) { return; } popMenu(event.target as HTMLElement, { options: { input: { initValue: view.view.name, onComplete: text => { view.updateView(_data => ({ name: text, })); }, }, items: [ { type: 'action', name: 'Edit View', icon: renderUniLit( viewRendererManager.getView(view.view.mode).icon, {} ), select: () => { this.closest('affine-data-view-native') ?.querySelector('data-view-header-tools-view-options') ?.clickMoreAction(event); }, }, { type: 'action', name: 'Move Left', hide: () => index === 0, icon: MoveLeftIcon, select: () => { const target = views[index - 1]; this.viewSource.moveTo( view.view.id, target ? { before: true, id: target.view.id } : 'start' ); }, }, { type: 'action', name: 'Move Right', icon: MoveRightIcon, hide: () => index === views.length - 1, select: () => { const target = views[index + 1]; this.viewSource.moveTo( view.view.id, target ? { before: false, id: target.view.id } : 'end' ); }, }, { type: 'action', name: 'Duplicate', icon: DuplicateIcon, select: () => { this.viewSource.duplicate(view.view.id); }, }, { type: 'group', name: '', children: () => [ { type: 'action', name: 'Delete View', icon: DeleteIcon, select: () => { view.delete(); }, class: 'delete-item', }, ], }, ], }, }); } override connectedCallback() { super.connectedCallback(); this.disposables.add( this.viewSource.updateSlot.on(() => { this.requestUpdate(); }) ); } renderMore() { const views = this.viewSource.views; if (views.length <= 3) { if (this.readonly) { return; } return html`
${AddCursorIcon}
`; } return html`
${views.length - 3} More
`; } override render() { const views = this.viewSource.views; const i = views.findIndex(v => v.view.id === this.viewSource.currentViewId); const needShow = i > 2 ? [...views.slice(0, 2), views[i]] : views.slice(0, 3); return html` ${repeat( needShow, v => v.view.id, view => { const classList = classMap({ 'database-view-button': true, 'dv-hover': true, active: this.viewSource.currentViewId === view.view.id, }); return html`
${view.view.name}
`; } )} ${this.renderMore()} `; } } declare global { interface HTMLElementTagNameMap { 'data-view-header-views': DataViewHeaderViews; } }