import { popupTargetFromElement } from '@blocksuite/affine-components/context-menu'; import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit'; import { CenterPeekIcon, MoreHorizontalIcon } from '@blocksuite/icons/lit'; import { ShadowlessElement } from '@blocksuite/std'; import { signal } from '@preact/signals-core'; import { cssVarV2 } from '@toeverything/theme/v2'; import { css, unsafeCSS } from 'lit'; import { property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { repeat } from 'lit/directives/repeat.js'; import { html } from 'lit/static-html.js'; import type { KanbanColumn } from '../kanban-view-manager.js'; import type { KanbanViewUILogic } from './kanban-view-ui-logic.js'; import { openDetail, popCardMenu } from './menu.js'; const styles = css` affine-data-view-kanban-card { display: flex; position: relative; flex-direction: column; border: 1px solid ${unsafeCSS(cssVarV2.layer.insideBorder.border)}; box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.05); border-radius: 8px; transition: background-color 100ms ease-in-out; background-color: var(--affine-background-kanban-card-color); } affine-data-view-kanban-card:hover { background-color: var(--affine-hover-color); } affine-data-view-kanban-card .card-header { padding: 8px; display: flex; flex-direction: column; gap: 8px; } affine-data-view-kanban-card .card-header-title uni-lit { width: 100%; } .card-header.has-divider { border-bottom: 0.5px solid ${unsafeCSS(cssVarV2.layer.insideBorder.border)}; } affine-data-view-kanban-card .card-header-title { font-size: var(--data-view-cell-text-size); line-height: var(--data-view-cell-text-line-height); } affine-data-view-kanban-card .card-header-icon { padding: 4px; background-color: var(--affine-background-secondary-color); display: flex; align-items: center; border-radius: 4px; width: max-content; } affine-data-view-kanban-card .card-header-icon svg { width: 16px; height: 16px; fill: var(--affine-icon-color); color: var(--affine-icon-color); } affine-data-view-kanban-card .card-body { display: flex; flex-direction: column; padding: 8px; gap: 4px; } affine-data-view-kanban-card:hover .card-ops { visibility: visible; } affine-data-view-kanban-card:has(.active) .card-ops { visibility: visible; } affine-data-view-kanban-card:has([data-editing='true']) .card-ops { visibility: hidden; } .card-ops { position: absolute; right: 8px; top: 8px; visibility: hidden; display: flex; gap: 4px; cursor: pointer; } .card-op { display: flex; position: relative; padding: 4px; border-radius: 4px; box-shadow: 0px 0px 4px 0px rgba(66, 65, 73, 0.14); background-color: var(--affine-background-primary-color); } .card-op:hover:before { content: ''; border-radius: 4px; position: absolute; left: 0; right: 0; top: 0; bottom: 0; background-color: var(--affine-hover-color); } .card-op svg { fill: var(--affine-icon-color); color: var(--affine-icon-color); width: 16px; height: 16px; } `; export class KanbanCard extends SignalWatcher( WithDisposable(ShadowlessElement) ) { static override styles = styles; private readonly clickEdit = (e: MouseEvent) => { e.stopPropagation(); const selection = this.getSelection(); if (selection) { openDetail(this.kanbanViewLogic, this.cardId, selection); } }; private readonly clickMore = (e: MouseEvent) => { e.stopPropagation(); const selection = this.getSelection(); const ele = e.currentTarget as HTMLElement; if (selection) { selection.selection = { selectionType: 'card', cards: [ { groupKey: this.groupKey, cardId: this.cardId, }, ], }; popCardMenu( this.kanbanViewLogic, popupTargetFromElement(ele), this.cardId, selection ); } }; private readonly contextMenu = (e: MouseEvent) => { e.stopPropagation(); e.preventDefault(); const selection = this.getSelection(); if (selection) { selection.selection = { selectionType: 'card', cards: [ { groupKey: this.groupKey, cardId: this.cardId, }, ], }; const target = e.target as HTMLElement; const ref = target.closest('affine-data-view-kanban-cell') ?? this; popCardMenu( this.kanbanViewLogic, popupTargetFromElement(ref), this.cardId, selection ); } }; private getSelection() { return this.kanbanViewLogic.selectionController; } private renderBody(columns: KanbanColumn[]) { if (columns.length === 0) { return ''; } return html`