forked from platypush/platypush
Added entities panel
This commit is contained in:
parent
8ec9c8f203
commit
58861afb1c
10 changed files with 621 additions and 4 deletions
|
@ -6,7 +6,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="plugins">
|
<ul class="plugins">
|
||||||
<li v-for="name in Object.keys(panels).sort()" :key="name" class="entry" :class="{selected: name === selectedPanel}"
|
<li v-for="name in panelNames" :key="name" class="entry" :class="{selected: name === selectedPanel}"
|
||||||
:title="name" @click="onItemClick(name)">
|
:title="name" @click="onItemClick(name)">
|
||||||
<a :href="`/#${name}`">
|
<a :href="`/#${name}`">
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
<img :src="icons[name].imgUrl" v-else-if="icons[name]?.imgUrl" alt="name"/>
|
<img :src="icons[name].imgUrl" v-else-if="icons[name]?.imgUrl" alt="name"/>
|
||||||
<i class="fas fa-puzzle-piece" v-else />
|
<i class="fas fa-puzzle-piece" v-else />
|
||||||
</span>
|
</span>
|
||||||
<span class="name" v-if="!collapsed" v-text="name" />
|
<span class="name" v-if="!collapsed" v-text="name == 'entities' ? 'Home' : name" />
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -66,6 +66,16 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
panelNames() {
|
||||||
|
let panelNames = Object.keys(this.panels)
|
||||||
|
const homeIdx = panelNames.indexOf('entities')
|
||||||
|
if (homeIdx >= 0)
|
||||||
|
return ['entities'].concat((panelNames.slice(0, homeIdx).concat(panelNames.slice(homeIdx+1))).sort())
|
||||||
|
return panelNames.sort()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onItemClick(name) {
|
onItemClick(name) {
|
||||||
this.$emit('select', name)
|
this.$emit('select', name)
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<div class="row item entity">
|
||||||
|
<Loading v-if="loading" />
|
||||||
|
<Icon v-bind="value.meta?.icon || {}" />
|
||||||
|
<div class="component-container">
|
||||||
|
<component :is="component" :value="value" @input="$emit('input', $event)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
import Utils from "@/Utils"
|
||||||
|
import Loading from "@/components/Loading"
|
||||||
|
import Icon from "@/components/elements/Icon";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Entity",
|
||||||
|
components: {Loading, Icon},
|
||||||
|
mixins: [Utils],
|
||||||
|
emits: ['input'],
|
||||||
|
props: {
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
component: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
type() {
|
||||||
|
let entityType = (this.value.type || '')
|
||||||
|
return entityType.charAt(0).toUpperCase() + entityType.slice(1)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
if (this.type !== 'Entity')
|
||||||
|
this.component = defineAsyncComponent(
|
||||||
|
() => import(`@/components/panels/Entities/${this.type}`)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "vars";
|
||||||
|
|
||||||
|
.entity {
|
||||||
|
width: 100%;
|
||||||
|
display: table;
|
||||||
|
|
||||||
|
.icon-container,
|
||||||
|
.component-container {
|
||||||
|
height: 100%;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.component-container {
|
||||||
|
width: calc(100% - #{$icon-container-size});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,242 @@
|
||||||
|
<template>
|
||||||
|
<div class="row plugin entities-container">
|
||||||
|
<Loading v-if="loading" />
|
||||||
|
|
||||||
|
<div class="entity-selector-container">
|
||||||
|
<Selector :entity-groups="entityGroups" :value="selector" @input="selector = $event" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="groups-canvas">
|
||||||
|
<div class="groups-container">
|
||||||
|
<div class="group fade-in" v-for="group in displayGroups" :key="group.name">
|
||||||
|
<div class="frame">
|
||||||
|
<div class="header">
|
||||||
|
<span class="section left">
|
||||||
|
<Icon v-bind="entitiesMeta[group.name].icon || {}"
|
||||||
|
v-if="selector.grouping === 'type' && entitiesMeta[group.name]" />
|
||||||
|
<Icon :class="pluginIcons[group.name]?.class" :url="pluginIcons[group.name]?.imgUrl"
|
||||||
|
v-else-if="selector.grouping === 'plugin' && pluginIcons[group.name]" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="section center">
|
||||||
|
<div class="title" v-text="entitiesMeta[group.name].name_plural"
|
||||||
|
v-if="selector.grouping === 'type' && entitiesMeta[group.name]"/>
|
||||||
|
<div class="title" v-text="group.name" v-else-if="selector.grouping === 'plugin'"/>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="section right" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="body">
|
||||||
|
<div class="entity-frame" v-for="entity in group.entities" :key="entity.id">
|
||||||
|
<Entity :value="entity" @input="entities[entity.id] = $event" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Utils from "@/Utils"
|
||||||
|
import Loading from "@/components/Loading";
|
||||||
|
import Icon from "@/components/elements/Icon";
|
||||||
|
import Entity from "./Entity.vue";
|
||||||
|
import Selector from "./Selector.vue";
|
||||||
|
import icons from '@/assets/icons.json'
|
||||||
|
import meta from './meta.json'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Entities",
|
||||||
|
components: {Loading, Icon, Entity, Selector},
|
||||||
|
mixins: [Utils],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
entities: {},
|
||||||
|
selector: {
|
||||||
|
grouping: 'type',
|
||||||
|
selectedEntities: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
entitiesMeta() {
|
||||||
|
return meta
|
||||||
|
},
|
||||||
|
|
||||||
|
pluginIcons() {
|
||||||
|
return icons
|
||||||
|
},
|
||||||
|
|
||||||
|
entityGroups() {
|
||||||
|
return {
|
||||||
|
'id': Object.entries(this.groupEntities('id')).reduce((obj, [id, entities]) => {
|
||||||
|
obj[id] = entities[0]
|
||||||
|
return obj
|
||||||
|
}, {}),
|
||||||
|
'type': this.groupEntities('type'),
|
||||||
|
'plugin': this.groupEntities('plugin'),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
displayGroups() {
|
||||||
|
return Object.entries(this.entityGroups[this.selector.grouping]).filter(
|
||||||
|
(entry) => entry[1].filter(
|
||||||
|
(e) => !!this.selector.selectedEntities[e.id]
|
||||||
|
).length > 0
|
||||||
|
).sort((a, b) => a[0].localeCompare(b[0])).map(
|
||||||
|
([grouping, entities]) => {
|
||||||
|
return {
|
||||||
|
name: grouping,
|
||||||
|
entities: entities,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
groupEntities(attr) {
|
||||||
|
return Object.values(this.entities).reduce((obj, entity) => {
|
||||||
|
const entities = obj[entity[attr]] || {}
|
||||||
|
entities[entity.id] = entity
|
||||||
|
obj[entity[attr]] = Object.values(entities).sort((a, b) => {
|
||||||
|
return a.name.localeCompare(b.name)
|
||||||
|
})
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}, {})
|
||||||
|
},
|
||||||
|
|
||||||
|
async refresh() {
|
||||||
|
this.loading = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.entities = (await this.request('entities.get')).reduce((obj, entity) => {
|
||||||
|
entity.meta = {
|
||||||
|
...(meta[entity.type] || {}),
|
||||||
|
...(entity.meta || {}),
|
||||||
|
}
|
||||||
|
|
||||||
|
obj[entity.id] = entity
|
||||||
|
return obj
|
||||||
|
}, {})
|
||||||
|
|
||||||
|
this.selector.selectedEntities = this.entityGroups.id
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.refresh()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "vars";
|
||||||
|
@import "~@/style/items";
|
||||||
|
|
||||||
|
.entities-container {
|
||||||
|
--groups-per-row: 1;
|
||||||
|
|
||||||
|
@include from($desktop) {
|
||||||
|
--groups-per-row: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include from($fullhd) {
|
||||||
|
--groups-per-row: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: auto;
|
||||||
|
color: $default-fg-2;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
.entity-selector-container {
|
||||||
|
height: $selector-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.groups-canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - #{$selector-height});
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.groups-container {
|
||||||
|
overflow: auto;
|
||||||
|
@include from($desktop) {
|
||||||
|
column-count: var(--groups-per-row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.group {
|
||||||
|
width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
position: relative;
|
||||||
|
padding: $main-margin 0;
|
||||||
|
display: flex;
|
||||||
|
break-inside: avoid;
|
||||||
|
|
||||||
|
@include from($tablet) {
|
||||||
|
padding: $main-margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame {
|
||||||
|
max-height: calc(100% - #{2 * $main-margin});
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: $group-shadow;
|
||||||
|
border-radius: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
width: 100%;
|
||||||
|
height: $header-height;
|
||||||
|
display: table;
|
||||||
|
background: $header-bg;
|
||||||
|
box-shadow: $header-shadow;
|
||||||
|
border-radius: 1em 1em 0 0;
|
||||||
|
|
||||||
|
.section {
|
||||||
|
height: 100%;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
&.left, &.right {
|
||||||
|
width: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.center {
|
||||||
|
width: 80%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
background: $default-bg-2;
|
||||||
|
max-height: calc(100% - #{$header-height});
|
||||||
|
overflow: auto;
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
.entity-frame:last-child {
|
||||||
|
border-radius: 0 0 1em 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,198 @@
|
||||||
|
<template>
|
||||||
|
<div class="entities-selectors-container">
|
||||||
|
<div class="selector">
|
||||||
|
<Dropdown title="Group by" icon-class="fas fa-layer-group"
|
||||||
|
:text="prettifyGroupingName(value.grouping)" ref="groupingSelector">
|
||||||
|
<DropdownItem v-for="g in visibleGroupings" :key="g" :text="prettifyGroupingName(g)"
|
||||||
|
:item-class="{selected: value?.grouping === g}"
|
||||||
|
@click="onGroupingChanged(g)" />
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="selector" :class="{active: isGroupFilterActive}" v-if="value?.grouping">
|
||||||
|
<Dropdown title="Filter by" icon-class="fas fa-filter" ref="groupSelector"
|
||||||
|
keep-open-on-item-click>
|
||||||
|
<DropdownItem v-for="g in sortedGroups" :key="g" :text="g"
|
||||||
|
v-bind="iconForGroup(g)" :item-class="{selected: !!selectedGroups[g]}"
|
||||||
|
@click.stop="toggleGroup(g)" />
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Utils from '@/Utils'
|
||||||
|
import Dropdown from "@/components/elements/Dropdown";
|
||||||
|
import DropdownItem from "@/components/elements/DropdownItem";
|
||||||
|
import meta from './meta.json'
|
||||||
|
import pluginIcons from '@/assets/icons.json'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Selector",
|
||||||
|
emits: ['input'],
|
||||||
|
mixins: [Utils],
|
||||||
|
components: {Dropdown, DropdownItem},
|
||||||
|
props: {
|
||||||
|
entityGroups: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedGroups: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
visibleGroupings() {
|
||||||
|
return Object.keys(this.entityGroups).filter(
|
||||||
|
(grouping) => grouping !== 'id'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
sortedGroups() {
|
||||||
|
return Object.keys(this.entityGroups[this.value?.grouping] || {}).sort()
|
||||||
|
},
|
||||||
|
|
||||||
|
typesMeta() {
|
||||||
|
return meta
|
||||||
|
},
|
||||||
|
|
||||||
|
isGroupFilterActive() {
|
||||||
|
return Object.keys(this.selectedGroups).length !== this.sortedGroups.length
|
||||||
|
},
|
||||||
|
|
||||||
|
selectedEntities() {
|
||||||
|
return Object.values(this.entityGroups.id).filter((entity) =>
|
||||||
|
!!this.selectedGroups[entity[this.value?.grouping]]
|
||||||
|
).reduce((obj, entity) => {
|
||||||
|
obj[entity.id] = entity
|
||||||
|
return obj
|
||||||
|
}, {})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
prettifyGroupingName(name) {
|
||||||
|
return name ? this.prettify(name) + 's' : ''
|
||||||
|
},
|
||||||
|
|
||||||
|
iconForGroup(group) {
|
||||||
|
if (this.value.grouping === 'plugin' && pluginIcons[group]) {
|
||||||
|
const icon = pluginIcons[group]
|
||||||
|
return {
|
||||||
|
'icon-class': icon['class']?.length || !icon.imgUrl?.length ?
|
||||||
|
icon['class'] : 'fas fa-gears',
|
||||||
|
'icon-url': icon.imgUrl,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
|
||||||
|
synchronizeSelectedEntities() {
|
||||||
|
const value = {...this.value}
|
||||||
|
value.selectedEntities = this.selectedEntities
|
||||||
|
this.$emit('input', value)
|
||||||
|
},
|
||||||
|
|
||||||
|
resetGroupFilter() {
|
||||||
|
this.selectedGroups = Object.keys(
|
||||||
|
this.entityGroups[this.value?.grouping] || {}
|
||||||
|
).reduce(
|
||||||
|
(obj, group) => {
|
||||||
|
obj[group] = true
|
||||||
|
return obj
|
||||||
|
}, {}
|
||||||
|
)
|
||||||
|
|
||||||
|
this.synchronizeSelectedEntities()
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleGroup(group) {
|
||||||
|
if (this.selectedGroups[group])
|
||||||
|
delete this.selectedGroups[group]
|
||||||
|
else
|
||||||
|
this.selectedGroups[group] = true
|
||||||
|
|
||||||
|
this.synchronizeSelectedEntities()
|
||||||
|
},
|
||||||
|
|
||||||
|
onGroupingChanged(grouping) {
|
||||||
|
if (!this.entityGroups[grouping] || grouping === this.value?.grouping)
|
||||||
|
return false
|
||||||
|
|
||||||
|
const value = {...this.value}
|
||||||
|
value.grouping = grouping
|
||||||
|
this.$emit('input', value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.resetGroupFilter()
|
||||||
|
this.$watch(() => this.value?.grouping, this.resetGroupFilter)
|
||||||
|
this.$watch(() => this.entityGroups, this.resetGroupFilter)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.entities-selectors-container {
|
||||||
|
width: 100%;
|
||||||
|
background: $default-bg-2;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
box-shadow: $border-shadow-bottom;
|
||||||
|
|
||||||
|
.selector {
|
||||||
|
height: 100%;
|
||||||
|
display: inline-flex;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
::v-deep(.dropdown-container) {
|
||||||
|
button {
|
||||||
|
color: $default-hover-fg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep(.dropdown-container) {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 100%;
|
||||||
|
background: $default-bg-2;
|
||||||
|
border: 0;
|
||||||
|
padding: 0.5em;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $default-hover-fg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
padding: 0.5em 4em 0.5em 0.5em;
|
||||||
|
border: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
font-weight: bold;
|
||||||
|
background: #ffffff00;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $hover-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,53 @@
|
||||||
|
<template>
|
||||||
|
<div class="switch">
|
||||||
|
<div class="col-10 label">
|
||||||
|
<div class="name" v-text="value.name" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-2 switch pull-right">
|
||||||
|
<ToggleSwitch :value="value.state" @input="toggle" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ToggleSwitch from "@/components/elements/ToggleSwitch"
|
||||||
|
import Utils from "@/Utils"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Switch',
|
||||||
|
components: {ToggleSwitch},
|
||||||
|
emits: ['input'],
|
||||||
|
mixins: [Utils],
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
component: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async toggle() {
|
||||||
|
const response = await this.request('entities.execute', {
|
||||||
|
id: this.value.id,
|
||||||
|
action: 'toggle',
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$emit('input', {
|
||||||
|
...this.value,
|
||||||
|
state: response.on,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "vars";
|
||||||
|
</style>
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"entity": {
|
||||||
|
"name": "Entity",
|
||||||
|
"name_plural": "Entities",
|
||||||
|
"icon": {
|
||||||
|
"class": "fas fa-circle-question"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"device": {
|
||||||
|
"name": "Device",
|
||||||
|
"name_plural": "Devices",
|
||||||
|
"icon": {
|
||||||
|
"class": "fas fa-gear"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"switch": {
|
||||||
|
"name": "Switch",
|
||||||
|
"name_plural": "Switches",
|
||||||
|
"icon": {
|
||||||
|
"class": "fas fa-toggle-on"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"light": {
|
||||||
|
"name": "Light",
|
||||||
|
"name_plural": "Lights",
|
||||||
|
"icon": {
|
||||||
|
"class": "fas fa-lightbulb"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
$main-margin: 1em;
|
||||||
|
$selector-height: 2.5em;
|
|
@ -1,3 +1,5 @@
|
||||||
|
$header-height: 3.5em;
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -10,6 +10,7 @@ $default-bg-7: #e4e4e4 !default;
|
||||||
$default-fg: black !default;
|
$default-fg: black !default;
|
||||||
$default-fg-2: #23513a !default;
|
$default-fg-2: #23513a !default;
|
||||||
$default-fg-3: #195331b3 !default;
|
$default-fg-3: #195331b3 !default;
|
||||||
|
$header-bg: linear-gradient(0deg, #c0e8e4, #e4f8f4) !default;
|
||||||
|
|
||||||
//// Notifications
|
//// Notifications
|
||||||
$notification-bg: rgba(185, 255, 193, 0.9) !default;
|
$notification-bg: rgba(185, 255, 193, 0.9) !default;
|
||||||
|
@ -51,6 +52,8 @@ $border-shadow-bottom: 0 3px 2px -1px $default-shadow-color;
|
||||||
$border-shadow-left: -2.5px 0 4px 0 $default-shadow-color;
|
$border-shadow-left: -2.5px 0 4px 0 $default-shadow-color;
|
||||||
$border-shadow-right: 2.5px 0 4px 0 $default-shadow-color;
|
$border-shadow-right: 2.5px 0 4px 0 $default-shadow-color;
|
||||||
$border-shadow-bottom-right: 2.5px 2.5px 3px 0 $default-shadow-color;
|
$border-shadow-bottom-right: 2.5px 2.5px 3px 0 $default-shadow-color;
|
||||||
|
$header-shadow: 0px 1px 3px 1px #bbb !default;
|
||||||
|
$group-shadow: 3px -2px 6px 1px #98b0a0;
|
||||||
|
|
||||||
//// Modals
|
//// Modals
|
||||||
$modal-header-bg: #e0e0e0 !default;
|
$modal-header-bg: #e0e0e0 !default;
|
||||||
|
@ -141,5 +144,5 @@ $dropdown-shadow: 1px 1px 1px #bbb !default;
|
||||||
//// Scrollbars
|
//// Scrollbars
|
||||||
$scrollbar-track-bg: $slider-bg !default;
|
$scrollbar-track-bg: $slider-bg !default;
|
||||||
$scrollbar-track-shadow: inset 1px 0px 3px 0 $slider-track-shadow !default;
|
$scrollbar-track-shadow: inset 1px 0px 3px 0 $slider-track-shadow !default;
|
||||||
$scrollbar-thumb-bg: #50ca80 !default;
|
$scrollbar-thumb-bg: #a5a2a2 !default;
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ export default {
|
||||||
|
|
||||||
initializeDefaultViews() {
|
initializeDefaultViews() {
|
||||||
this.plugins.execute = {}
|
this.plugins.execute = {}
|
||||||
this.plugins.switches = {}
|
this.plugins.entities = {}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue