Skip to content

Commit

Permalink
Refactor card widgets to use a shared base component (#2781)
Browse files Browse the repository at this point in the history
Supersedes #1801.

Implements the proposal from
#1801 (comment).

-----

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
  • Loading branch information
florian-h05 authored Oct 1, 2024
1 parent 4785cfa commit dcbc549
Show file tree
Hide file tree
Showing 34 changed files with 726 additions and 290 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions bundles/org.openhab.ui/doc/components/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ source: https://github.com/openhab/openhab-webui/edit/main/bundles/org.openhab.u

| Component | Name | Description |
|--------|------|-------------|
| [`oh-card`](./oh-card.html) | [Card](./oh-card.html) | The basic structure of all card widgets, providing title and footer and requiring a content slot |
| [`oh-clock-card`](./oh-clock-card.html) | [Digital Clock Card](./oh-clock-card.html) | Display a digital clock in a card |
| [`oh-colorpicker-card`](./oh-colorpicker-card.html) | [Color Picker Card](./oh-colorpicker-card.html) | Display a color picker in a card |
| [`oh-gauge-card`](./oh-gauge-card.html) | [Gauge Card](./oh-gauge-card.html) | Display a read-only gauge in a card to visualize a quantifiable item |
Expand Down
2 changes: 1 addition & 1 deletion bundles/org.openhab.ui/doc/components/oh-canvas-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Position widgets on a canvas layout with arbitrary position and size down to pix
</PropBlock>
<PropBlock type="INTEGER" name="screenHeight" label="Screen Height">
<PropDescription>
Screen width in pixels (default 720)
Screen height in pixels (default 720)
</PropDescription>
</PropBlock>
<PropBlock type="BOOLEAN" name="scale" label="Scaling">
Expand Down
505 changes: 505 additions & 0 deletions bundles/org.openhab.ui/doc/components/oh-card.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bundles/org.openhab.ui/doc/components/oh-slider-card.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Display a slider in a card to control an item
Minimum interval between values
</PropDescription>
</PropBlock>
<PropBlock type="DECIMAL" name="vertical" label="Vertical">
<PropBlock type="BOOLEAN" name="vertical" label="Vertical">
<PropDescription>
Display the slider vertically
</PropDescription>
Expand Down
2 changes: 1 addition & 1 deletion bundles/org.openhab.ui/doc/components/oh-slider-cell.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ A cell expanding to a big vertical slider
Minimum interval between values
</PropDescription>
</PropBlock>
<PropBlock type="DECIMAL" name="vertical" label="Vertical">
<PropBlock type="BOOLEAN" name="vertical" label="Vertical">
<PropDescription>
Display the slider vertically
</PropDescription>
Expand Down
2 changes: 1 addition & 1 deletion bundles/org.openhab.ui/doc/components/oh-slider-item.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ Display a slider control in a list
Minimum interval between values
</PropDescription>
</PropBlock>
<PropBlock type="DECIMAL" name="vertical" label="Vertical">
<PropBlock type="BOOLEAN" name="vertical" label="Vertical">
<PropDescription>
Display the slider vertically
</PropDescription>
Expand Down
2 changes: 1 addition & 1 deletion bundles/org.openhab.ui/doc/components/oh-slider.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Slider control, allows to pick a number value on a scale
Minimum interval between values
</PropDescription>
</PropBlock>
<PropBlock type="DECIMAL" name="vertical" label="Vertical">
<PropBlock type="BOOLEAN" name="vertical" label="Vertical">
<PropDescription>
Display the slider vertically
</PropDescription>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,15 @@ export function pt (name, label, description) {
* @param {string} name the name of the widget (in kebab case)
* @param {string} label the untranslated (English) name of the widget
* @param {string} description the untranslated (English) description of the widget
* @param {string} icon an optional icon to illustrate the widget, used for map/plan markers
* @param {string} [icon] an optional icon to illustrate the widget, used for map/plan markers
* @param {boolean} [hidden=false] whether the widget is hidden and should not be shown in the widget picker
*/
export function WidgetDefinition (name, label, description, icon) {
export function WidgetDefinition (name, label, description, icon, hidden = false) {
this.name = name
this.label = label
this.description = description
if (icon) this.icon = icon
this.hidden = hidden
this.props = {
parameterGroups: [],
parameters: []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export function OhCanvasLayoutDefinition () {
])
.paramGroup(pg('screenSettings', 'Screen Settings'), [
pn('screenWidth', 'Screen Width', 'Screen width in pixels (default 1280)'),
pn('screenHeight', 'Screen Height', 'Screen width in pixels (default 720)'),
pn('screenHeight', 'Screen Height', 'Screen height in pixels (default 720)'),
pb('scale', 'Scaling', 'Scale content to screen width (can lead to unexpected styling issues) (default false)'),
pt('imageUrl', 'Image URL', 'The URL of the image to display as background').c('url'),
pt('imageSrcSet', 'Image Source Set', 'The src-set attribute of background image element to take into account multiple device resolutions. For example: "/static/floorplans/floor-0.jpg, /static/floorplans/floor-0@2x.jpg 2x"')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ export const CardParameters = () => [
pb('outline', 'Outline', 'Show the card outline').a()
]

// OhCard
export const OhCardDefinition = () => new WidgetDefinition('oh-card', 'Card', 'The basic structure of all card widgets, providing title and footer and requiring a content slot', undefined, true)
.paramGroup(CardParameterGroup(), CardParameters())
.paramGroup(actionGroup(), actionParams())
.paramGroup(actionGroup('Tap Hold', 'Action performed when tapping and holding card (or calling contextual menu on desktop)', 'taphold'), actionParams(null, 'taphold'), true)

// OhLabelCard
import TrendParameters from '../system/trend.js'
export const OhLabelCardDefinition = () => new WidgetDefinition('oh-label-card', 'Label Card', 'Display the state of an item in a card')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default () => [
pd('min', 'Min', 'Minimum value'),
pd('max', 'Max', 'Maximum value'),
pd('step', 'Step', 'Minimum interval between values'),
pd('vertical', 'Vertical', 'Display the slider vertically'),
pb('vertical', 'Vertical', 'Display the slider vertically'),
pb('label', 'Display Label', 'Display a label above the slider knob while sliding'),
pb('scale', 'Display Scale', 'Display a scale on the slider'),
pn('scaleSteps', 'Scale steps', 'Number of (major) scale markers'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
<generic-widget-component v-else :context="childContext(slotComponent)" v-for="(slotComponent, idx) in slotComponents" :slot="slotName" :key="slotName + '-' + idx" @command="onCommand" />
</template>
</component>
<oh-card v-else-if="componentType && componentType === 'oh-card' && visible" :context="context">
<!-- eslint-disable-next-line vue/no-unused-vars -->
<template v-for="(slotComponents, slotName) in context.component.slots" #[slotName]>
<generic-widget-component :context="childContext(slotComponent)" v-for="(slotComponent, idx) in slotComponents" :slot="slotName" :key="slotName + '-' + idx" @command="onCommand" />
</template>
</oh-card>
<generic-widget-component v-else-if="componentType && componentType.startsWith('widget:') && visible" :context="childWidgetContext()" @command="onCommand" />
<component v-else-if="componentType && componentType.startsWith('oh-') && visible" :is="componentType" :context="context" @command="onCommand" />
<div v-else-if="componentType && componentType === 'Label' && visible" :class="config.class" :style="config.style">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* Add any new widget to this file - the name of the export should be "OhSomething" */

export { default as OhCard } from './oh-card.vue'
export { default as OhEquipmentCard } from './oh-equipment-card.vue'
export { default as OhLabelCard } from './oh-label-card.vue'
export { default as OhToggleCard } from './oh-toggle-card.vue'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<template>
<f7-card :no-border="config.noBorder" :no-shadow="config.noShadow" :outline="config.outline" :style="config.style" :class="config.class">
<slot name="header">
<f7-card-header v-if="config.title" :style="config.headerStyle" :class="config.headerClass">
<div>{{ config.title }}</div>
</f7-card-header>
</slot>
<slot name="content-root">
<f7-card-content @click.native="config.action ? performAction : ''" :style="{ ...contentStyle, ...config.contentStyle}" :class="[ ...(Array.isArray(contentClass) ? contentClass : ['padding']), ...(Array.isArray(config.contentClass) ? config.contentClass : []) ]">
<slot name="content" />
</f7-card-content>
</slot>
<slot name="footer">
<f7-card-footer v-if="config.footer && !Array.isArray(config.footer)">
{{ config.footer }}
</f7-card-footer>
<f7-card-footer v-else-if="config.footer && Array.isArray(config.footer)">
<span v-for="text in config.footer" :key="text">
{{ text }}
</span>
</f7-card-footer>
</slot>
</f7-card>
</template>

<script>
import mixin from '../widget-mixin'
import { actionsMixin } from '@/components/widgets/widget-actions'
import { OhCardDefinition } from '@/assets/definitions/widgets/standard/cards'
export default {
mixins: [mixin, actionsMixin],
widget: OhCardDefinition,
props: ['context', 'contentStyle', 'contentClass'],
slotProps: ['header', 'content', 'content-root', 'footer']
}
</script>
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
<template>
<f7-card :no-border="config.noBorder" :no-shadow="config.noShadow" :outline="config.outline" :style="{ background: config.background }">
<f7-card-header v-if="config.title">
<div>{{ config.title }}</div>
</f7-card-header>
<f7-card-content @click.native="performAction" class="clock-card-content text-align-center">
<oh-card :context="context" :content-class="['clock-card-content', 'text-align-center']">
<template #content>
<f7-row v-if="config.showDate && config.datePos !== 'below'">
<f7-col>
<oh-clock :context="{ component: { component: 'oh-clock', config: {} }}" :style="{ 'font-size': config.dateFontSize || '1vw', 'font-weight': config.dateFontWeight || 'normal' }" :format="config.dateFormat" />
Expand All @@ -19,23 +16,22 @@
<oh-clock :context="{ component: { component: 'oh-clock', config: {} }}" :style="{ 'font-size': config.dateFontSize || '1vw', 'font-weight': config.dateFontWeight || 'normal' }" :format="config.dateFormat" />
</f7-col>
</f7-row>
</f7-card-content>
<oh-card-footer v-if="config.footer" :texts="config.footer" />
</f7-card>
</template>
</oh-card>
</template>

<script>
import mixin from '../widget-mixin'
import { actionsMixin } from '../widget-actions'
import OhCard from '@/components/widgets/standard/oh-card.vue'
import OhClock from '../system/oh-clock.vue'
import OhCardFooter from '../system/oh-card-footer.vue'
import { OhClockCardDefinition } from '@/assets/definitions/widgets/standard/cards'
export default {
mixins: [mixin, actionsMixin],
components: {
OhClock,
OhCardFooter
OhCard,
OhClock
},
widget: OhClockCardDefinition
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,22 @@
<template>
<f7-card :no-border="config.noBorder" :no-shadow="config.noShadow" :outline="config.outline">
<f7-card-header v-if="config.title">
<div>{{ config.title }}</div>
</f7-card-header>
<f7-card-content class="display-flex justify-content-center">
<oh-card :context="context" :content-class="['display-flex', 'justify-content-center']">
<template #content>
<oh-colorpicker :context="context" @command="onCommand" />
</f7-card-content>
<oh-card-footer v-if="config.footer" :texts="config.footer" />
</f7-card>
</template>
</oh-card>
</template>

<style lang="stylus">
</style>

<script>
import mixin from '../widget-mixin'
import OhCard from '@/components/widgets/standard/oh-card.vue'
import OhColorpicker from '../system/oh-colorpicker.vue'
import OhCardFooter from '../system/oh-card-footer.vue'
import { OhColorpickerCardDefinition } from '@/assets/definitions/widgets/standard/cards'
export default {
mixins: [mixin],
components: {
OhColorpicker,
OhCardFooter
OhCard,
OhColorpicker
},
widget: OhColorpickerCardDefinition,
data () {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,22 @@
<template>
<f7-card :no-border="config.noBorder" :no-shadow="config.noShadow" :outline="config.outline">
<f7-card-header v-if="config.title">
<div>{{ config.title }}</div>
</f7-card-header>
<f7-card-content class="oh-gauge-card display-flex justify-content-center">
<f7-link v-if="config.action" class="oh-gauge-link" @click="performAction">
<oh-gauge :context="childContext(context.component)" />
</f7-link>
<oh-gauge v-else :context="childContext(context.component)" />
</f7-card-content>
<oh-card-footer v-if="config.footer" :texts="config.footer" />
</f7-card>
<oh-card :context="context" :content-class="['oh-gauge-card', 'display-flex', 'justify-content-center']">
<template #content>
<oh-gauge :context="childContext(context.component)" />
</template>
</oh-card>
</template>

<style lang="stylus">
.oh-gauge-link
position absolute
top 0
left 0
width 100%
height 100%
</style>

<script>
import mixin from '../widget-mixin'
import OhCard from '@/components/widgets/standard/oh-card.vue'
import OhGauge from '../system/oh-gauge.vue'
import OhCardFooter from '../system/oh-card-footer.vue'
import { actionsMixin } from '../widget-actions'
import { OhGaugeCardDefinition } from '@/assets/definitions/widgets/standard/cards'
export default {
mixins: [mixin, actionsMixin],
mixins: [mixin],
components: {
OhGauge,
OhCardFooter
OhCard,
OhGauge
},
widget: OhGaugeCardDefinition
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,48 +1,34 @@
<template>
<f7-card :no-border="config.noBorder" :no-shadow="config.noShadow" :outline="config.outline">
<f7-card-header v-if="config.title">
<div>{{ config.title }}</div>
</f7-card-header>
<f7-card-content :padding="false" class="oh-image-card">
<f7-list v-if="config.action" class="image-link">
<f7-list-item class="oh-image-clickable" link="#" no-chevron @click="performAction">
<oh-image slot="content-start" :context="childContext(context.component)" />
</f7-list-item>
</f7-list>
<oh-image v-else :context="childContext(context.component)" />
</f7-card-content>
<oh-card-footer v-if="config.footer" :texts="config.footer" />
</f7-card>
<oh-card :context="context" :content-class="['oh-image-card', 'no-padding']">
<template #content>
<oh-image class="oh-image" :context="childContext(context.component)" />
</template>
</oh-card>
</template>

<style lang="stylus">
.oh-image-clickable
.oh-image-card-clickable
--f7-list-item-padding-horizontal: 0px
.oh-image-card
.oh-image
margin-top 5px
margin-left 5px
margin-right 5px
width calc(100% - 10px)
.image-link
.item-inner
display none
.oh-image
margin-bottom 5px
</style>

<script>
import mixin from '../widget-mixin'
import OhCard from '@/components/widgets/standard/oh-card.vue'
import { actionsMixin } from '../widget-actions'
import OhImage from '../system/oh-image.vue'
import OhCardFooter from '../system/oh-card-footer.vue'
import { OhImageCardDefinition } from '@/assets/definitions/widgets/standard/cards'
export default {
mixins: [mixin, actionsMixin],
components: {
OhImage,
OhCardFooter
OhCard,
OhImage
},
widget: OhImageCardDefinition
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
<template>
<f7-card :no-border="config.noBorder" :no-shadow="config.noShadow" :outline="config.outline">
<f7-card-header v-if="config.title">
<div>{{ config.title }}</div>
</f7-card-header>
<f7-card-content class="padding">
<oh-card :context="context">
<template #content>
<oh-input class="input-card-content" :context="childContext(context.component)" @command="onCommand" />
</f7-card-content>
<oh-card-footer v-if="config.footer" :texts="config.footer" />
</f7-card>
</template>
</oh-card>
</template>

<style lang="stylus">
.input-card-content
width calc(100% - 2*var(--f7-card-content-padding)) !important
.input-field
Expand All @@ -20,15 +15,15 @@

<script>
import mixin from '../widget-mixin'
import OhInput from '../system/oh-input.vue'
import OhCardFooter from '../system/oh-card-footer.vue'
import OhCard from '@/components/widgets/standard/oh-card.vue'
import { OhInput } from '@/components/widgets/system'
import { OhInputCardDefinition } from '@/assets/definitions/widgets/standard/cards'
export default {
mixins: [mixin],
components: {
OhInput,
OhCardFooter
OhCard,
OhInput
},
widget: OhInputCardDefinition
}
Expand Down
Loading

0 comments on commit dcbc549

Please sign in to comment.