Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(edgeless): mindmap gen #6675

Merged
merged 42 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
16721b1
feat: add edgeless copilot panel
doouding Mar 28, 2024
e40b270
fix: copilot panel
doouding Mar 28, 2024
f3623cd
feat: add edgeless panel
doouding Apr 1, 2024
ac018fe
Merge branch 'master' into fix/text-selection-error
doouding Apr 1, 2024
d24bf0e
Merge remote-tracking branch 'refs/remotes/origin/fix/text-selection-…
doouding Apr 1, 2024
a948390
fix: naming
doouding Apr 1, 2024
1c30955
fix: copilot
doouding Apr 1, 2024
d91b2d9
fix: move edgeless copilot spec
doouding Apr 1, 2024
abf5b97
fix: copilot panel
doouding Apr 1, 2024
bdb88a4
fix: make it real
doouding Apr 1, 2024
2025015
Merge remote-tracking branch 'origin/master' into fix/text-selection-…
doouding Apr 1, 2024
93ff395
fix: build
doouding Apr 1, 2024
eeb5469
fix: circular
doouding Apr 1, 2024
4d10a7b
Merge branch 'master' into fix/text-selection-error
doouding Apr 1, 2024
9f1bf41
fix: test
doouding Apr 1, 2024
5f37948
Merge remote-tracking branch 'refs/remotes/origin/fix/text-selection-…
doouding Apr 2, 2024
cf0154e
feat: add mini mindmap editor
doouding Apr 2, 2024
bc45bc4
feat: mindmap gen and preview
doouding Apr 8, 2024
a359c5a
Merge branch 'master' into feat/mindmap-gen
doouding Apr 8, 2024
0a2c0b5
fix: lint
doouding Apr 8, 2024
cd2f40f
fix: build
doouding Apr 8, 2024
5aaa57b
fix: lint
doouding Apr 8, 2024
a86066f
fix: build
doouding Apr 8, 2024
1956b4c
fix: build
doouding Apr 8, 2024
9754ebc
fix: mindmap interactive
doouding Apr 8, 2024
cf1cf3b
fix: mindmap style
doouding Apr 8, 2024
c196938
fix: use static id
doouding Apr 8, 2024
2822ea5
fix: shape text editor
doouding Apr 8, 2024
01948be
fix: mindmap undo/redo
doouding Apr 8, 2024
2696cfc
fix: groups
doouding Apr 8, 2024
23b4f43
fix: group
doouding Apr 8, 2024
4498662
fix: circular
doouding Apr 8, 2024
81a7e9f
Merge branch 'master' into feat/mindmap-gen
doouding Apr 8, 2024
39f11e1
Merge remote-tracking branch 'origin/feat/mindmap-gen' into feat/mind…
doouding Apr 8, 2024
4c49a83
fix: naming
doouding Apr 8, 2024
ff78b1a
Merge remote-tracking branch 'origin/master' into feat/mindmap-gen
doouding Apr 8, 2024
b0078ef
fix: remove unnecessary change
doouding Apr 9, 2024
d44ff87
Merge branch 'master' into feat/mindmap-gen
doouding Apr 9, 2024
49fc24d
fix: ai panel
doouding Apr 9, 2024
ce21128
fix: conflict
doouding Apr 9, 2024
6c91eff
fix: hide
doouding Apr 9, 2024
8174e82
Merge branch 'master' into feat/mindmap-gen
doouding Apr 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@
"postinstall": "husky"
},
"lint-staged": {
"*": "prettier --write --cache --ignore-unknown",
"*.{ts,tsx,js,jsx}": "eslint --cache --fix"
"*": "pnpm exec prettier --write --cache --ignore-unknown",
"!(examples/**/*).{ts,tsx,js,jsx}": "pnpm exec eslint --cache --fix"
doouding marked this conversation as resolved.
Show resolved Hide resolved
},
"keywords": [],
"author": "toeverything",
Expand Down
6 changes: 6 additions & 0 deletions packages/blocks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export type {
TemplateCategory,
TemplateManager,
} from './root-block/edgeless/components/toolbar/template/template-type.js';
export { CopilotSelectionController } from './root-block/edgeless/controllers/tools/copilot-tool.js';
export * from './root-block/index.js';
export * from './schemas.js';
export {
Expand All @@ -110,6 +111,10 @@ export {
ElementModel,
generateKeyBetween,
GroupElementModel,
MindmapElementModel,
MindmapRootBlock,
MindmapService,
MindmapSurfaceBlock,
type PointStyle,
type SerializedXYWH,
ShapeElementModel,
Expand All @@ -118,6 +123,7 @@ export {
SurfaceBlockModel,
TextElementModel,
} from './surface-block/index.js';
export { MiniMindmapPreview } from './surface-block/mini-mindmap/mindmap-preview.js';
export { SurfaceBlockComponent } from './surface-block/surface-block.js';
export { SurfaceBlockSchema } from './surface-block/surface-model.js';
export * from './surface-block/surface-service.js';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) {
return this.inlineEditor.rootElement;
}

private _lastXYWH = '';
private _keeping = false;
private _resizeObserver: ResizeObserver | null = null;

Expand All @@ -62,6 +63,10 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) {
const containerWidth = this.richText.offsetWidth;
const textResizing = this.element.textResizing;

if (this._lastXYWH !== this.element.xywh) {
this.requestUpdate();
}

if (
(containerHeight !== this.element.h &&
textResizing === TextResizing.AUTO_HEIGHT) ||
Expand Down Expand Up @@ -286,6 +291,8 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) {
zIndex: '1',
});

this._lastXYWH = this.element.xywh;

return html`<rich-text
.yText=${this.element.text}
.enableFormat=${false}
Expand Down
6 changes: 3 additions & 3 deletions packages/blocks/src/root-block/edgeless/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ import type {
ElementModel,
GroupLikeModel,
} from '../../surface-block/element-model/base.js';
import type { SurfaceBlockModel } from '../../surface-block/surface-model.js';
import { Bound } from '../../surface-block/utils/bound.js';
import {
getBoundsWithRotation,
getPointsFromBoundsWithRotation,
linePolygonIntersects,
polygonGetPointTangent,
polygonNearestPoint,
rotatePoints,
} from '../../surface-block/index.js';
import type { SurfaceBlockModel } from '../../surface-block/surface-model.js';
import { Bound } from '../../surface-block/utils/bound.js';
} from '../../surface-block/utils/math-utils.js';
import { PointLocation } from '../../surface-block/utils/point-location.js';
import type { IVec } from '../../surface-block/utils/vec.js';
import type { SerializedXYWH } from '../../surface-block/utils/xywh.js';
Expand Down
7 changes: 5 additions & 2 deletions packages/blocks/src/root-block/edgeless/utils/viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export class Viewport {
private _syncFlag = false;
protected _cumulativeParentScale = 1;

ZOOM_MAX = ZOOM_MAX;
ZOOM_MIN = ZOOM_MIN;

viewportUpdated = new Slot<{ zoom: number; center: IVec2 }>();
sizeUpdated = new Slot<{
width: number;
Expand Down Expand Up @@ -176,7 +179,7 @@ export class Viewport {
setZoom(zoom: number, focusPoint?: IPoint) {
const prevZoom = this.zoom;
focusPoint = (focusPoint ?? this._center) as IPoint;
this._zoom = clamp(zoom, ZOOM_MIN, ZOOM_MAX);
this._zoom = clamp(zoom, this.ZOOM_MIN, this.ZOOM_MAX);
const newZoom = this.zoom;

const offset = Vec.sub(Vec.toVec(this.center), Vec.toVec(focusPoint));
Expand Down Expand Up @@ -240,7 +243,7 @@ export class Viewport {
const [pt, pr, pb, pl] = padding;
const zoom = clamp(
(this.width - (pr + pl)) / bound.w,
ZOOM_MIN,
this.ZOOM_MIN,
(this.height - (pt + pb)) / bound.h
);
const center = [
Expand Down
15 changes: 9 additions & 6 deletions packages/blocks/src/root-block/widgets/ai-panel/ai-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ import type {
} from './components/index.js';

export interface AffineAIPanelWidgetConfig {
answerRenderer: (answer: string) => TemplateResult<1>;
answerRenderer: (
answer: string,
state: AffineAIPanelState
doouding marked this conversation as resolved.
Show resolved Hide resolved
) => TemplateResult<1> | typeof nothing;
generateAnswer?: (props: {
input: string;
update: (answer: string) => void;
Expand Down Expand Up @@ -79,6 +82,8 @@ export class AffineAIPanelWidget extends WidgetElement {
}
`;

ctx: unknown = null;

@property({ attribute: false })
config: AffineAIPanelWidgetConfig | null = null;

Expand Down Expand Up @@ -129,7 +134,6 @@ export class AffineAIPanelWidget extends WidgetElement {
assertExists(text);
assertExists(this.config.generateAnswer);

this._resetAbortController();
doouding marked this conversation as resolved.
Show resolved Hide resolved
// reset answer
this._answer = null;

Expand All @@ -143,8 +147,6 @@ export class AffineAIPanelWidget extends WidgetElement {
} else {
this.state = 'finished';
}

this._resetAbortController();
};

this.state = 'generating';
Expand Down Expand Up @@ -267,7 +269,8 @@ export class AffineAIPanelWidget extends WidgetElement {
.finish=${false}
.config=${config.finishStateConfig}
>
${this.answer && config.answerRenderer(this.answer)}
${this.answer &&
config.answerRenderer(this.answer, this.state)}
</ai-panel-answer>
`
: nothing}
Expand All @@ -280,7 +283,7 @@ export class AffineAIPanelWidget extends WidgetElement {
'finished',
() => html`
<ai-panel-answer .config=${config.finishStateConfig}>
${this.answer && config.answerRenderer(this.answer)}
${this.answer && config.answerRenderer(this.answer, this.state)}
</ai-panel-answer>
`,
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export class EdgelessCopilotPanel extends WithDisposable(LitElement) {
return this.edgeless.service.std.command.chain();
}

hide() {
this.remove();
}

override render() {
const chain = this._getChain();
const groups = this.groups.reduce((pre, group) => {
Expand Down
36 changes: 30 additions & 6 deletions packages/blocks/src/root-block/widgets/edgeless-copilot/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import { styleMap } from 'lit/directives/style-map.js';
import type { AIItemGroupConfig } from '../../../_common/components/ai-item/types.js';
import {
MOUSE_BUTTON,
on,
once,
requestConnectedFrame,
} from '../../../_common/utils/event.js';
import type { CopilotSelectionController } from '../../edgeless/controllers/tools/copilot-tool.js';
import type { EdgelessRootBlockComponent } from '../../edgeless/edgeless-root-block.js';
import type { RootBlockModel } from '../../index.js';
import { actionWithAI, dragWithAI } from '../edgeless-copilot-panel/config.js';
import { type RootBlockModel } from '../../root-model.js';
import type { AffineAIPanelWidget } from '../ai-panel/ai-panel.js';
import { AFFINE_AI_PANEL_WIDGET } from '../ai-panel/ai-panel.js';
import { EdgelessCopilotPanel } from '../edgeless-copilot-panel/index.js';

export const AFFINE_EDGELESS_COPILOT_WIDGET = 'affine-edgeless-copilot-widget';
Expand Down Expand Up @@ -47,19 +47,36 @@ export class EdgelessCopilotWidget extends WidgetElement<
@query('.copilot-selection-rect')
private _selectionRectEl!: HTMLDivElement;

private _selectionModelRect!: DOMRect;

private _clickOutsideOff: (() => void) | null = null;
private _listenClickOutsideId: number | null = null;

private _copilotPanel!: EdgelessCopilotPanel | null;
private _showCopilotPanelOff: (() => void) | null = null;

groups: AIItemGroupConfig[] = [actionWithAI, dragWithAI];
groups: AIItemGroupConfig[] = [];

get selectionRect() {
return this._selectionRect;
}

get selectionModelRect() {
return this._selectionModelRect;
}

get edgeless() {
return this.blockElement;
}

hide() {
this._copilotPanel?.hide();
this._showCopilotPanelOff?.();
}

private _updateSelection(rect: DOMRect) {
this._selectionModelRect = rect;

const zoom = this.edgeless.service.viewport.zoom;
const [x, y] = this.edgeless.service.viewport.toViewCoord(
rect.left,
Expand All @@ -83,10 +100,17 @@ export class EdgelessCopilotWidget extends WidgetElement<
return;
}

const off = on(this.ownerDocument, 'mousedown', e => {
const off = this.blockElement.dispatcher.add('pointerDown', ctx => {
const e = ctx.get('pointerState').raw;
const aiPanel = this.host.view.getWidget(
AFFINE_AI_PANEL_WIDGET,
this.doc.root!.id
) as AffineAIPanelWidget;

if (
e.button === MOUSE_BUTTON.MAIN &&
!this.contains(e.target as HTMLElement)
!this.contains(e.target as HTMLElement) &&
(!aiPanel || !aiPanel.contains(e.target as HTMLElement))
) {
off();
this._copilotPanel?.remove();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import {
deltaInsertsToChunks,
getFontString,
getLineHeight,
getLineWidth,
getTextWidth,
type TextDelta,
wrapText,
wrapTextDeltas,
} from '../text/utils.js';

export const SHAPE_TEXT_PADDING = 20;
Expand Down Expand Up @@ -185,3 +187,32 @@ export function normalizeShapeBound(

return bound;
}

export function updateMindmapNodeRect(shape: ShapeElementModel) {
const font = getFontString(shape);

if (!shape.text) {
return;
}

const lines = deltaInsertsToChunks(
wrapTextDeltas(shape.text, font, shape.maxWidth || Number.MAX_SAFE_INTEGER)
);
const lineHeight = getLineHeight(font, shape.fontSize);
let maxWidth = 0;
let height = 0;

lines.forEach(line => {
for (const delta of line) {
const str = delta.insert;

maxWidth = Math.max(maxWidth, getLineWidth(str, font));
height += lineHeight;
}
});

maxWidth += SHAPE_TEXT_PADDING * 2;
height += SHAPE_TEXT_VERTICAL_PADDING * 2;

shape.xywh = `[${shape.x},${shape.y},${maxWidth},${height}]`;
}