diff --git a/README.md b/README.md index 8590dcd..e98a035 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,21 @@ [![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge)](https://github.com/custom-components/hacs) # Sidebar card -Popup lovelace card with slider and optional actions to add more control for your cover. -Can be used in combination with my homekit style card: https://github.com/DBuit/Homekit-panel-card +This card adds a sidebar to your interface which you can configure globally so every page has the sidebar. It can replace your top navigation but can also give extra functionality. Buy Me A Coffee -## Configuration -### Installation instructions +## Installation instructions **HACS installation:** -Go to the hacs store and use the repo url `https://github.com/DBuit/cover-popup-card` and add this as a custom repository under settings. +Go to the hacs store and use the repo url `https://github.com/DBuit/sidebar-card` and add this as a custom repository under settings. Add the following to your ui-lovelace.yaml: ```yaml resources: - url: /community_plugin/cover-popup-card/cover-popup-card.js + url: /community_plugin/sidebar-card/sidebar-card.js type: module ``` @@ -26,17 +24,109 @@ Copy the .js file from the dist directory to your www directory and add the foll ```yaml resources: - url: /local/cover-popup-card.js + url: /local/sidebar-card.js type: module ``` +## Configuration + +The YAML configuration happens at the root of your Lovelace config under sidebar: at the same level as resources: and views:. Example: + +``` +resources: + - url: /local/sidebar-card.js?v=0.0.1 + type: module +sidebar: + title: "Sidebar title" +views: +.... +``` + ### Main Options +Under sidebar you can configur the following options + | Name | Type | Default | Supported options | Description | | -------------- | ----------- | ------------ | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `entity` | string | **Required** | `cover.kitchen` | Entity of the light | +| `title` | string | optional | `Title` | Title to show in the sidebar | +| `clock` | boolean | optional | `true` | Show analog clock in sidebar | +| `digitalClock` | boolean | optional | `true` | Show digital clock in sidebar | +| `digitalClockWithSeconds` | boolean | optional | `true` | If digitalClock is enabled you can also enable to show seconds | +| `width` | object | optional | more info | The width of the sidebar in percentages for different screens | +| `hideTopMenu` | boolean | optional | `true` | Hide the top home assistant menu | +| `showTopMenuOnMobile` | boolean | optional | `true` | If you hide the top menu you can set this to `true` so that it will be shown on mobile | +| `breakpoints` | object | optional | more info | For the width we set different sizes for different screens with breakpoints you can overwrite these breakpoints | +| `sidebarMenu` | object | optional | more inf | Create a menu that can switch to different pages but also call any service you want | +| `template` | template | optional | more info | Template rules that will show messages to inform you for example with how many lights are on | + +##### Width + +``` +sidebar: + width: + mobile: 0 + tablet: 25 + desktop: 20 +``` + +##### Breakpoints + +``` +sidebar: + breakpoints: + mobile: 768 + tablet: 1024 +``` + +##### sidebarMenu + +``` +sidebar: + sidebarMenu: + - action: navigate + navigation_path: "/lovelace/home" + name: "Home" + icon: mdi:home + active: true + - action: navigate + navigation_path: "/lovelace/lampen" + name: "Lampen" + icon: mdi:home + - action: navigate + navigation_path: "/lovelace/music" + name: "Muziek" + icon: mdi:home + - action: navigate + navigation_path: "/lovelace/4" + name: "Test" + icon: mdi:home +``` + +##### template + +``` +sidebar: + template: | +
  • + {% if now().hour < 5 %} Goede nacht {{'\U0001F634'}} + {% elif now().hour < 12 %} Goedemorgen {{'\u2615\uFE0F'}} + {% elif now().hour < 18 %} Goedenmiddag {{'\U0001F44B\U0001F3FB'}} + {% else %} Goedenavond {{'\U0001F44B\U0001F3FB'}}{% endif %} +
  • + {% if "Vandaag" in states('sensor.blink_gft') %}
  • Vandaag groenebak aan de straat
  • {% endif %} + {% if "Vandaag" in states('sensor.blink_papier') %}
  • Vandaag oudpapier aan de straat
  • {% endif %} + {% if "Vandaag" in states('sensor.blink_pmd') %}
  • Vandaag plastic aan de straat
  • {% endif %} + {% if "Vandaag" in states('sensor.blink_restafval') %}
  • Vandaag grijzebak aan de straat
  • {% endif %} + {% if "Morgen" in states('sensor.blink_gft') %}
  • Morgen groenebak aan de straat
  • {% endif %} + {% if "Morgen" in states('sensor.blink_papier') %}
  • Morgen oudpapier aan de straat
  • {% endif %} + {% if "Morgen" in states('sensor.blink_pmd') %}
  • Morgen plastic aan de straat
  • {% endif %} + {% if "Morgen" in states('sensor.blink_restafval') %}
  • Morgen grijzebak aan de straat
  • {% endif %} + {% if states('sensor.current_lights_on') | float > 0 %}
  • {{states('sensor.current_lights_on')}} lampen aan
  • {% endif %} + {% if states('sensor.current_media_players_on') | float > 0 %}
  • {{states('sensor.current_media_players_on')}} speakers aan
  • {% endif %} +``` -### Screenshot +### Screenshots - +![Screenshot default](screenshot-default.png) +![Screenshot styled](screenshot-styled.png) diff --git a/dist/sidebar-card.js b/dist/sidebar-card.js index d70ab22..1687ca3 100644 --- a/dist/sidebar-card.js +++ b/dist/sidebar-card.js @@ -2899,6 +2899,9 @@ class SidebarCard extends LitElement { constructor() { super(); this.templateLines = []; + this.clock = false; + this.digitalClock = false; + this.digitalClockWithSeconds = false; } static get properties() { return { @@ -2909,10 +2912,10 @@ class SidebarCard extends LitElement { } render() { const sidebarMenu = this.config.sidebarMenu; - const sidebarMenuColor = this.config.sidebarMenuColor; const title = "title" in this.config ? this.config.title : false; - const clock = this.config.clock && this.hass.states['sensor.time'] ? this.config.clock : false; - const textColor = "textColor" in this.config ? this.config.textColor : false; + this.clock = this.config.clock ? this.config.clock : false; + this.digitalClock = this.config.digitalClock ? this.config.digitalClock : false; + this.digitalClockWithSeconds = this.config.digitalClockWithSeconds ? this.config.digitalClockWithSeconds : false; const addStyle = "style" in this.config ? true : false; return html ` ${addStyle ? html ` @@ -2921,11 +2924,21 @@ class SidebarCard extends LitElement { ` : html ``} `; } + _runClock() { + const date = new Date(); + const fullhours = date.getHours().toString(); + const hours = ((date.getHours() + 11) % 12 + 1); + const minutes = date.getMinutes(); + const seconds = date.getSeconds(); + const hour = hours * 30; + const minute = minutes * 6; + const second = seconds * 6; + if (this.clock) { + this.shadowRoot.querySelector('.hour').style.transform = `rotate(${hour}deg)`; + this.shadowRoot.querySelector('.minute').style.transform = `rotate(${minute}deg)`; + this.shadowRoot.querySelector('.second').style.transform = `rotate(${second}deg)`; + } + if (this.digitalClock) { + const minutesString = minutes.toString(); + var digitalTime = fullhours.length < 2 ? '0' + fullhours + ':' : fullhours + ':'; + if (this.digitalClockWithSeconds) { + digitalTime += minutesString.length < 2 ? '0' + minutesString + ':' : minutesString + ':'; + const secondsString = seconds.toString(); + digitalTime += secondsString.length < 2 ? '0' + secondsString : secondsString; + } + else { + digitalTime += minutesString.length < 2 ? '0' + minutesString : minutesString; + } + this.shadowRoot.querySelector('.digitalClock').textContent = digitalTime; + } + } firstUpdated() { B().querySelectorAll("paper-tab").forEach(paperTab => { paperTab.addEventListener('click', () => { this._updateActiveMenu(); }); }); + if (this.clock || this.digitalClock) { + const inc = 1000; + const self = this; + self._runClock(); + setInterval(function () { + self._runClock(); + }, inc); + } } updated() { } _updateActiveMenu() { @@ -3026,6 +3075,15 @@ class SidebarCard extends LitElement { height: 100%; display: flex; flex-direction: column; + // --face-color: #FFF; + // --face-border-color: #FFF; + // --clock-hands-color: #000; + // --clock-seconds-hand-color: #FF4B3E; + // --clock-middle-background: #FFF; + // --clock-middle-border: #000; + // --sidebar-background: #FFF; + // --sidebar-text-color: #000; + background-color: var(--sidebar-background, #FFF); } .sidebar-inner { padding: 20px; @@ -3036,6 +3094,7 @@ class SidebarCard extends LitElement { padding: 20px 0; border-top: 1px solid rgba(255,255,255,0.2); border-bottom: 1px solid rgba(255,255,255,0.2); + color: var(--sidebar-text-color, #000); } .sidebarMenu li { padding: 10px 20px; @@ -3056,19 +3115,25 @@ class SidebarCard extends LitElement { margin-bottom: 20px; font-size: 32px; line-height: 32px; - font-weight: 300; + font-weight: 200; + color: var(--sidebar-text-color, #000); } - h1.clock { + h1.digitalClock { font-size:60px; line-height: 60px; } - h1.clock.with-title { + h1.digitalClock.with-seconds { + font-size: 48px; + line-height:48px; + } + h1.digitalClock.with-title { margin-bottom:0; } .template { margin: 0; padding: 0; list-style:none; + color: var(--sidebar-text-color, #000); } .template li { @@ -3079,6 +3144,87 @@ class SidebarCard extends LitElement { font-weight:300; white-space: normal; } + + .clock { + margin:20px 0; + position:relative; + padding-top: calc(100% - 10px); + width: calc(100% - 10px); + border-radius: 100%; + background: var(--face-color, #FFF); + font-family: "Montserrat"; + border: 5px solid var(--face-border-color, #FFF); + box-shadow: inset 2px 3px 8px 0 rgba(0, 0, 0, 0.1); + } + + .clock .wrap { + overflow: hidden; + position: absolute; + top:0; + left:0; + width: 100%; + height: 100%; + border-radius: 100%; + } + + .clock .minute, + .clock .hour { + position: absolute; + height: 28%; + width: 6px; + margin: auto; + top: -27%; + left: 0; + bottom: 0; + right: 0; + background: var(--clock-hands-color, #000); + transform-origin: bottom center; + transform: rotate(0deg); + box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.4); + z-index: 1; + } + + .clock .minute { + position: absolute; + height: 41%; + width: 4px; + top: -38%; + left: 0; + box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.4); + transform: rotate(90deg); + } + + .clock .second { + position: absolute; + top: -48%; + height: 48%; + width: 2px; + margin: auto; + left: 0; + bottom: 0; + right: 0; + border-radius: 4px; + background: var(--clock-seconds-hand-color, #FF4B3E); + transform-origin: bottom center; + transform: rotate(180deg); + z-index: 1; + } + + .clock .dot { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 12px; + height: 12px; + border-radius: 100px; + background: var(--clock-middle-background, #FFF); + border: 2px solid var(--clock-middle-border, #000); + border-radius: 100px; + margin: auto; + z-index: 1; + } `; } } @@ -3155,7 +3301,6 @@ function subscribeEvens(appLayout, sidebarConfig) { const width = document.body.clientWidth; appLayout.shadowRoot.querySelector('#customSidebarStyle').textContent = createCSS(sidebarConfig, width); if (sidebarConfig.hideTopMenu && sidebarConfig.hideTopMenu === true && sidebarConfig.showTopMenuOnMobile && sidebarConfig.showTopMenuOnMobile === true && width <= sidebarConfig.breakpoints.mobile) { - console.log('displayMobile'); root.querySelector('ch-header').style.display = 'flex'; } else if (sidebarConfig.hideTopMenu && sidebarConfig.hideTopMenu === true) { @@ -3255,8 +3400,8 @@ buildSidebar(); // return html` //
    // //
    //
    diff --git a/screenshot-default.png b/screenshot-default.png new file mode 100644 index 0000000..780ca12 Binary files /dev/null and b/screenshot-default.png differ diff --git a/screenshot-styled.png b/screenshot-styled.png new file mode 100644 index 0000000..b327a3a Binary files /dev/null and b/screenshot-styled.png differ diff --git a/src/sidebar-card.ts b/src/sidebar-card.ts index f8f755f..274afd4 100644 --- a/src/sidebar-card.ts +++ b/src/sidebar-card.ts @@ -17,6 +17,9 @@ class SidebarCard extends LitElement { shadowRoot: any; renderCard: any; templateLines: any = []; + clock = false; + digitalClock = false; + digitalClockWithSeconds = false; static get properties() { return { @@ -32,10 +35,10 @@ class SidebarCard extends LitElement { render() { const sidebarMenu = this.config.sidebarMenu; - const sidebarMenuColor = this.config.sidebarMenuColor; const title = "title" in this.config ? this.config.title : false; - const clock = this.config.clock && this.hass.states['sensor.time'] ? this.config.clock : false; - const textColor = "textColor" in this.config ? this.config.textColor : false; + this.clock = this.config.clock ? this.config.clock : false; + this.digitalClock = this.config.digitalClock ? this.config.digitalClock : false; + this.digitalClockWithSeconds = this.config.digitalClockWithSeconds ? this.config.digitalClockWithSeconds : false; const addStyle = "style" in this.config ? true : false; return html` ${addStyle ? html` @@ -44,19 +47,29 @@ class SidebarCard extends LitElement { ` : html``}