diff --git a/blocksuite/affine/blocks/paragraph/src/paragraph-block.ts b/blocksuite/affine/blocks/paragraph/src/paragraph-block.ts index 4f8edd2a01..4fe9c98a4b 100644 --- a/blocksuite/affine/blocks/paragraph/src/paragraph-block.ts +++ b/blocksuite/affine/blocks/paragraph/src/paragraph-block.ts @@ -28,6 +28,7 @@ import { query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { styleMap } from 'lit/directives/style-map.js'; import { unsafeHTML } from 'lit/directives/unsafe-html.js'; +import { repeat } from 'lit/directives/repeat.js'; import { ParagraphBlockConfigExtension } from './paragraph-block-config.js'; import { paragraphBlockStyles } from './styles.js'; @@ -227,6 +228,12 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent { + const widgets = html`${repeat( + Object.entries(this.widgets), + ([id]) => id, + ([_, widget]) => widget + )}`; + const { type$ } = this.model.props; const collapsed = this.store.readonly ? this._readonlyCollapsed @@ -341,6 +348,7 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent ${children} + ${widgets} `; } diff --git a/packages/frontend/core/src/blocksuite/ai/effects.ts b/packages/frontend/core/src/blocksuite/ai/effects.ts index 8832858c25..bb2e569c46 100644 --- a/packages/frontend/core/src/blocksuite/ai/effects.ts +++ b/packages/frontend/core/src/blocksuite/ai/effects.ts @@ -71,6 +71,7 @@ import { } from './widgets/ai-panel/components'; import { AIFinishTip } from './widgets/ai-panel/components/finish-tip'; import { GeneratingPlaceholder } from './widgets/ai-panel/components/generating-placeholder'; +import { AFFINE_BLOCK_DIFF_WIDGET, AffineBlockDiffWidget } from './widgets/block-diff/widget'; import { AFFINE_EDGELESS_COPILOT_WIDGET, EdgelessCopilotWidget, @@ -158,6 +159,7 @@ export function registerAIEffects() { customElements.define(AFFINE_AI_PANEL_WIDGET, AffineAIPanelWidget); customElements.define(AFFINE_EDGELESS_COPILOT_WIDGET, EdgelessCopilotWidget); + customElements.define(AFFINE_BLOCK_DIFF_WIDGET, AffineBlockDiffWidget); customElements.define('edgeless-copilot-panel', EdgelessCopilotPanel); customElements.define( diff --git a/packages/frontend/core/src/blocksuite/ai/services/block-diff.ts b/packages/frontend/core/src/blocksuite/ai/services/block-diff.ts new file mode 100644 index 0000000000..1d82291c52 --- /dev/null +++ b/packages/frontend/core/src/blocksuite/ai/services/block-diff.ts @@ -0,0 +1,52 @@ +import { createIdentifier } from '@blocksuite/global/di'; +import type { PatchOp } from '../utils/apply-model/markdown-diff'; + +interface DiffMap { + // removed blocks + deletes: string[]; + // inserted blocks + // key is the start block id, value is the blocks(markdowns) inserted + inserts: Record; + // updated blocks + // key is the block id, value is the block(markdown) + updates: Record; +} + +export interface BlockDiffService { + /** + * Set the patches to the block diffs + * @param patches - The patches to set. + * @returns The diff map. + */ + setPatches(patches: PatchOp[]): DiffMap; +} + +export const BlockDiffService = createIdentifier( + 'AffineBlockDiffService' +); + +export class BlockDiffServiceImpl implements BlockDiffService { + setPatches(patches: PatchOp[]): DiffMap { + const diffMap: DiffMap = { + deletes: [], + inserts: {}, + updates: {}, + }; + + for (const patch of patches) { + switch (patch.op) { + case 'delete': + diffMap.deletes.push(patch.block_id); + break; + case 'insert_at': + diffMap.inserts[patch.new_block.id] = [patch.new_block.content]; + break; + case 'replace': + diffMap.updates[patch.block_id] = patch.new_content; + break; + } + } + + return diffMap; + } +} diff --git a/packages/frontend/core/src/blocksuite/ai/widgets/ai-panel/ai-panel.ts b/packages/frontend/core/src/blocksuite/ai/widgets/ai-panel/ai-panel.ts index 7555cdd84b..c9e59957df 100644 --- a/packages/frontend/core/src/blocksuite/ai/widgets/ai-panel/ai-panel.ts +++ b/packages/frontend/core/src/blocksuite/ai/widgets/ai-panel/ai-panel.ts @@ -505,6 +505,7 @@ export class AffineAIPanelWidget extends WidgetComponent { } override render() { + console.log if (this.state === 'hidden') { return nothing; } diff --git a/packages/frontend/core/src/blocksuite/ai/widgets/block-diff/widget.ts b/packages/frontend/core/src/blocksuite/ai/widgets/block-diff/widget.ts new file mode 100644 index 0000000000..16dfa7a8c9 --- /dev/null +++ b/packages/frontend/core/src/blocksuite/ai/widgets/block-diff/widget.ts @@ -0,0 +1,23 @@ +import { WidgetComponent, WidgetViewExtension } from '@blocksuite/affine/std'; +import { html } from 'lit'; +import { literal, unsafeStatic } from 'lit/static-html.js'; + +export const AFFINE_BLOCK_DIFF_WIDGET = 'affine-block-diff-widget'; + +export class AffineBlockDiffWidget extends WidgetComponent { + override render() { + const attached = this.block?.blockId; + return html`
+

Block Diff

+
`; + } +} + +export const blockDiffWidget = WidgetViewExtension( + 'affine:paragraph', + AFFINE_BLOCK_DIFF_WIDGET, + literal`${unsafeStatic(AFFINE_BLOCK_DIFF_WIDGET)}` +); diff --git a/packages/frontend/core/src/blocksuite/view-extensions/ai/index.ts b/packages/frontend/core/src/blocksuite/view-extensions/ai/index.ts index 8f82676eed..4f5410206b 100644 --- a/packages/frontend/core/src/blocksuite/view-extensions/ai/index.ts +++ b/packages/frontend/core/src/blocksuite/view-extensions/ai/index.ts @@ -20,6 +20,7 @@ import { FrameworkProvider } from '@toeverything/infra'; import { z } from 'zod'; import { EdgelessClipboardAIChatConfig } from './edgeless-clipboard'; +import { blockDiffWidget } from '../../ai/widgets/block-diff/widget'; const optionsSchema = z.object({ enable: z.boolean().optional(), @@ -50,6 +51,8 @@ export class AIViewExtension extends ViewExtensionProvider { config: imageToolbarAIEntryConfig(), }) ); + + if (context.scope === 'edgeless' || context.scope === 'page') { context.register([ aiPanelWidget, @@ -73,6 +76,7 @@ export class AIViewExtension extends ViewExtensionProvider { ]); } if (context.scope === 'page') { + context.register(blockDiffWidget); context.register(getAIPageRootWatcher(framework)); } }