Skip to content

Commit 635890b

Browse files
authored
Merge pull request #1840 from umbraco/feature/media-picker-filter-and-media-input-config
Feature: MediaPickerModal Filters & InputMedia Configuration
2 parents 912c07f + c8b3cb7 commit 635890b

File tree

15 files changed

+280
-147
lines changed

15 files changed

+280
-147
lines changed

src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,13 @@ export class UmbMediaGridCollectionViewElement extends UmbLitElement {
153153
grid-auto-rows: 200px;
154154
gap: var(--uui-size-space-5);
155155
}
156+
157+
img {
158+
background-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" fill-opacity=".1"><path d="M50 0h50v50H50zM0 50h50v50H0z"/></svg>');
159+
background-size: 10px 10px;
160+
background-repeat: repeat;
161+
}
162+
156163
umb-icon {
157164
font-size: var(--uui-size-8);
158165
}

src/packages/media/media/components/input-media/input-media.context.ts

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { UMB_MEDIA_PICKER_MODAL, type UmbMediaCardItemModel } from '../../modals/index.js';
1+
import {
2+
UMB_MEDIA_PICKER_MODAL,
3+
type UmbMediaPickerModalData,
4+
type UmbMediaPickerModalValue,
5+
type UmbMediaCardItemModel,
6+
} from '../../modals/index.js';
27
import { UMB_MEDIA_ITEM_REPOSITORY_ALIAS } from '../../repository/index.js';
38
import type { UmbMediaItemModel } from '../../repository/item/types.js';
4-
import type { UmbMediaTreeItemModel } from '../../tree/index.js';
5-
import type {
6-
UmbMediaTreePickerModalData,
7-
UmbMediaTreePickerModalValue,
8-
} from '../../tree/media-tree-picker-modal.token.js';
99
import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
1010
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
1111
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
@@ -14,9 +14,9 @@ import { ImageCropModeModel } from '@umbraco-cms/backoffice/external/backend-api
1414

1515
export class UmbMediaPickerContext extends UmbPickerInputContext<
1616
UmbMediaItemModel,
17-
UmbMediaTreeItemModel,
18-
UmbMediaTreePickerModalData,
19-
UmbMediaTreePickerModalValue
17+
UmbMediaItemModel,
18+
UmbMediaPickerModalData<UmbMediaItemModel>,
19+
UmbMediaPickerModalValue
2020
> {
2121
#imagingRepository: UmbImagingRepository;
2222

@@ -40,14 +40,7 @@ export class UmbMediaPickerContext extends UmbPickerInputContext<
4040
this.#cardItems.setValue(
4141
selectedItems.map((item) => {
4242
const url = data?.find((x) => x.unique === item.unique)?.url;
43-
return {
44-
icon: item.mediaType.icon,
45-
name: item.name,
46-
unique: item.unique,
47-
isTrashed: item.isTrashed,
48-
entityType: item.entityType,
49-
url,
50-
};
43+
return { ...item, url };
5144
}),
5245
);
5346
});

src/packages/media/media/components/input-media/input-media.element.ts

Lines changed: 33 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
88
import { UmbModalRouteRegistrationController, UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal';
99
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
1010
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
11-
import type { UmbUploadableFileModel } from '@umbraco-cms/backoffice/media';
1211

1312
@customElement('umb-input-media')
1413
export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '') {
@@ -22,9 +21,10 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '')
2221
identifier: 'Umb.SorterIdentifier.InputMedia',
2322
itemSelector: 'uui-card-media',
2423
containerSelector: '.container',
24+
/** TODO: This component probably needs some grid-like logic for resolve placement... [LI] */
25+
resolvePlacement: () => false,
2526
onChange: ({ model }) => {
2627
this.selection = model;
27-
2828
this.dispatchEvent(new UmbChangeEvent());
2929
},
3030
});
@@ -89,6 +89,12 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '')
8989
@property({ type: Boolean })
9090
showOpenButton?: boolean;
9191

92+
@property({ type: String })
93+
startNode = '';
94+
95+
@property({ type: Boolean })
96+
multiple = false;
97+
9298
@property()
9399
public set value(idsString: string) {
94100
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
@@ -99,10 +105,10 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '')
99105
}
100106

101107
@state()
102-
private _editMediaPath = '';
108+
protected editMediaPath = '';
103109

104110
@state()
105-
private _items?: Array<UmbMediaCardItemModel>;
111+
protected items?: Array<UmbMediaCardItemModel>;
106112

107113
#pickerContext = new UmbMediaPickerContext(this);
108114

@@ -115,12 +121,12 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '')
115121
return { data: { entityType: 'media', preset: {} } };
116122
})
117123
.observeRouteBuilder((routeBuilder) => {
118-
this._editMediaPath = routeBuilder({});
124+
this.editMediaPath = routeBuilder({});
119125
});
120126

121127
this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')));
122128
this.observe(this.#pickerContext.cardItems, (cardItems) => {
123-
this._items = cardItems;
129+
this.items = cardItems;
124130
});
125131

126132
this.addValidator(
@@ -149,43 +155,31 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '')
149155

150156
#openPicker() {
151157
this.#pickerContext.openPicker({
152-
hideTreeRoot: true,
158+
multiple: this.multiple,
159+
startNode: this.startNode,
153160
pickableFilter: this.#pickableFilter,
154161
});
155162
}
156163

157-
async #onUploadCompleted(e: CustomEvent) {
158-
const completed = e.detail?.completed as Array<UmbUploadableFileModel>;
159-
const uploaded = completed.map((file) => file.unique);
160-
161-
this.selection = [...this.selection, ...uploaded];
162-
this.dispatchEvent(new UmbChangeEvent());
164+
protected onRemove(item: UmbMediaCardItemModel) {
165+
this.#pickerContext.requestRemoveItem(item.unique);
163166
}
164167

165168
render() {
166-
return html`${this.#renderDropzone()}
167-
<div class="container">${this.#renderItems()} ${this.#renderAddButton()}</div>`;
168-
}
169-
170-
#renderDropzone() {
171-
if (this._items && this._items.length >= this.max) return;
172-
return html`<umb-dropzone
173-
id="dropzone"
174-
?multiple=${this.max === 1}
175-
@change=${this.#onUploadCompleted}></umb-dropzone>`;
169+
return html`<div class="container">${this.#renderItems()} ${this.#renderAddButton()}</div>`;
176170
}
177171

178172
#renderItems() {
179-
if (!this._items?.length) return;
173+
if (!this.items?.length) return;
180174
return html`${repeat(
181-
this._items,
175+
this.items,
182176
(item) => item.unique,
183-
(item) => this.#renderItem(item),
177+
(item) => this.renderItem(item),
184178
)}`;
185179
}
186180

187181
#renderAddButton() {
188-
if (this._items && this.max && this._items.length >= this.max) return;
182+
if ((this.items && this.max && this.items.length >= this.max) || (this.items?.length && !this.multiple)) return;
189183
return html`
190184
<uui-button
191185
id="btn-add"
@@ -198,30 +192,29 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '')
198192
`;
199193
}
200194

201-
#renderItem(item: UmbMediaCardItemModel) {
195+
protected renderItem(item: UmbMediaCardItemModel) {
202196
return html`
203-
<uui-card-media name=${ifDefined(item.name === null ? undefined : item.name)} detail=${ifDefined(item.unique)}>
197+
<uui-card-media
198+
name=${ifDefined(item.name === null ? undefined : item.name)}
199+
detail=${ifDefined(item.unique)}
200+
href="${this.editMediaPath}edit/${item.unique}">
204201
${item.url
205202
? html`<img src=${item.url} alt=${item.name} />`
206-
: html`<umb-icon name=${ifDefined(item.icon)}></umb-icon>`}
207-
${this.#renderIsTrashed(item)}
203+
: html`<umb-icon name=${ifDefined(item.mediaType.icon)}></umb-icon>`}
204+
${this.renderIsTrashed(item)}
208205
<uui-action-bar slot="actions">
209-
${this.#renderOpenButton(item)}
210-
<uui-button label="Copy media" look="secondary">
211-
<uui-icon name="icon-documents"></uui-icon>
212-
</uui-button>
213206
<uui-button
207+
label=${this.localize.term('general_remove')}
214208
look="secondary"
215-
@click=${() => this.#pickerContext.requestRemoveItem(item.unique)}
216-
label="Remove media ${item.name}">
209+
@click=${() => this.onRemove(item)}>
217210
<uui-icon name="icon-trash"></uui-icon>
218211
</uui-button>
219212
</uui-action-bar>
220213
</uui-card-media>
221214
`;
222215
}
223216

224-
#renderIsTrashed(item: UmbMediaCardItemModel) {
217+
protected renderIsTrashed(item: UmbMediaCardItemModel) {
225218
if (!item.isTrashed) return;
226219
return html`
227220
<uui-tag size="s" slot="tag" color="danger">
@@ -230,18 +223,6 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '')
230223
`;
231224
}
232225

233-
#renderOpenButton(item: UmbMediaCardItemModel) {
234-
if (!this.showOpenButton) return;
235-
return html`
236-
<uui-button
237-
compact
238-
href="${this._editMediaPath}edit/${item.unique}"
239-
label=${this.localize.term('general_edit') + ` ${item.name}`}>
240-
<uui-icon name="icon-edit"></uui-icon>
241-
</uui-button>
242-
`;
243-
}
244-
245226
static styles = [
246227
css`
247228
:host {
@@ -250,8 +231,8 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '')
250231
.container {
251232
display: grid;
252233
gap: var(--uui-size-space-3);
253-
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
254-
grid-template-rows: repeat(auto-fill, minmax(160px, 1fr));
234+
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
235+
grid-auto-rows: 150px;
255236
}
256237
257238
#btn-add {

0 commit comments

Comments
 (0)