diff --git a/panels/config/ha-panel-config.html b/panels/config/ha-panel-config.html
index 91621b8b9e..1b76377fd9 100644
--- a/panels/config/ha-panel-config.html
+++ b/panels/config/ha-panel-config.html
@@ -8,6 +8,7 @@
+
@@ -53,6 +54,14 @@
hass='[[hass]]'
>
+
+
+
+
+
diff --git a/panels/config/themes/ha-config-section-themes.html b/panels/config/themes/ha-config-section-themes.html
new file mode 100644
index 0000000000..4735d32566
--- /dev/null
+++ b/panels/config/themes/ha-config-section-themes.html
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+ Set a theme
+
+ Choose 'default' to use whatever theme the backend chooses or pick a theme for this device.
+
+
+
+
+
+
+
+ [[theme]]
+
+
+
+
+
+
+
+
+
+
diff --git a/src/home-assistant.html b/src/home-assistant.html
index 1e49e19037..6f1907b677 100644
--- a/src/home-assistant.html
+++ b/src/home-assistant.html
@@ -85,6 +85,10 @@ Polymer({
},
},
+ listeners: {
+ settheme: 'setTheme',
+ },
+
computeShowMain: function (hass, iconsLoaded) {
return hass && hass.states && hass.config && iconsLoaded;
},
@@ -158,13 +162,13 @@ Polymer({
}, this.$.storage.getStoredState());
var reconnected = () => {
- this.hass = Object.assign({}, this.hass, { connected: true });
+ this._updateHass({ connected: true });
};
conn.addEventListener('ready', reconnected);
var disconnected = () => {
- this.hass = Object.assign({}, this.hass, { connected: false });
+ this._updateHass({ connected: false });
};
conn.addEventListener('disconnected', disconnected);
@@ -172,7 +176,7 @@ Polymer({
var unsubEntities;
window.HAWS.subscribeEntities(conn, (states) => {
- this.hass = Object.assign({}, this.hass, { states: states });
+ this._updateHass({ states: states });
}).then(function (unsub) {
unsubEntities = unsub;
});
@@ -180,7 +184,7 @@ Polymer({
var unsubConfig;
window.HAWS.subscribeConfig(conn, (config) => {
- this.hass = Object.assign({}, this.hass, { config: config });
+ this._updateHass({ config: config });
}).then(function (unsub) {
unsubConfig = unsub;
});
@@ -188,12 +192,12 @@ Polymer({
var unsubThemes;
this.hass.callApi('get', 'themes').then((themes) => {
- this.hass.themes = themes;
- window.hassUtil.applyThemesOnElement(this, themes);
+ this._updateHass({ themes: themes });
+ window.hassUtil.applyThemesOnElement(this, themes, this.hass.selectedTheme, true);
});
conn.subscribeEvents((event) => {
- this.hass.themes = event.data;
- window.hassUtil.applyThemesOnElement(this, event.data);
+ this._updateHass({ themes: event.data });
+ window.hassUtil.applyThemesOnElement(this, event.data, this.hass.selectedTheme, true);
}, 'themes_updated').then(function (unsub) {
unsubThemes = unsub;
});
@@ -220,16 +224,12 @@ Polymer({
handleMoreInfo: function (ev) {
ev.stopPropagation();
- this.hass = Object.assign(
- {}, this.hass,
- { moreInfoEntityId: ev.detail.entityId });
+ this._updateHass({ moreInfoEntityId: ev.detail.entityId });
},
handleDockSidebar: function (ev) {
ev.stopPropagation();
- this.hass = Object.assign(
- {}, this.hass,
- { dockedSidebar: ev.detail.dock });
+ this._updateHass({ dockedSidebar: ev.detail.dock });
this.$.storage.storeState();
},
@@ -253,5 +253,15 @@ Polymer({
ready: function () {
this.loadIcons();
},
+
+ setTheme: function (event) {
+ this._updateHass({ selectedTheme: event.detail });
+ window.hassUtil.applyThemesOnElement(this, this.hass.themes, this.hass.selectedTheme, true);
+ this.$.storage.storeState();
+ },
+
+ _updateHass: function (obj) {
+ this.hass = Object.assign({}, this.hass, obj);
+ },
});
diff --git a/src/util/ha-pref-storage.html b/src/util/ha-pref-storage.html
index 55410c66dc..f4eb2c289e 100644
--- a/src/util/ha-pref-storage.html
+++ b/src/util/ha-pref-storage.html
@@ -2,6 +2,7 @@
(function () {
var STORED_STATE = [
'dockedSidebar',
+ 'selectedTheme',
];
Polymer({
diff --git a/src/util/hass-util.html b/src/util/hass-util.html
index e145f7834a..ddcd320645 100644
--- a/src/util/hass-util.html
+++ b/src/util/hass-util.html
@@ -492,25 +492,34 @@ window.hassUtil.computeLocationName = function (hass) {
return hass && hass.config.core.location_name;
};
-window.hassUtil.applyThemesOnElement = function (element, themes, localTheme) {
+window.hassUtil.applyThemesOnElement = function (element, themes, localTheme, updateMeta) {
if (!element._themes) {
element._themes = {};
}
- var themeName = themes.default_theme;
+ let themeName = themes.default_theme;
if (localTheme === 'default' || (localTheme && themes.themes[localTheme])) {
themeName = localTheme;
}
- if (themeName === 'default') {
- element.updateStyles(element._themes);
- return;
+ const styles = Object.assign({}, element._themes);
+ if (themeName !== 'default') {
+ var theme = themes.themes[themeName];
+ Object.keys(theme).forEach((key) => {
+ var prefixedKey = '--' + key;
+ element._themes[prefixedKey] = '';
+ styles[prefixedKey] = theme[key];
+ });
}
- var theme = themes.themes[themeName];
- var styles = Object.assign({}, element._themes);
- Object.keys(theme).forEach(function (key) {
- var prefixedKey = '--' + key;
- element._themes[prefixedKey] = '';
- styles[prefixedKey] = theme[key];
- });
element.updateStyles(styles);
+
+ if (!updateMeta) return;
+
+ const meta = document.querySelector('meta[name=theme-color]');
+ if (meta) {
+ if (!meta.hasAttribute('default-content')) {
+ meta.setAttribute('default-content', meta.getAttribute('content'));
+ }
+ const themeColor = styles['--primary-color'] || meta.getAttribute('default-content');
+ meta.setAttribute('content', themeColor);
+ }
};