Hu Dimitris,
Really nice design. I tried something similar with my limited design and coding skills. But I didn’t get such nice results lile you here in the team of course.
The color schema is nice, too. But maybe you can deliver different sets of color schema maybe something with blue or green
Thank Jan. Good point - I have spend some time with this in the past.
Here you are:
HOMEUIv2.pdf (201.9 KB)
Themes that includes color schemes is something that I’m thinking of since when Nic and me started this project. For now, we have to deal with the top navbar… One piece at a time!
PS. Will be very happy if you join the Team, no matter what you are capable of
Well, that’s at least proof positive that the styling format is now correct and being applied. Unfortunately, that means that the problem is that the css variables are not being passed to the svg. As far as I know, really this must mean that when the svg is loaded as a resource (instead of being included inline in the code), it is outside the DOM.
I don’t know, off the top of my head, if there’s a way to deal with that. I’ll have to think about it for a while.
i was waiting for the new topic to post widgets based on @Dimitris style, but i’ll post them here.
90% are complete, i’m not a skilled programmer, so i ask to who believe in this project to take these widgets and improve and complete them. please forgive me if in the code there are big mistakes or stupid things, i would like to learn from anyone has better knowns.
here is the security widget:
uid: test:Security_V3
tags:
- MadeByEvil
props:
parameters:
- label: Icona
name: Icon
required: false
type: TEXT
- label: Titolo della card
name: title
required: false
type: TEXT
- default: Item 1
label: Item 1 Label
name: label1
required: false
type: TEXT
- context: item
label: Item 1
name: item1
required: false
type: TEXT
- label: Item 2 Label
name: label2
required: false
type: TEXT
- context: item
label: Item 2
name: item2
required: false
type: TEXT
- label: Item 3 Label
name: label3
required: false
type: TEXT
- context: item
label: Item 3
name: item3
required: false
type: TEXT
- label: Item 4 Label
name: label4
required: false
type: TEXT
- context: item
label: Item 4
name: item4
required: false
type: TEXT
- label: Item 5 Label
name: label5
required: false
type: TEXT
- context: item
label: Item 5
name: item5
required: false
type: TEXT
parameterGroups:
- name: widgetAction
context: action
label: Action
description: Action to perform when the element is clicked
timestamp: Aug 25, 2022, 6:46:53 PM
component: f7-card
config:
style:
border-radius: 10px
height: 320px
min-height: 320px
slots:
content:
- component: oh-icon
config:
icon: iconify:bi:shield-check
color: green
height: 20px
style:
position: absolute
- component: Label
config:
text: Contacts & Alarm
top: 13px
style:
position: absolute
left: 35%
font-weight: 500
- component: oh-icon
config:
icon: '=items[props.item1].state == "ON" ? "iconify:akar-icons:square-fill" : "iconify:akar-icons:square"'
color: green
height: 10px
style:
position: absolute
top: 40px
left: 95px
- component: oh-icon
config:
icon: '=items[props.item2].state == "ON" ? "iconify:akar-icons:square-fill" : "iconify:akar-icons:square"'
color: green
height: 10px
style:
position: absolute
top: 40px
left: 115px
- component: oh-icon
config:
icon: '=items[props.item3].state == "ON" ? "iconify:akar-icons:square-fill" : "iconify:akar-icons:square"'
color: green
height: 10px
style:
position: absolute
top: 40px
left: 135px
- component: oh-icon
config:
icon: '=items[props.item4].state == "ON" ? "iconify:akar-icons:square-fill" : "iconify:akar-icons:square"'
color: green
height: 10px
style:
position: absolute
top: 40px
left: 155px
- component: oh-icon
config:
icon: '=items[props.item5].state == "ON" ? "iconify:akar-icons:square-fill" : "iconify:akar-icons:square"'
color: green
height: 10px
style:
position: absolute
top: 40px
left: 175px
- component: oh-icon
config:
icon: '=items[props.item6].state == "ON" ? "iconify:akar-icons:square-fill" : "iconify:akar-icons:square"'
color: green
height: 10px
style:
position: absolute
top: 40px
left: 195px
- component: oh-icon
config:
icon: '=items[props.item7].state == "ON" ? "iconify:akar-icons:square-fill" : "iconify:akar-icons:square"'
color: green
height: 10px
style:
position: absolute
top: 40px
left: 215px
- component: oh-icon
config:
icon: '=items[props.item8].state == "ON" ? "iconify:akar-icons:square-fill" : "iconify:akar-icons:square"'
color: green
height: 10px
style:
position: absolute
top: 40px
left: 235px
- component: oh-icon
config:
icon: iconify:bi:shield-check
color: '=items[props.item5].state == "ON" ? "green" : items[props.item4].state == "ON" ? "green" : items[props.item3].state == "ON" ? "green" : items[props.item2].state == "ON" ? "green" : items[props.item1].state == "ON" ? "green" : "grey"'
height: 50px
style:
position: absolute
top: 70px
left: 4%
- component: Label
config:
text: Stay
style:
position: absolute
top: 125px
left: 7%
font-weight: 500
- component: oh-icon
config:
icon: iconify:bi:shield-check
color: grey
height: 50px
style:
position: absolute
top: 70px
left: 43%
- component: Label
config:
text: Off
style:
position: absolute
top: 125px
left: 48%
font-weight: 500
- component: oh-icon
config:
icon: iconify:bi:shield-check
color: '=items[props.item5].state == "OFF" && items[props.item4].state == "OFF" && items[props.item3].state == "OFF" && items[props.item2].state == "OFF" && items[props.item1].state == "OFF" ? "red" : "grey"'
height: 50px
style:
position: absolute
top: 70px
left: 81%
- component: Label
config:
text: Arm
style:
position: absolute
top: 125px
left: 85%
font-weight: 500
- component: Label
config:
text: =props.label1
style:
position: absolute
top: 180px
left: 6%
- component: oh-toggle
config:
item: =props.item1
color: green
style:
--f7-toggle-height: 20px
--f7-toggle-width: 40px
font-size: 100%
top: 160px
left: 250px
- component: Label
config:
visible: '=props.item2 ? "true" : "false"'
text: =props.label2
style:
position: absolute
top: 205px
left: 6%
- component: oh-toggle
config:
visible: '=props.item2 ? "true" : "false"'
item: =props.item2
color: green
style:
--f7-toggle-height: 20px
--f7-toggle-width: 40px
top: 185px
left: 210px
- component: Label
config:
visible: '=props.item3 ? "true" : "false"'
text: =props.label3
style:
position: absolute
top: 230px
left: 6%
- component: oh-toggle
config:
visible: '=props.item3 ? "true" : "false"'
item: =props.item3
color: green
style:
--f7-toggle-height: 20px
--f7-toggle-width: 40px
top: 210px
left: 170px
- component: Label
config:
visible: '=props.item4 ? "true" : "false"'
text: =props.label4
style:
position: absolute
top: 255px
left: 6%
- component: oh-toggle
config:
visible: '=props.item4 ? "true" : "false"'
item: =props.item4
color: green
style:
--f7-toggle-height: 20px
--f7-toggle-width: 40px
top: 235px
left: 130px
- component: Label
config:
visible: '=props.item5 ? "true" : "false"'
text: =props.label5
style:
position: absolute
top: 280px
left: 6%
- component: oh-toggle
config:
visible: '=props.item5 ? "true" : "false"'
item: =props.item5
color: green
style:
--f7-toggle-height: 20px
--f7-toggle-width: 40px
top: 260px
left: 90px
footer:
- component: f7-block
config:
style:
top: 125px
left: 0
position: absolute
and here the rollershutter widget:
uid: Rollershutter Preset
tags:
- New UI
props:
parameters:
- description: Title of the card
label: Title
name: Title
required: false
type: TEXT
- context: item
description: Das Item mit dem die Solltemperatur eingestellt wird
label: Rollershutter Item
name: RollerItem
required: true
type: TEXT
timestamp: Aug 22, 2022, 11:41:00 PM
component: f7-card
config:
noShadow: false
padding: false
style:
padding: 0px
border-radius: 10px
box-shadow: 5px 5px 15px 1px rgba(0,0,0,0.05)
--f7-card-header-border-color: transparent
min-width: 90%
slots:
default:
- component: f7-card-header
config:
style:
--f7-card-header-border-color: none
slots:
default:
- component: oh-icon
config:
icon: iconify:mdi:window-shutter-alert
height: 30px
style:
margin-top: 3%
margin-bottom: 3%
- component: Label
config:
text: =props.Title
style:
position: absolute
top: 8%
left: 17%
- component: Label
config:
text: =items[props.RollerItem].state + "% " + " close"
style:
position: absolute
top: 30%
left: 17%
background: gray
border-radius: 9px
- component: oh-button
config:
iconColor: teal
iconF7: arrow_up_circle
iconSize: 30
action: command
actionItem: =props.RollerItem
actionCommand: UP
style:
position: absolute
top: 15%
right: 20%
height: 33px
background: transparent
z-index: 98
- component: oh-button
config:
iconColor: gray
iconF7: stop_circle
iconSize: 30
action: command
actionItem: =props.RollerItem
actionCommand: STOP
style:
position: absolute
top: 15%
right: 10%
height: 33px
background: transparent
z-index: 98
- component: oh-button
config:
iconColor: teal
iconF7: arrow_down_circle
iconSize: 30
action: command
actionItem: =props.RollerItem
actionCommand: DOWN
style:
position: absolute
top: 15%
right: 0%
height: 33px
background: transparent
z-index: 98
- component: f7-card-footer
config:
style:
height: 60px
background: "#B1ACA2"
border-radius: 0 0 10px 10px
slots:
default:
- component: Label
config:
text: "Preset positions:"
style:
position: absolute
top: 5%
color: white
- component: oh-button
config:
round: true
text: "0"
action: command
actionItem: =(props.RollerItem)
actionCommand: UP
class:
- margin
- display-flex
- flex-direction-column
style:
position: absolute
height: 24px
width: 10px
top: 63%
left: 20%
z-index: 98
background: '=items[props.RollerItem].state == "0" ? "teal" : "gray"'
color: white
- component: oh-button
config:
round: true
text: 50
action: command
actionItem: =(props.RollerItem)
actionCommand: 50
class:
- margin
- display-flex
- flex-direction-column
style:
position: absolute
height: 24px
width: 10px
top: 63%
left: 33%
z-index: 98
background: '=items[props.RollerItem].state == "50" ? "teal" : "gray"'
color: white
- component: oh-button
config:
round: true
text: 75
action: command
actionItem: =(props.RollerItem)
actionCommand: 75
class:
- margin
- display-flex
- flex-direction-column
style:
position: absolute
height: 24px
width: 10px
top: 63%
right: 33%
z-index: 98
background: '=items[props.RollerItem].state == "75" ? "teal" : "gray"'
color: white
- component: oh-button
config:
round: true
text: 100
action: command
actionItem: =(props.RollerItem)
actionCommand: DOWN
class:
- margin
- display-flex
- flex-direction-column
style:
position: absolute
height: 24px
width: 10px
top: 63%
right: 20%
z-index: 98
background: '=items[props.RollerItem].state == "100" ? "teal" : "gray"'
color: white
both are missing the function “expandable” and the “hours bars” details of when the item have been modified.
width and weight are perfect for iphone layout.
hope someone can help me/us adding functions and better screen adapt.
bye!
Hey Master J.
Do we have some info re how the OH render/recolor mechanism works? SVG contains colored vectors . If ,for example OH can recolor only Black and White or Grey scale vectors, then the SVG must designed in that Color Space to be capable of recoloring.
Can someone try to re-color attached svg’s and post the results?
I do not believe that OH recolors svgs at any point. The included “classic” icons are in svg format, but do not ever get recolored. The f7 icons are included in the page as a font, if I recall, so recoloring those is as simple as changing the appropriate css color
property. I have never looked into the material icons, so I don’t know how those work, but my guess would be that they are similar to the f7 icons.
Hey @JustinG,
I think the first option (with an array) is a good starting point.
Is there a part in the docu of how to use arrays (how to iterate over the elements, how to read which position the pointer has, etc.) for widget development?
And is there also a part where looping / repeat is explained / documented? In my mind I think I have found an approach to integrate the “forward” and “back” buttons - but I need to get deeper in the technical things…
Within widgets, the only available option for looping is the oh-repeater
.
My gut feeling is that to allow the most configurable widget, you want users to be able to choose which locations appear or don’t appear. To do that I would recommend that you come up with an item tag that’s distinct to your widget configuration and apply that tag to any locations that are going to be in the widget, then you can use the itemsWithTags
source for the repeater to fetch those locations.
To restrict the repeater’s output to only 3 of those at a time, you’ll need to use the fitler
property of the repeater and the index variable that gets created. I don’t think the index variable is documented yet, but if you search the forums for “repeater idx”, you should see some good examples of the index variable in use.
I was correct. The svgs loaded as resources will not be included in the scope of the page’s css (learn something new every day).
There is, however, a fun workaround using svg sprites. It’ll be instructive and interesting for more people than just the readers of this thread, so I’ll post it as new thread in the next couple of days when I get a chance.
Edit: Here’s a link to the svg icon method.
Are you hiding from me Mr OH Developer?
Hue_overview.pdf (95.6 KB)
I’m joking: This is just to share some latest (graphic) experiments. Ahh, and to push a liiiittle bit the navbar sub-project!
With color bars - dizzy layout, but with better “what-if” understanding.
Hue_overviewv1.pdf (45.7 KB)
Sorry, last days have been turbulent.
I still work on the navbar and make efforts - but this week i am Limited a Little bit with time…
Hey @JustinG ,
I am testing different approaches.
With this code I have the problem, that the flex-row option is ignored.
Could you have - once again - a look, what’s going wrong here:
uid: test_Arr
tags: []
props: {}
timestamp: Aug 29, 2022, 11:11:07 PM
component: f7-card
config: {}
slots:
content:
- component: f7-segmented
config:
style:
display: flex
flex-direction: row
slots:
default:
- component: oh-repeater
config:
for: rooms
sourceType: array
in:
- name: Room1
- name: Room2
- name: Room3
- name: Room4
- name: Room5
map: loop.rooms.name
slots:
default:
- component: oh-button
config:
action: variable
actionVariable: selectSection
actionVariableValue: SECTION1
large: true
style:
color: '=vars.selectSection=="SECTION1" ? "black" : "#8C8C8C"'
font-size: 30px
font-weight: 200
text-decoration: underline
text-decoration-color: '=vars.selectSection=="SECTION1" ? "#F8BB00" : "transparent"'
text-underline-offset: 4px
text: =loop.rooms
You need to add fragment: true
to the repeater. In it’s normal setting, the repeater wraps all of the elements it produces in a div
element container. So your f7-segmented
is flex spacing correctly, it’s just spacing one div
element (which just happens to contains lots of buttons that the segmented doesn’t care about at all). When you add the fragment property to the repeater it strips that extra container from around the repeated elements and makes them direct children of the repeater’s parent element.
… Oh my dear… I still have a lot to learn - but to be honest it’s a cool thing to learn all this stuff.
Just another question (please tell me when to stop asking questions to you…):
How could I determine where the oh-repeater should start and where it should end - or in other words could I use an index for iterating over the elements?.
let me say it in words:
I have for example 8 Rooms in an array.
The oh-repeater should only show me the first 3 Rooms (index 1 to 3)
I click on “>” and the oh-repeater now should show me show 3 Rooms with the index 2 to 4.
How could I tell the repeater where to start, where to end and how could I know where the index stands?
I hope I described it well.
here my first attempt in code - simplified to just decrease the variable of the Range:
uid: ButtonGridd2
tags: []
props: {}
timestamp: Aug 30, 2022, 9:44:07 AM
component: f7-card
config: {}
slots:
content:
- component: f7-segmented
config:
style:
display: flex
flex-direction: row
slots:
default:
- component: oh-repeater
config:
fragment: true
for: rooms
rangeStart: 1
rangeStop: =vars.rstp
sourceType: array
in:
- name: Room1
- name: Room2
- name: Room3
- name: Room4
- name: Room5
map: loop.rooms.name
slots:
default:
- component: oh-button
config:
action: variable
actionVariable: selectSection
actionVariableValue: =loop.rooms
large: true
style:
color: '=vars.selectSection=="SECTION1" ? "black" : "#8C8C8C"'
text: =loop.rooms
- component: Label
config:
style:
flex: 1 1 auto
overflow-y: auto
position: relative
text: =vars.selectSection
- component: Label
config:
style:
flex: 1 1 auto
overflow-y: auto
position: relative
text: =vars.rstp
- component: oh-button
config:
text: ">"
action: variable
actionVariable: rstp
actionVariableValue: =vars.rstp + 1
Hey Pal. Is there any chance to create a “Dynamic Index”? In the original design the displayed rooms may vary from 1 to 3 (or more if they can fit!) depending on the width of the text -see attachment. I don’t want to add more complexity, but i think this is decision time for the navbar!
See Allign_v1.pdf (71.4 KB) or
No worries, just be sure, as you learn more and more, to pass on what you know to others.
The repeater not only gives you a single element of its array at a time (loop.whatever
) it also creates two other variables you can use in the scope of the repeater: loop.whatever_idx
and loop.whatever_source
. Whereas the regular variable is just the current element of the overall array, the _idx
variable is the index of that current element and the _source
variable is the entire array that the repeater is working form.
The filter
property filters the entire array down to a subset based on whatever expression (without the =
in front) that you give it. So here you want the subset of the original array where the index is equal to some position variable or that position plus 1 or 2. Your filter statement would look something like this:
filter: (loop.whatever_idx >= vars.buttonIndex) && (loop.whatever_idx <= (vars.buttonIndex +2))
As far as I know, there is really only one reliable way to do this with css (I’d be interested to hear if other’s know of a different way). You have to keep the container from expanding vertically (i.e., set a fixed height), let it use block spacing for the child elements and set it to hide overflow elements. Then you have to set the child elements to float: left
. Here’s a quick example. If you put this in your editor and adjust the window width you should see the right-hand buttons disappear as they run out of room.
uid: demo:hide_buttons
props:
parameterGroups: []
parameters: []
tags: []
component: f7-block
config:
slots:
default:
- component: f7-row
config:
style:
overflow: hidden
display: block
height: 28px
slots:
default:
- component: oh-button
config:
text: Very very very long button here
outline: true
style:
float: left
width: auto
- component: oh-button
config:
text: Short button
outline: true
style:
float: left
width: auto
- component: oh-button
config:
text: Regular button here
outline: true
style:
float: left
width: auto
There’s actually an advantage to this setup: the filter
property for the repeater becomes easier because you just have to rule out buttons before the position variable and then let the css do the rest of figuring out how many buttons are visible.
Definitively, this is the most beautiful reply that i have read here. The definition of the Community.
that’s cool - but for our use case the overflow should scroll horizontal.
But if I set overflow: scroll
it scrolls vertical. Could we get rid of this?
Until we manage this I will go further with the array approach…
That sound like the thing I am looking for. But if I want so show for example the length of source I get an TypeError: undefined is not an object (evaluating 'n[e.property.name]')
.
Did I understand it wrong?
uid: ButtonGridd2
tags: []
props: {}
timestamp: Aug 30, 2022, 9:44:16 AM
component: f7-card
config: {}
slots:
content:
- component: f7-segmented
config:
style:
display: flex
flex-direction: row
slots:
default:
- component: oh-repeater
config:
fragment: true
for: rooms
sourceType: array
in:
- name: Room1
- name: Room2
- name: Room3
- name: Room4
- name: Room5
map: loop.rooms.name
slots:
default:
- component: oh-button
config:
action: variable
actionVariable: selectSection
actionVariableValue: =loop.rooms_source.length
large: true
style:
color: '=vars.selectSection=="SECTION1" ? "black" : "#8C8C8C"'
text: =loop.rooms
- component: Label
config:
style:
flex: 1 1 auto
overflow-y: auto
position: relative
text: =loop.rooms_source.length
# text: =loop.rooms_source.length
Hey @Nic0205 I need to enlighten me on this:
While I’m trying to add
component: f7-navbar
in an OH Page, the OH draws a Navbar. Maybe it thinks that i’m just another Mac User and reacts accordingly
My thought is, -if this works and you can configure it- maybe it’s an alternative for what we are trying to do. PLS don’t spend more than of 2-5 minutes on this, I just wanted to show to @JustinG that I’m reading (…not studying) code!!!