donteatfriedrice
2024-08-01 01:37:23 +00:00
parent 2093685385
commit 3a0241340c
2 changed files with 86 additions and 20 deletions

View File

@@ -10,7 +10,6 @@ import {
ConnectorMode,
type EdgelessRootService,
} from '@blocksuite/blocks';
import { Bound } from '@blocksuite/global/utils';
import {
type AIChatBlockModel,
type ChatMessage,
@@ -32,6 +31,7 @@ import { AIChatErrorRenderer } from '../messages/error';
import { AIProvider } from '../provider';
import { PeekViewStyles } from './styles';
import type { ChatContext } from './types';
import { calcChildBound } from './utils';
@customElement('ai-chat-block-peek-view')
export class AIChatBlockPeekView extends LitElement {
@@ -53,10 +53,6 @@ export class AIChatBlockPeekView extends LitElement {
return this.parentModel.messages;
}
private get parentXYWH() {
return this.parentModel.xywh;
}
private get parentChatBlockId() {
return this.parentModel.id;
}
@@ -156,21 +152,6 @@ export class AIChatBlockPeekView extends LitElement {
return;
}
const parentXYWH = Bound.deserialize(this.parentXYWH);
const {
x: parentX,
y: parentY,
w: parentWidth,
h: parentHeight,
} = parentXYWH;
// Add AI chat block to the center of the viewport
// TODO: optimize the position of the AI chat block
const gap = parentWidth;
const x = parentX + parentWidth + gap;
const y = parentY;
const bound = new Bound(x, y, parentWidth, parentHeight);
// Get fork session messages
const messages = await this._constructBranchChatBlockMessages(
doc,
@@ -181,6 +162,7 @@ export class AIChatBlockPeekView extends LitElement {
}
const edgelessService = this._rootService as EdgelessRootService;
const bound = calcChildBound(this.parentModel, edgelessService);
const aiChatBlockId = edgelessService.addBlock(
'affine:embed-ai-chat' as keyof BlockSuite.BlockModels,
{

View File

@@ -0,0 +1,84 @@
import type { EdgelessRootService } from '@blocksuite/blocks';
import { Bound } from '@blocksuite/global/utils';
import {
type AIChatBlockModel,
CHAT_BLOCK_HEIGHT,
CHAT_BLOCK_WIDTH,
} from '@blocksuite/presets';
/**
* Calculates the bounding box for a child block
* Based on the parent block's position and the existing connectors.
* Place the child block to the right of the parent block as much as possible.
* If the parent block already has connected child blocks
* Distribute them evenly along the y-axis as much as possible.
* @param parentModel - The model of the parent block.
* @param service - The EdgelessRootService instance.
* @returns The calculated bounding box for the child block.
*/
export function calcChildBound(
parentModel: AIChatBlockModel,
service: EdgelessRootService
) {
const parentXYWH = Bound.deserialize(parentModel.xywh);
const { x: parentX, y: parentY, w: parentWidth } = parentXYWH;
const connectors = service.getConnectors(parentModel.id);
const gapX = CHAT_BLOCK_WIDTH;
const gapY = 60;
const defaultX = parentX + parentWidth + gapX;
const defaultY = parentY;
if (!connectors.length) {
return new Bound(defaultX, defaultY, CHAT_BLOCK_WIDTH, CHAT_BLOCK_HEIGHT);
} else {
// Filter out the connectors which source is the parent block
const childConnectors = connectors.filter(
connector => connector.source.id === parentModel.id
);
// Get all the target blocks of the child connectors
const targetBlocks = childConnectors
.map(connector => connector.target.id)
.filter(id => id !== undefined)
.map(id => service.getElementById(id))
.filter(block => !!block);
if (targetBlocks.length) {
// Sort target blocks by their y position
targetBlocks.sort(
(a, b) => Bound.deserialize(a.xywh).y - Bound.deserialize(b.xywh).y
);
let x, y;
// Calculate the position based on the number of target blocks
const middleIndex = Math.floor((targetBlocks.length - 1) / 2);
const middleBlock = targetBlocks[middleIndex];
const { y: middleY, h: middleHeight } = Bound.deserialize(
middleBlock.xywh
);
const lastBlock = targetBlocks[targetBlocks.length - 1];
const {
x: lastX,
y: lastY,
h: lastHeight,
} = Bound.deserialize(lastBlock.xywh);
if (targetBlocks.length % 2 === 0) {
// If even number of target blocks
// place the new bound above the middle block with same same gap as the last block
x = lastX;
const gap = lastY - (middleY + middleHeight);
y = middleY - gap - CHAT_BLOCK_HEIGHT;
} else {
// If odd number of target blocks, place the new bound below the last block with a gap
x = lastX;
y = lastY + lastHeight + gapY;
}
return new Bound(x, y, CHAT_BLOCK_WIDTH, CHAT_BLOCK_HEIGHT);
} else {
// If no valid target blocks, fallback to default position
return new Bound(defaultX, defaultY, CHAT_BLOCK_WIDTH, CHAT_BLOCK_HEIGHT);
}
}
}