From 6fb7e1045a5321bed5d4da3a0b07b10d4adcc937 Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Wed, 10 Jul 2024 10:54:48 +0200
Subject: [PATCH 01/12] feat: add thumbnail component that can request a media
key and show it or fallback to an icon
---
.../components/imaging-thumbnail.element.ts | 144 ++++++++++++++++++
.../media/imaging/components/index.ts | 1 +
.../media/imaging/imaging.repository.ts | 5 +-
src/packages/media/imaging/index.ts | 1 +
src/packages/media/imaging/types.ts | 6 +-
5 files changed, 152 insertions(+), 5 deletions(-)
create mode 100644 src/packages/media/imaging/components/imaging-thumbnail.element.ts
create mode 100644 src/packages/media/imaging/components/index.ts
diff --git a/src/packages/media/imaging/components/imaging-thumbnail.element.ts b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
new file mode 100644
index 0000000000..caf6261772
--- /dev/null
+++ b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
@@ -0,0 +1,144 @@
+import { UmbImagingCropMode } from '../types.js';
+import { UmbImagingRepository } from '../imaging.repository.js';
+import { css, customElement, html, nothing, property, state, when } from '@umbraco-cms/backoffice/external/lit';
+import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
+import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
+
+const ELEMENT_NAME = 'umb-imaging-thumbnail';
+
+@customElement(ELEMENT_NAME)
+export class UmbImagingThumbnailElement extends UmbLitElement {
+ /**
+ * The unique identifier for the media item.
+ * @remark This is also known as the media key and is used to fetch the resource.
+ */
+ @property()
+ unique = '';
+
+ /**
+ * The width of the thumbnail.
+ */
+ @property({ type: Number })
+ width = 400;
+
+ /**
+ * The height of the thumbnail.
+ */
+ @property({ type: Number })
+ height = 400;
+
+ /**
+ * The mode of the thumbnail.
+ * @remark The mode determines how the image is cropped.
+ * @enum {UmbImagingCropMode}
+ */
+ @property()
+ mode: UmbImagingCropMode = UmbImagingCropMode.MIN;
+
+ /**
+ * The alt text for the thumbnail.
+ */
+ @property()
+ alt = '';
+
+ /**
+ * The fallback icon for the thumbnail.
+ */
+ @property()
+ icon = 'icon-picture';
+
+ /**
+ * The `loading` state of the thumbnail.
+ * @enum {'lazy' | 'eager'}
+ * @default 'lazy'
+ */
+ @property()
+ loading: 'lazy' | 'eager' = 'lazy';
+
+ @state()
+ private _isLoading = true;
+
+ @state()
+ private _thumbnailUrl = '';
+
+ #imagingRepository = new UmbImagingRepository(this);
+
+ protected override async firstUpdated() {
+ await this.#generateThumbnailUrl();
+ this._isLoading = false;
+ }
+
+ override render() {
+ return html` ${this.#renderThumbnail()} ${when(this._isLoading, () => this.#renderLoading())} `;
+ }
+
+ #renderLoading() {
+ return html`
`;
+ }
+
+ #renderThumbnail() {
+ if (this._isLoading) return nothing;
+
+ return when(
+ this._thumbnailUrl,
+ () =>
+ html``,
+ () => html``,
+ );
+ }
+
+ async #generateThumbnailUrl() {
+ const { data } = await this.#imagingRepository.requestThumbnailUrls(
+ [this.unique],
+ this.height,
+ this.width,
+ this.mode,
+ );
+ this._thumbnailUrl = data[0]?.url ?? '';
+ }
+
+ static override styles = [
+ UmbTextStyles,
+ css`
+ :host {
+ display: block;
+ position: relative;
+ overflow: hidden;
+ }
+
+ .container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ #figure {
+ display: block;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+
+ background-image: url('data:image/svg+xml;charset=utf-8,');
+ background-size: 10px 10px;
+ background-repeat: repeat;
+ }
+
+ #icon {
+ width: 100%;
+ height: 100%;
+ font-size: var(--uui-size-8);
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ [ELEMENT_NAME]: UmbImagingThumbnailElement;
+ }
+}
diff --git a/src/packages/media/imaging/components/index.ts b/src/packages/media/imaging/components/index.ts
new file mode 100644
index 0000000000..60818ea906
--- /dev/null
+++ b/src/packages/media/imaging/components/index.ts
@@ -0,0 +1 @@
+export * from './imaging-thumbnail.element.js';
diff --git a/src/packages/media/imaging/imaging.repository.ts b/src/packages/media/imaging/imaging.repository.ts
index d6f7935283..c602078a52 100644
--- a/src/packages/media/imaging/imaging.repository.ts
+++ b/src/packages/media/imaging/imaging.repository.ts
@@ -1,7 +1,6 @@
-import type { UmbImagingModel } from './types.js';
+import { UmbImagingCropMode, type UmbImagingModel } from './types.js';
import { UmbImagingServerDataSource } from './imaging.server.data.js';
import { UMB_IMAGING_STORE_CONTEXT } from './imaging.store.token.js';
-import { ImageCropModeModel } from '@umbraco-cms/backoffice/external/backend-api';
import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
@@ -68,7 +67,7 @@ export class UmbImagingRepository extends UmbRepositoryBase implements UmbApi {
* @param {ImageCropModeModel} mode - The crop mode
* @memberof UmbImagingRepository
*/
- async requestThumbnailUrls(uniques: Array, height: number, width: number, mode = ImageCropModeModel.MIN) {
+ async requestThumbnailUrls(uniques: Array, height: number, width: number, mode = UmbImagingCropMode.MIN) {
const imagingModel: UmbImagingModel = { height, width, mode };
return this.requestResizedItems(uniques, imagingModel);
}
diff --git a/src/packages/media/imaging/index.ts b/src/packages/media/imaging/index.ts
index afd4abe3b5..d05152d5dc 100644
--- a/src/packages/media/imaging/index.ts
+++ b/src/packages/media/imaging/index.ts
@@ -1,2 +1,3 @@
+export * from './components/index.js';
export { UmbImagingRepository } from './imaging.repository.js';
export { UMB_IMAGING_REPOSITORY_ALIAS } from './constants.js';
diff --git a/src/packages/media/imaging/types.ts b/src/packages/media/imaging/types.ts
index 41df2f5b95..0411433515 100644
--- a/src/packages/media/imaging/types.ts
+++ b/src/packages/media/imaging/types.ts
@@ -1,7 +1,9 @@
-import type { ImageCropModeModel } from '@umbraco-cms/backoffice/external/backend-api';
+import { ImageCropModeModel as UmbImagingCropMode } from '@umbraco-cms/backoffice/external/backend-api';
+
+export { UmbImagingCropMode };
export interface UmbImagingModel {
height?: number;
width?: number;
- mode?: ImageCropModeModel;
+ mode?: UmbImagingCropMode;
}
From 83e2785b782efae1e40f421c16f7b5c107332b17 Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Wed, 10 Jul 2024 10:55:02 +0200
Subject: [PATCH 02/12] feat: use the `` element in
media collections
---
.../collection/media-collection.context.ts | 29 ++++---------------
.../media-grid-collection-view.element.ts | 20 ++-----------
2 files changed, 7 insertions(+), 42 deletions(-)
diff --git a/src/packages/media/media/collection/media-collection.context.ts b/src/packages/media/media/collection/media-collection.context.ts
index 60ca5a16f5..4785fc9b8c 100644
--- a/src/packages/media/media/collection/media-collection.context.ts
+++ b/src/packages/media/media/collection/media-collection.context.ts
@@ -1,7 +1,5 @@
import type { UmbMediaCollectionFilterModel, UmbMediaCollectionItemModel } from './types.js';
import { UMB_MEDIA_GRID_COLLECTION_VIEW_ALIAS } from './views/index.js';
-import { UmbImagingRepository } from '@umbraco-cms/backoffice/imaging';
-import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
import { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
@@ -9,31 +7,14 @@ export class UmbMediaCollectionContext extends UmbDefaultCollectionContext<
UmbMediaCollectionItemModel,
UmbMediaCollectionFilterModel
> {
- #imagingRepository: UmbImagingRepository;
-
- #thumbnailItems = new UmbArrayState([], (x) => x.unique);
- public readonly thumbnailItems = this.#thumbnailItems.asObservable();
+ /**
+ * The thumbnail items that are currently displayed in the collection.
+ * @deprecated Use the `` element instead.
+ */
+ public readonly thumbnailItems = this.items;
constructor(host: UmbControllerHost) {
super(host, UMB_MEDIA_GRID_COLLECTION_VIEW_ALIAS);
- this.#imagingRepository = new UmbImagingRepository(host);
-
- this.observe(this.items, async (items) => {
- if (!items?.length) return;
-
- const { data } = await this.#imagingRepository.requestThumbnailUrls(
- items.map((m) => m.unique),
- 400,
- 400,
- );
-
- this.#thumbnailItems.setValue(
- items.map((item) => {
- const thumbnail = data?.find((m) => m.unique === item.unique)?.url;
- return { ...item, url: thumbnail };
- }),
- );
- });
}
}
diff --git a/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts b/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts
index 2345df4307..b4d6909278 100644
--- a/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts
+++ b/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts
@@ -52,7 +52,7 @@ export class UmbMediaGridCollectionViewElement extends UmbLitElement {
this.observe(this.#collectionContext.loading, (loading) => (this._loading = loading), '_observeLoading');
- this.observe(this.#collectionContext.thumbnailItems, (items) => (this._items = items), '_observeItems');
+ this.observe(this.#collectionContext.items, (items) => (this._items = items), '_observeItems');
this.observe(
this.#collectionContext.selection.selection,
@@ -127,13 +127,7 @@ export class UmbMediaGridCollectionViewElement extends UmbLitElement {
@selected=${() => this.#onSelect(item)}
@deselected=${() => this.#onDeselect(item)}
class="media-item">
- ${when(
- item.url,
- () => html``,
- () => html``,
- )}
-
-
+
`;
}
@@ -158,16 +152,6 @@ export class UmbMediaGridCollectionViewElement extends UmbLitElement {
grid-auto-rows: 200px;
gap: var(--uui-size-space-5);
}
-
- img {
- background-image: url('data:image/svg+xml;charset=utf-8,');
- background-size: 10px 10px;
- background-repeat: repeat;
- }
-
- umb-icon {
- font-size: var(--uui-size-8);
- }
`,
];
}
From a60b177b3b0305dbf247716c301baff3a11775b0 Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Wed, 10 Jul 2024 11:00:39 +0200
Subject: [PATCH 03/12] feat: use the `` element in the
media picker modal
---
.../media-picker-modal.element.ts | 35 ++++---------------
1 file changed, 6 insertions(+), 29 deletions(-)
diff --git a/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts
index 97c3f20f4f..bf346bbeec 100644
--- a/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts
+++ b/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts
@@ -2,13 +2,11 @@ import { UmbMediaItemRepository } from '../../repository/index.js';
import { UmbMediaTreeRepository } from '../../tree/media-tree.repository.js';
import { UMB_MEDIA_ROOT_ENTITY_TYPE } from '../../entity.js';
import type { UmbDropzoneElement } from '../../dropzone/dropzone.element.js';
-import type { UmbMediaItemModel } from '../../repository/index.js';
import type { UmbMediaCardItemModel, UmbMediaPathModel } from './types.js';
import type { UmbMediaPickerFolderPathElement } from './components/media-picker-folder-path.element.js';
import type { UmbMediaPickerModalData, UmbMediaPickerModalValue } from './media-picker-modal.token.js';
import { css, html, customElement, state, repeat, ifDefined, query } from '@umbraco-cms/backoffice/external/lit';
import { debounce } from '@umbraco-cms/backoffice/utils';
-import { UmbImagingRepository } from '@umbraco-cms/backoffice/imaging';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { UMB_CONTENT_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content';
import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
@@ -22,13 +20,9 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement<
> {
#mediaTreeRepository = new UmbMediaTreeRepository(this); // used to get file structure
#mediaItemRepository = new UmbMediaItemRepository(this); // used to search
- #imagingRepository = new UmbImagingRepository(this); // used to get image renditions
#dataType?: { unique: string };
- @state()
- private _filter: (item: UmbMediaCardItemModel) => boolean = () => true;
-
@state()
private _selectableFilter: (item: UmbMediaCardItemModel) => boolean = () => true;
@@ -62,7 +56,6 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement<
override async connectedCallback(): Promise {
super.connectedCallback();
- if (this.data?.filter) this._filter = this.data?.filter;
if (this.data?.pickableFilter) this._selectableFilter = this.data?.pickableFilter;
if (this.data?.startNode) {
@@ -87,27 +80,10 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement<
take: 100,
});
- this.#mediaItemsCurrentFolder = await this.#mapMediaUrls(data?.items ?? []);
+ this.#mediaItemsCurrentFolder = data?.items ?? [];
this.#filterMediaItems();
}
- async #mapMediaUrls(items: Array): Promise> {
- if (!items.length) return [];
-
- const { data } = await this.#imagingRepository.requestThumbnailUrls(
- items.map((item) => item.unique),
- 400,
- 400,
- );
-
- return items
- .map((item): UmbMediaCardItemModel => {
- const src = data?.find((media) => media.unique === item.unique)?.url;
- return { ...item, src };
- })
- .filter((item) => this._filter(item));
- }
-
#onOpen(item: UmbMediaCardItemModel) {
this._currentMediaEntity = {
name: item.name,
@@ -152,7 +128,7 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement<
}
// Map urls for search results as we are going to show for all folders (as long they aren't trashed).
- this._mediaFilteredList = await this.#mapMediaUrls(data.filter((found) => found.isTrashed === false));
+ this._mediaFilteredList = data.filter((found) => found.isTrashed === false);
}
#debouncedSearch = debounce(() => {
@@ -240,9 +216,10 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement<
@deselected=${() => this.#onDeselected(item)}
?selected=${this.value?.selection?.find((value) => value === item.unique)}
?selectable=${!disabled}>
- ${item.src
- ? html``
- : html``}
+
`;
}
From 3b8dd65dc34d4c18eff0b304c60c9e7e43d1100c Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Wed, 10 Jul 2024 11:00:56 +0200
Subject: [PATCH 04/12] feat: use the `` element in the
media picker property editor
---
.../input-rich-media/input-rich-media.element.ts | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts b/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts
index 82bda097f4..2fa650211e 100644
--- a/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts
+++ b/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts
@@ -4,11 +4,10 @@ import { UMB_IMAGE_CROPPER_EDITOR_MODAL, UMB_MEDIA_PICKER_MODAL } from '../../mo
import type { UmbCropModel, UmbMediaPickerPropertyValue } from '../../property-editors/index.js';
import type { UmbMediaItemModel } from '../../repository/index.js';
import type { UmbUploadableFileModel } from '../../dropzone/index.js';
-import { customElement, html, ifDefined, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit';
+import { customElement, html, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit';
import { umbConfirmModal, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbId } from '@umbraco-cms/backoffice/id';
-import { UmbImagingRepository } from '@umbraco-cms/backoffice/imaging';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
@@ -162,8 +161,6 @@ export class UmbInputRichMediaElement extends UUIFormControlMixin(UmbLitElement,
#itemRepository = new UmbMediaItemRepository(this);
- #imagingRepository = new UmbImagingRepository(this);
-
#modalRouter: UmbModalRouteRegistrationController;
#modalManager?: UmbModalManagerContext;
@@ -249,16 +246,13 @@ export class UmbInputRichMediaElement extends UUIFormControlMixin(UmbLitElement,
const uniques = this.items.map((item) => item.mediaKey);
const { data: items } = await this.#itemRepository.requestItems(uniques);
- const { data: thumbnails } = await this.#imagingRepository.requestThumbnailUrls(uniques, 400, 400);
this._cards = this.items.map((item) => {
const media = items?.find((x) => x.unique === item.mediaKey);
- const thumbnail = thumbnails?.find((x) => x.unique === item.mediaKey);
return {
unique: item.key,
media: item.mediaKey,
name: media?.name ?? '',
- src: thumbnail?.url,
icon: media?.mediaType?.icon,
isTrashed: media?.isTrashed ?? false,
};
@@ -366,9 +360,10 @@ export class UmbInputRichMediaElement extends UUIFormControlMixin(UmbLitElement,
const href = this._routeBuilder?.({ key: item.unique });
return html`
- ${item.src
- ? html``
- : html``}
+
${this.#renderIsTrashed(item)}
Date: Wed, 10 Jul 2024 11:01:11 +0200
Subject: [PATCH 05/12] feat: set defaults to 300x300 thumbnails
---
.../imaging/components/imaging-thumbnail.element.ts | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/packages/media/imaging/components/imaging-thumbnail.element.ts b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
index caf6261772..c1c3a59275 100644
--- a/src/packages/media/imaging/components/imaging-thumbnail.element.ts
+++ b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
@@ -16,16 +16,18 @@ export class UmbImagingThumbnailElement extends UmbLitElement {
unique = '';
/**
- * The width of the thumbnail.
+ * The width of the thumbnail in pixels.
+ * @default 300
*/
@property({ type: Number })
- width = 400;
+ width = 300;
/**
- * The height of the thumbnail.
+ * The height of the thumbnail in pixels.
+ * @default 300
*/
@property({ type: Number })
- height = 400;
+ height = 300;
/**
* The mode of the thumbnail.
From a4496f9a172ae34ae4ed748303a00a0c52c8e81d Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Wed, 10 Jul 2024 11:06:52 +0200
Subject: [PATCH 06/12] feat: use the `` element in the
`` element
---
.../input-media/input-media.element.ts | 29 +++++--------------
1 file changed, 7 insertions(+), 22 deletions(-)
diff --git a/src/packages/media/media/components/input-media/input-media.element.ts b/src/packages/media/media/components/input-media/input-media.element.ts
index 7affdb7650..8377fa87d1 100644
--- a/src/packages/media/media/components/input-media/input-media.element.ts
+++ b/src/packages/media/media/components/input-media/input-media.element.ts
@@ -1,7 +1,6 @@
import type { UmbMediaCardItemModel } from '../../modals/index.js';
import type { UmbMediaItemModel } from '../../repository/index.js';
import { UmbMediaPickerContext } from './input-media.context.js';
-import { UmbImagingRepository } from '@umbraco-cms/backoffice/imaging';
import { css, customElement, html, ifDefined, property, repeat, state } from '@umbraco-cms/backoffice/external/lit';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
@@ -11,6 +10,8 @@ import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
+import '@umbraco-cms/backoffice/imaging';
+
const elementName = 'umb-input-media';
@customElement(elementName)
@@ -123,8 +124,6 @@ export class UmbInputMediaElement extends UmbFormControlMixin !this._cards.find((card) => card.unique === item.unique));
if (selectedItems?.length && !missingCards.length) return;
- if (!selectedItems?.length) {
- this._cards = [];
- return;
- }
-
- const uniques = selectedItems.map((x) => x.unique);
-
- const { data: thumbnails } = await this.#imagingRepository.requestThumbnailUrls(uniques, 400, 400);
-
- this._cards = selectedItems.map((item) => {
- const thumbnail = thumbnails?.find((x) => x.unique === item.unique);
- return {
- ...item,
- src: thumbnail?.url,
- };
- });
+ this._cards = selectedItems ?? [];
});
this.addValidator(
@@ -228,9 +212,10 @@ export class UmbInputMediaElement extends UmbFormControlMixin
- ${item.src
- ? html``
- : html``}
+
${this.#renderIsTrashed(item)}
Date: Wed, 10 Jul 2024 11:07:11 +0200
Subject: [PATCH 07/12] chore: add imports in case the elements are shown
outside Content or Media
---
.../collection/views/grid/media-grid-collection-view.element.ts | 2 ++
.../components/input-rich-media/input-rich-media.element.ts | 2 ++
.../media/modals/media-picker/media-picker-modal.element.ts | 2 ++
3 files changed, 6 insertions(+)
diff --git a/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts b/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts
index b4d6909278..27042a9738 100644
--- a/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts
+++ b/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts
@@ -8,6 +8,8 @@ import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal';
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
+import '@umbraco-cms/backoffice/imaging';
+
@customElement('umb-media-grid-collection-view')
export class UmbMediaGridCollectionViewElement extends UmbLitElement {
@state()
diff --git a/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts b/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts
index 2fa650211e..43d8a51bc7 100644
--- a/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts
+++ b/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts
@@ -16,6 +16,8 @@ import type { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal';
import type { UmbModalRouteBuilder } from '@umbraco-cms/backoffice/router';
import type { UmbVariantId } from '@umbraco-cms/backoffice/variant';
+import '@umbraco-cms/backoffice/imaging';
+
type UmbRichMediaCardModel = {
unique: string;
media: string;
diff --git a/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts
index bf346bbeec..b83579178f 100644
--- a/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts
+++ b/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts
@@ -11,6 +11,8 @@ import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { UMB_CONTENT_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content';
import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
+import '@umbraco-cms/backoffice/imaging';
+
const root: UmbMediaPathModel = { name: 'Media', unique: null, entityType: UMB_MEDIA_ROOT_ENTITY_TYPE };
@customElement('umb-media-picker-modal')
From 0459403e14597e16dac47dc800083ab6a46f2c0c Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Wed, 10 Jul 2024 11:18:58 +0200
Subject: [PATCH 08/12] chore: avoid having firstUpdated async
---
.../imaging/components/imaging-thumbnail.element.ts | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/packages/media/imaging/components/imaging-thumbnail.element.ts b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
index c1c3a59275..f2e8cf5482 100644
--- a/src/packages/media/imaging/components/imaging-thumbnail.element.ts
+++ b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
@@ -65,9 +65,8 @@ export class UmbImagingThumbnailElement extends UmbLitElement {
#imagingRepository = new UmbImagingRepository(this);
- protected override async firstUpdated() {
- await this.#generateThumbnailUrl();
- this._isLoading = false;
+ protected override firstUpdated() {
+ this.#generateThumbnailUrl();
}
override render() {
@@ -101,7 +100,9 @@ export class UmbImagingThumbnailElement extends UmbLitElement {
this.width,
this.mode,
);
- this._thumbnailUrl = data[0]?.url ?? '';
+
+ this._thumbnailUrl = data[0].url ?? '';
+ this._isLoading = false;
}
static override styles = [
From 39f5a2399c363acd7bbf136005a2449938bffe6b Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Wed, 10 Jul 2024 11:19:39 +0200
Subject: [PATCH 09/12] fix: check for undefined
---
.../media/imaging/components/imaging-thumbnail.element.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/packages/media/imaging/components/imaging-thumbnail.element.ts b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
index f2e8cf5482..9450c74f76 100644
--- a/src/packages/media/imaging/components/imaging-thumbnail.element.ts
+++ b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
@@ -101,7 +101,7 @@ export class UmbImagingThumbnailElement extends UmbLitElement {
this.mode,
);
- this._thumbnailUrl = data[0].url ?? '';
+ this._thumbnailUrl = data?.[0].url ?? '';
this._isLoading = false;
}
From 844fdb6bab42b4b55e4b4b8e8e6b3a5d2aa385ea Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Wed, 10 Jul 2024 11:20:20 +0200
Subject: [PATCH 10/12] fix: check for undefined
---
.../media/imaging/components/imaging-thumbnail.element.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/packages/media/imaging/components/imaging-thumbnail.element.ts b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
index 9450c74f76..1407b2f15b 100644
--- a/src/packages/media/imaging/components/imaging-thumbnail.element.ts
+++ b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
@@ -101,7 +101,7 @@ export class UmbImagingThumbnailElement extends UmbLitElement {
this.mode,
);
- this._thumbnailUrl = data?.[0].url ?? '';
+ this._thumbnailUrl = data?.[0]?.url ?? '';
this._isLoading = false;
}
From afa2cdefcfba8092d20ba1305116026b1e64af21 Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Wed, 10 Jul 2024 11:32:44 +0200
Subject: [PATCH 11/12] feat: add support for an IntersectionObserver in case
the images are lazily loaded
---
.../components/imaging-thumbnail.element.ts | 25 ++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/src/packages/media/imaging/components/imaging-thumbnail.element.ts b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
index 1407b2f15b..cdcb474deb 100644
--- a/src/packages/media/imaging/components/imaging-thumbnail.element.ts
+++ b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
@@ -65,14 +65,33 @@ export class UmbImagingThumbnailElement extends UmbLitElement {
#imagingRepository = new UmbImagingRepository(this);
- protected override firstUpdated() {
- this.#generateThumbnailUrl();
- }
+ #intersectionObserver?: IntersectionObserver;
override render() {
return html` ${this.#renderThumbnail()} ${when(this._isLoading, () => this.#renderLoading())} `;
}
+ override connectedCallback() {
+ super.connectedCallback();
+
+ if (this.loading === 'lazy') {
+ this.#intersectionObserver = new IntersectionObserver((entries) => {
+ if (entries[0].isIntersecting) {
+ this.#generateThumbnailUrl();
+ this.#intersectionObserver?.disconnect();
+ }
+ });
+ this.#intersectionObserver.observe(this);
+ } else {
+ this.#generateThumbnailUrl();
+ }
+ }
+
+ override disconnectedCallback() {
+ super.disconnectedCallback();
+ this.#intersectionObserver?.disconnect();
+ }
+
#renderLoading() {
return html`
`;
}
From ff90ca1dbb879a6fdedf3d3065fec82a2fdbc7f3 Mon Sep 17 00:00:00 2001
From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Date: Wed, 10 Jul 2024 11:33:07 +0200
Subject: [PATCH 12/12] feat: center all items inside whether they be the
figure, icon, or loader
---
.../imaging/components/imaging-thumbnail.element.ts | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/packages/media/imaging/components/imaging-thumbnail.element.ts b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
index cdcb474deb..81ae2ff903 100644
--- a/src/packages/media/imaging/components/imaging-thumbnail.element.ts
+++ b/src/packages/media/imaging/components/imaging-thumbnail.element.ts
@@ -93,7 +93,7 @@ export class UmbImagingThumbnailElement extends UmbLitElement {
}
#renderLoading() {
- return html`
`;
+ return html`
`;
}
#renderThumbnail() {
@@ -131,12 +131,19 @@ export class UmbImagingThumbnailElement extends UmbLitElement {
display: block;
position: relative;
overflow: hidden;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
}
- .container {
+ #loader {
display: flex;
justify-content: center;
align-items: center;
+ height: 100%;
+ width: 100%;
}
#figure {