Skip to content

Commit

Permalink
feat(database): title cell open center peek (#8590)
Browse files Browse the repository at this point in the history
close: BS-1616
  • Loading branch information
zzj3720 committed Oct 24, 2024
1 parent b17901e commit 4d028bb
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 83 deletions.
8 changes: 8 additions & 0 deletions packages/affine/data-view/src/core/common/detail/detail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { DetailSelection } from './selection.js';
export type DetailSlotProps = {
view: SingleView;
rowId: string;
openDoc: (docId: string) => void;
};

export interface DetailSlots {
Expand Down Expand Up @@ -143,6 +144,7 @@ export class RecordDetail extends SignalWatcher(
const props: DetailSlotProps = {
view: this.view,
rowId: this.rowId,
openDoc: this.openDoc,
};
return renderUniLit(header, props);
}
Expand All @@ -155,6 +157,7 @@ export class RecordDetail extends SignalWatcher(
const props: DetailSlotProps = {
view: this.view,
rowId: this.rowId,
openDoc: this.openDoc,
};
return renderUniLit(note, props);
}
Expand Down Expand Up @@ -256,6 +259,9 @@ export class RecordDetail extends SignalWatcher(
@property({ attribute: false })
accessor detailSlots: DetailSlots | undefined;

@property({ attribute: false })
accessor openDoc!: (docId: string) => void;

@property({ attribute: false })
accessor rowId!: string;

Expand All @@ -272,11 +278,13 @@ export const createRecordDetail = (ops: {
view: SingleView;
rowId: string;
detail: DetailSlots;
openDoc: (docId: string) => void;
}) => {
return html` <affine-data-view-record-detail
.view=${ops.view}
.rowId=${ops.rowId}
.detailSlots=${ops.detail}
.openDoc=${ops.openDoc}
class="data-view-popup-container"
></affine-data-view-record-detail>`;
};
2 changes: 0 additions & 2 deletions packages/affine/model/src/blocks/database/database-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ export type DatabaseBlockProps = {
title: Text;
cells: SerializedCells;
columns: Array<Column>;
// rowId -> pageId
notes?: Record<string, string>;
};

export class DatabaseBlockModel extends BlockModel<DatabaseBlockProps> {}
Expand Down
1 change: 1 addition & 0 deletions packages/blocks/src/data-view-block/data-view-block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ export class DataViewBlockComponent extends CaptionedBlockComponent<DataViewBloc
if (peekViewService) {
const template = createRecordDetail({
...data,
openDoc: () => {},
detail: {
header: uniMap(
createUniComponentFromWebComponent(BlockRenderer),
Expand Down
89 changes: 64 additions & 25 deletions packages/blocks/src/database-block/database-block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
type DataViewWidgetProps,
defineUniComponent,
renderUniLit,
type SingleView,
uniMap,
} from '@blocksuite/data-view';
import { widgetPresets } from '@blocksuite/data-view/widget-presets';
Expand Down Expand Up @@ -52,7 +53,10 @@ import { popSideDetail } from './components/layout.js';
import { HostContextKey } from './context/host-context.js';
import { DatabaseBlockDataSource } from './data-source.js';
import { BlockRenderer } from './detail-panel/block-renderer.js';
import { NoteRenderer } from './detail-panel/note-renderer.js';
import {
getDocIdsFromText,
NoteRenderer,
} from './detail-panel/note-renderer.js';

export class DatabaseBlockComponent extends CaptionedBlockComponent<
DatabaseBlockModel,
Expand Down Expand Up @@ -178,6 +182,36 @@ export class DatabaseBlockComponent extends CaptionedBlockComponent<
};
};

createTemplate = (
data: {
view: SingleView;
rowId: string;
},
openDoc: (docId: string) => void
) => {
return createRecordDetail({
...data,
openDoc,
detail: {
header: uniMap(
createUniComponentFromWebComponent(BlockRenderer),
props => ({
...props,
host: this.host,
})
),
note: uniMap(
createUniComponentFromWebComponent(NoteRenderer),
props => ({
...props,
model: this.model,
host: this.host,
})
),
},
});
};

getRootService = () => {
return this.std.getService<RootService>('affine:page');
};
Expand Down Expand Up @@ -364,33 +398,38 @@ export class DatabaseBlockComponent extends CaptionedBlockComponent<
std: this.std,
detailPanelConfig: {
openDetailPanel: (target, data) => {
const template = createRecordDetail({
...data,
detail: {
header: uniMap(
createUniComponentFromWebComponent(BlockRenderer),
props => ({
...props,
host: this.host,
})
),
note: uniMap(
createUniComponentFromWebComponent(NoteRenderer),
props => ({
...props,
model: this.model,
host: this.host,
})
),
},
});
if (peekViewService) {
return peekViewService.peek({
target,
template,
const openDoc = (docId: string) => {
return peekViewService.peek({ docId });
};
const docs = getDocIdsFromText(
this.model.doc.getBlock(data.rowId)?.model?.text
);
if (docs.length === 1) {
return openDoc(docs[0]);
}
const abort = new AbortController();
return new Promise<void>(focusBack => {
peekViewService
.peek(
{
target,
template: this.createTemplate(data, docId => {
// abort.abort();
openDoc(docId).then(focusBack).catch(focusBack);
}),
},
{ abortSignal: abort.signal }
)
.then(focusBack)
.catch(focusBack);
});
} else {
return popSideDetail(template);
return popSideDetail(
this.createTemplate(data, () => {
//
})
);
}
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ export class BlockRenderer
@property({ attribute: false })
accessor host!: EditorHost;

@property({ attribute: false })
accessor openDoc!: (docId: string) => void;

@property({ attribute: false })
accessor rowId!: string;

Expand Down
115 changes: 60 additions & 55 deletions packages/blocks/src/database-block/detail-panel/note-renderer.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
import type { DatabaseBlockModel } from '@blocksuite/affine-model';
import type {
DatabaseBlockModel,
RootBlockModel,
} from '@blocksuite/affine-model';
import type { DetailSlotProps, SingleView } from '@blocksuite/data-view';
import type { BaseTextAttributes } from '@blocksuite/inline';
import type { Text } from '@blocksuite/store';

import { focusTextModel } from '@blocksuite/affine-components/rich-text';
import {
type AffineTextAttributes,
REFERENCE_NODE,
} from '@blocksuite/affine-components/rich-text';
import {
createDefaultDoc,
matchFlavours,
} from '@blocksuite/affine-shared/utils';
import {
BlockStdScope,
type EditorHost,
ShadowlessElement,
} from '@blocksuite/block-std';
import { WithDisposable } from '@blocksuite/global/utils';
import { type EditorHost, ShadowlessElement } from '@blocksuite/block-std';
import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
import { computed } from '@preact/signals-core';
import { css, html } from 'lit';
import { property, query } from 'lit/decorators.js';
import { property } from 'lit/decorators.js';

export const getDocIdsFromText = (text?: Text) => {
return (
text?.deltas$.value
?.filter(delta => {
const attributes: AffineTextAttributes | undefined = delta.attributes;
return attributes?.reference?.type === 'LinkedPage';
})
?.map(delta => delta.attributes?.reference?.pageId as string) ?? []
);
};

export class NoteRenderer
extends WithDisposable(ShadowlessElement)
extends SignalWatcher(WithDisposable(ShadowlessElement))
implements DetailSlotProps
{
static override styles = css`
Expand All @@ -26,6 +43,15 @@ export class NoteRenderer
}
`;

allowCreateDoc$ = computed(() => {
console.log(this.rowText$.value, getDocIdsFromText(this.rowText$.value));
return getDocIdsFromText(this.rowText$.value).length === 0;
});

rowText$ = computed(() => {
return this.databaseBlock.doc.getBlock(this.rowId)?.model?.text;
});

get databaseBlock(): DatabaseBlockModel {
return this.model;
}
Expand All @@ -35,15 +61,25 @@ export class NoteRenderer
if (!collection) {
return;
}
if (!this.databaseBlock.notes) {
this.databaseBlock.notes = {};
}
const note = createDefaultDoc(collection);
if (note) {
this.databaseBlock.notes[this.rowId] = note.id;
this.requestUpdate();
requestAnimationFrame(() => {
const block = note.root?.children
this.openDoc(note.id);
const rowContent = this.rowText$.value?.toString();
this.rowText$.value?.replace(
0,
this.rowText$.value.length,
REFERENCE_NODE,
{
reference: {
type: 'LinkedPage',
pageId: note.id,
},
} satisfies AffineTextAttributes as BaseTextAttributes
);
collection.setDocMeta(note.id, { title: rowContent });
if (note.root) {
(note.root as RootBlockModel).title.insert(rowContent ?? '', 0);
note.root.children
.find(child => child.flavour === 'affine:note')
?.children.find(block =>
matchFlavours(block, [
Expand All @@ -52,28 +88,11 @@ export class NoteRenderer
'affine:code',
])
);
if (this.subHost && block) {
focusTextModel(this.subHost.std, block.id);
}
});
}
}

override connectedCallback() {
super.connectedCallback();
this.databaseBlock.propsUpdated.on(({ key }) => {
if (key === 'notes') {
this.requestUpdate();
}
});
}
}

protected override render(): unknown {
if (
!this.model.doc.awarenessStore.getFlag('enable_database_attachment_note')
) {
return null;
}
return html`
<div
style="height: 1px;max-width: var(--affine-editor-width);background-color: var(--affine-border-color);margin: auto;margin-bottom: 16px"
Expand All @@ -83,31 +102,17 @@ export class NoteRenderer
}

renderNote() {
const host = this.host;
const std = host?.std;
if (!std || !host) {
return;
}
const pageId = this.databaseBlock.notes?.[this.rowId];
if (!pageId) {
if (this.allowCreateDoc$.value) {
return html` <div>
<div
@click="${this.addNote}"
style="max-width: var(--affine-editor-width);margin: auto;cursor: pointer;color: var(--affine-text-disable-color)"
>
Click to add note
Click to create a linked doc in center peek.
</div>
</div>`;
}
const page = std.collection.getDoc(pageId);
if (!page) {
return;
}
const previewStd = new BlockStdScope({
doc: page,
extensions: std.userExtensions,
});
return html`${previewStd.render()} `;
return;
}

@property({ attribute: false })
Expand All @@ -117,10 +122,10 @@ export class NoteRenderer
accessor model!: DatabaseBlockModel;

@property({ attribute: false })
accessor rowId!: string;
accessor openDoc!: (docId: string) => void;

@query('editor-host')
accessor subHost!: EditorHost;
@property({ attribute: false })
accessor rowId!: string;

@property({ attribute: false })
accessor view!: SingleView;
Expand Down
3 changes: 2 additions & 1 deletion packages/framework/store/src/reactive/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface OptionalAttributes {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
attributes?: Record<string, any>;
}

export type DeltaOperation = {
insert?: string;
delete?: number;
Expand Down Expand Up @@ -67,7 +68,7 @@ export class Text {
}

this._length$ = signal(length);
this._deltas$ = signal([]);
this._deltas$ = signal(this._yText.doc ? this._yText.toDelta() : []);
this._yText.observe(() => {
this._length$.value = this._yText.length;
this._deltas$.value = this._yText.toDelta();
Expand Down

0 comments on commit 4d028bb

Please sign in to comment.