<div
class="p-l-24 p-r-24 p-t-8 p-b-8 separator-bottom sticky-top"
style="background: var(--c8y-root-component-background-default); z-index: 2"
>
<div class="row d-flex-sm">
<div class="col-sm-5 m-b-8">
<div
class="input-group-search input-group"
style="width: auto"
>
<label
class="sr-only"
for="filter-icons"
translate
>Filter icons</label
>
<input
class="form-control"
id="filter-icons"
placeholder="{{ 'Type to filter icons…' | translate }}"
type="search"
[ngModel]="searchTerm$ | async"
(ngModelChange)="onSearchChange($event)"
/>
@if (searchTerm$ | async) {
<button
class="input-group-addon"
[attr.aria-label]="'Clear search' | translate"
type="button"
(click)="onSearchChange('')"
>
<i
c8yIcon="times"
aria-hidden="true"
></i>
</button>
} @else {
<span
class="input-group-addon"
aria-hidden="true"
>
<i
c8yIcon="search"
aria-hidden="true"
></i>
</span>
}
</div>
</div>
<div class="col-sm-7 m-b-8">
<div class="d-flex a-i-center j-c-end gap-16 text-left">
<div class="d-flex a-i-center flex-grow">
<label
class="m-b-0 m-r-8 flex-no-shrink"
id="icon-category-filter-label"
translate
>Collection</label
>
<c8y-select
class="flex-grow"
[attr.aria-labelledby]="'icon-category-filter-label'"
[items]="availableIconCategoryItems$ | async"
[selected]="selectedIconCategory$ | async"
[canDeselect]="true"
(onSelect)="onCategoryFilterChanged($any($event).value)"
(onDeselect)="onCategoryFilterChanged(allIconCategory)"
></c8y-select>
</div>
@if (isAdmin()) {
<button
class="btn btn-clean p-l-8 p-r-8 flex-no-shrink"
[title]="'Add custom icon' | translate"
[attr.aria-label]="'Add custom icon' | translate"
type="button"
(click)="onAddIconClicked()"
>
<i
class="m-r-4"
c8yIcon="plus-circle"
aria-hidden="true"
></i>
<span translate>Add icon</span>
</button>
<button
class="btn btn-clean flex-no-shrink"
[attr.aria-label]="'Import icons from ZIP' | translate"
[tooltip]="'Import icons from ZIP' | translate"
placement="top"
container="body"
type="button"
[delay]="500"
[adaptivePosition]="false"
(click)="onImportClicked()"
>
<i
class="m-r-4"
c8yIcon="data-import"
aria-hidden="true"
></i>
<span>{{ 'Import`verb, imports icons from a ZIP file`' | translate }}</span>
</button>
@if (hasCustomIcons()) {
<button
class="btn btn-clean flex-no-shrink"
[attr.aria-label]="'Export custom icons as ZIP' | translate"
[tooltip]="'Export custom icons as ZIP' | translate"
placement="top"
container="body"
type="button"
[delay]="500"
[adaptivePosition]="false"
(click)="onExportClicked()"
>
<i
class="m-r-4"
c8yIcon="data-export"
aria-hidden="true"
></i>
<span>{{ 'Export`verb, exports custom icons as a ZIP file`' | translate }}</span>
</button>
}
}
</div>
</div>
</div>
@if (isSaving()) {
<div
class="p-absolute m-t-4 p-b-4 overflow-hidden"
style="left: 0; right: 0"
[attr.aria-label]="'Saving…' | translate"
role="status"
>
<c8y-loading layout="page"></c8y-loading>
</div>
}
</div>
<div class="p-16">
@if (iconsLoading()) {
<div
class="d-flex a-i-center j-c-center p-32"
[attr.aria-label]="'Loading icons…' | translate"
role="status"
>
<c8y-loading></c8y-loading>
</div>
} @else {
<p
class="sr-only"
role="status"
>
@if (filteredIconCount() === 0) {
{{ 'No icons found' | translate }}
} @else {
{{ '{{count}} icon(s) found' | translate: { count: filteredIconCount() } }}
}
</p>
<section
class="dtm-icon-grid"
[attr.aria-label]="'Icon grid' | translate"
[attr.aria-busy]="visibleDefinitions().length === 0 ? 'true' : null"
role="region"
>
@for (iconDefinition of visibleDefinitions(); track iconDefinition.label) {
<div
class="d-contents"
[attr.aria-label]="iconDefinition.label | translate"
role="group"
>
<div class="legend form-block center grid__col--fullspan d-flex a-i-center gap-8">
{{ iconDefinition.label | translate }}
@if (customCategoryLabels().has(iconDefinition.label)) {
<span class="tag tag--info m-l-4 m-t-0 m-b-0">{{
'Custom`badge indicating a user-added icon category`' | translate
}}</span>
}
</div>
@for (icon of iconDefinition.icons; track icon[0]) {
@let isCustom = isCustomIcon(icon[0]);
@let isOverridden = isIconOverridden(icon[0]);
@let overriddenLabel = gettext('{{name}} (overridden)');
@let deleteHint = 'Select a different icon before deleting this one.' | translate;
<div class="d-contents">
<div
class="dtm-icon-grid__item"
[class.dtm-icon-grid__item--selected]="selectedIcon && icon[0] === selectedIcon"
[class.dtm-icon-grid__item--overridden]="isOverridden"
>
<button
class="dtm-icon-grid__btn"
[title]="icon[0] | iconName"
[attr.aria-label]="
isOverridden
? (overriddenLabel | translate: { name: icon[0] | iconName })
: (icon[0] | iconName)
"
[attr.aria-current]="selectedIcon && icon[0] === selectedIcon ? 'true' : null"
(click)="onIconClicked(icon)"
>
<i
class="icon-40 c8y-icon-duocolor"
[c8yIcon]="icon[0]"
aria-hidden="true"
></i>
@if (showIconClass) {
<small
class="d-block text-center text-break-word"
aria-hidden="true"
>
{{ icon[0] | iconName }}
</small>
}
</button>
@if (isOverridden) {
<span
class="dtm-icon-grid__override-marker"
[tooltip]="'Overridden icon' | translate"
placement="top"
container="body"
aria-hidden="true"
[delay]="500"
>
<i c8yIcon="replace"></i>
</span>
}
@if (isAdmin()) {
<div
class="dtm-icon-grid__actions"
[attr.aria-label]="'{{name}} actions' | translate: { name: icon[0] | iconName }"
role="group"
>
@if (isCustom) {
<button
class="btn btn-dot"
[attr.aria-label]="
'Edit {{name}}' | translate: { name: icon[0] | iconName }
"
[tooltip]="'Edit {{name}}' | translate: { name: icon[0] | iconName }"
placement="top"
container="body"
type="button"
[delay]="500"
(click)="$event.stopPropagation(); onEditIconClicked(icon[0])"
>
<i
c8yIcon="pencil"
aria-hidden="true"
></i>
</button>
<span
[tooltip]="icon[0] === selectedIcon ? deleteHint : null"
placement="top"
container="body"
[delay]="500"
>
<button
class="btn btn-dot btn-dot--danger m-0"
[class.disabled]="icon[0] === selectedIcon"
[attr.aria-label]="
'Delete {{name}}' | translate: { name: icon[0] | iconName }
"
[tooltip]="'Delete {{name}}' | translate: { name: icon[0] | iconName }"
placement="top"
container="body"
[attr.aria-disabled]="icon[0] === selectedIcon ? 'true' : null"
[attr.aria-describedby]="
icon[0] === selectedIcon ? 'delete-hint-' + icon[0] : null
"
type="button"
[delay]="500"
(click)="
$event.stopPropagation();
icon[0] === selectedIcon || onDeleteIconClicked(icon[0])
"
>
<i
c8yIcon="minus-circle"
aria-hidden="true"
></i>
</button>
@if (icon[0] === selectedIcon) {
<span
class="sr-only"
[id]="'delete-hint-' + icon[0]"
>{{ deleteHint }}</span
>
}
</span>
} @else {
@let overrideKey =
isOverridden
? gettext('Replace override for {{name}}')
: gettext('Override {{name}}');
<button
class="btn btn-dot"
[attr.aria-label]="overrideKey | translate: { name: icon[0] | iconName }"
[tooltip]="overrideKey | translate: { name: icon[0] | iconName }"
placement="top"
container="body"
type="button"
[delay]="500"
(click)="$event.stopPropagation(); onOverrideIconClicked(icon)"
>
<i
c8yIcon="replace"
aria-hidden="true"
></i>
</button>
@if (isOverridden) {
<button
class="btn btn-dot btn-dot--danger"
[attr.aria-label]="
'Reset override for {{name}}' | translate: { name: icon[0] | iconName }
"
[tooltip]="
'Reset override for {{name}}' | translate: { name: icon[0] | iconName }
"
placement="top"
container="body"
type="button"
[delay]="500"
(click)="$event.stopPropagation(); onResetOverrideClicked(icon[0])"
>
<i
c8yIcon="undo"
aria-hidden="true"
></i>
</button>
}
}
</div>
}
</div>
</div>
}
</div>
} @empty {
<c8y-ui-empty-state
class="grid__col--fullspan"
icon="search"
[title]="'No icons found' | translate"
[subtitle]="
'Try adjusting your search or filter to find what you\'re looking for.' | translate
"
[horizontal]="true"
></c8y-ui-empty-state>
}
</section>
}
<!-- end @else iconsLoading -->
</div>