diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index 5561554..c364afa 100644 --- a/custom_components/browser_mod/browser_mod.js +++ b/custom_components/browser_mod/browser_mod.js @@ -1864,20 +1864,24 @@ const AutoSettingsMixin = (SuperClass) => { constructor() { super(); this._auto_settings_setup(); + this.addEventListener("browser-mod-config-update", () => this._auto_settings_setup()); } async _auto_settings_setup() { await this.connectionPromise; const settings = this.settings; + // Sidebar panel order and hiding if (settings.sidebarPanelOrder) { localStorage.setItem("sidebarPanelOrder", settings.sidebarPanelOrder); } if (settings.sidebarHiddenPanels) { localStorage.setItem("sidebarHiddenPanels", settings.sidebarHiddenPanels); } + // Hide sidebar if (settings.hideSidebar === true) { selectTree(document.body, "home-assistant$home-assistant-main$app-drawer-layout").then((el) => el.style.setProperty("--app-drawer-width", "0px")); selectTree(document.body, "home-assistant$home-assistant-main$app-drawer-layout app-drawer").then((el) => el.remove()); } + // Hide header if (settings.hideHeader === true) { customElements.whenDefined("app-header-layout").then(() => { const appHeader = customElements.get("app-header").prototype; @@ -1888,6 +1892,40 @@ const AutoSettingsMixin = (SuperClass) => { }; }); } + // Favicon template + if (settings.faviconTemplate !== undefined) { + (async () => { + if (this._faviconTemplateSubscription) { + this._faviconTemplateSubscription(); + } + this._faviconTemplateSubscription = undefined; + this._faviconTemplateSubscription = + await this.connection.subscribeMessage(this._updateFavicon, { + type: "render_template", + template: settings.faviconTemplate, + variables: {}, + }); + })(); + } + // Title template + if (settings.titleTemplate !== undefined) ; + } + get _currentFavicon() { + const link = document.head.querySelector("link[rel~='icon']"); + return link === null || link === void 0 ? void 0 : link.href; + } + _updateFavicon({ result }) { + // TEMP: Template for testing + /* + {% if is_state("light.bed_light", "on") %} + /local/workspace/test/icons/green.png + {% else %} + /local/workspace/test/icons/red.png + {% endif %} + */ + const link = document.head.querySelector("link[rel~='icon']"); + link.href = result; + window.browser_mod.fireEvent("browser-mod-favicon-update"); } }; }; @@ -1931,9 +1969,9 @@ const AutoSettingsMixin = (SuperClass) => { x Kiosk mode - Default panel? - Screensaver? - - Tweaks - - Favicon templates + x Favicon templates - Title templates + - Tweaks - Quickbar tweaks (ctrl+enter)? - Video player? - Media_seek diff --git a/custom_components/browser_mod/browser_mod_panel.js b/custom_components/browser_mod/browser_mod_panel.js index 4af3c37..d45c6c6 100644 --- a/custom_components/browser_mod/browser_mod_panel.js +++ b/custom_components/browser_mod/browser_mod_panel.js @@ -67,7 +67,7 @@ const i=(i,e)=>"method"===e.kind&&e.descriptor&&!("value"in e.descriptor)?{...e, // Loads in ha-config-dashboard which is used to copy styling // Also provides ha-settings-row -const loadDevTools = async () => { +const loadConfigDashboard = async () => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l; await customElements.whenDefined("partial-panel-resolver"); const ppResolver = document.createElement("partial-panel-resolver"); @@ -83,8 +83,25 @@ const loadDevTools = async () => { await ((_g = (_f = (_e = (_d = configRouter === null || configRouter === void 0 ? void 0 : configRouter.routerOptions) === null || _d === void 0 ? void 0 : _d.routes) === null || _e === void 0 ? void 0 : _e.dashboard) === null || _f === void 0 ? void 0 : _f.load) === null || _g === void 0 ? void 0 : _g.call(_f)); // Load ha-config-dashboard await ((_l = (_k = (_j = (_h = configRouter === null || configRouter === void 0 ? void 0 : configRouter.routerOptions) === null || _h === void 0 ? void 0 : _h.routes) === null || _j === void 0 ? void 0 : _j.cloud) === null || _k === void 0 ? void 0 : _k.load) === null || _l === void 0 ? void 0 : _l.call(_k)); // Load ha-settings-row await customElements.whenDefined("ha-config-dashboard"); +}; +const loadDeveloperToolsTemplate = async () => { + var _a, _b, _c, _d, _e, _f, _g; + await customElements.whenDefined("partial-panel-resolver"); + await customElements.whenDefined("partial-panel-resolver"); + const ppResolver = document.createElement("partial-panel-resolver"); + const routes = ppResolver.getRoutes([ + { + component_name: "developer-tools", + url_path: "a", + }, + ]); + await ((_c = (_b = (_a = routes === null || routes === void 0 ? void 0 : routes.routes) === null || _a === void 0 ? void 0 : _a.a) === null || _b === void 0 ? void 0 : _b.load) === null || _c === void 0 ? void 0 : _c.call(_b)); + const dtRouter = document.createElement("developer-tools-router"); + await ((_g = (_f = (_e = (_d = dtRouter === null || dtRouter === void 0 ? void 0 : dtRouter.routerOptions) === null || _d === void 0 ? void 0 : _d.routes) === null || _e === void 0 ? void 0 : _e.template) === null || _f === void 0 ? void 0 : _f.load) === null || _g === void 0 ? void 0 : _g.call(_f)); + await customElements.whenDefined("developer-tools-template"); }; +loadDeveloperToolsTemplate(); class BrowserModSettingsCard extends s { constructor() { super(...arguments); @@ -92,6 +109,7 @@ class BrowserModSettingsCard extends s { } firstUpdated() { window.browser_mod.addEventListener("browser-mod-config-update", () => this.requestUpdate()); + window.browser_mod.addEventListener("browser-mod-favicon-update", () => this.requestUpdate()); } _handleSwitchTab(ev) { this._selectedTab = parseInt(ev.detail.index, 10); @@ -101,12 +119,30 @@ class BrowserModSettingsCard extends s { return $ `
+

+ Please note: Those settings severely change the way the Home + Assistant frontend works and looks. It is very easy to forget that + you made a setting here when you switch devices or user. +

+

+ Do not report any issues to Home Assistant before clearing + EVERY setting here and thouroghly clearing all your browser + caches. Failure to do so means you risk wasting a lot of peoples + time, and you will be severly and rightfully ridiculed. +

+

+ Global settings are applied for all users and browsers.
+ User settings are applied to the current user and overrides any Global settings.
+ Browser settings are applied for the current browser and overrides any User or Global settings. +

+ + @@ -120,7 +156,7 @@ class BrowserModSettingsCard extends s { const user = window.browser_mod.user_settings; const browser = window.browser_mod.browser_settings; const current = { global, user, browser }[level]; - const DESC_BOOLEAN = (val) => ({ true: "Enabled", false: "Disabled", undefined: "unset" }[String(val)]); + const DESC_BOOLEAN = (val) => ({ true: "Enabled", false: "Disabled", undefined: "Unset" }[String(val)]); const DESC_SET_UNSET = (val) => (val === undefined ? "Unset" : "Set"); const OVERRIDDEN = (key) => { if (level !== "browser" && browser[key] !== undefined) @@ -129,112 +165,133 @@ class BrowserModSettingsCard extends s { return $ `
Overridden by user setting`; }; return $ ` - - Hide Sidebar - Hide the sidebar and hamburger menu - Currenty: ${DESC_BOOLEAN(current.hideSidebar)} - ${OVERRIDDEN("hideSidebar")} - - - window.browser_mod.set_setting("hideSidebar", true, level)} - > - Enable - - window.browser_mod.set_setting("hideSidebar", false, level)} - > - Disable - - window.browser_mod.set_setting("hideSidebar", undefined, level)} - > - Clear - - +
+ + Favicon template + ${OVERRIDDEN("faviconTemplate")} + + + { + const tpl = ev.detail.value || undefined; + window.browser_mod.set_setting("faviconTemplate", tpl, level); + }} + > + + window.browser_mod.set_setting("faviconTemplate", undefined, level)} + > + Clear + + - - Hide Header - Hide the header on all pages - Currenty: ${DESC_BOOLEAN(current.hideHeader)} - ${OVERRIDDEN("hideHeader")} - - - window.browser_mod.set_setting("hideHeader", true, level)} - > - Enable - - window.browser_mod.set_setting("hideHeader", false, level)} - > - Disable - - window.browser_mod.set_setting("hideHeader", undefined, level)} - > - Clear - - +
- - Sidebar order - Order and visibility of sidebar buttons - Currenty: ${DESC_SET_UNSET(current.sidebarPanelOrder)} - ${OVERRIDDEN("sidebarPanelOrder")} - - - { + + Hide Sidebar + Hide the sidebar and hamburger menu + Currenty: ${DESC_BOOLEAN(current.hideSidebar)} + ${OVERRIDDEN("hideSidebar")} + + + window.browser_mod.set_setting("hideSidebar", true, level)} + > + Enable + + window.browser_mod.set_setting("hideSidebar", false, level)} + > + Disable + + window.browser_mod.set_setting("hideSidebar", undefined, level)} + > + Clear + + + +
+ + + Hide Header + Hide the header on all pages + Currenty: ${DESC_BOOLEAN(current.hideHeader)} + ${OVERRIDDEN("hideHeader")} + + + window.browser_mod.set_setting("hideHeader", true, level)} + > + Enable + + window.browser_mod.set_setting("hideHeader", false, level)} + > + Disable + + window.browser_mod.set_setting("hideHeader", undefined, level)} + > + Clear + + + +
+ + + Sidebar order + Order and visibility of sidebar buttons + Currenty: ${DESC_SET_UNSET(current.sidebarPanelOrder)} + ${OVERRIDDEN("sidebarPanelOrder")} + + + + Clearing this does NOT restore the original button order. + + { window.browser_mod.set_setting("sidebarPanelOrder", localStorage.getItem("sidebarPanelOrder"), level); window.browser_mod.set_setting("sidebarHiddenPanels", localStorage.getItem("sidebarHiddenPanels"), level); }} - > - Set - - { + > + Set + + { window.browser_mod.set_setting("sidebarPanelOrder", undefined, level); window.browser_mod.set_setting("sidebarHiddenPanels", undefined, level); }} - > - Clear - - + > + Clear +
+
+
`; } - _render_user() { - return $ ` - User - - Kiosk mode - Hide sidebar and header - Currenty: Overridden - - - Set screensaver - Set screensaver card - Enable - Disable - Clear - - `; - } - _render_browser() { - return $ ` - Browser - - Kiosk mode - Hide sidebar and header - Currenty: Overridden - - - Set screensaver - Set screensaver card - Enable - Disable - Clear - + static get styles() { + return r$2 ` + .box { + border: 1px solid var(--divider-color); + padding: 8px; + } + .separator { + border-bottom: 1px solid var(--divider-color); + margin: 0 -8px; + } + img.favicon { + width: 64px; + height: 64px; + margin-left: 16px; + } + mwc-tab-bar ha-icon { + display: flex; + align-items: center; + } `; } } @@ -247,7 +304,7 @@ __decorate([ customElements.define("browser-mod-settings-card", BrowserModSettingsCard); const bmWindow = window; -loadDevTools().then(() => { +loadConfigDashboard().then(() => { class BrowserModPanel extends s { constructor() { super(...arguments); diff --git a/custom_components/browser_mod/store.py b/custom_components/browser_mod/store.py index b140df5..5b4dbee 100644 --- a/custom_components/browser_mod/store.py +++ b/custom_components/browser_mod/store.py @@ -16,6 +16,8 @@ class Settings: defaultPanel = attr.ib(type=str, default=None) sidebarPanelOrder = attr.ib(type=list, default=None) sidebarHiddenPanels = attr.ib(type=list, default=None) + faviconTemplate = attr.ib(type=str, default=None) + titleTemplate = attr.ib(type=str, default=None) @classmethod def from_dict(cls, data): diff --git a/js/config_panel/main.ts b/js/config_panel/main.ts index 3b13d45..dfca215 100644 --- a/js/config_panel/main.ts +++ b/js/config_panel/main.ts @@ -1,13 +1,13 @@ import { LitElement, html, css } from "lit"; import { property } from "lit/decorators.js"; -import { loadDevTools } from "../helpers"; +import { loadConfigDashboard } from "../helpers"; import { loadHaForm } from "../helpers"; import "./settings-card"; const bmWindow = window as any; -loadDevTools().then(() => { +loadConfigDashboard().then(() => { class BrowserModPanel extends LitElement { @property() hass; @property() narrow; diff --git a/js/config_panel/settings-card.ts b/js/config_panel/settings-card.ts index a102756..400088b 100644 --- a/js/config_panel/settings-card.ts +++ b/js/config_panel/settings-card.ts @@ -1,5 +1,8 @@ import { LitElement, html, css } from "lit"; import { property, state } from "lit/decorators.js"; +import { loadDeveloperToolsTemplate } from "../helpers"; + +loadDeveloperToolsTemplate(); class BrowserModSettingsCard extends LitElement { @property() hass; @@ -10,6 +13,9 @@ class BrowserModSettingsCard extends LitElement { window.browser_mod.addEventListener("browser-mod-config-update", () => this.requestUpdate() ); + window.browser_mod.addEventListener("browser-mod-favicon-update", () => + this.requestUpdate() + ); } _handleSwitchTab(ev: CustomEvent) { @@ -21,12 +27,30 @@ class BrowserModSettingsCard extends LitElement { return html`
+

+ Please note: Those settings severely change the way the Home + Assistant frontend works and looks. It is very easy to forget that + you made a setting here when you switch devices or user. +

+

+ Do not report any issues to Home Assistant before clearing + EVERY setting here and thouroghly clearing all your browser + caches. Failure to do so means you risk wasting a lot of peoples + time, and you will be severly and rightfully ridiculed. +

+

+ Global settings are applied for all users and browsers.
+ User settings are applied to the current user and overrides any Global settings.
+ Browser settings are applied for the current browser and overrides any User or Global settings. +

+ + @@ -43,7 +67,7 @@ class BrowserModSettingsCard extends LitElement { const current = { global, user, browser }[level]; const DESC_BOOLEAN = (val) => - ({ true: "Enabled", false: "Disabled", undefined: "unset" }[String(val)]); + ({ true: "Enabled", false: "Disabled", undefined: "Unset" }[String(val)]); const DESC_SET_UNSET = (val) => (val === undefined ? "Unset" : "Set"); const OVERRIDDEN = (key) => { if (level !== "browser" && browser[key] !== undefined) @@ -53,136 +77,161 @@ class BrowserModSettingsCard extends LitElement { }; return html` - - Hide Sidebar - Hide the sidebar and hamburger menu - Currenty: ${DESC_BOOLEAN(current.hideSidebar)} - ${OVERRIDDEN("hideSidebar")} - - - - window.browser_mod.set_setting("hideSidebar", true, level)} - > - Enable - - - window.browser_mod.set_setting("hideSidebar", false, level)} - > - Disable - - - window.browser_mod.set_setting("hideSidebar", undefined, level)} - > - Clear - - - - - Hide Header - Hide the header on all pages - Currenty: ${DESC_BOOLEAN(current.hideHeader)} - ${OVERRIDDEN("hideHeader")} - - - - window.browser_mod.set_setting("hideHeader", true, level)} - > - Enable - - - window.browser_mod.set_setting("hideHeader", false, level)} - > - Disable - - - window.browser_mod.set_setting("hideHeader", undefined, level)} - > - Clear - - - - - Sidebar order - Order and visibility of sidebar buttons - Currenty: ${DESC_SET_UNSET(current.sidebarPanelOrder)} - ${OVERRIDDEN("sidebarPanelOrder")} - - - { - window.browser_mod.set_setting( - "sidebarPanelOrder", - localStorage.getItem("sidebarPanelOrder"), - level - ); - window.browser_mod.set_setting( - "sidebarHiddenPanels", - localStorage.getItem("sidebarHiddenPanels"), - level - ); +
+ + Favicon template + ${OVERRIDDEN("faviconTemplate")} + + + { + const tpl = ev.detail.value || undefined; + window.browser_mod.set_setting("faviconTemplate", tpl, level); }} - > - Set - - { - window.browser_mod.set_setting( - "sidebarPanelOrder", - undefined, - level - ); - window.browser_mod.set_setting( - "sidebarHiddenPanels", - undefined, - level - ); - }} - > - Clear - - + > + + + window.browser_mod.set_setting( + "faviconTemplate", + undefined, + level + )} + > + Clear + + + +
+ + + Hide Sidebar + Hide the sidebar and hamburger menu + Currenty: ${DESC_BOOLEAN(current.hideSidebar)} + ${OVERRIDDEN("hideSidebar")} + + + + window.browser_mod.set_setting("hideSidebar", true, level)} + > + Enable + + + window.browser_mod.set_setting("hideSidebar", false, level)} + > + Disable + + + window.browser_mod.set_setting("hideSidebar", undefined, level)} + > + Clear + + + +
+ + + Hide Header + Hide the header on all pages + Currenty: ${DESC_BOOLEAN(current.hideHeader)} + ${OVERRIDDEN("hideHeader")} + + + + window.browser_mod.set_setting("hideHeader", true, level)} + > + Enable + + + window.browser_mod.set_setting("hideHeader", false, level)} + > + Disable + + + window.browser_mod.set_setting("hideHeader", undefined, level)} + > + Clear + + + +
+ + + Sidebar order + Order and visibility of sidebar buttons + Currenty: ${DESC_SET_UNSET(current.sidebarPanelOrder)} + ${OVERRIDDEN("sidebarPanelOrder")} + + + + Clearing this does NOT restore the original button order. + + { + window.browser_mod.set_setting( + "sidebarPanelOrder", + localStorage.getItem("sidebarPanelOrder"), + level + ); + window.browser_mod.set_setting( + "sidebarHiddenPanels", + localStorage.getItem("sidebarHiddenPanels"), + level + ); + }} + > + Set + + { + window.browser_mod.set_setting( + "sidebarPanelOrder", + undefined, + level + ); + window.browser_mod.set_setting( + "sidebarHiddenPanels", + undefined, + level + ); + }} + > + Clear + + +
`; } - _render_user() { - return html` - User - - Kiosk mode - Hide sidebar and header - Currenty: Overridden - - - Set screensaver - Set screensaver card - Enable - Disable - Clear - - `; - } - - _render_browser() { - return html` - Browser - - Kiosk mode - Hide sidebar and header - Currenty: Overridden - - - Set screensaver - Set screensaver card - Enable - Disable - Clear - + static get styles() { + return css` + .box { + border: 1px solid var(--divider-color); + padding: 8px; + } + .separator { + border-bottom: 1px solid var(--divider-color); + margin: 0 -8px; + } + img.favicon { + width: 64px; + height: 64px; + margin-left: 16px; + } + mwc-tab-bar ha-icon { + display: flex; + align-items: center; + } `; } } diff --git a/js/helpers.ts b/js/helpers.ts index 4f1e87c..b819948 100644 --- a/js/helpers.ts +++ b/js/helpers.ts @@ -88,7 +88,7 @@ export const loadHaForm = async () => { // Loads in ha-config-dashboard which is used to copy styling // Also provides ha-settings-row -export const loadDevTools = async () => { +export const loadConfigDashboard = async () => { await customElements.whenDefined("partial-panel-resolver"); const ppResolver = document.createElement("partial-panel-resolver"); const routes = (ppResolver as any).getRoutes([ @@ -99,8 +99,24 @@ export const loadDevTools = async () => { ]); await routes?.routes?.a?.load?.(); await customElements.whenDefined("ha-panel-config"); - const configRouter = document.createElement("ha-panel-config"); - await (configRouter as any)?.routerOptions?.routes?.dashboard?.load?.(); // Load ha-config-dashboard - await (configRouter as any)?.routerOptions?.routes?.cloud?.load?.(); // Load ha-settings-row + const configRouter: any = document.createElement("ha-panel-config"); + await configRouter?.routerOptions?.routes?.dashboard?.load?.(); // Load ha-config-dashboard + await configRouter?.routerOptions?.routes?.cloud?.load?.(); // Load ha-settings-row await customElements.whenDefined("ha-config-dashboard"); }; + +export const loadDeveloperToolsTemplate = async () => { + await customElements.whenDefined("partial-panel-resolver"); + await customElements.whenDefined("partial-panel-resolver"); + const ppResolver = document.createElement("partial-panel-resolver"); + const routes = (ppResolver as any).getRoutes([ + { + component_name: "developer-tools", + url_path: "a", + }, + ]); + await routes?.routes?.a?.load?.(); + const dtRouter: any = document.createElement("developer-tools-router"); + await dtRouter?.routerOptions?.routes?.template?.load?.(); + await customElements.whenDefined("developer-tools-template"); +}; diff --git a/js/plugin/auto-settings.ts b/js/plugin/auto-settings.ts index 2da274c..fa2ac06 100644 --- a/js/plugin/auto-settings.ts +++ b/js/plugin/auto-settings.ts @@ -2,10 +2,16 @@ import { selectTree } from "../helpers"; export const AutoSettingsMixin = (SuperClass) => { return class AutoSettingsMixinClass extends SuperClass { + _faviconTemplateSubscription; + _titleTemplateSubscription; + constructor() { super(); this._auto_settings_setup(); + this.addEventListener("browser-mod-config-update", () => + this._auto_settings_setup() + ); } async _auto_settings_setup() { @@ -13,6 +19,7 @@ export const AutoSettingsMixin = (SuperClass) => { const settings = this.settings; + // Sidebar panel order and hiding if (settings.sidebarPanelOrder) { localStorage.setItem("sidebarPanelOrder", settings.sidebarPanelOrder); } @@ -23,6 +30,7 @@ export const AutoSettingsMixin = (SuperClass) => { ); } + // Hide sidebar if (settings.hideSidebar === true) { selectTree( document.body, @@ -33,6 +41,8 @@ export const AutoSettingsMixin = (SuperClass) => { "home-assistant$home-assistant-main$app-drawer-layout app-drawer" ).then((el) => el.remove()); } + + // Hide header if (settings.hideHeader === true) { customElements.whenDefined("app-header-layout").then(() => { const appHeader = customElements.get("app-header").prototype; @@ -43,6 +53,45 @@ export const AutoSettingsMixin = (SuperClass) => { }; }); } + + // Favicon template + if (settings.faviconTemplate !== undefined) { + (async () => { + if (this._faviconTemplateSubscription) { + this._faviconTemplateSubscription(); + } + this._faviconTemplateSubscription = undefined; + this._faviconTemplateSubscription = + await this.connection.subscribeMessage(this._updateFavicon, { + type: "render_template", + template: settings.faviconTemplate, + variables: {}, + }); + })(); + } + + // Title template + if (settings.titleTemplate !== undefined) { + } + } + + get _currentFavicon() { + const link: any = document.head.querySelector("link[rel~='icon']"); + return link?.href; + } + + _updateFavicon({ result }) { + // TEMP: Template for testing + /* + {% if is_state("light.bed_light", "on") %} + /local/workspace/test/icons/green.png + {% else %} + /local/workspace/test/icons/red.png + {% endif %} + */ + const link: any = document.head.querySelector("link[rel~='icon']"); + link.href = result; + window.browser_mod.fireEvent("browser-mod-favicon-update"); } }; }; diff --git a/js/plugin/main.ts b/js/plugin/main.ts index 7e57cd2..5dffd97 100644 --- a/js/plugin/main.ts +++ b/js/plugin/main.ts @@ -55,9 +55,9 @@ import { AutoSettingsMixin } from "./auto-settings"; x Kiosk mode - Default panel? - Screensaver? - - Tweaks - - Favicon templates + x Favicon templates - Title templates + - Tweaks - Quickbar tweaks (ctrl+enter)? - Video player? - Media_seek