@fleetbase/ember-ui
Version:
Fleetbase UI provides all the interface components, helpers, services and utilities for building a Fleetbase extension into the Console.
147 lines (130 loc) • 4.13 kB
JavaScript
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
/**
* TemplateBuilderLayersPanelComponent
*
* Left panel showing the element tree (layers). Supports:
* - Selecting an element by clicking its row
* - Toggling element visibility
* - Deleting an element
* - Reordering via z_index controls (move up/down)
* - Renaming an element label
*
* @argument {Array} elements - The template content array (elements)
* @argument {Object} selectedElement - Currently selected element
* @argument {Function} onSelectElement - Called with element when row is clicked
* @argument {Function} onUpdateElement - Called with (uuid, changes) to update an element
* @argument {Function} onDeleteElement - Called with uuid to delete an element
* @argument {Function} onReorderElement - Called with (uuid, direction) — 'up' or 'down'
*/
export default class TemplateBuilderLayersPanelComponent extends Component {
renamingUuid = null;
renameValue = '';
get sortedElements() {
const elements = this.args.elements ?? [];
// Sort descending by z_index so highest layer is at top of list (like Figma/Sketch)
return [...elements].sort((a, b) => (b.z_index ?? 1) - (a.z_index ?? 1));
}
elementIcon(type) {
const icons = {
text: 'font',
image: 'image',
table: 'table',
line: 'minus',
shape: 'square',
qr_code: 'qrcode',
barcode: 'barcode',
};
return icons[type] ?? 'layer-group';
}
elementLabel(element) {
if (element.label) return element.label;
const typeLabels = {
text: 'Text',
image: 'Image',
table: 'Table',
line: 'Line',
shape: 'Shape',
qr_code: 'QR Code',
barcode: 'Barcode',
};
return typeLabels[element.type] ?? 'Element';
}
isSelected(element) {
return this.args.selectedElement?.uuid === element.uuid;
}
isVisible(element) {
return element.visible !== false;
}
isRenaming(element) {
return this.renamingUuid === element.uuid;
}
selectElement(element, event) {
event.stopPropagation();
if (this.args.onSelectElement) {
this.args.onSelectElement(element);
}
}
toggleVisibility(element, event) {
event.stopPropagation();
if (this.args.onUpdateElement) {
this.args.onUpdateElement(element.uuid, { visible: !this.isVisible(element) });
}
}
deleteElement(element, event) {
event.stopPropagation();
if (this.args.onDeleteElement) {
this.args.onDeleteElement(element.uuid);
}
}
moveUp(element, event) {
event.stopPropagation();
if (this.args.onReorderElement) {
this.args.onReorderElement(element.uuid, 'up');
}
}
moveDown(element, event) {
event.stopPropagation();
if (this.args.onReorderElement) {
this.args.onReorderElement(element.uuid, 'down');
}
}
startRename(element, event) {
event.stopPropagation();
this.renamingUuid = element.uuid;
this.renameValue = this.elementLabel(element);
}
commitRename(element) {
if (this.renameValue.trim() && this.args.onUpdateElement) {
this.args.onUpdateElement(element.uuid, { label: this.renameValue.trim() });
}
this.renamingUuid = null;
this.renameValue = '';
}
cancelRename() {
this.renamingUuid = null;
this.renameValue = '';
}
handleRenameKeydown(element, event) {
if (event.key === 'Enter') {
this.commitRename(element);
} else if (event.key === 'Escape') {
this.cancelRename();
}
}
}