I totaly agree and also trying to write down some notes of the steps I take while creating my widgets.
But I realized, that it’s kinda hard finding a balance between ‘basic’ custom widgets (without too many classes and styles, which might overwhelm people) and those that are fullfills a real life usecase AND looking good but mostly depends on the usage (and styling) of standard components.
Sounds like a good idea starting with a widget which would be useful for a lot of people and also fullfills the above mentioned limited complexity - what applies here I think.
You can set-up the width of a widget via the ‘Column Options’, individually for each page. The fact, that it creates 3 rows of widgets is related to the use of the component ‘oh-grid-row’.
But this isn’t anything to worry about at all, as the height of the row depends on the largest widget it holds.
The components ‘oh-block’, ‘oh-grid-row’ and ‘oh-grid-col’ are components which were intended to use specifically to match the layout pattern of the pages and so it`s by design that they might extend over multiple rows.
If you just don’t want you components ‘flying’ exchange you ‘oh-block’ root component with a ‘f7-card’-
Which is more arguable, is the usage of pre-made widget-components (like ‘oh-image-card’, ‘oh-player-card’ and so on) inside another widget, whom have styles and classes already applied to them and were build upon the idea that they works as a standalone widget. They are easy to set-up and can be used without fiddling around with the YAML-structure whatsoever.
You can do this, but might loose some flexibility and be forced to remove some of the already applied classes again to make them look nice inside a custom-widget. (like removing borders, shadows and so on)
All of the things I’m talking about here are based on my current knowledge and the experiences I made so far - so take them with a grain of salt. I’m sure @ysc could give you a much more profound answer here.
Another approach (which I personally prefer) would be to use ‘smaller’ components (which the pre-defined components are based on) and rearrange / style them to your needs.
As an example let’s take your widget-idea from above, split it up and try to recreate it with ‘smaller’ components…
From what I understand, you would like to have a frame with 3 rows of contents (1st row: Image of the played media; 2nd row: player controls on the left / volume control and stop button on the right; 3rd row: Name of the currently used app) inside and some basic logic (like hiding elements based on item-status).
So the first thing here would be some card around your content to make it look like a single usable widget. ‘f7-card’ would be the right choice here, as its meant to act as a holder for different widget-components and you can already apply some basic informations like a title, footer, background-color and so on.
component: f7-card config: title: Chromecast widget example slots: default:
Now we create the first row inside that card, which should hold the image of the played content. So ‘oh-image’ would be a good fit to that requirement as we can define an image-url here as well as an item, which holds an image(-url).
- component: f7-block config: class: - padding slots: default: - component: f7-row slots: default: - component: oh-image config: url: https://picsum.photos/600/300 style: width: 100% height: auto
You might ask, what the reason for the f7-block component is, which the content (f7-row) is sitting in.
We will use this as a container around all the components inside the content area of the widget which we can apply styles and classes to later on. The ‘style’ part inside the oh-image component just makes our image responsive in width and height.
I added an image url for demonstration purposes to the ‘oh-image’ component.
The second row should have 2 columns in which we can put the different components. Each column will adapt to the available space which it sits in - so it will use 50% of the row each in our example.
Instead of ‘oh-player-item’ (which is normaly used as a component inside a ‘oh-list’) we use the standalone version of this control-component which is called ‘oh-player-controlls’ inside the first column and doing the same for ‘oh-slider’ (instead of ‘oh-slider-item’) as well as ‘oh-button’ (instead of ‘oh-label-item’) in the second column.
- component: f7-row config: class: - padding-top - padding-bottom slots: default: - component: f7-col slots: default: - component: oh-player-controls config: item: =props.prefix+"_MediaControl" - component: f7-col slots: default: - component: oh-slider config: item: =props.prefix+"_Volume" min: 0 max: 100 step: 10 unit: % label: true - component: oh-button config: text: Stop iconF7: stop fill: true color: red action: command actionCommand: ON actionFeedback: Media Stopped actionItem: =props.prefix+"_Stop" class: - margin-top
Now to the 3rd row which should show the title of the currently played app.
This could be realized with a simple component named ‘Label’ which is nothing else than what it says, a label…
As we`re using this basic component, we have to apply some styles to it to make it fit our needs.
- component: f7-row config: class: - padding-top - justify-content-center style: border-top: 1px solid lightgray slots: default: - component: Label config: text: YouTube Music style: font-size: 24px
If you then want to hide some components based on item states, I would do that with the ‘visible:’ configuration feature and an expression which you have to add to the corresponding component.
All of the above should look like this…