From a212a70b1dae52f823f95e1e0c160c13b4d0b074 Mon Sep 17 00:00:00 2001 From: Arcadio Quintero Date: Fri, 3 Jul 2026 15:16:58 -0400 Subject: [PATCH 1/5] feat(ui): unify content thumbnails into dot-content-thumbnail component Introduce a single Angular presentational thumbnail viewer in libs/ui that replaces both the Stencil dot-contentlet-thumbnail web component and the Angular dot-temp-file-thumbnail across the whole admin app. - New dot-content-thumbnail viewer with per-type internal renderers (image/svg/pdf via img, playable/first-frame video, Material Symbols icon), a loading state machine (PrimeNG-skeleton shimmer, 300ms cross-fade reveal) and icon fallback on media error. - Consumers pass the contentlet directly ([contentlet] + [options]) or a pre-resolved model ([thumbnail]); mappers replicate the legacy Stencil URL strategies (/dA, /contentAsset, pdf_page, svg raw asset) with deliberate fixes: SVG resolves before the fieldVariable path (never rasterized, renders object-contain) and image/* content types qualify as images when isImage is absent (image-editor saves). - Icon glyph auto-scales via container queries (iconSize input as override) and recolors through the --dot-content-thumbnail-icon-color CSS property. - Playable videos are never masked by the skeleton: the native element owns its loading UX; first-frame previews use a #t=0.1 media fragment instead of the legacy canvas approach. - Migrate all 10 usages: file-field preview (temp + contentlet), asset-search card, browser-selector dataview, content-drive folder list, UVE palette, block-editor contentlet block + suggestions, relationship field (list and select-existing dialog). - Delete dot-temp-file-thumbnail (single consumer, absorbed) and mark the Stencil dot-contentlet-thumbnail as deprecated (kept for dot-card-contentlet and legacy JSP). - Fix a pre-existing crash in the file-field preview info dialog when a temp file arrives without metadata (image-editor save) by synthesizing fallback metadata. Refs: #36295 --- .../src/lib/block-editor.module.ts | 6 +- .../contentlet-block.component.html | 7 +- .../suggestions-list-item.component.css | 6 +- .../suggestions-list-item.component.html | 6 +- .../src/lib/shared/shared.module.ts | 5 +- .../dotcms-webcomponents/src/components.d.ts | 28 ++ .../dot-contentlet-thumbnail.tsx | 7 + .../dot-contentlet-thumbnail/readme.md | 6 + .../dot-file-field-preview.component.html | 16 +- .../dot-file-field-preview.component.scss | 11 - .../dot-file-field-preview.component.spec.ts | 30 +- .../dot-file-field-preview.component.ts | 23 +- .../dot-relationship-field.component.html | 14 +- .../dot-relationship-field.component.ts | 9 +- ...dot-select-existing-content.component.html | 4 +- .../dot-select-existing-content.component.ts | 13 +- .../dot-folder-list-view.component.html | 5 +- .../dot-folder-list-view.component.spec.ts | 6 +- .../dot-folder-list-view.component.ts | 4 +- .../dot-uve-palette-contentlet.component.html | 11 +- ...t-uve-palette-contentlet.component.spec.ts | 15 +- .../dot-uve-palette-contentlet.component.ts | 24 +- core-web/libs/ui/src/index.ts | 4 +- .../dot-asset-card.component.html | 4 +- .../dot-asset-card.component.scss | 13 +- .../dot-asset-card.component.spec.ts | 6 +- .../dot-asset-card.component.ts | 8 +- .../dot-dataview/dot-dataview.component.html | 6 +- .../dot-dataview/dot-dataview.component.scss | 3 +- .../dot-dataview/dot-dataview.component.ts | 8 +- .../dot-content-thumbnail-icon.component.ts | 30 ++ .../dot-content-thumbnail-image.component.ts | 33 ++ .../dot-content-thumbnail-video.component.ts | 48 ++ .../dot-content-thumbnail.component.spec.ts | 319 ++++++++++++ .../dot-content-thumbnail.component.ts | 189 ++++++++ .../models/dot-content-thumbnail.model.ts | 49 ++ .../utils/dot-content-thumbnail.utils.spec.ts | 459 ++++++++++++++++++ .../utils/dot-content-thumbnail.utils.ts | 317 ++++++++++++ .../dot-temp-file-thumbnail.component.html | 34 -- .../dot-temp-file-thumbnail.component.scss | 1 - .../dot-temp-file-thumbnail.component.spec.ts | 135 ------ .../dot-temp-file-thumbnail.component.ts | 126 ----- 42 files changed, 1609 insertions(+), 439 deletions(-) create mode 100644 core-web/libs/ui/src/lib/components/dot-content-thumbnail/components/dot-content-thumbnail-icon.component.ts create mode 100644 core-web/libs/ui/src/lib/components/dot-content-thumbnail/components/dot-content-thumbnail-image.component.ts create mode 100644 core-web/libs/ui/src/lib/components/dot-content-thumbnail/components/dot-content-thumbnail-video.component.ts create mode 100644 core-web/libs/ui/src/lib/components/dot-content-thumbnail/dot-content-thumbnail.component.spec.ts create mode 100644 core-web/libs/ui/src/lib/components/dot-content-thumbnail/dot-content-thumbnail.component.ts create mode 100644 core-web/libs/ui/src/lib/components/dot-content-thumbnail/models/dot-content-thumbnail.model.ts create mode 100644 core-web/libs/ui/src/lib/components/dot-content-thumbnail/utils/dot-content-thumbnail.utils.spec.ts create mode 100644 core-web/libs/ui/src/lib/components/dot-content-thumbnail/utils/dot-content-thumbnail.utils.ts delete mode 100644 core-web/libs/ui/src/lib/components/dot-temp-file-thumbnail/dot-temp-file-thumbnail.component.html delete mode 100644 core-web/libs/ui/src/lib/components/dot-temp-file-thumbnail/dot-temp-file-thumbnail.component.scss delete mode 100644 core-web/libs/ui/src/lib/components/dot-temp-file-thumbnail/dot-temp-file-thumbnail.component.spec.ts delete mode 100644 core-web/libs/ui/src/lib/components/dot-temp-file-thumbnail/dot-temp-file-thumbnail.component.ts diff --git a/core-web/libs/block-editor/src/lib/block-editor.module.ts b/core-web/libs/block-editor/src/lib/block-editor.module.ts index d4ea4982160..bd63a98a684 100644 --- a/core-web/libs/block-editor/src/lib/block-editor.module.ts +++ b/core-web/libs/block-editor/src/lib/block-editor.module.ts @@ -29,7 +29,8 @@ import { DotFieldRequiredDirective, DotMessagePipe, DotSpinnerComponent, - DotContentletStatusBadgeComponent + DotContentletStatusBadgeComponent, + DotContentThumbnailComponent } from '@dotcms/ui'; //Editor @@ -78,7 +79,8 @@ const initTranslations = (dotMessageService: DotMessageService) => { DragHandleDirective, DotContextMenuComponent, DotAddButtonComponent, - DotContentletStatusBadgeComponent + DotContentletStatusBadgeComponent, + DotContentThumbnailComponent ], declarations: [ EditorDirective, diff --git a/core-web/libs/block-editor/src/lib/nodes/contentlet-block/contentlet-block.component.html b/core-web/libs/block-editor/src/lib/nodes/contentlet-block/contentlet-block.component.html index 5b5a8577dc8..23755727367 100644 --- a/core-web/libs/block-editor/src/lib/nodes/contentlet-block/contentlet-block.component.html +++ b/core-web/libs/block-editor/src/lib/nodes/contentlet-block/contentlet-block.component.html @@ -2,12 +2,7 @@
- +
diff --git a/core-web/libs/block-editor/src/lib/shared/components/suggestion-list/components/suggestions-list-item/suggestions-list-item.component.css b/core-web/libs/block-editor/src/lib/shared/components/suggestion-list/components/suggestions-list-item/suggestions-list-item.component.css index 0dc1936a60c..0a8694ea23b 100644 --- a/core-web/libs/block-editor/src/lib/shared/components/suggestion-list/components/suggestions-list-item/suggestions-list-item.component.css +++ b/core-web/libs/block-editor/src/lib/shared/components/suggestion-list/components/suggestions-list-item/suggestions-list-item.component.css @@ -28,9 +28,7 @@ width: 32px; } -.icon-wrapper dot-contentlet-thumbnail { - align-items: center; - display: block; +.icon-wrapper dot-content-thumbnail { position: relative; width: 42px; height: 42px; @@ -43,7 +41,7 @@ } .icon-wrapper.page, -.icon-wrapper.page dot-contentlet-thumbnail { +.icon-wrapper.page dot-content-thumbnail { flex-basis: 64px; height: 64px; width: 64px; diff --git a/core-web/libs/block-editor/src/lib/shared/components/suggestion-list/components/suggestions-list-item/suggestions-list-item.component.html b/core-web/libs/block-editor/src/lib/shared/components/suggestion-list/components/suggestions-list-item/suggestions-list-item.component.html index c21a1b35c9a..17e6b3fe2a3 100644 --- a/core-web/libs/block-editor/src/lib/shared/components/suggestion-list/components/suggestions-list-item/suggestions-list-item.component.html +++ b/core-web/libs/block-editor/src/lib/shared/components/suggestion-list/components/suggestions-list-item/suggestions-list-item.component.html @@ -3,11 +3,7 @@ {{ url }} } @else { @if (data?.contentlet) { - + } @else { } diff --git a/core-web/libs/block-editor/src/lib/shared/shared.module.ts b/core-web/libs/block-editor/src/lib/shared/shared.module.ts index a49172b5bf6..38bfeca5080 100644 --- a/core-web/libs/block-editor/src/lib/shared/shared.module.ts +++ b/core-web/libs/block-editor/src/lib/shared/shared.module.ts @@ -5,7 +5,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { ButtonModule } from 'primeng/button'; import { TagModule } from 'primeng/tag'; -import { DotContentletStatusBadgeComponent } from '@dotcms/ui'; +import { DotContentletStatusBadgeComponent, DotContentThumbnailComponent } from '@dotcms/ui'; // Shared import { @@ -26,7 +26,8 @@ import { SuggestionsService } from './services'; ReactiveFormsModule, ButtonModule, TagModule, - DotContentletStatusBadgeComponent + DotContentletStatusBadgeComponent, + DotContentThumbnailComponent ], declarations: [ SuggestionsComponent, diff --git a/core-web/libs/dotcms-webcomponents/src/components.d.ts b/core-web/libs/dotcms-webcomponents/src/components.d.ts index d6e8a0d372e..328b8083b09 100644 --- a/core-web/libs/dotcms-webcomponents/src/components.d.ts +++ b/core-web/libs/dotcms-webcomponents/src/components.d.ts @@ -450,6 +450,13 @@ export namespace Components { */ "size": string; } + /** + * @deprecated Angular code must use `DotContentThumbnailComponent` + * (`dot-content-thumbnail`) from `@dotcms/ui` instead — pass the contentlet + * via its `contentlet`/`options` inputs or a resolved model via `thumbnail`. + * This web component remains only for Stencil-internal use + * (`dot-card-contentlet`) and legacy JSP pages. See dotCMS/core#36295. + */ interface DotContentletThumbnail { /** * @default '' @@ -1840,6 +1847,13 @@ declare global { prototype: HTMLDotContentletLockIconElement; new (): HTMLDotContentletLockIconElement; }; + /** + * @deprecated Angular code must use `DotContentThumbnailComponent` + * (`dot-content-thumbnail`) from `@dotcms/ui` instead — pass the contentlet + * via its `contentlet`/`options` inputs or a resolved model via `thumbnail`. + * This web component remains only for Stencil-internal use + * (`dot-card-contentlet`) and legacy JSP pages. See dotCMS/core#36295. + */ interface HTMLDotContentletThumbnailElement extends Components.DotContentletThumbnail, HTMLStencilElement { } var HTMLDotContentletThumbnailElement: { @@ -2751,6 +2765,13 @@ declare namespace LocalJSX { */ "size"?: string; } + /** + * @deprecated Angular code must use `DotContentThumbnailComponent` + * (`dot-content-thumbnail`) from `@dotcms/ui` instead — pass the contentlet + * via its `contentlet`/`options` inputs or a resolved model via `thumbnail`. + * This web component remains only for Stencil-internal use + * (`dot-card-contentlet`) and legacy JSP pages. See dotCMS/core#36295. + */ interface DotContentletThumbnail { /** * @default '' @@ -3891,6 +3912,13 @@ declare module "@stencil/core" { */ "dot-contentlet-icon": LocalJSX.DotContentletIcon & JSXBase.HTMLAttributes; "dot-contentlet-lock-icon": LocalJSX.DotContentletLockIcon & JSXBase.HTMLAttributes; + /** + * @deprecated Angular code must use `DotContentThumbnailComponent` + * (`dot-content-thumbnail`) from `@dotcms/ui` instead — pass the contentlet + * via its `contentlet`/`options` inputs or a resolved model via `thumbnail`. + * This web component remains only for Stencil-internal use + * (`dot-card-contentlet`) and legacy JSP pages. See dotCMS/core#36295. + */ "dot-contentlet-thumbnail": LocalJSX.DotContentletThumbnail & JSXBase.HTMLAttributes; "dot-context-menu": LocalJSX.DotContextMenu & JSXBase.HTMLAttributes; "dot-data-view-button": LocalJSX.DotDataViewButton & JSXBase.HTMLAttributes; diff --git a/core-web/libs/dotcms-webcomponents/src/elements/dot-contentlet-thumbnail/dot-contentlet-thumbnail.tsx b/core-web/libs/dotcms-webcomponents/src/elements/dot-contentlet-thumbnail/dot-contentlet-thumbnail.tsx index 3c5869f4ad0..0bd228d800f 100644 --- a/core-web/libs/dotcms-webcomponents/src/elements/dot-contentlet-thumbnail/dot-contentlet-thumbnail.tsx +++ b/core-web/libs/dotcms-webcomponents/src/elements/dot-contentlet-thumbnail/dot-contentlet-thumbnail.tsx @@ -5,6 +5,13 @@ import { Component, h, Host, Prop, State } from '@stencil/core'; import { DotContentletItem } from '../../models/dot-contentlet-item.model'; +/** + * @deprecated Angular code must use `DotContentThumbnailComponent` + * (`dot-content-thumbnail`) from `@dotcms/ui` instead — pass the contentlet + * via its `contentlet`/`options` inputs or a resolved model via `thumbnail`. + * This web component remains only for Stencil-internal use + * (`dot-card-contentlet`) and legacy JSP pages. See dotCMS/core#36295. + */ @Component({ tag: 'dot-contentlet-thumbnail', styleUrl: 'dot-contentlet-thumbnail.scss' diff --git a/core-web/libs/dotcms-webcomponents/src/elements/dot-contentlet-thumbnail/readme.md b/core-web/libs/dotcms-webcomponents/src/elements/dot-contentlet-thumbnail/readme.md index e78b1227215..b827f615f28 100644 --- a/core-web/libs/dotcms-webcomponents/src/elements/dot-contentlet-thumbnail/readme.md +++ b/core-web/libs/dotcms-webcomponents/src/elements/dot-contentlet-thumbnail/readme.md @@ -3,6 +3,12 @@ +> **[DEPRECATED]** Angular code must use `DotContentThumbnailComponent` +(`dot-content-thumbnail`) from `@dotcms/ui` instead — pass the contentlet +via its `contentlet`/`options` inputs or a resolved model via `thumbnail`. +This web component remains only for Stencil-internal use +(`dot-card-contentlet`) and legacy JSP pages. See dotCMS/core#36295. + ## Properties | Property | Attribute | Description | Type | Default | diff --git a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/components/dot-file-field-preview/dot-file-field-preview.component.html b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/components/dot-file-field-preview/dot-file-field-preview.component.html index 2a8e2a1ae6b..8bf2d5b690c 100644 --- a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/components/dot-file-field-preview/dot-file-field-preview.component.html +++ b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/components/dot-file-field-preview/dot-file-field-preview.component.html @@ -15,19 +15,9 @@ } @else {
- @if (fileInfo.source === 'temp') { - - } @else { - - } +