Skip to content

Commit 193d8af

Browse files
authored
Icon Picker: Deselect current icon & add “No icon” tile inside the modal. (#20342)
* Show selected icon and color(if any) when open the modal. * Add a button inside the modal that clears the value * Deselect the value if we click the already selected icon. * Add placeholder icon and some localization for labels * Remove unused variable * Added config for the placeholder icon in case no icon is selected.
1 parent dc92cf4 commit 193d8af

File tree

7 files changed

+90
-44
lines changed

7 files changed

+90
-44
lines changed

src/Umbraco.Web.UI.Client/src/assets/lang/en.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ export default {
531531
anchorLinkPicker: 'Anchor or querystring',
532532
anchorInsert: 'Name',
533533
closeThisWindow: 'Close this window',
534+
colorSwitcher: 'Color switcher',
534535
confirmdelete: (name: string) => `Are you sure you want to delete${name ? ` <strong>${name}</strong>` : ''}?`,
535536
confirmdeleteNumberOfItems: 'Are you sure you want to delete <strong>%0%</strong> of <strong>%1%</strong> items',
536537
confirmdisable: 'Are you sure you want to disable',
@@ -621,6 +622,7 @@ export default {
621622
selectUser: 'Select user',
622623
selectUsers: 'Select users',
623624
chooseUsers: 'Choose users',
625+
noIcon: 'No icon',
624626
noIconsFound: 'No icons were found',
625627
noMacroParams: 'There are no parameters for this macro',
626628
noMacros: 'There are no macros available to insert',

src/Umbraco.Web.UI.Client/src/assets/lang/es.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ export default {
286286
anchorInsert: 'Nombre',
287287
assignDomain: 'Administrar dominios',
288288
closeThisWindow: 'Cerrar esta ventana',
289+
colorSwitcher: 'Selector de color',
289290
confirmdelete: 'Estás seguro que quieres borrar',
290291
confirmdisable: 'Estás seguro que quieres deshabilitar',
291292
confirmlogout: '¿Estás seguro?',
@@ -349,6 +350,7 @@ export default {
349350
selectLanguages: 'Seleccionar idiomas',
350351
selectSections: 'Selecciona secciones',
351352
selectUsers: 'Selecciona usuarios',
353+
noIcon: 'Sin icono',
352354
noIconsFound: 'No se encontraron iconos',
353355
noMacroParams: 'No hay parámetros para esta macro',
354356
noMacros: 'No hay macros disponibles para insertar',

src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icon-picker-modal/icon-picker-modal.element.ts

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
import type { UmbIconDefinition } from '../types.js';
22
import { UMB_ICON_REGISTRY_CONTEXT } from '../icon-registry.context-token.js';
33
import type { UmbIconPickerModalData, UmbIconPickerModalValue } from './icon-picker-modal.token.js';
4-
import { css, customElement, html, nothing, query, repeat, state } from '@umbraco-cms/backoffice/external/lit';
4+
import {
5+
css,
6+
customElement,
7+
html,
8+
ifDefined,
9+
nothing,
10+
query,
11+
repeat,
12+
state,
13+
} from '@umbraco-cms/backoffice/external/lit';
514
import { extractUmbColorVariable, umbracoColors } from '@umbraco-cms/backoffice/resources';
615
import { umbFocus } from '@umbraco-cms/backoffice/lit-element';
716
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
@@ -21,12 +30,6 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
2130
@state()
2231
private _colorList = umbracoColors.filter((color) => !color.legacy);
2332

24-
@state()
25-
private _currentIcon?: string;
26-
27-
@state()
28-
private _currentColor = 'text';
29-
3033
constructor() {
3134
super();
3235
this.consumeContext(UMB_ICON_REGISTRY_CONTEXT, (context) => {
@@ -47,44 +50,32 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
4750
}
4851
}
4952

50-
override connectedCallback() {
51-
super.connectedCallback();
52-
this._iconsFiltered = this.#icons;
53-
54-
if (this.modalContext) {
55-
this.observe(
56-
this.modalContext?.value,
57-
(newValue) => {
58-
this._currentIcon = newValue?.icon;
59-
this._currentColor = newValue?.color ?? 'text';
60-
},
61-
'_observeModalContextValue',
62-
);
63-
}
64-
}
65-
6653
#changeIcon(e: InputEvent | KeyboardEvent, iconName: string) {
67-
if (e.type == 'click' || (e.type == 'keyup' && (e as KeyboardEvent).key == 'Enter')) {
68-
this.modalContext?.updateValue({ icon: iconName });
69-
}
54+
const isActivate = e.type === 'click' || (e.type === 'keyup' && (e as KeyboardEvent).key === 'Enter');
55+
if (!isActivate) return;
56+
57+
const nextIcon = this.value.icon === iconName ? '' : iconName;
58+
this.modalContext?.updateValue({ icon: nextIcon });
7059
}
7160

7261
#onColorChange(e: UUIColorSwatchesEvent) {
7362
const colorAlias = e.target.value;
7463
this.modalContext?.updateValue({ color: colorAlias });
75-
this._currentColor = colorAlias;
7664
}
7765

66+
#clearIcon = () => {
67+
this.modalContext?.updateValue({ icon: '' });
68+
};
69+
7870
override render() {
79-
// TODO: Missing localization in general. [NL]
8071
return html`
81-
<umb-body-layout headline="Select Icon">
72+
<umb-body-layout headline=${this.localize.term('defaultdialogs_selectIcon')}>
8273
<div id="container">
8374
${this.renderSearch()}
8475
<hr />
8576
<uui-color-swatches
86-
.value=${this._currentColor}
87-
label="Color switcher for icons"
77+
value=${ifDefined(this.value.color)}
78+
label=${this.localize.term('defaultdialogs_colorSwitcher')}
8879
@change=${this.#onColorChange}>
8980
${
9081
// TODO: Missing localization for the color aliases. [NL]
@@ -101,7 +92,18 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
10192
}
10293
</uui-color-swatches>
10394
<hr />
104-
<uui-scroll-container id="icons">${this.renderIcons()}</uui-scroll-container>
95+
<uui-scroll-container id="icons">
96+
<uui-button
97+
class=${!this.value.icon ? 'selected' : ''}
98+
label=${this.localize.term('defaultdialogs_noIcon')}
99+
title=${this.localize.term('defaultdialogs_noIcon')}
100+
@click=${this.#clearIcon}
101+
@keyup=${(e: KeyboardEvent) => {
102+
if (e.key === 'Enter' || e.key === ' ') this.#clearIcon();
103+
}}>
104+
<uui-icon style="opacity:.35" name=${ifDefined(this.data?.placeholder)}></uui-icon> </uui-button
105+
>${this.renderIcons()}</uui-scroll-container
106+
>
105107
</div>
106108
<uui-button
107109
slot="actions"
@@ -140,11 +142,11 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
140142
<uui-button
141143
label=${icon.name}
142144
title=${icon.name}
143-
class=${icon.name === this._currentIcon ? 'selected' : ''}
145+
class=${icon.name === this.value.icon ? 'selected' : ''}
144146
@click=${(e: InputEvent) => this.#changeIcon(e, icon.name)}
145147
@keyup=${(e: KeyboardEvent) => this.#changeIcon(e, icon.name)}>
146148
<uui-icon
147-
style="--uui-icon-color: var(${extractUmbColorVariable(this._currentColor)})"
149+
style="--uui-icon-color: var(${extractUmbColorVariable(this.value.color ?? 'text')})"
148150
name=${icon.name}></uui-icon>
149151
</uui-button>
150152
`,
@@ -199,7 +201,7 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
199201
border-radius: var(--uui-border-radius);
200202
font-size: 16px; /* specific for icons */
201203
}
202-
#icons uui-button:focus,
204+
#icons uui-button:focus-visible,
203205
#icons uui-button:hover,
204206
#icons uui-button.selected {
205207
outline: 2px solid var(--uui-color-selected);

src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icon-picker-modal/icon-picker-modal.token.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
22

3-
export type UmbIconPickerModalData = never;
3+
export interface UmbIconPickerModalData {
4+
placeholder?: string;
5+
}
46

57
export interface UmbIconPickerModalValue {
68
color: string | undefined;

src/Umbraco.Web.UI.Client/src/packages/property-editors/collection/manifests.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ const propertyEditorUiManifest: ManifestPropertyEditorUi = {
4646
label: 'Workspace View icon',
4747
description: "The icon for the Collection's Workspace View.",
4848
propertyEditorUiAlias: 'Umb.PropertyEditorUi.IconPicker',
49+
config: [{ alias: 'placeholder', value: 'icon-grid' }],
4950
},
5051
{
5152
alias: 'tabName',

src/Umbraco.Web.UI.Client/src/packages/property-editors/icon-picker/manifests.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ export const manifests: Array<UmbExtensionManifest> = [
88
label: 'Icon Picker',
99
icon: 'icon-autofill',
1010
group: 'common',
11+
settings: {
12+
properties: [
13+
{
14+
alias: 'placeholder',
15+
label: 'Placeholder icon (empty state)',
16+
description: 'Icon name to show when no icon is selected',
17+
propertyEditorUiAlias: 'Umb.PropertyEditorUi.IconPicker',
18+
},
19+
],
20+
},
1121
},
1222
},
1323
];

src/Umbraco.Web.UI.Client/src/packages/property-editors/icon-picker/property-editor-ui-icon-picker.element.ts

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
2-
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/property-editor';
1+
import { html, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
2+
import type {
3+
UmbPropertyEditorConfigCollection,
4+
UmbPropertyEditorUiElement,
5+
} from '@umbraco-cms/backoffice/property-editor';
36
import { umbOpenModal } from '@umbraco-cms/backoffice/modal';
47
import { UMB_ICON_PICKER_MODAL } from '@umbraco-cms/backoffice/icon';
58
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@@ -35,11 +38,29 @@ export class UmbPropertyEditorUIIconPickerElement extends UmbLitElement implemen
3538
@state()
3639
private _color = '';
3740

41+
@state()
42+
private _placeholderIcon = '';
43+
44+
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
45+
if (!config) return;
46+
const placeholder = config.getValueByAlias('placeholder');
47+
this._placeholderIcon = typeof placeholder === 'string' ? placeholder : '';
48+
}
49+
3850
private async _openModal() {
39-
const data = await umbOpenModal(this, UMB_ICON_PICKER_MODAL).catch(() => undefined);
51+
const data = await umbOpenModal(this, UMB_ICON_PICKER_MODAL, {
52+
value: {
53+
icon: this._icon,
54+
color: this._color,
55+
},
56+
data: { placeholder: this._placeholderIcon },
57+
}).catch(() => undefined);
58+
4059
if (!data) return;
4160

42-
if (data.color) {
61+
if (!data.icon) {
62+
this.value = '';
63+
} else if (data.color) {
4364
this.value = `${data.icon} color-${data.color}`;
4465
} else {
4566
this.value = data.icon as string;
@@ -49,15 +70,21 @@ export class UmbPropertyEditorUIIconPickerElement extends UmbLitElement implemen
4970
}
5071

5172
override render() {
73+
const isEmpty = !this._icon;
74+
5275
return html`
5376
<uui-button
5477
compact
55-
label=${this.localize.term('defaultdialogs_selectIcon')}
5678
look="outline"
79+
label=${this.localize.term('defaultdialogs_selectIcon')}
5780
@click=${this._openModal}>
58-
${this._color
59-
? html` <uui-icon name="${this._icon}" style="color:var(${extractUmbColorVariable(this._color)})"></uui-icon>`
60-
: html` <uui-icon name="${this._icon}"></uui-icon>`}
81+
${isEmpty
82+
? html` <uui-icon name="${ifDefined(this._placeholderIcon)}" style="opacity:.35"></uui-icon> `
83+
: this._color
84+
? html`
85+
<uui-icon name="${this._icon}" style="color:var(${extractUmbColorVariable(this._color)})"> </uui-icon>
86+
`
87+
: html`<uui-icon name="${this._icon}"></uui-icon>`}
6188
</uui-button>
6289
`;
6390
}

0 commit comments

Comments
 (0)