From 66012da4de8ef7278ec5496c516d9d2699559d1a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 27 May 2018 17:04:18 -0400 Subject: [PATCH] Generate Hass and Hass.io specific iconset (#1214) * Generate hass icons * Generate Hass.io icons * Convert hass.io to use hassio iconset * Convert src to use hass iconset * Give mdi-icons a chunk name * gen-index-html aware of hass-icons * Use ha-icon for rendering state icon --- .gitignore | 1 - gulp/tasks/gen-icons.js | 94 ++++++++++++++++--- gulp/tasks/gen-index-html.js | 4 +- hassio/.gitignore | 2 + hassio/index.html | 1 - hassio/script/build_hassio | 1 + hassio/script/develop | 1 + hassio/script/gen-icons.js | 13 +++ .../addon-store/hassio-addon-repository.js | 2 +- .../addon-store/hassio-repositories-editor.js | 4 +- hassio/src/addon-view/hassio-addon-info.js | 6 +- hassio/src/addon-view/hassio-addon-view.js | 2 +- hassio/src/components/hassio-card-content.js | 2 +- hassio/src/dashboard/hassio-addons.js | 2 +- hassio/src/dashboard/hassio-hass-update.js | 2 +- hassio/src/hassio-app.js | 1 + hassio/src/hassio-markdown-dialog.js | 2 +- hassio/src/hassio-pages-with-tabs.js | 2 +- hassio/src/resources/hassio-icons.js | 6 ++ hassio/src/snapshots/hassio-snapshot.js | 6 +- hassio/src/snapshots/hassio-snapshots.js | 2 +- hassio/webpack.config.js | 10 ++ index.html | 2 +- src/cards/ha-media_player-card.js | 12 +-- src/cards/ha-plant-card.js | 10 +- src/cards/ha-weather-card.js | 26 ++--- src/common/const.js | 2 +- src/common/entity/binary_sensor_icon.js | 38 ++++---- src/common/entity/cover_icon.js | 2 +- src/common/entity/domain_icon.js | 92 +++++++++--------- src/common/entity/input_dateteime_icon.js | 4 +- src/common/entity/sensor_icon.js | 27 ++++-- src/components/entity/ha-entity-picker.js | 4 +- src/components/entity/ha-entity-toggle.js | 4 +- src/components/entity/ha-state-icon.js | 6 +- src/components/entity/ha-state-label-badge.js | 16 ++-- src/components/ha-climate-control.js | 4 +- src/components/ha-combo-box.js | 4 +- src/components/ha-cover-controls.js | 6 +- src/components/ha-cover-tilt-controls.js | 6 +- src/components/ha-demo-badge.js | 2 +- src/components/ha-icon.js | 18 ++++ src/components/ha-menu-button.js | 2 +- src/components/ha-sidebar.js | 23 +++-- src/components/ha-start-voice-button.js | 2 +- src/dialogs/ha-voice-command-dialog.js | 2 +- .../more-info/controls/more-info-fan.js | 4 +- .../more-info/controls/more-info-light.js | 6 +- .../controls/more-info-media_player.js | 22 ++--- .../more-info/controls/more-info-vacuum.js | 12 +-- .../more-info/controls/more-info-weather.js | 36 +++---- src/dialogs/more-info/more-info-controls.js | 4 +- src/dialogs/more-info/more-info-settings.js | 2 +- src/entrypoints/hass-icons.js | 1 + src/layouts/hass-subpage.js | 2 +- .../config/automation/ha-automation-editor.js | 4 +- .../config/automation/ha-automation-picker.js | 6 +- .../config/cloud/ha-config-cloud-login.js | 4 +- src/panels/config/core/ha-config-core.js | 2 +- .../config/customize/ha-config-customize.js | 2 +- .../customize/ha-customize-attribute.js | 2 +- .../customize/types/ha-customize-icon.js | 2 +- .../config/dashboard/ha-config-cloud-menu.js | 2 +- .../dashboard/ha-config-entries-menu.js | 2 +- .../config/dashboard/ha-config-navigation.js | 2 +- .../config/js/condition/condition_row.js | 2 +- src/panels/config/js/script/action_row.js | 2 +- src/panels/config/js/trigger/trigger_row.js | 2 +- src/panels/config/script/ha-script-editor.js | 4 +- src/panels/config/script/ha-script-picker.js | 6 +- src/panels/config/zwave/ha-config-zwave.js | 4 +- src/panels/config/zwave/zwave-network.js | 2 +- src/panels/dev-info/ha-panel-dev-info.js | 2 +- src/panels/dev-state/ha-panel-dev-state.js | 2 +- src/panels/logbook/ha-panel-logbook.js | 2 +- src/panels/mailbox/ha-panel-mailbox.js | 2 +- src/panels/map/ha-entity-marker.js | 2 - .../shopping-list/ha-panel-shopping-list.js | 4 +- src/resources/hass-icons.js | 6 ++ .../mdi.js => resources/mdi-icons.js} | 0 webpack.config.js | 2 +- 81 files changed, 384 insertions(+), 257 deletions(-) create mode 100644 hassio/.gitignore create mode 100755 hassio/script/gen-icons.js create mode 100644 hassio/src/resources/hassio-icons.js create mode 100644 src/components/ha-icon.js create mode 100644 src/entrypoints/hass-icons.js create mode 100644 src/resources/hass-icons.js rename src/{entrypoints/mdi.js => resources/mdi-icons.js} (100%) diff --git a/.gitignore b/.gitignore index c7368a40b8..9fa46f4c80 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ build build-translations/* -hassio/build-es5/* node_modules/* npm-debug.log .DS_Store diff --git a/gulp/tasks/gen-icons.js b/gulp/tasks/gen-icons.js index bb99d4d9c8..71bbc0bebb 100644 --- a/gulp/tasks/gen-icons.js +++ b/gulp/tasks/gen-icons.js @@ -7,16 +7,30 @@ const ICON_PACKAGE_PATH = path.resolve(__dirname, '../../node_modules/@mdi/svg/' const META_PATH = path.resolve(ICON_PACKAGE_PATH, 'meta.json'); const ICON_PATH = path.resolve(ICON_PACKAGE_PATH, 'svg'); const OUTPUT_DIR = path.resolve(__dirname, '../../build'); -const OUTPUT_PATH = path.resolve(OUTPUT_DIR, 'mdi.html'); +const MDI_OUTPUT_PATH = path.resolve(OUTPUT_DIR, 'mdi.html'); +const HASS_OUTPUT_PATH = path.resolve(OUTPUT_DIR, 'hass-icons.html'); -function iconPath(name) { - return path.resolve(ICON_PATH, `${name}.svg`); -} +const BUILT_IN_PANEL_ICONS = [ + 'settings', // Config + 'home-assistant', // Hass.io + 'poll-box', // History panel + 'format-list-bulleted-type', // Logbook + 'mailbox', // Mailbox + 'account-location', // Map + 'cart', // Shopping List +]; +// Given an icon name, load the SVG file function loadIcon(name) { - return fs.readFileSync(iconPath(name), 'utf-8'); + const iconPath = path.resolve(ICON_PATH, `${name}.svg`); + try { + return fs.readFileSync(iconPath, 'utf-8'); + } catch (err) { + return null; + } } +// Given an SVG file, convert it to an iron-iconset-svg definition function transformXMLtoPolymer(name, xml) { const start = xml.indexOf('>${path}`; } -function generateIconset(name, iconDefs) { - return ` - -${iconDefs} - - `; +// Given an iconset name and icon names, generate a polymer iconset +function generateIconset(name, iconNames) { + const iconDefs = iconNames.map(name => { + const iconDef = loadIcon(name); + if (!iconDef) { + throw new Error(`Unknown icon referenced: ${name}`); + } + return transformXMLtoPolymer(name, iconDef) + }).join(''); + return `${iconDefs}`; } -async function genIcons(es6) { +// Generate the full MDI iconset +function genMDIIcons() { const meta = JSON.parse(fs.readFileSync(path.resolve(ICON_PACKAGE_PATH, META_PATH), 'UTF-8')); - const iconDefs = meta.map(iconInfo => transformXMLtoPolymer(iconInfo.name, loadIcon(iconInfo.name))).join(''); + const iconNames = meta.map(iconInfo => iconInfo.name); fs.existsSync(OUTPUT_DIR) || fs.mkdirSync(OUTPUT_DIR); - fs.writeFileSync(OUTPUT_PATH, generateIconset('mdi', iconDefs)); + fs.writeFileSync(MDI_OUTPUT_PATH, generateIconset('mdi', iconNames)); } -gulp.task('gen-icons', () => genIcons()); +// Helper function to map recursively over files in a folder and it's subfolders +function mapFiles(startPath, filter, mapFunc) { + const files = fs.readdirSync(startPath); + for (let i = 0; i < files.length; i++) { + const filename = path.join(startPath, files[i]); + const stat = fs.lstatSync(filename); + if (stat.isDirectory()) { + mapFiles(filename, filter, mapFunc); + } else if (filename.indexOf(filter) >= 0) { + mapFunc(filename); + } + } +} + +// Find all icons used by the project. +function findIcons(path, iconsetName) { + const iconRegex = new RegExp(`${iconsetName}:[\\w-]+`, 'g'); + const icons = new Set(); + function processFile(filename) { + const content = fs.readFileSync(filename); + let match; + // eslint-disable-next-line + while (match = iconRegex.exec(content)) { + // strip off "hass:" and add to set + icons.add(match[0].substr(iconsetName.length + 1)); + } + } + mapFiles(path, '.js', processFile); + return Array.from(icons); +} + +function genHassIcons() { + const iconNames = findIcons('./src', 'hass').concat(BUILT_IN_PANEL_ICONS); + fs.existsSync(OUTPUT_DIR) || fs.mkdirSync(OUTPUT_DIR); + fs.writeFileSync(HASS_OUTPUT_PATH, generateIconset('hass', iconNames)); +} + +gulp.task('gen-icons-mdi', () => genMDIIcons()); +gulp.task('gen-icons-hass', () => genHassIcons()); +gulp.task('gen-icons-hassio', () => genHassIcons()); +gulp.task('gen-icons', ['gen-icons-hass', 'gen-icons-mdi'], () => {}); + +module.exports = { + findIcons, + generateIconset, +}; diff --git a/gulp/tasks/gen-index-html.js b/gulp/tasks/gen-index-html.js index 76c128f94d..756b76595a 100644 --- a/gulp/tasks/gen-index-html.js +++ b/gulp/tasks/gen-index-html.js @@ -18,8 +18,8 @@ function generateIndex(es6) { const toReplace = [ // Needs to look like a color during CSS minifiaction ['{{ theme_color }}', '#THEME'], - ['/frontend_latest/mdi.js', - `/frontend_latest/mdi-${md5(path.resolve(config.output, 'mdi.js'))}.js`], + ['/frontend_latest/hass-icons.js', + `/frontend_latest/hass-icons-${md5(path.resolve(config.output, 'hass-icons.js'))}.js`], ]; if (!es6) { diff --git a/hassio/.gitignore b/hassio/.gitignore new file mode 100644 index 0000000000..e996d33877 --- /dev/null +++ b/hassio/.gitignore @@ -0,0 +1,2 @@ +build-es5/* +hassio-icons.html diff --git a/hassio/index.html b/hassio/index.html index 6b88a23d21..abf2d78649 100644 --- a/hassio/index.html +++ b/hassio/index.html @@ -30,6 +30,5 @@ } - diff --git a/hassio/script/build_hassio b/hassio/script/build_hassio index eac3313364..8388b902ef 100755 --- a/hassio/script/build_hassio +++ b/hassio/script/build_hassio @@ -9,5 +9,6 @@ cd "$(dirname "$0")/.." OUTPUT_DIR_ES5=build-es5 rm -rf $OUTPUT_DIR_ES5 +node script/gen-icons.js NODE_ENV=production ../node_modules/.bin/webpack -p node script/gen-index-html.js diff --git a/hassio/script/develop b/hassio/script/develop index a74c1e178e..b2344bd7e7 100755 --- a/hassio/script/develop +++ b/hassio/script/develop @@ -9,4 +9,5 @@ OUTPUT_DIR_ES5=build-es5 rm -rf $OUTPUT_DIR_ES5 mkdir $OUTPUT_DIR_ES5 node script/gen-index-html.js +node script/gen-icons.js ../node_modules/.bin/webpack --watch --progress diff --git a/hassio/script/gen-icons.js b/hassio/script/gen-icons.js new file mode 100755 index 0000000000..21c6f3b9e4 --- /dev/null +++ b/hassio/script/gen-icons.js @@ -0,0 +1,13 @@ +#!/usr/bin/env node +const fs = require('fs'); +const { + findIcons, + generateIconset, +} = require('../../gulp/tasks/gen-icons.js'); + +function genHassIcons() { + const iconNames = findIcons('./src', 'hassio'); + fs.writeFileSync('./hassio-icons.html', generateIconset('hassio', iconNames)); +} + +genHassIcons(); diff --git a/hassio/src/addon-store/hassio-addon-repository.js b/hassio/src/addon-store/hassio-addon-repository.js index f35a655693..6498f8d71e 100644 --- a/hassio/src/addon-store/hassio-addon-repository.js +++ b/hassio/src/addon-store/hassio-addon-repository.js @@ -51,7 +51,7 @@ class HassioAddonRepository extends NavigateMixin(PolymerElement) { } computeIcon(addon) { - return addon.installed && addon.installed !== addon.version ? 'mdi:arrow-up-bold-circle' : 'mdi:puzzle'; + return addon.installed && addon.installed !== addon.version ? 'hassio:arrow-up-bold-circle' : 'hassio:puzzle'; } computeIconTitle(addon) { diff --git a/hassio/src/addon-store/hassio-repositories-editor.js b/hassio/src/addon-store/hassio-repositories-editor.js index 78edea7e34..3ecbc8917a 100644 --- a/hassio/src/addon-store/hassio-repositories-editor.js +++ b/hassio/src/addon-store/hassio-repositories-editor.js @@ -35,7 +35,7 @@ class HassioRepositoriesEditor extends PolymerElement {
- +
diff --git a/hassio/src/addon-view/hassio-addon-info.js b/hassio/src/addon-view/hassio-addon-info.js index 39113be4ac..50e73db38a 100644 --- a/hassio/src/addon-view/hassio-addon-info.js +++ b/hassio/src/addon-view/hassio-addon-info.js @@ -66,7 +66,7 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) {
- + `; } diff --git a/src/panels/config/script/ha-script-picker.js b/src/panels/config/script/ha-script-picker.js index 3e6cb898ee..6f82647e83 100644 --- a/src/panels/config/script/ha-script-picker.js +++ b/src/panels/config/script/ha-script-picker.js @@ -52,7 +52,7 @@ class HaScriptPicker extends LocalizeMixin(NavigateMixin(PolymerElement)) { - +
[[localize('ui.panel.config.script.caption')]]
@@ -76,13 +76,13 @@ class HaScriptPicker extends LocalizeMixin(NavigateMixin(PolymerElement)) {
[[computeName(script)]]
[[computeDescription(script)]]
- +
- + `; } diff --git a/src/panels/config/zwave/ha-config-zwave.js b/src/panels/config/zwave/ha-config-zwave.js index 6a1c0a5e55..4fc7126e98 100644 --- a/src/panels/config/zwave/ha-config-zwave.js +++ b/src/panels/config/zwave/ha-config-zwave.js @@ -83,7 +83,7 @@ class HaConfigZwave extends LocalizeMixin(PolymerElement) { - +
[[localize('ui.panel.config.zwave.caption')]]
@@ -94,7 +94,7 @@ class HaConfigZwave extends LocalizeMixin(PolymerElement) {
Z-Wave Node Management - +
diff --git a/src/panels/config/zwave/zwave-network.js b/src/panels/config/zwave/zwave-network.js index a4b25b14f8..c31860f5fb 100644 --- a/src/panels/config/zwave/zwave-network.js +++ b/src/panels/config/zwave/zwave-network.js @@ -45,7 +45,7 @@ class ZwaveNetwork extends PolymerElement {
Z-Wave Network Management - +
diff --git a/src/panels/dev-info/ha-panel-dev-info.js b/src/panels/dev-info/ha-panel-dev-info.js index da51b87185..74cb80ea1c 100644 --- a/src/panels/dev-info/ha-panel-dev-info.js +++ b/src/panels/dev-info/ha-panel-dev-info.js @@ -198,7 +198,7 @@ class HaPanelDevInfo extends PolymerElement {

Press the button to load the full Home Assistant log. - +

[[errorLog]]
diff --git a/src/panels/dev-state/ha-panel-dev-state.js b/src/panels/dev-state/ha-panel-dev-state.js index 347066e60b..a182603524 100644 --- a/src/panels/dev-state/ha-panel-dev-state.js +++ b/src/panels/dev-state/ha-panel-dev-state.js @@ -121,7 +121,7 @@ class HaPanelDevState extends EventsMixin(PolymerElement) { diff --git a/src/panels/logbook/ha-panel-logbook.js b/src/panels/logbook/ha-panel-logbook.js index c80e7547c5..8d85ddc9ef 100644 --- a/src/panels/logbook/ha-panel-logbook.js +++ b/src/panels/logbook/ha-panel-logbook.js @@ -61,7 +61,7 @@ class HaPanelLogbook extends LocalizeMixin(PolymerElement) {
[[localize('panel.logbook')]]
diff --git a/src/panels/mailbox/ha-panel-mailbox.js b/src/panels/mailbox/ha-panel-mailbox.js index f0fb1bfccb..028770317b 100644 --- a/src/panels/mailbox/ha-panel-mailbox.js +++ b/src/panels/mailbox/ha-panel-mailbox.js @@ -134,7 +134,7 @@ class HaPanelMailbox extends LocalizeMixin(PolymerElement) { [[localize('ui.panel.mailbox.playback_title')]]
diff --git a/src/panels/map/ha-entity-marker.js b/src/panels/map/ha-entity-marker.js index 110743af3f..3ff8b2e7ab 100644 --- a/src/panels/map/ha-entity-marker.js +++ b/src/panels/map/ha-entity-marker.js @@ -1,9 +1,7 @@ -import '@polymer/iron-icon/iron-icon.js'; import '@polymer/iron-image/iron-image.js'; import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { PolymerElement } from '@polymer/polymer/polymer-element.js'; - import EventsMixin from '../../mixins/events-mixin.js'; /* diff --git a/src/panels/shopping-list/ha-panel-shopping-list.js b/src/panels/shopping-list/ha-panel-shopping-list.js index a755d29645..8ddeeac71b 100644 --- a/src/panels/shopping-list/ha-panel-shopping-list.js +++ b/src/panels/shopping-list/ha-panel-shopping-list.js @@ -79,7 +79,7 @@ class HaPanelShoppingList extends LocalizeMixin(PolymerElement) { vertical-offset="-5" > @@ -96,7 +96,7 @@ class HaPanelShoppingList extends LocalizeMixin(PolymerElement) { diff --git a/src/resources/hass-icons.js b/src/resources/hass-icons.js new file mode 100644 index 0000000000..ee234cf367 --- /dev/null +++ b/src/resources/hass-icons.js @@ -0,0 +1,6 @@ +import iconSetContent from '../../build/hass-icons.html'; + +const documentContainer = document.createElement('template'); +documentContainer.setAttribute('style', 'display: none;'); +documentContainer.innerHTML = iconSetContent; +document.head.appendChild(documentContainer.content); diff --git a/src/entrypoints/mdi.js b/src/resources/mdi-icons.js similarity index 100% rename from src/entrypoints/mdi.js rename to src/resources/mdi-icons.js diff --git a/webpack.config.js b/webpack.config.js index 5a1bc8f21f..5816e51240 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -64,7 +64,7 @@ function createConfig(isProdBuild, latestBuild) { copyPluginOpts.push('node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js') copyPluginOpts.push({ from: 'node_modules/leaflet/dist/leaflet.css', to: `images/leaflet/` }); copyPluginOpts.push({ from: 'node_modules/leaflet/dist/images', to: `images/leaflet/` }); - entry.mdi = './src/entrypoints/mdi.js'; + entry['hass-icons'] = './src/entrypoints/hass-icons.js'; } else { copyPluginOpts.push('node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js'); babelOptions.presets = [