Changed the Image crop UI component to fit the new Backoffice UI design (#19204)
* Changed the Image crop UI component to fit the new Backoffice UI * style adjustments --------- Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
This commit is contained in:
@@ -10,7 +10,7 @@ export const manifest: ManifestPropertyEditorSchema = {
|
||||
properties: [
|
||||
{
|
||||
alias: 'crops',
|
||||
label: 'Define Crops',
|
||||
label: 'Crop options',
|
||||
propertyEditorUiAlias: 'Umb.PropertyEditorUi.ImageCropsConfiguration',
|
||||
},
|
||||
],
|
||||
|
||||
@@ -13,9 +13,6 @@ export type UmbCrop = {
|
||||
height: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* @element umb-property-editor-ui-image-crops
|
||||
*/
|
||||
@customElement('umb-property-editor-ui-image-crops')
|
||||
export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implements UmbPropertyEditorUiElement {
|
||||
@query('#label')
|
||||
@@ -24,6 +21,9 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen
|
||||
@state()
|
||||
private _value: Array<UmbCrop> = [];
|
||||
|
||||
@state()
|
||||
private _isCreating = false;
|
||||
|
||||
@property({ type: Array })
|
||||
public set value(value: Array<UmbCrop>) {
|
||||
this._value = value ?? [];
|
||||
@@ -39,13 +39,8 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen
|
||||
#oldInputValue = '';
|
||||
|
||||
#sorter = new UmbSorterController(this, {
|
||||
getUniqueOfElement: (element: HTMLElement) => {
|
||||
const unique = element.dataset['alias'];
|
||||
return unique;
|
||||
},
|
||||
getUniqueOfModel: (modelEntry: UmbCrop) => {
|
||||
return modelEntry.alias;
|
||||
},
|
||||
getUniqueOfElement: (element: HTMLElement) => element.dataset['alias'],
|
||||
getUniqueOfModel: (modelEntry: UmbCrop) => modelEntry.alias,
|
||||
identifier: 'Umb.SorterIdentifier.ImageCrops',
|
||||
itemSelector: '.crop',
|
||||
containerSelector: '.crops',
|
||||
@@ -64,45 +59,28 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen
|
||||
|
||||
#onEdit(crop: UmbCrop) {
|
||||
this.editCropAlias = crop.alias;
|
||||
|
||||
const form = this.shadowRoot?.querySelector('form') as HTMLFormElement;
|
||||
if (!form) return;
|
||||
|
||||
const label = form.querySelector('#label') as HTMLInputElement;
|
||||
const alias = form.querySelector('#alias') as HTMLInputElement;
|
||||
const width = form.querySelector('#width') as HTMLInputElement;
|
||||
const height = form.querySelector('#height') as HTMLInputElement;
|
||||
|
||||
if (!alias || !width || !height) return;
|
||||
|
||||
label.value = crop.label;
|
||||
alias.value = crop.alias;
|
||||
width.value = crop.width.toString();
|
||||
height.value = crop.height.toString();
|
||||
this._isCreating = false;
|
||||
}
|
||||
|
||||
#onEditCancel() {
|
||||
this.editCropAlias = '';
|
||||
this._isCreating = false;
|
||||
}
|
||||
|
||||
#onSubmit(event: Event) {
|
||||
event.preventDefault();
|
||||
const form = event.target as HTMLFormElement;
|
||||
if (!form) return;
|
||||
|
||||
if (!form.checkValidity()) return;
|
||||
if (!form || !form.checkValidity()) return;
|
||||
|
||||
const formData = new FormData(form);
|
||||
|
||||
const label = formData.get('label') as string;
|
||||
const alias = formData.get('alias') as string;
|
||||
const width = formData.get('width') as string;
|
||||
const height = formData.get('height') as string;
|
||||
|
||||
if (!label || !alias || !width || !height) return;
|
||||
if (!this.value) this.value = [];
|
||||
|
||||
const newCrop = {
|
||||
const newCrop: UmbCrop = {
|
||||
label,
|
||||
alias,
|
||||
width: parseInt(width),
|
||||
@@ -112,7 +90,6 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen
|
||||
if (this.editCropAlias) {
|
||||
const index = this.value.findIndex((item) => item.alias === this.editCropAlias);
|
||||
if (index === -1) return;
|
||||
|
||||
const temp = [...this.value];
|
||||
temp[index] = newCrop;
|
||||
this.value = [...temp];
|
||||
@@ -120,40 +97,14 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen
|
||||
} else {
|
||||
this.value = [...this.value, newCrop];
|
||||
}
|
||||
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
|
||||
form.reset();
|
||||
this._labelInput.focus();
|
||||
this._labelInput?.focus();
|
||||
this._isCreating = false;
|
||||
}
|
||||
|
||||
#renderActions() {
|
||||
return this.editCropAlias
|
||||
? html`<uui-button @click=${this.#onEditCancel}>Cancel</uui-button>
|
||||
<uui-button look="secondary" type="submit" label="Save"></uui-button>`
|
||||
: html`<uui-button look="secondary" type="submit" label="Add"></uui-button>`;
|
||||
}
|
||||
|
||||
#onLabelInput() {
|
||||
const value = this._labelInput.value ?? '';
|
||||
|
||||
const aliasValue = generateAlias(value);
|
||||
|
||||
const alias = this.shadowRoot?.querySelector('#alias') as HTMLInputElement;
|
||||
|
||||
if (!alias) return;
|
||||
|
||||
const oldAliasValue = generateAlias(this.#oldInputValue);
|
||||
|
||||
if (alias.value === oldAliasValue || !alias.value) {
|
||||
alias.value = aliasValue;
|
||||
}
|
||||
|
||||
this.#oldInputValue = value;
|
||||
}
|
||||
|
||||
override render() {
|
||||
if (!this.value) this.value = [];
|
||||
|
||||
#renderForm(initial?: UmbCrop) {
|
||||
return html`
|
||||
<uui-form>
|
||||
<form @submit=${this.#onSubmit}>
|
||||
@@ -165,54 +116,118 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen
|
||||
id="label"
|
||||
name="label"
|
||||
type="text"
|
||||
autocomplete="false"
|
||||
value=""></uui-input>
|
||||
required
|
||||
.value=${initial?.label ?? ''}></uui-input>
|
||||
</div>
|
||||
<div class="input">
|
||||
<uui-label for="alias">Alias</uui-label>
|
||||
<uui-input label="Alias" id="alias" name="alias" type="text" autocomplete="false" value=""></uui-input>
|
||||
<uui-input
|
||||
label="Alias"
|
||||
id="alias"
|
||||
name="alias"
|
||||
type="text"
|
||||
autocomplete="false"
|
||||
required
|
||||
.value=${initial?.alias ?? ''}></uui-input>
|
||||
</div>
|
||||
<div class="input">
|
||||
<uui-label for="width">Width</uui-label>
|
||||
<uui-input label="Width" id="width" name="width" type="number" autocomplete="false" value="" min="0">
|
||||
<uui-input
|
||||
label="Width"
|
||||
id="width"
|
||||
name="width"
|
||||
type="number"
|
||||
autocomplete="false"
|
||||
required
|
||||
.value=${initial?.width ?? ''}
|
||||
min="0">
|
||||
<span class="append" slot="append">px</span>
|
||||
</uui-input>
|
||||
</div>
|
||||
<div class="input">
|
||||
<uui-label for="height">Height</uui-label>
|
||||
<uui-input label="Height" id="height" name="height" type="number" autocomplete="false" value="" min="0">
|
||||
<uui-input
|
||||
label="Height"
|
||||
id="height"
|
||||
name="height"
|
||||
type="number"
|
||||
autocomplete="false"
|
||||
required
|
||||
.value=${initial?.height ?? ''}
|
||||
min="0">
|
||||
<span class="append" slot="append">px</span>
|
||||
</uui-input>
|
||||
</div>
|
||||
<div class="action-wrapper">${this.#renderActions()}</div>
|
||||
<div class="action-wrapper">
|
||||
${this.editCropAlias
|
||||
? html`<uui-button @click=${this.#onEditCancel}>Cancel</uui-button>
|
||||
<uui-button look="secondary" type="submit" label=${this.localize.term('general_edit')}></uui-button>`
|
||||
: html`<uui-button
|
||||
look="secondary"
|
||||
type="submit"
|
||||
label=${this.localize.term('general_create')}></uui-button>`}
|
||||
</div>
|
||||
</form>
|
||||
</uui-form>
|
||||
<div class="crops">
|
||||
`;
|
||||
}
|
||||
|
||||
#onLabelInput() {
|
||||
const value = this._labelInput.value ?? '';
|
||||
const aliasValue = generateAlias(value);
|
||||
const alias = this.shadowRoot?.querySelector('#alias') as HTMLInputElement;
|
||||
if (!alias) return;
|
||||
|
||||
const oldAliasValue = generateAlias(this.#oldInputValue);
|
||||
if (alias.value === oldAliasValue || !alias.value) {
|
||||
alias.value = aliasValue;
|
||||
}
|
||||
|
||||
this.#oldInputValue = value;
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`
|
||||
<uui-ref-list class="crops">
|
||||
${repeat(
|
||||
this.value,
|
||||
(item) => item.alias,
|
||||
(item) => html`
|
||||
<div class="crop" data-alias="${item.alias}">
|
||||
<uui-icon name="icon-grip" class="crop-drag"></uui-icon>
|
||||
<span><strong>${item.label}</strong> <em>(${item.alias})</em></span>
|
||||
<span class="crop-size">(${item.width} x ${item.height}px)</span>
|
||||
<div class="crop-actions">
|
||||
<uui-button
|
||||
label=${this.localize.term('general_edit')}
|
||||
color="default"
|
||||
@click=${() => this.#onEdit(item)}></uui-button>
|
||||
<uui-button
|
||||
label=${this.localize.term('general_remove')}
|
||||
color="danger"
|
||||
@click=${() => this.#onRemove(item.alias)}></uui-button>
|
||||
</div>
|
||||
</div>
|
||||
${this.editCropAlias === item.alias
|
||||
? html`<div class="crop-form">${this.#renderForm(item)}</div>`
|
||||
: html`
|
||||
<uui-ref-node
|
||||
class="crop"
|
||||
data-alias="${item.alias}"
|
||||
detail="${item.width} x ${item.height}px"
|
||||
name="${item.label} (${item.alias})">
|
||||
<uui-icon slot="icon" name="icon-crop"></uui-icon>
|
||||
<uui-action-bar slot="actions">
|
||||
<uui-button
|
||||
label=${this.localize.term('general_edit')}
|
||||
data-mark="action:crop-edit"
|
||||
@click=${() => this.#onEdit(item)}></uui-button>
|
||||
<uui-button
|
||||
label=${this.localize.term('general_remove')}
|
||||
data-mark="action:crop-remove"
|
||||
@click=${() => this.#onRemove(item.alias)}></uui-button>
|
||||
</uui-action-bar>
|
||||
</uui-ref-node>
|
||||
`}
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
</uui-ref-list>
|
||||
${!this._isCreating && !this.editCropAlias
|
||||
? html`<uui-button
|
||||
id="create"
|
||||
data-mark="action:crop-create"
|
||||
look="placeholder"
|
||||
@click=${() => (this._isCreating = true)}
|
||||
label=${this.localize.term('general_create')}></uui-button>`
|
||||
: ''}
|
||||
${this._isCreating ? this.#renderForm() : ''}
|
||||
`;
|
||||
}
|
||||
|
||||
static override readonly styles = [
|
||||
UmbTextStyles,
|
||||
css`
|
||||
@@ -228,34 +243,16 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen
|
||||
.crop {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: var(--uui-color-background);
|
||||
}
|
||||
.crop-drag {
|
||||
cursor: grab;
|
||||
padding-inline: var(--uui-size-space-4);
|
||||
color: var(--uui-color-disabled-contrast);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.crop-drag:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.crop-size {
|
||||
font-size: 0.9em;
|
||||
padding-inline: var(--uui-size-space-4);
|
||||
}
|
||||
.crop-actions {
|
||||
display: flex;
|
||||
margin-left: auto;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
gap: var(--uui-size-space-2);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.input {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 200px;
|
||||
}
|
||||
uui-input[type='number'] {
|
||||
text-align: right;
|
||||
@@ -273,6 +270,9 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
#create {
|
||||
width: 100%;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user