[OH3] Main UI - New „main_widget“ - development and testing [deprecated]

Hey there. Thanks for your kind words. Nothing is finished yet- at the end I will upload all the icons, that’s for sure. Hint: if you can “edit” the PDF, you can grab the temporary/ sample icons right now.
Cheers

This is precisely why trying to nest all these toolbars is going to drive you crazy. If I were building something like this from scratch using the OH widget system, I would avoid using the tabbars. If you build your own links instead or use something like the segmented buttons you’ll have 1000% easier time with styling, positioning, and keeping track.

As for what’s going on, I don’t see that there are any missing tab sets. There are 4 tab toolbars specified in the code. One at the top with “Home - Floors - Rooms” and then one for each of those three content pages (nothing shows on the Home tab at the moment because there are no tab links listed in the toolbar).

Here’s an example of using segmented button to achieve something much more elegant than the tabs:

uid: demo:segmented
props:
  parameterGroups: []
  parameters: []
tags: []
component: f7-page
config:
slots:
  default:
    - component: f7-page-content
      config:
        style:
          height: 100%
      slots:
        default:
          - component: f7-segmented
            config:
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: SECTION1
                    actionVariable: selectSection
                    text: One
                    large: true
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: SECTION2
                    actionVariable: selectSection
                    text: Two
                    large: true
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: SECTION3
                    actionVariable: selectSection
                    text: Three
                    large: true
          - component: f7-segmented
            config:
              visible: =!!(vars.selectSection == "SECTION2")
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: DIV1
                    actionVariable: selectDivision
                    text: Division One
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: DIV2
                    actionVariable: selectDivision
                    text: Division Two
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: DIV3
                    actionVariable: selectDivision
                    text: Division Three
          - component: f7-segmented
            config:
              visible: =!!(vars.selectSection == "SECTION3")
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: OTHER1
                    actionVariable: selectOther
                    text: Other One
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: OTHER2
                    actionVariable: selectOther
                    text: Other Two
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: OTHER3
                    actionVariable: selectOther
                    text: Other Three
          - component: oh-toggle-card
          - component: f7-segmented
            config:
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: THING1
                    actionVariable: selectThing
                    text: Thing One
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: THING2
                    actionVariable: selectThing
                    text: Thing Two
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: THING3
                    actionVariable: selectThing
                    text: Thing Three

Hello @JustinG @ysc @Nic0205 , Hello Community,
Trying to understand the OH principles re pages, structure, design and tools I’m wondering which is the best way to implement a new UI without spending hours to hardcore the platform while giving to end users the ability to configure and install it in a simple way. Yes, i know nothing about coding :blush:.
I understand that we can create only pre-structured OH pages, like a tabbed page. What i missed from that type of page- in order to implement the mentioned UI- is the top menu / selector.
The idea is to investigate (ask OH Community?) if there is a way to create / add a new OH page type. - pls check the attachment.
Maybe what I’m thinking is not a solution, but I’m sure that we have to conform with what OH give us and support natively.
@all experienced members :raised_hands: Your direction and advice in this critical phase is extremely welcomed!

Create tabbed page with menu.pdf (206.4 KB)

Cheers

Hi @Dimitris

I hope one of the pros here can help us with extending the OH Standards.

Until that I will try to follow Justins approach.

I made some progress and will post the actual increment later.
In combination with the MVP approach we can together see how it grows and improve the usability (for administration and using) .

Hi @Dimitris

Could you give me a list with the hex-codes of the colors you used?

Hi @Nic0205
It’s not the final ones!

F8BB00
8C8C8C
F8EFDA
B1ACA2
F2F2F2
6A6A6A

Cool! Looks amazing.

One question to this approach. I tried it and in a “normal” layout-page the widget is not shown.

Do i have to use fixed-layout for it?

I just want to address this statement in case there is some confusion on this point. I’m more than a novice when it comes to MainUI widgets so I can’t help with any of the rest.

In OH some common terms have a specific technical meaning: Thing, Channel, Link, Item, Location (has two different meanings depending on context), Equipment, Point, Property, etc. I tend to capitalize these words when I’m using the technical OH meanings just to make it clear that when I use “Thing” I mean an OH Thing, not the generic meaning of the word “thing”.

So here, assuming you mean the openHAB definition for Equipments (a Group with a specific tag which groups one or more Items that are closely related to each other such as being part of the same device) then the statement above is not accurate. A widget controls and monitors Items. Those Items may or may not be a member of an Equipment.

It makes a lot of sense to create a single widget for each Equipment but it is not required. You could present a single widget with lots of different Equipment. You may not even use the semantic model so you might not even have Equipment.

1 Like

Thank you Sir.
Very clear and very straightforward.

Oh, sorry. It probably is shown it’s just compressed into a small space with a scroll-bar and so not easily visible unless you hunt around for it. That’s just because when I was typing up the quick example I wasn’t intending for it to be put on a page and I used f7-page and f7-page-content base elements which don’t always play well when added to other pages. If you just replace both of those with one f7-block it should show up just fine.

uid: demo:segmented
props:
  parameterGroups: []
  parameters: []
tags: []
component: f7-block
config:
slots:
  default:
    - component: f7-segmented
      config:
      slots:
        default:
          - component: oh-button
            config:
              action: variable
              actionVariableValue: SECTION1
...

This is always the trade-off in developing any system (computer or otherwise). If the system itself is simple, then you probably don’t need to create something to help users interact with it. If the system is complex then that complexity is always going to have to be addressed at some point in the pipeline to users. If you want the user interface to be simple and easy to use then the interface itself has to address that complexity “under the hood” so that the user doesn’t have to, but that is going to require a lot of work on the part of the developer (and also make the user interface more restrictive as many of the complexities have to be addressed by making assumptions that the user then doesn’t get control over).

In this case you could be talking about several different layers of options for “implement a new UI”.

  1. You could create a whole new add-on for OH that replaces MainUI or at least works along side it (habPanel would be one such example that still has a strong user base). That would be the most most complex coding but allow you to get your UI to the point were the user interaction could be streamlined and optimized for the new UI.
  2. You could create some additional pages for the MainUI and submit those additions as a pull request to the MainUI repository. Your pages would still require a heavy amount of coding and probably use the same structure that the current pages use (f7 framework using vue) which would include the styling and make it possible for much of the page to be automatically produced (similar to the overview page and it’s semantic tabs). This but would essentially require the same level of user setup and effort as any other MainUI page.
  3. You could simply release all the different components of the UI as widgets and example page configurations for users to install and setup as they see fit. This is the least coding for you (but, perhaps requiring the most help-doc generation) and the most labor intensive for the users.

My guess is that you are leaning toward the 3rd option. The work that you want to put in to this is creating pages and widgets with your distinct styling (something that many users don’t want to learn to do). But you’re then going to have to leave it up to the user to assemble and configure those different widgets in the way that fits their system the best.

In practice, I think, what this means is that you’ll want to produce pages that contain the essential parts of the UI (e.g., the tab systems) and leaves places where the users can insert widgets. There’s no mechanism at the moment for sharing complete pages other than just posting the yaml code for that page, but that’s fairly easy. Then you’ll want to add all the special widgets to the widget marketplace so that users can download the ones they need and add them to the page(s) where appropriate.

1 Like

Hey,

here the promised increment.

By clicking on Rooms / Living Room / Lights a test widget occurs.

Please give it a short try.

@JustinG : I replaced the f7-page and f7-page-content with f7-block.

Looks much better - but for now it does not scale correct for mobile device (iPhone).
Could you please have a look?

uid: test_ui
tags: []
props:
  parameters:
    - description: The label for the widget
      label: Title
      name: title
      required: false
      type: TEXT
    - context: item
      description: The light switch Item
      label: Item
      name: item
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Aug 16, 2022, 9:58:16 PM
component: f7-block
config:
  defineVars:
    selectSection: 0
    selectDivision: 0
    selectThing: Lights
    SecDiv: =vars.selectSection & vars.selectDivision
slots:
  default:
    - component: f7-block
      config:
        style:
          height: 100%
          min-width: 400px
      slots:
        default:
          - component: f7-segmented
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: SECTION1
                    actionVariable: selectSection
                    text: Home
                    large: true
                    style:
                      font-weight: 200
                      font-size: 30px
                      text-decoration: underline
                      text-decoration-color: '=vars.selectSection=="SECTION1" ? "#F8BB00" : "transparent"'
                      text-underline-offset: 4px
                      color: '=vars.selectSection=="SECTION1" ? "black" : "#8C8C8C"'
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: SECTION2
                    actionVariable: selectSection
                    text: Rooms
                    large: true
                    style:
                      font-weight: 200
                      font-size: 30px
                      color: '=vars.selectSection=="SECTION2" ? "black" : "#8C8C8C"'
                      text-decoration: underline
                      text-decoration-color: '=vars.selectSection=="SECTION2" ? "#F8BB00" : "transparent"'
                      text-underline-offset: 4px
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: SECTION3
                    actionVariable: selectSection
                    text: Floors
                    large: true
                    style:
                      font-weight: 200
                      font-size: 30px
                      color: "#8C8C8C"
          - component: f7-segmented
            config:
              visible: =!!(vars.selectSection == "SECTION2")
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: DIV1
                    actionVariable: selectDivision
                    text: Living Room
                    style:
                      color: '=vars.selectDivision=="DIV1" ? "black" : "#8C8C8C"'
                      text-decoration: underline
                      text-underline-offset: 4px
                      text-decoration-color: '=vars.selectSection + vars.selectDivision  == "SECTION2DIV1" ? "#F8BB00" : "transparent"'
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: DIV2
                    actionVariable: selectDivision
                    text: Bedroom
                    style:
                      color: '=vars.selectDivision=="DIV2" ? "black" : "#8C8C8C"'
                      text-decoration: underline
                      text-underline-offset: 3px
                      text-decoration-color: '=vars.selectSection + vars.selectDivision  == "SECTION2DIV2" ? "#F8BB00" : "transparent"'
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: DIV3
                    actionVariable: selectDivision
                    text: Kitchen
                    style:
                      color: '=vars.selectDivision=="DIV3" ? "black" : "#8C8C8C"'
                      text-decoration: underline
                      text-underline-offset: 3px
                      text-decoration-color: '=vars.selectSection + vars.selectDivision  == "SECTION2DIV3" ? "#F8BB00" : "transparent"'
          - component: f7-segmented
            config:
              visible: =!!(vars.selectSection == "SECTION3")
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: OTHER1
                    actionVariable: selectOther
                    text: Other One
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: OTHER2
                    actionVariable: selectOther
                    text: Other Two
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: OTHER3
                    actionVariable: selectOther
                    text: Other Three
          - component: oh-cell
            config:
              visible: =!!(vars.selectSection + vars.selectDivision + vars.selectThing == "SECTION2DIV1Lights")
              icon: f7:lightbulb
              title: I am a light card in the Living Room
              subtitle: only for testing
          - component: oh-cell
            config:
              visible: =!!(vars.selectSection + vars.selectDivision + vars.selectThing == "SECTION2DIV2Lights")
              icon: f7:lightbulb
              title: I am a light card in the Bedroom
              subtitle: only for testing
          - component: Label
            config:
              text: =vars.selectSection + vars.selectDivision
          - component: Label
            config:
              text: =vars.SecDiv
          - component: f7-segmented
            slots:
              default:
                - component: oh-link
                  config:
                    action: variable
                    actionVariableValue: Lights
                    actionVariable: selectThing
                    text: Lights
                    icon: f7:lightbulb
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: THING2
                    actionVariable: selectThing
                    text: Climate
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: THING3
                    actionVariable: selectThing
                    text: Rollers
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: THING3
                    actionVariable: selectThing
                    text: Security


I see a couple of possible issues. You have a min-width set for one of the f7-blocks of 400px. This is possibly greater than the width of the mobile device screen that you are using so the widget is overflowing off the side. However, if you take away that minimum width, you’re going to start to loose the text in the segmental buttons. So the main issue is that you’re now going to have to deal with scaling text. In my limited experience, dynamically scaling text without using javascript is very difficult (nigh impossible, as far as I can tell). You’re best hope is to find a fixed text scale that works well on the mobile screens and use the device object available in the widget expressions to determine what kind of screen is in use.

For example:

font-size: =(device.desktop)?('30px'):('18px')

As this gets more complex, I think you’re also going to want to use css variables throughout to simplfy. So in the top level f7-block you’ll want a style section where you define the variables once:

component: f7-block
config:
  style:
    --ui-widget-section-font-size:  =(device.desktop)?('30px'):('18px')

And then in the later style settings you can just reference that variable:

font-size: var(--ui-widget-section-font-size)

Some other quick notes:
The Lights button you added is an oh-link not an oh-button which is why it is not properly lined up with the other pieces of the segmented button.

The defineVars section in the top block doesn’t do anything. Unfortunately, at the moment, I don’t believe there’s a way to initialize variables within a widget. You can do so for page level variables that are shared between widgets, but not for a single widget as far as I am aware.

@JustinG I have read your reply 4 times so far. No words! Totally agree that option 3 is the only way -at least for now. Thanks for your time, you helped me a lot.
@Nic0205 Now i realize that i have to present a design that works in OH life. For this reason, i have start to enrich the idea with more info and documentation.
I’m sharing the latest version.
Thank you both!

HOMEUIv5.pdf (168.8 KB)

Dear friend, can you please take a look and give some hints about widgets optimization? A pair of widgets, smaller parent and bigger child called from parent:

uid: Cell_Temp_Card_3
tags:
  - temperature
  - humidity
  - co
  - motion
props:
  parameters:
    - description: Title on top of the card
      label: Title
      name: title
      required: false
      type: TEXT
    - description: Icon on top of the card (only f7 icons (without f7:))
      label: Icon
      name: icon
      required: false
      type: TEXT
    - description: Background image name
      label: Background image
      name: bg_image_url
      required: false
      type: TEXT
    - description: in rgba() or HEX or empty
      label: Background Color
      name: bgcolor
      required: false
      type: TEXT
    - context: item
      label: Temperature
      name: temp_item
      required: false
      type: TEXT
    - context: item
      label: Target Temperature
      name: temperatureset_item
      required: false
      type: TEXT
    - context: item
      label: Lightlevel
      name: lightlevel_item
      required: false
      type: TEXT
    - context: item
      label: Humidity
      name: humidity_item
      required: false
      type: TEXT
    - context: item
      label: Target Humidity
      name: humidityset_item
      required: false
      type: TEXT
    - context: item
      label: CO
      name: CO_item
      required: false
      type: TEXT
    - context: item
      label: Motion item
      name: motion_item
      required: false
      type: TEXT
    - context: item
      label: Lights group
      name: light
      required: false
      type: TEXT
    - context: item
      label: Door item
      name: door_item
      required: false
      type: TEXT
    - context: item
      label: Lock item
      name: lock_item
      required: false
      type: TEXT
    - context: item
      label: Window item
      name: window_item
      required: false
      type: TEXT
    - context: item
      label: Leakage item
      name: leakage_item
      required: false
      type: TEXT
    - context: item
      label: Smoke item
      name: smoke_item
      required: false
      type: TEXT
    - context: item
      label: Media Title
      name: mediaTitle
      required: false
      type: TEXT
    - context: item
      label: Power Item
      name: power
      required: false
      type: TEXT
    - context: item
      label: Channel
      name: channel
      required: false
      type: TEXT
    - context: item
      label: Key Code
      name: inputAction
      required: false
      type: TEXT
    - context: item
      label: Volume Control Item
      name: volumeControlItem
      required: false
      type: TEXT
    - context: item
      label: Source Name
      name: sourceName
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Aug 17, 2022, 2:57:35 PM
component: f7-card
config:
  style:
    background: transparent
    background-brightness: 60%
    background-color: "=props.bgcolor ? props.bgcolor : ''"
    background-image: "=props.bg_image_url ? 'url(/static/' + (props.bg_image_url) + ')' : ''"
    background-position: center
    background-repeat: no-repeat
    background-size: cover
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 10px 1px var(--f7-bars-bg-color)
    color: var(--f7-text-color)
    font-size: medium
    font-weight: 500
    height: 150px
    margin: 5
    noShadow: false
    padding: 0
    text-shadow: 1px 0px 2px var(--f7-bars-bg-color), -1px 0px 2px var(--f7-bars-bg-color), 0px 0px 2px var(--f7-bars-bg-color), 0px 0px 3px var(--f7-bars-bg-color)
slots:
  default:
    - component: f7-card-header
      config:
        style:
          justify-content: center
          margin: 0
          min-height: 30px
          padding: 0
      slots:
        default:
          - component: f7-icon
            config:
              f7: =props.icon
              size: 20
              visible: "=props.icon ? true : false"
          - component: Label
            config:
              style:
                font-size: 18px
                font-weight: bold
                margin-left: 5px
              text: "=props.title ? props.title : ''"
    - component: f7-card-content
      config:
        style:
          align-items: flex-start
          display: flex
          justify-content: space-between
          margin: 7px
          padding: 0
      slots:
        default:
          - component: f7-col
            config: {}
            slots:
              default:
                - component: f7-row
                  config:
                    style:
                      flex-wrap: nowrap
                      justify-content: flex-start
                    visible: "=props.temp_item ? true : false"
                  slots:
                    default:
                      - component: oh-icon
                        config:
                          icon: '=(Number.parseFloat(items[props.temp_item].state.split(" ")[0]) > 30) ? "my_temp_02" : (Number.parseFloat(items[props.temp_item].state.split(" ")[0]) < 0) ? "my_temp_06" : (Number.parseFloat(items[props.temp_item].state.split(" ")[0]) < 10) ? "my_temp_05" : "my_temp_10"'
                          width: 23
                      - component: Label
                        config:
                          style:
                            color: '=(Number.parseFloat(items[props.temp_item].state.split(" ")[0]) > 30) ? "rgb(242,75,36)" : (Number.parseFloat(items[props.temp_item].state.split(" ")[0]) < 10) ? "rgba(32, 185, 256,0.8)" : "var(--f7-text-color)"'
                            margin-left: 5px
                          text: =(Number.parseFloat(items[props.temp_item].state.split(".")[0]))+" °C"
                - component: f7-row
                  config:
                    style:
                      flex-wrap: nowrap
                      justify-content: flex-start
                      z-index: 2
                    visible: "=props.humidity_item ? true : false"
                  slots:
                    default:
                      - component: oh-icon
                        config:
                          icon: '=(Number.parseFloat(items[props.humidity_item].state.split(" ")[0]) < 35) ? "hum-14" : (Number.parseFloat(items[props.humidity_item].state.split(" ")[0]) > 75) ? "hum-70" : "hum-42"'
                          width: 23
                      - component: Label
                        config:
                          style:
                            color: '=(Number.parseFloat(items[props.humidity_item].state.split(" ")[0]) < 35) ? "rgb(242,75,36)" : (Number.parseFloat(items[props.humidity_item].state.split(" ")[0]) > 75) ? "green" : "var(--f7-text-color)"'
                            margin-left: 5px
                          text: =(Number.parseFloat(items[props.humidity_item].state.split(".")[0])) +" %"
                - component: f7-row
                  config:
                    style:
                      flex-wrap: nowrap
                      justify-content: flex-start
                      z-index: 2
                    visible: "=props.lightlevel_item ? true : false"
                  slots:
                    default:
                      - component: oh-icon
                        config:
                          icon: sun
                          width: 23
                      - component: Label
                        config:
                          style:
                            color: "=(items[props.lightlevel_item].state < 1) ? 'gray' : 'var(--f7-text-color)'"
                            margin-left: 5px
                          text: =(Number.parseFloat(items[props.lightlevel_item].state.split(".")[0])) +" lux"
                - component: f7-row
                  config:
                    style:
                      flex-wrap: nowrap
                      z-index: 2
                    visible: "=props.CO_item ? true : false"
                  slots:
                    default:
                      - component: oh-icon
                        config:
                          icon: carbondioxide
                          width: 23
                      - component: Label
                        config:
                          style:
                            color: '=(Number.parseFloat(items[props.CO_item].state.split(" ")[0]) > 1500) ? "red" : (Number.parseFloat(items[props.CO_item].state.split(" ")[0]) > 1000) ? "yellow" : "var(--f7-text-color)"'
                            margin-left: 5px
                            white-space: nowrap
                          text: =(Number.parseFloat(items[props.CO_item].state.split(".")[0])) +" ppm"
          - component: f7-col
            config:
              style:
                align-items: center
                display: flex
                flex-direction: column
            slots:
              default:
                - component: f7-col
                  config:
                    style:
                      z-index: 1
                    visible: "=props.motion_item || props.door_item || props.lock_item || props.window_item ? true : false"
                  slots:
                    default:
                      - component: oh-icon
                        config:
                          icon: "=(items[props.motion_item].state === 'ON') ? 'mymotion-on' : 'mymotion-off'"
                          width: 25
                          visible: "=props.motion_item ? true : false"
                      - component: oh-icon
                        config:
                          icon: "=(items[props.door_item].state === 'ON') ? 'door-closed' : 'door-open'"
                          width: 25
                          visible: "=props.door_item ? true : false"
                      - component: oh-icon
                        config:
                          icon: "=(items[props.lock_item].state === 'ON') ? 'lock' : 'lock-open'"
                          width: 25
                          visible: "=props.lock_item ? true : false"
                      - component: oh-icon
                        config:
                          icon: "=(items[props.window_item].state === 'ON') ? 'window' : 'window-open'"
                          width: 25
                          visible: "=props.window_item ? true : false"
                - component: oh-button
                  config:
                    action: group
                    actionGroupPopupItem: =props.light
                    style:
                      padding: 0
                      z-index: 99
                    visible: "=props.light ? true : false"
                  slots:
                    default:
                      - component: oh-repeater
                        config:
                          for: item
                          fragment: false
                          groupItem: =props.light
                          sourceType: itemsInGroup
                        slots:
                          default:
                            - component: oh-icon
                              config:
                                icon: light
                                width: 30
                                state: =items[loop.item.name].state
                                item: =loop.item.name
          - component: oh-link
            config:
              action: popup
              actionModal: widget:Cell_Temp_Card_Expanded
              actionModalConfig:
                title: =props.title
                icon: =props.icon
                bg_image_url: =props.bg_image_url
                bgcolor: =props.bgcolor
                temp_item: =props.temp_item
                lightlevel_item: =props.lightlevel_item
                humidity_item: =props.humidity_item
                CO_item: =props.CO_item
                motion_item: =props.motion_item
                light: =props.light
                door_item: =props.door_item
                lock_item: =props.lock_item
                window_item: =props.window_item
                leakage_item: =props.leakage_item
                smoke_item: =props.smoke_item
                temperatureset_item: =props.temperatureset_item
                humidityset_item: =props.humidityset_item
                mediaTitle: =props.
                power: =props.power
                channel: =props.channel
                inputAction: =props.inputAction
                volumeControlItem: =props.volumeControlItem
                sourceName: =props.sourceName
              style:
                height: 137px
                left: 0px
                margin: 0px
                padding: 0
                position: absolute
                top: -30px
                width: 100%
                z-index: 3

cell_temp_card_extended.txt (58.3 KB)

Hey @Dimitris ,

thanks for sharing the stylguide. Could you enrich it with example sizes for example for font-size, height of the Header, Footer, etc…

For the meanwhile:

Next Little step - give it a try;-)

uid: test_ui
tags: []
props:
  parameters:
    - description: The label for the widget
      label: Title
      name: title
      required: false
      type: TEXT
    - context: item
      description: The light switch Item
      label: Item
      name: item
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Aug 17, 2022, 6:13:01 PM
component: f7-block
config: {}
slots:
  default:
    - component: f7-block
      config:
        style:
          height: 100%
      slots:
        default:
          - component: f7-segmented
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: SECTION1
                    actionVariable: selectSection
                    text: Home
                    large: true
                    style:
                      font-weight: 200
                      font-size: 30px
                      text-decoration: underline
                      text-decoration-color: '=vars.selectSection=="SECTION1" ? "#F8BB00" : "transparent"'
                      text-underline-offset: 4px
                      color: '=vars.selectSection=="SECTION1" ? "black" : "#8C8C8C"'
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: SECTION2
                    actionVariable: selectSection
                    text: Rooms
                    large: true
                    style:
                      font-weight: 200
                      font-size: 30px
                      color: '=vars.selectSection=="SECTION2" ? "black" : "#8C8C8C"'
                      text-decoration: underline
                      text-decoration-color: '=vars.selectSection=="SECTION2" ? "#F8BB00" : "transparent"'
                      text-underline-offset: 4px
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: SECTION3
                    actionVariable: selectSection
                    text: Floors
                    large: true
                    style:
                      font-weight: 200
                      font-size: 30px
                      color: "#8C8C8C"
          - component: f7-segmented
            config:
              visible: =!!(vars.selectSection == "SECTION2")
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: DIV1
                    actionVariable: selectDivision
                    text: Living Room
                    style:
                      color: '=vars.selectDivision=="DIV1" ? "black" : "#8C8C8C"'
                      text-decoration: underline
                      text-underline-offset: 4px
                      text-decoration-color: '=vars.selectSection + vars.selectDivision  == "SECTION2DIV1" ? "#F8BB00" : "transparent"'
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: DIV2
                    actionVariable: selectDivision
                    text: Bedroom
                    style:
                      color: '=vars.selectDivision=="DIV2" ? "black" : "#8C8C8C"'
                      text-decoration: underline
                      text-underline-offset: 3px
                      text-decoration-color: '=vars.selectSection + vars.selectDivision  == "SECTION2DIV2" ? "#F8BB00" : "transparent"'
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: DIV3
                    actionVariable: selectDivision
                    text: Kitchen
                    style:
                      color: '=vars.selectDivision=="DIV3" ? "black" : "#8C8C8C"'
                      text-decoration: underline
                      text-underline-offset: 3px
                      text-decoration-color: '=vars.selectSection + vars.selectDivision  == "SECTION2DIV3" ? "#F8BB00" : "transparent"'
          - component: f7-segmented
            config:
              visible: =!!(vars.selectSection == "SECTION3")
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: OTHER1
                    actionVariable: selectOther
                    text: Other One
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: OTHER2
                    actionVariable: selectOther
                    text: Other Two
                - component: oh-button
                  config:
                    action: variable
                    actionVariableValue: OTHER3
                    actionVariable: selectOther
                    text: Other Three
          - component: oh-cell
            config:
              visible: =!!(vars.selectSection + vars.selectDivision + vars.selectThing == "SECTION2DIV1Lights")
              icon: f7:lightbulb
              title: I am a light card in the Living Room
              subtitle: only for testing
          - component: oh-cell
            config:
              visible: =!!(vars.selectSection + vars.selectDivision + vars.selectThing == "SECTION2DIV2Lights")
              icon: f7:lightbulb
              title: I am a light card in the Bedroom
              subtitle: only for testing
          - component: Label
            config:
              text: =vars.selectSection + vars.selectDivision
          - component: Label
            config:
              text: =vars.SecDiv
          - component: f7-segmented
            config:
              class:
                - segmented-strong
              style:
                --f7-segmented-strong-padding: 0px
                --f7-segmented-strong-between-buttons: 0px
                --f7-segmented-strong-button-font-weight: 300
                --f7-segmented-strong-bg-color: transparent
                g--f7-segmented-strong-button-hover-bg-color: rgba(255, 255, 255, 0.15)
            slots:
              default:
                - component: oh-button
                  config:
                    class:
                      - padding-top-half
                      - display-flex
                      - flex-direction-column
                    text: Lights
                    action: variable
                    actionVariable: selectThing
                    actionVariableValue: Lights
                    icon-f7: lightbulb
                    iconSize: 20
                    iconColor: black
                    fill: '=vars.selectThing=="Lights" ? true : false'
                    style:
                      --f7-button-text-color: '=vars.selectThing=="Lights" ? "#6A6A6A" : "#8C8C8C"'
                      --f7-button-border-radius: 15px
                      --f7-button-padding-vertical: 0px
                      --f7-button-padding-horizontal: 0px
                      --f7-button-bg-color: '=vars.selectThing=="Lights" ? "#F8BB00" : "transparent"'
                      --f7-button-hover-bg-color: '=vars.selectThing=="Lights" ? "F8BB00" : "transparent"'
                      height: auto
                      font-size: 12px
                - component: oh-button
                  config:
                    class:
                      - padding-top-half
                      - display-flex
                      - flex-direction-column
                    text: Climate
                    action: variable
                    actionVariable: selectThing
                    actionVariableValue: Climate
                    icon-f7: snow
                    iconSize: 20
                    iconColor: black
                    fill: '=vars.selectThing=="Climate" ? true : false'
                    style:
                      --f7-button-text-color: '=vars.selectThing=="Climate" ? "#6A6A6A" : "#8C8C8C"'
                      --f7-button-border-radius: 15px
                      --f7-button-padding-vertical: 0px
                      --f7-button-padding-horizontal: 0px
                      --f7-button-bg-color: '=vars.selectThing=="Climate" ? "#F8BB00" : "transparent"'
                      --f7-button-hover-bg-color: '=vars.selectThing=="Climate" ? "F8BB00" : "transparent"'
                      height: auto
                      font-size: 12px
                - component: oh-button
                  config:
                    class:
                      - padding-top-half
                      - display-flex
                      - flex-direction-column
                    text: Rollers
                    action: variable
                    actionVariable: selectThing
                    actionVariableValue: Rollers
                    icon-f7: archivebox
                    iconSize: 20
                    iconColor: black
                    fill: '=vars.selectThing=="Rollers" ? true : false'
                    style:
                      --f7-button-text-color: '=vars.selectThing=="Rollers" ? "#6A6A6A" : "#8C8C8C"'
                      --f7-button-border-radius: 15px
                      --f7-button-padding-vertical: 0px
                      --f7-button-padding-horizontal: 0px
                      --f7-button-bg-color: '=vars.selectThing=="Rollers" ? "#F8BB00" : "transparent"'
                      --f7-button-hover-bg-color: '=vars.selectThing=="Rollers" ? "F8BB00" : "transparent"'
                      height: auto
                      font-size: 12px
                - component: oh-button
                  config:
                    class:
                      - padding-top-half
                      - display-flex
                      - flex-direction-column
                    text: Security
                    action: variable
                    actionVariable: selectThing
                    actionVariableValue: Security
                    icon-f7: camera
                    iconSize: 20
                    iconColor: black
                    fill: '=vars.selectThing=="Security" ? true : false'
                    style:
                      --f7-button-text-color: '=vars.selectThing=="Security" ? "#6A6A6A" : "#8C8C8C"'
                      --f7-button-border-radius: 15px
                      --f7-button-padding-vertical: 0px
                      --f7-button-padding-horizontal: 0px
                      --f7-button-bg-color: '=vars.selectThing=="Security" ? "#F8BB00" : "transparent"'
                      --f7-button-hover-bg-color: '=vars.selectThing=="Security" ? "F8BB00" : "transparent"'
                      height: auto
                      font-size: 12px

Beware of browser’s dark theme =) Black on black isn’t good to read. Try to use something like color: var(–f7-text-color), var(–f7-bars-bg-color)- they will change depending of theme used. The vars and their colors are seen in browser’s page inspector.

The only thing, in my experience, that noticeably impacts widget performance is too many oh-repeater components that require an API call, such as the itemsWithTags etc. You only have one of those and it’s not really a very complex one so there’s not much performance to optimize.

There are a few places where, if you are interested, the code can be simplified a little:

You have a few places where something like this happens:

text: =(Number.parseFloat(items[props.temp_item].state.split(".")[0]))+" °C"

There are lots of places where you properly use the Number.parseFloat method to change a string into a number for numerical comparison. Here, however, it is unnecessary. For the text property you are just creating a string so you don’t need to change the state from a string to a number first, just leave it as a string:

text: =items[props.temp_item].state.split(".")[0] + " °C"

Alternately, if you are splitting the state at the decimal point because you just want an integer value, you can use the Number object, but just use parseInt and then you don’t need the split:

text: =Number.parseInt(items[props.temp_item].state)+" °C"

You have several instance where you test a variable (or one instance where you test 4 or 5 variables) with a ternary expression such as:

visible: "=props.humidity_item ? true : false"

This is redundant. The ternary expression tests the first part for true or false and provides the first listed result in case the of true and the second in case of false. So what this says is “If this is true then true, but if it’s false, then false.” So, for properties such as the visible property that take a boolean value, you can just use the initial expression:

visible: =props.humidity_item

Any real value (except false and 0) is true, and undefined values are false. So if the variable exists and has a real value this will be true and if the variable is undefined, then it will be false.

Lastly, perhaps the biggest increase in clarity can come where you have all the possible icon definitions such as here:

icon: '=(Number.parseFloat(items[props.temp_item].state.split(" ")[0]) > 30) ? "my_temp_02" : (Number.parseFloat(items[props.temp_item].state.split(" ")[0]) < 0) ? "my_temp_06" : (Number.parseFloat(items[props.temp_item].state.split(" ")[0]) < 10) ? "my_temp_05" : "my_temp_10"'

There are instructions in the docs for creating icons that follow the OH system for dynamic icons. If you work out how to change the names of your icons to follow that system, then you will probably just be able to replace that whole expression with the base name of the icon.

1 Like

This looks fantastic! Is this possible in MainUI If so, would you be so kind as to share? Mine looks terrible

Hey @dastrix80,

we try put the things together - but we are still at a starting point.

A first technical draft - based on @Dimitris Design-draft is here:

https://community.openhab.org/t/oh3-main-ui-examples/117928/315?u=nic0205

At the moment it looks like this:

For now I am working to get the Menu-structure working. After that, we will develop the widgets and put all together :wink:

And yes - all this is then a combinations of widgets in the MainUI.

Help is appreciate :wink:

3 Likes