mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-04 19:11:57 +08:00
refactor(editor): new icon picker (#13658)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * In-tree icon picker for Callout blocks (emoji, app icons, images) with popup UI and editor-wide extension/service. * Callout toolbar adds background color presets, an icon-picker action, and a destructive Delete action. * **Refactor** * Replaced legacy emoji workflow with icon-based rendering, updated state, styling, and lifecycle for callouts. * **Tests** * Updated callout E2E to reflect new default icon and picker behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: L-Sun <zover.v@gmail.com>
This commit is contained in:
@@ -175,6 +175,7 @@ const usePreviewExtensions = () => {
|
||||
.ai(enableAI, framework)
|
||||
.theme(framework)
|
||||
.database(framework)
|
||||
.iconPicker(framework)
|
||||
.linkedDoc(framework)
|
||||
.paragraph(enableAI)
|
||||
.linkPreview(framework)
|
||||
|
||||
@@ -117,6 +117,7 @@ const usePatchSpecs = (mode: DocMode, shared?: boolean) => {
|
||||
.electron(framework)
|
||||
.linkPreview(framework)
|
||||
.codeBlockPreview(framework)
|
||||
.iconPicker(framework)
|
||||
.comment(enableComment, framework).value;
|
||||
|
||||
if (BUILD_CONFIG.isMobileEdition) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
type AffineEditorViewOptions,
|
||||
} from '@affine/core/blocksuite/view-extensions/editor-view/editor-view';
|
||||
import { ElectronViewExtension } from '@affine/core/blocksuite/view-extensions/electron';
|
||||
import { AffineIconPickerExtension } from '@affine/core/blocksuite/view-extensions/icon-picker';
|
||||
import { AffineLinkPreviewExtension } from '@affine/core/blocksuite/view-extensions/link-preview-service';
|
||||
import { MobileViewExtension } from '@affine/core/blocksuite/view-extensions/mobile';
|
||||
import { PdfViewExtension } from '@affine/core/blocksuite/view-extensions/pdf';
|
||||
@@ -58,6 +59,7 @@ type Configure = {
|
||||
electron: (framework?: FrameworkProvider) => Configure;
|
||||
linkPreview: (framework?: FrameworkProvider) => Configure;
|
||||
codeBlockPreview: (framework?: FrameworkProvider) => Configure;
|
||||
iconPicker: (framework?: FrameworkProvider) => Configure;
|
||||
comment: (
|
||||
enableComment?: boolean,
|
||||
framework?: FrameworkProvider
|
||||
@@ -86,6 +88,7 @@ class ViewProvider {
|
||||
AffineThemeViewExtension,
|
||||
AffineEditorViewExtension,
|
||||
AffineEditorConfigViewExtension,
|
||||
AffineIconPickerExtension,
|
||||
CodeBlockPreviewViewExtension,
|
||||
EdgelessBlockHeaderConfigViewExtension,
|
||||
TurboRendererViewExtension,
|
||||
@@ -123,6 +126,7 @@ class ViewProvider {
|
||||
electron: this._configureElectron,
|
||||
linkPreview: this._configureLinkPreview,
|
||||
codeBlockPreview: this._configureCodeBlockHtmlPreview,
|
||||
iconPicker: this._configureIconPicker,
|
||||
comment: this._configureComment,
|
||||
value: this._manager,
|
||||
};
|
||||
@@ -146,6 +150,7 @@ class ViewProvider {
|
||||
.electron()
|
||||
.linkPreview()
|
||||
.codeBlockPreview()
|
||||
.iconPicker()
|
||||
.comment();
|
||||
|
||||
return this.config;
|
||||
@@ -333,6 +338,11 @@ class ViewProvider {
|
||||
return this.config;
|
||||
};
|
||||
|
||||
private readonly _configureIconPicker = (framework?: FrameworkProvider) => {
|
||||
this._manager.configure(AffineIconPickerExtension, { framework });
|
||||
return this.config;
|
||||
};
|
||||
|
||||
private readonly _configureComment = (
|
||||
enableComment?: boolean,
|
||||
framework?: FrameworkProvider
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { IconPickerServiceIdentifier } from '@blocksuite/affine/shared/services';
|
||||
import { type ExtensionType } from '@blocksuite/affine/store';
|
||||
import type { Container } from '@blocksuite/global/di';
|
||||
import type { FrameworkProvider } from '@toeverything/infra';
|
||||
|
||||
import { IconPickerService } from '../../../modules/icon-picker/services/icon-picker';
|
||||
|
||||
/**
|
||||
* Patch the icon picker service to make it available in BlockSuite
|
||||
* @param framework
|
||||
* @returns
|
||||
*/
|
||||
export function patchIconPickerService(
|
||||
framework: FrameworkProvider
|
||||
): ExtensionType {
|
||||
return {
|
||||
setup: (di: Container) => {
|
||||
di.override(IconPickerServiceIdentifier, () => {
|
||||
return framework.get(IconPickerService);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import {
|
||||
type ViewExtensionContext,
|
||||
ViewExtensionProvider,
|
||||
} from '@blocksuite/affine/ext-loader';
|
||||
import { FrameworkProvider } from '@toeverything/infra';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { patchIconPickerService } from './icon-picker-service';
|
||||
|
||||
const optionsSchema = z.object({
|
||||
framework: z.instanceof(FrameworkProvider).optional(),
|
||||
});
|
||||
|
||||
type AffineIconPickerViewOptions = z.infer<typeof optionsSchema>;
|
||||
|
||||
export class AffineIconPickerExtension extends ViewExtensionProvider<AffineIconPickerViewOptions> {
|
||||
override name = 'affine-icon-picker-extension';
|
||||
|
||||
override schema = optionsSchema;
|
||||
|
||||
override setup(
|
||||
context: ViewExtensionContext,
|
||||
options?: AffineIconPickerViewOptions
|
||||
) {
|
||||
super.setup(context, options);
|
||||
if (!options?.framework) {
|
||||
return;
|
||||
}
|
||||
const { framework } = options;
|
||||
context.register(patchIconPickerService(framework));
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,7 @@ export const useAISpecs = () => {
|
||||
.mobile(framework)
|
||||
.electron(framework)
|
||||
.linkPreview(framework)
|
||||
.iconPicker(framework)
|
||||
.codeBlockPreview(framework).value;
|
||||
|
||||
return manager.get('page');
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { type Framework } from '@toeverything/infra';
|
||||
|
||||
import { IconPickerService } from './services/icon-picker';
|
||||
|
||||
export { IconPickerService } from './services/icon-picker';
|
||||
|
||||
export function configureIconPickerModule(framework: Framework) {
|
||||
framework.service(IconPickerService);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { IconPicker, uniReactRoot } from '@affine/component';
|
||||
// Import the identifier for internal use
|
||||
import { type IconPickerService as IIconPickerService } from '@blocksuite/affine-shared/services';
|
||||
import { Service } from '@toeverything/infra';
|
||||
|
||||
// Re-export types from BlockSuite shared services
|
||||
export type {
|
||||
IconData,
|
||||
IconPickerService as IIconPickerService,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
export { IconPickerServiceIdentifier } from '@blocksuite/affine-shared/services';
|
||||
|
||||
export class IconPickerService extends Service implements IIconPickerService {
|
||||
public readonly iconPickerComponent =
|
||||
uniReactRoot.createUniComponent(IconPicker);
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import { configureFavoriteModule } from './favorite';
|
||||
import { configureFeatureFlagModule } from './feature-flag';
|
||||
import { configureGlobalContextModule } from './global-context';
|
||||
import { configureI18nModule } from './i18n';
|
||||
import { configureIconPickerModule } from './icon-picker';
|
||||
import { configureImportClipperModule } from './import-clipper';
|
||||
import { configureImportTemplateModule } from './import-template';
|
||||
import { configureIntegrationModule } from './integration';
|
||||
@@ -132,4 +133,5 @@ export function configureCommonModules(framework: Framework) {
|
||||
configureCommentModule(framework);
|
||||
configureDocSummaryModule(framework);
|
||||
configurePaywallModule(framework);
|
||||
configureIconPickerModule(framework);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user