feat(editor): add feature flag for code block html preview (#12397)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced an experimental "Code block HTML preview" feature, allowing users to preview HTML within code blocks when enabled.
- **Settings**
  - Added a toggle in experimental features to enable or disable the code block HTML preview.
- **Localization**
  - Added English translations for the new code block HTML preview feature and its description in workspace settings.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Flrande
2025-05-21 07:52:24 +00:00
parent 20e93543e2
commit 2de15e2677
8 changed files with 56 additions and 6 deletions

View File

@@ -171,7 +171,8 @@ const usePreviewExtensions = () => {
.database(framework) .database(framework)
.linkedDoc(framework) .linkedDoc(framework)
.paragraph(enableAI) .paragraph(enableAI)
.linkPreview(framework).value; .linkPreview(framework)
.codeBlockHtmlPreview(framework).value;
const specs = manager.get('preview-page'); const specs = manager.get('preview-page');
return [...specs, patchReferenceRenderer(reactToLit, referenceRenderer)]; return [...specs, patchReferenceRenderer(reactToLit, referenceRenderer)];
}, [reactToLit, referenceRenderer, framework, enableAI]); }, [reactToLit, referenceRenderer, framework, enableAI]);

View File

@@ -102,7 +102,8 @@ const usePatchSpecs = (mode: DocMode) => {
.paragraph(enableAI) .paragraph(enableAI)
.mobile(framework) .mobile(framework)
.electron(framework) .electron(framework)
.linkPreview(framework).value; .linkPreview(framework)
.codeBlockHtmlPreview(framework).value;
if (BUILD_CONFIG.isMobileEdition) { if (BUILD_CONFIG.isMobileEdition) {
if (mode === 'page') { if (mode === 'page') {

View File

@@ -55,6 +55,7 @@ type Configure = {
ai: (enable?: boolean, framework?: FrameworkProvider) => Configure; ai: (enable?: boolean, framework?: FrameworkProvider) => Configure;
electron: (framework?: FrameworkProvider) => Configure; electron: (framework?: FrameworkProvider) => Configure;
linkPreview: (framework?: FrameworkProvider) => Configure; linkPreview: (framework?: FrameworkProvider) => Configure;
codeBlockHtmlPreview: (framework?: FrameworkProvider) => Configure;
value: ViewExtensionManager; value: ViewExtensionManager;
}; };
@@ -114,6 +115,7 @@ class ViewProvider {
ai: this._configureAI, ai: this._configureAI,
electron: this._configureElectron, electron: this._configureElectron,
linkPreview: this._configureLinkPreview, linkPreview: this._configureLinkPreview,
codeBlockHtmlPreview: this._configureCodeBlockHtmlPreview,
value: this._manager, value: this._manager,
}; };
} }
@@ -134,7 +136,8 @@ class ViewProvider {
.mobile() .mobile()
.ai() .ai()
.electron() .electron()
.linkPreview(); .linkPreview()
.codeBlockHtmlPreview();
return this.config; return this.config;
}; };
@@ -313,6 +316,13 @@ class ViewProvider {
this._manager.configure(AffineLinkPreviewExtension, { framework }); this._manager.configure(AffineLinkPreviewExtension, { framework });
return this.config; return this.config;
}; };
private readonly _configureCodeBlockHtmlPreview = (
framework?: FrameworkProvider
) => {
this._manager.configure(CodeBlockPreviewViewExtension, { framework });
return this.config;
};
} }
export function getViewManager() { export function getViewManager() {

View File

@@ -1,25 +1,43 @@
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { import {
type ViewExtensionContext, type ViewExtensionContext,
ViewExtensionProvider, ViewExtensionProvider,
} from '@blocksuite/affine/ext-loader'; } from '@blocksuite/affine/ext-loader';
import { FrameworkProvider } from '@toeverything/infra';
import { z } from 'zod';
import { import {
CodeBlockHtmlPreview, CodeBlockHtmlPreview,
effects as htmlPreviewEffects, effects as htmlPreviewEffects,
} from './html-preview'; } from './html-preview';
const optionsSchema = z.object({
framework: z.instanceof(FrameworkProvider).optional(),
});
export class CodeBlockPreviewViewExtension extends ViewExtensionProvider { export class CodeBlockPreviewViewExtension extends ViewExtensionProvider {
override name = 'code-block-preview'; override name = 'code-block-preview';
override schema = optionsSchema;
override effect() { override effect() {
super.effect(); super.effect();
htmlPreviewEffects(); htmlPreviewEffects();
} }
override setup(context: ViewExtensionContext) { override setup(
super.setup(context); context: ViewExtensionContext,
options?: z.infer<typeof optionsSchema>
) {
super.setup(context, options);
const framework = options?.framework;
if (!framework) return;
const flag =
framework.get(FeatureFlagService).flags.enable_code_block_html_preview.$
.value;
if (!flag) return;
context.register(CodeBlockHtmlPreview); context.register(CodeBlockHtmlPreview);
} }
} }

View File

@@ -61,7 +61,8 @@ export const EdgelessSnapshot = (props: Props) => {
.foundation(framework) .foundation(framework)
.theme(framework) .theme(framework)
.database(framework) .database(framework)
.linkedDoc(framework).value; .linkedDoc(framework)
.codeBlockHtmlPreview(framework).value;
return manager return manager
.get('preview-edgeless') .get('preview-edgeless')
.concat([ViewportElementExtension('.ref-viewport')]); .concat([ViewportElementExtension('.ref-viewport')]);

View File

@@ -325,6 +325,15 @@ export const AFFINE_FLAGS = {
configurable: isBetaBuild || isCanaryBuild, configurable: isBetaBuild || isCanaryBuild,
defaultState: false, defaultState: false,
}, },
enable_code_block_html_preview: {
category: 'affine',
displayName:
'com.affine.settings.workspace.experimental-features.enable-code-block-html-preview.name',
description:
'com.affine.settings.workspace.experimental-features.enable-code-block-html-preview.description',
configurable: isCanaryBuild,
defaultState: true,
},
} satisfies { [key in string]: FlagInfo }; } satisfies { [key in string]: FlagInfo };
// oxlint-disable-next-line no-redeclare // oxlint-disable-next-line no-redeclare

View File

@@ -5882,6 +5882,14 @@ export function useAFFiNEI18N(): {
* `Once enabled, switch table view to virtual scroll mode in Database Block.` * `Once enabled, switch table view to virtual scroll mode in Database Block.`
*/ */
["com.affine.settings.workspace.experimental-features.enable-table-virtual-scroll.description"](): string; ["com.affine.settings.workspace.experimental-features.enable-table-virtual-scroll.description"](): string;
/**
* `Code block HTML preview`
*/
["com.affine.settings.workspace.experimental-features.enable-code-block-html-preview.name"](): string;
/**
* `Once enabled, you can preview HTML in code block.`
*/
["com.affine.settings.workspace.experimental-features.enable-code-block-html-preview.description"](): string;
/** /**
* `Only an owner can edit the workspace avatar and name. Changes will be shown for everyone.` * `Only an owner can edit the workspace avatar and name. Changes will be shown for everyone.`
*/ */

View File

@@ -1469,6 +1469,8 @@
"com.affine.settings.workspace.experimental-features.enable-edgeless-scribbled-style.description": "Once enabled, you can use scribbled style in edgeless mode.", "com.affine.settings.workspace.experimental-features.enable-edgeless-scribbled-style.description": "Once enabled, you can use scribbled style in edgeless mode.",
"com.affine.settings.workspace.experimental-features.enable-table-virtual-scroll.name": "Database block table view virtual scroll", "com.affine.settings.workspace.experimental-features.enable-table-virtual-scroll.name": "Database block table view virtual scroll",
"com.affine.settings.workspace.experimental-features.enable-table-virtual-scroll.description": "Once enabled, switch table view to virtual scroll mode in Database Block.", "com.affine.settings.workspace.experimental-features.enable-table-virtual-scroll.description": "Once enabled, switch table view to virtual scroll mode in Database Block.",
"com.affine.settings.workspace.experimental-features.enable-code-block-html-preview.name": "Code block HTML preview",
"com.affine.settings.workspace.experimental-features.enable-code-block-html-preview.description": "Once enabled, you can preview HTML in code block.",
"com.affine.settings.workspace.not-owner": "Only an owner can edit the workspace avatar and name. Changes will be shown for everyone.", "com.affine.settings.workspace.not-owner": "Only an owner can edit the workspace avatar and name. Changes will be shown for everyone.",
"com.affine.settings.workspace.preferences": "Preference", "com.affine.settings.workspace.preferences": "Preference",
"com.affine.settings.workspace.billing": "Team's Billing", "com.affine.settings.workspace.billing": "Team's Billing",