mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-10 21:48:48 +08:00
feat(editor): improve status display in attachment embed view (#12180)
Closes: [BS-3438](https://linear.app/affine-design/issue/BS-3438/attachment-embed-view-中的-status-组件) Closes: [BS-3447](https://linear.app/affine-design/issue/BS-3447/触发-litportal-re-render) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a visual status indicator for embedded attachments with reload capability. - Added a new resource status component to display error messages and reload actions. - **Improvements** - Enhanced attachment rendering flow with reactive state and unified embed handling. - Simplified resource state and blob URL lifecycle management. - Added status visibility flags for PDF and video embeds. - **Bug Fixes** - Improved error handling and refresh support for embedded content including PDFs, videos, and audio. - **Style** - Added styles for the attachment embed status indicator positioning. - **Refactor** - Streamlined attachment and resource controller implementations for better maintainability. - **Tests** - Added end-to-end test verifying PDF viewer reload and re-rendering in embed mode. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -39,9 +39,22 @@ export type AttachmentEmbedConfig = {
|
||||
std: BlockStdScope
|
||||
) => Promise<void> | void;
|
||||
/**
|
||||
* The template will be used to render the embed view.
|
||||
* Renders the embed view.
|
||||
*/
|
||||
template?: (model: AttachmentBlockModel, blobUrl: string) => TemplateResult;
|
||||
render?: (
|
||||
model: AttachmentBlockModel,
|
||||
blobUrl: string
|
||||
) => TemplateResult | null;
|
||||
|
||||
/**
|
||||
* Should show status when turned on.
|
||||
*/
|
||||
shouldShowStatus?: boolean;
|
||||
|
||||
/**
|
||||
* Should block type conversion be required.
|
||||
*/
|
||||
shouldBeConverted?: boolean;
|
||||
};
|
||||
|
||||
// Single embed config.
|
||||
@@ -115,26 +128,38 @@ export class AttachmentEmbedService extends Extension {
|
||||
return this.values.some(config => config.check(model, maxFileSize));
|
||||
}
|
||||
|
||||
render(
|
||||
getRender(model: AttachmentBlockModel, maxFileSize = this._maxFileSize) {
|
||||
return (
|
||||
this.values.find(config => config.check(model, maxFileSize))?.render ??
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
shouldShowStatus(
|
||||
model: AttachmentBlockModel,
|
||||
blobUrl?: string,
|
||||
maxFileSize = this._maxFileSize
|
||||
) {
|
||||
if (!model.props.embed || !blobUrl) return;
|
||||
return (
|
||||
this.values.find(config => config.check(model, maxFileSize))
|
||||
?.shouldShowStatus ?? false
|
||||
);
|
||||
}
|
||||
|
||||
const config = this.values.find(config => config.check(model, maxFileSize));
|
||||
if (!config || !config.template) {
|
||||
console.error('No embed view template found!', model, model.props.type);
|
||||
return;
|
||||
}
|
||||
|
||||
return config.template(model, blobUrl);
|
||||
shouldBeConverted(
|
||||
model: AttachmentBlockModel,
|
||||
maxFileSize = this._maxFileSize
|
||||
) {
|
||||
return (
|
||||
this.values.find(config => config.check(model, maxFileSize))
|
||||
?.shouldBeConverted ?? false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const embedConfig: AttachmentEmbedConfig[] = [
|
||||
{
|
||||
name: 'image',
|
||||
shouldBeConverted: true,
|
||||
check: model =>
|
||||
model.store.schema.flavourSchemaMap.has('affine:image') &&
|
||||
model.props.type.startsWith('image/'),
|
||||
@@ -147,6 +172,7 @@ const embedConfig: AttachmentEmbedConfig[] = [
|
||||
},
|
||||
{
|
||||
name: 'pdf',
|
||||
shouldShowStatus: true,
|
||||
check: (model, maxFileSize) =>
|
||||
model.props.type === 'application/pdf' && model.props.size <= maxFileSize,
|
||||
action: model => {
|
||||
@@ -159,7 +185,7 @@ const embedConfig: AttachmentEmbedConfig[] = [
|
||||
xywh: bound.serialize(),
|
||||
});
|
||||
},
|
||||
template: (_, blobUrl) => {
|
||||
render: (_, blobUrl) => {
|
||||
// More options: https://tinytip.co/tips/html-pdf-params/
|
||||
// https://chromium.googlesource.com/chromium/src/+/refs/tags/121.0.6153.1/chrome/browser/resources/pdf/open_pdf_params_parser.ts
|
||||
const parameters = '#toolbar=0';
|
||||
@@ -185,6 +211,7 @@ const embedConfig: AttachmentEmbedConfig[] = [
|
||||
},
|
||||
{
|
||||
name: 'video',
|
||||
shouldShowStatus: true,
|
||||
check: (model, maxFileSize) =>
|
||||
model.props.type.startsWith('video/') && model.props.size <= maxFileSize,
|
||||
action: model => {
|
||||
@@ -197,7 +224,7 @@ const embedConfig: AttachmentEmbedConfig[] = [
|
||||
xywh: bound.serialize(),
|
||||
});
|
||||
},
|
||||
template: (_, blobUrl) =>
|
||||
render: (_, blobUrl) =>
|
||||
html`<video
|
||||
style=${styleMap({
|
||||
display: 'flex',
|
||||
@@ -216,8 +243,12 @@ const embedConfig: AttachmentEmbedConfig[] = [
|
||||
name: 'audio',
|
||||
check: (model, maxFileSize) =>
|
||||
model.props.type.startsWith('audio/') && model.props.size <= maxFileSize,
|
||||
template: (_, blobUrl) =>
|
||||
html`<audio controls src=${blobUrl} style="margin: 4px;"></audio>`,
|
||||
render: (_, blobUrl) =>
|
||||
html`<audio
|
||||
style=${styleMap({ margin: '4px' })}
|
||||
src=${blobUrl}
|
||||
controls
|
||||
></audio>`,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user