mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-22 19:53:48 +08:00
feat(core): comment panel (#12989)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Introduced a full-featured document comment system with sidebar for viewing, filtering, replying, resolving, and managing comments and replies. * Added a rich text comment editor supporting editable and read-only modes. * Enabled comment-based navigation and highlighting within documents. * Integrated comment functionality into the workspace sidebar (excluding local workspaces). * Added internationalization support and new UI strings for comment features. * Added new feature flag `enable_comment` for toggling comment functionality. * Enhanced editor focus to support comment-related selections. * Added snapshot and store helpers for comment content management. * Implemented backend GraphQL support for comment and reply operations. * Added services for comment entity management and comment panel behavior. * Extended comment configuration to support optional framework providers. * Added preview generation from user selections when creating comments. * Enabled automatic sidebar opening on new pending comments. * Added comment-related query parameter support for navigation. * Included inline comment module exports for integration. * Improved comment provider implementation with full lifecycle management and UI integration. * Added comment highlight state tracking and refined selection handling in inline comments. * **Style** * Added comprehensive styles for the comment editor and sidebar components. * **Chores** * Updated language completeness percentages for multiple locales. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: L-Sun <zover.v@gmail.com>
This commit is contained in:
@@ -174,6 +174,7 @@
|
||||
"./inlines/footnote": "./src/inlines/footnote/index.ts",
|
||||
"./inlines/footnote/view": "./src/inlines/footnote/view.ts",
|
||||
"./inlines/footnote/store": "./src/inlines/footnote/store.ts",
|
||||
"./inlines/comment": "./src/inlines/comment/index.ts",
|
||||
"./inlines/latex": "./src/inlines/latex/index.ts",
|
||||
"./inlines/latex/store": "./src/inlines/latex/store.ts",
|
||||
"./inlines/latex/view": "./src/inlines/latex/view.ts",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from '@blocksuite/affine-inline-comment';
|
||||
@@ -1 +1,2 @@
|
||||
export * from './inline-spec';
|
||||
export * from './utils';
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
TextSelection,
|
||||
} from '@blocksuite/std';
|
||||
import type { BaseSelection, BlockModel } from '@blocksuite/store';
|
||||
import { signal } from '@preact/signals-core';
|
||||
|
||||
import { extractCommentIdFromDelta, findCommentedTexts } from './utils';
|
||||
|
||||
@@ -20,6 +21,8 @@ export class InlineCommentManager extends LifeCycleWatcher {
|
||||
|
||||
private readonly _disposables = new DisposableGroup();
|
||||
|
||||
private readonly _highlightedCommentId$ = signal<CommentId | null>(null);
|
||||
|
||||
private get _provider() {
|
||||
return this.std.getOptional(CommentProviderIdentifier);
|
||||
}
|
||||
@@ -35,6 +38,9 @@ export class InlineCommentManager extends LifeCycleWatcher {
|
||||
this._disposables.add(
|
||||
provider.onCommentResolved(this._handleDeleteAndResolve)
|
||||
);
|
||||
this._disposables.add(
|
||||
provider.onCommentHighlighted(this._handleHighlightComment)
|
||||
);
|
||||
this._disposables.add(
|
||||
this.std.selection.slots.changed.subscribe(this._handleSelectionChanged)
|
||||
);
|
||||
@@ -131,14 +137,20 @@ export class InlineCommentManager extends LifeCycleWatcher {
|
||||
});
|
||||
};
|
||||
|
||||
private readonly _handleHighlightComment = (id: CommentId | null) => {
|
||||
this._highlightedCommentId$.value = id;
|
||||
};
|
||||
|
||||
private readonly _handleSelectionChanged = (selections: BaseSelection[]) => {
|
||||
const currentHighlightedCommentId = this._highlightedCommentId$.peek();
|
||||
|
||||
if (selections.length === 1) {
|
||||
const selection = selections[0];
|
||||
|
||||
// InlineCommentManager only handle text selection
|
||||
if (!selection.is(TextSelection)) return;
|
||||
|
||||
if (!selection.isCollapsed()) {
|
||||
if (!selection.isCollapsed() && currentHighlightedCommentId !== null) {
|
||||
this._provider?.highlightComment(null);
|
||||
return;
|
||||
}
|
||||
@@ -156,6 +168,8 @@ export class InlineCommentManager extends LifeCycleWatcher {
|
||||
if (commentIds.length !== 0) return;
|
||||
}
|
||||
|
||||
this._provider?.highlightComment(null);
|
||||
if (currentHighlightedCommentId !== null) {
|
||||
this._provider?.highlightComment(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ export const ReferenceParamsSchema = z
|
||||
databaseId: z.string().optional(),
|
||||
databaseRowId: z.string().optional(),
|
||||
xywh: SerializedXYWHSchema.optional(),
|
||||
commentId: z.string().optional(),
|
||||
})
|
||||
.partial();
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ export interface BlockSuiteFlags {
|
||||
enable_table_virtual_scroll: boolean;
|
||||
enable_turbo_renderer: boolean;
|
||||
enable_dom_renderer: boolean;
|
||||
enable_comment: boolean;
|
||||
}
|
||||
|
||||
export class FeatureFlagService extends StoreExtension {
|
||||
@@ -46,6 +47,7 @@ export class FeatureFlagService extends StoreExtension {
|
||||
enable_table_virtual_scroll: false,
|
||||
enable_turbo_renderer: false,
|
||||
enable_dom_renderer: false,
|
||||
enable_comment: false,
|
||||
});
|
||||
|
||||
setFlag(key: keyof BlockSuiteFlags, value: boolean) {
|
||||
|
||||
Reference in New Issue
Block a user