diff --git a/CHANGELOG.md b/CHANGELOG.md index d13427ee..3331c53b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ IMPORTANT NOTE: This version only works on CACTI 1.x++! --- develop --- +* Add a searchable node icon picker and bundled enterprise site icons + * issue#299: Keep editor picker results open when browsing and allow changing an existing selection * feature#298: Fit or stretch background images within the map canvas diff --git a/README.md b/README.md index 213d3bcc..db6d0f00 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,13 @@ See CHANGELOG.md for the most recent updates, listed by version. See COPYING for the license under which php-weathermap is released. +## Bundled building icons + +The node icon library in `images/objects/` includes modern corporate building, +branch office, hospital, clinic, data centre and warehouse icons. These +transparent PNGs are 96 × 96 pixels and can be selected from the editor's node +icon picker without uploading additional files. + ## Compatibility This version only works with Cacti 1.2.x onwards. A re-write of the user interface diff --git a/css/editor.css b/css/editor.css index 4f8571b1..c850da35 100644 --- a/css/editor.css +++ b/css/editor.css @@ -316,3 +316,43 @@ body#mainView #wm-node-delete-bar { min-height: 32px; } .ui-dialog.wm-editor-dialog { overflow: visible; } + +/* Searchable node icon gallery; keep backgrounds on their existing selector. */ +body#mainView .wm-icon-source { display: none; } +body#mainView .wm-icon-picker { width: 320px; max-width: 100%; } +body#mainView .wm-icon-picker summary { + display: flex; align-items: center; gap: 10px; cursor: pointer; + padding: 8px 12px; min-height: 48px; box-sizing: border-box; + border: 1px solid var(--border-color, #888); border-radius: 4px; + background: var(--background, #fff); color: var(--text-color-lighter, #333); + list-style: none; +} +body#mainView .wm-icon-picker summary::-webkit-details-marker { display: none; } +body#mainView .wm-icon-picker summary::after { content: '▾'; margin-left: auto; } +body#mainView .wm-icon-picker[open] summary::after { content: '▴'; } +body#mainView .wm-icon-picker summary img { width: 40px; height: 40px; object-fit: contain; } +body#mainView .wm-icon-panel { + padding: 8px; border: 1px solid var(--border-color, #888); border-top: 0; + background: var(--background, #fff); color: var(--text-color-lighter, #333); box-sizing: border-box; +} +body#mainView .wm-icon-panel input[type="search"] { width: 100%; box-sizing: border-box; margin: 0; caret-color: auto; } +body#mainView .wm-icon-count { font-size: 12px; margin: 6px 0; } +body#mainView .wm-icon-grid { + display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 6px; max-height: 220px; overflow-y: auto; overscroll-behavior: contain; +} +body#mainView .wm-icon-grid .wm-icon-choice { + display: flex; flex-direction: column; align-items: center; gap: 5px; + width: 100%; min-width: 0; min-height: 86px; padding: 6px; margin: 0; + border: 1px solid var(--border-color, #888); border-radius: 4px; + background: var(--background, #fff); color: var(--text-color-lighter, #333); + cursor: pointer; white-space: normal; font-size: 12px; line-height: 1.25; +} +body#mainView .wm-icon-choice[hidden] { display: none !important; } +body#mainView .wm-icon-choice img { width: 48px; height: 48px; object-fit: contain; } +body#mainView .wm-icon-choice span { overflow-wrap: anywhere; } +body#mainView .wm-icon-choice:hover, +body#mainView .wm-icon-choice[aria-pressed="true"] { + background: var(--background-lowlight, #eee); + border-color: var(--text-color-highlight-a, #2874aa); +} diff --git a/images/objects/branch-office.png b/images/objects/branch-office.png new file mode 100644 index 00000000..f51665df Binary files /dev/null and b/images/objects/branch-office.png differ diff --git a/images/objects/clinic-red.png b/images/objects/clinic-red.png new file mode 100644 index 00000000..5d6e04ae Binary files /dev/null and b/images/objects/clinic-red.png differ diff --git a/images/objects/corporate-building.png b/images/objects/corporate-building.png new file mode 100644 index 00000000..64f8ef2b Binary files /dev/null and b/images/objects/corporate-building.png differ diff --git a/images/objects/data-centre.png b/images/objects/data-centre.png new file mode 100644 index 00000000..838bbb7c Binary files /dev/null and b/images/objects/data-centre.png differ diff --git a/images/objects/hospital-red.png b/images/objects/hospital-red.png new file mode 100644 index 00000000..5b77f078 Binary files /dev/null and b/images/objects/hospital-red.png differ diff --git a/images/objects/warehouse.png b/images/objects/warehouse.png new file mode 100644 index 00000000..22ec8c2d Binary files /dev/null and b/images/objects/warehouse.png differ diff --git a/js/editor.js b/js/editor.js index dad82c1a..c15fbcef 100644 --- a/js/editor.js +++ b/js/editor.js @@ -1050,14 +1050,7 @@ function show_node(name) { if (success) { $('#action').val('set_node_properties'); - if ($('#node_iconfilename.dd-container').length) { - $('#node_iconfilename').ddslick('destroy'); - } - - $('#node_iconfilename').val(selectedNode).ddslick({ - height:240, - defaultSelectedIndex:selectedNode - }); + wmNodeIconPicker(); $('.dd-container').on('click', function() { $('.ui-dialog').css('z-index', '100'); @@ -1075,6 +1068,71 @@ function show_node(name) { } } +function wmNodeIconPicker() { + var select = $('#node_iconfilename'); + if (select.hasClass('dd-container')) { + select.ddslick('destroy'); + select = $('#node_iconfilename'); + } + select.val(selectedNode).addClass('wm-icon-source'); + $('#wm-icon-picker').remove(); + var picker = $('
').insertAfter(select); + var summary = $('').appendTo(picker); + var panel = $('
').appendTo(picker); + var search = $('').attr({placeholder: wmEditorText.iconSearchPlaceholder, 'aria-label': wmEditorText.iconSearchLabel}).appendTo(panel); + var count = $('
').appendTo(panel); + var grid = $('
').attr({role: 'group', 'aria-label': wmEditorText.iconGroupLabel}).appendTo(panel); + function title(option) { + return option.text.replace(/\.(png|gif|jpe?g)$/i, '').replace(/[-_]+/g, ' '); + } + function content(target, option) { + var src = $(option).attr('data-imagesrc'); + if (src) $('').attr('src', src).appendTo(target); + $('').text(title(option)).appendTo(target); + } + function updateSelection() { + var option = select.find('option:selected')[0]; + summary.empty(); + if (option) content(summary, option); + else summary.text(wmEditorText.iconChoosePrompt); + grid.find('button').each(function() { + $(this).attr('aria-pressed', String($(this).data('value') === select.val())); + }); + } + select.find('option').each(function() { + var option = this; + var button = $('