adds placeholders to the empty dashboard fields, that can be used to add new widgets to the dashboard

This commit is contained in:
SimonGschnell
2024-10-18 11:18:36 +02:00
parent e475fe568e
commit 236c4bbdfc
4 changed files with 116 additions and 26 deletions
+12 -1
View File
@@ -4,13 +4,24 @@
.empty-tile-hover {
height: 100%;
width: 100%;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-500 -500 1448 1512"><path fill="lightgray" d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zM200 344V280H136c-13.3 0-24-10.7-24-24s10.7-24 24-24h64V168c0-13.3 10.7-24 24-24s24 10.7 24 24v64h64c13.3 0 24 10.7 24 24s-10.7 24-24 24H248v64c0 13.3-10.7 24-24 24s-24-10.7-24-24z"/></svg>');
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-500 -500 1448 1512"><path fill="rgb(211, 211, 211,0.35)" d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zM200 344V280H136c-13.3 0-24-10.7-24-24s10.7-24 24-24h64V168c0-13.3 10.7-24 24-24s24 10.7 24 24v64h64c13.3 0 24 10.7 24 24s-10.7 24-24 24H248v64c0 13.3-10.7 24-24 24s-24-10.7-24-24z"/></svg>');
background-repeat: no-repeat;
background-position: center;
background-size: cover;
cursor:pointer;
}
.empty-tile-hover:hover {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-500 -500 1448 1512"><path fill="rgb(211, 211, 211)" d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zM200 344V280H136c-13.3 0-24-10.7-24-24s10.7-24 24-24h64V168c0-13.3 10.7-24 24-24s24 10.7 24 24v64h64c13.3 0 24 10.7 24 24s-10.7 24-24 24H248v64c0 13.3-10.7 24-24 24s-24-10.7-24-24z"/></svg>');
}
/*.empty-tile-background {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-500 -500 1448 1512"><path fill="rgb(211, 211, 211, 0.35)" d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zM200 344V280H136c-13.3 0-24-10.7-24-24s10.7-24 24-24h64V168c0-13.3 10.7-24 24-24s24 10.7 24 24v64h64c13.3 0 24 10.7 24 24s-10.7 24-24 24H248v64c0 13.3-10.7 24-24 24s-24-10.7-24-24z"/></svg>');
background-repeat: repeat;
background-size: var(--fhc-dg-col-width);
cursor: pointer;
}*/
.alert-danger .form-check-input:checked {
border-color: #842029;
background-color: #842029;
+1 -1
View File
@@ -86,7 +86,7 @@ export default {
config() {
this.arguments = { ...this.widget.arguments, ...this.config };
this.tmpConfig = { ...this.arguments };
this.$refs.config.hide();
this.$refs.config && this.$refs.config.hide();
this.isLoading = false;
},
},
+70 -8
View File
@@ -26,15 +26,65 @@ export default {
data() {
return {
gridWidth: 1,
gridHeight: null,
editMode: this.adminMode
}
},
computed: {
items() {
return this.widgets.map(item => {
return {...item, ...(item.place[this.gridWidth] || {h: 1, w:1, x:0, y:0})};
return { ...item, ...(item.place[this.gridWidth] || {h: 1, w:1, x:0, y:0})};
});
}
},
items_hashmap() {
let items = {};
this.items.forEach(item => {
items[`x${item.x}y${item.y}`] = item;
});
return items
},
items_placeholders(){
let placeholders = [];
let col_max = this.gridWidth;
// OLD way of calculating the max rows
//let max_row = Math.max(...this.items.map(item => item.y)) + 1;
//let max_row_max_height = Math.max(...this.items.filter(item => item.y == (max_row - 1)).map(item => item.h));
//max_row + max_row_max_height - 1;
let rows_max = this.gridHeight;
// occupied hashmap to keep track of the occupied cells
let occupied = {};
for (let y = 0; y < rows_max; y++) {
for (let x = 0; x < col_max; x++) {
// skip current position if it was registered as occupied
if (Object.keys(occupied).length && occupied[`x${x}y${y}`]) {
continue;
}
let current_item = this.items_hashmap[`x${x}y${y}`];
if (current_item) {
//calculate the occupied cells from the width and the height from the items
let width = current_item.w;
let height = current_item.h;
let max_x = x + width - 1;
let max_y = y + height - 1;
if(x != max_x || y != max_y){
for (let occupied_y = y; occupied_y <= max_y; occupied_y++) {
for (let occupied_x = x; occupied_x <= max_x; occupied_x++) {
if (occupied_x != x || occupied_y != y) {
occupied[`x${occupied_x}y${occupied_y}`]=true;
}
}
}
}
}
else {
placeholders.push({ x: x, y: y, w: 1, h: 1, placeholder: true });
}
}
}
return placeholders;
},
},
methods: {
checkResizeLimit(item, w, h) {
@@ -80,7 +130,9 @@ export default {
updatePositions(updated) {
let result = {};
updated.forEach(update => {
let item = {...update.item};
if (!item.placeholder) {
if (!item.place[this.gridWidth])
item.place[this.gridWidth] = {x: 0, y: 0, w: 1, h: 1};
delete item.x;
@@ -97,7 +149,9 @@ export default {
item.place[this.gridWidth].h = update.h;
result[item.id] = item;
}
});
this.updatePreset(result);
},
updatePreset(update) {
@@ -121,9 +175,10 @@ export default {
<span class="col">{{name}}</span>
<button class="col-auto btn" @click.prevent="editMode = !editMode"><i class="fa-solid fa-gear"></i></button>
</h3>
<drop-grid v-model:cols="gridWidth" :items="items" :active="editMode" :resize-limit="checkResizeLimit" :margin-for-extra-row=".01" @rearrange-items="updatePositions">
<template v-slot="item">
<dashboard-item
<drop-grid v-model:cols="gridWidth" :items="items" :placeholders="items_placeholders" :active="editMode" :resize-limit="checkResizeLimit" :margin-for-extra-row=".01" @rearrange-items="updatePositions" @gridHeight="gridHeight=$event" >
<template #default="item" #default>
<dashboard-item v-if="!item.placeholder"
:id="item.widget"
:width="item.w"
:height="item.h"
@@ -135,10 +190,17 @@ export default {
@change="saveConfig($event, item)"
@remove="removeWidget(item, $event)">
</dashboard-item>
<div v-else class="empty-tile-hover" @click="$emit('widgetAdd', name, { widget: 1, config: {}, place: {[gridWidth]: {x:item.x,y:item.y,w:1,h:1}}, custom: 1 })"></div>
</template>
<template #empty-tile-hover="{x,y}">
<div class="empty-tile-hover" @click="$emit('widgetAdd', name, { widget: 1, config: {}, place: {[gridWidth]: {x,y,w:1,h:1}}, custom: 1 })"></div>
</template>
</drop-grid>
</div>`
}
/*
OLD VERSION - ON HOVER
<template #empty-tile-hover="{x,y}">
<div class="empty-tile-hover" @click="$emit('widgetAdd', name, { widget: 1, config: {}, place: {[gridWidth]: {x,y,w:1,h:1}}, custom: 1 })"></div>
</template>
*/
+33 -16
View File
@@ -24,11 +24,16 @@ export default {
marginForExtraRow: {
type: Number,
default: 0
},
placeholders: {
type: Array,
default: () => []
}
},
emits: [
"rearrangeItems",
"newItem"
"newItem",
"gridHeight"
],
data() {
return {
@@ -108,6 +113,9 @@ export default {
};
});
},
placedItems_withPlaceholders(){
return [...this.placedItems,...this.placeholders];
},
showEmptyTileHover() {
if (!this.active || !this.grid || this.mode != MODE_IDLE || this.x < 0 || this.y < 0 || this.x >= this.cols || this.y >= this.rows)
return false;
@@ -122,6 +130,9 @@ export default {
cols() {
this.dragCancel();
},
rows(value){
this.$emit('gridHeight',value);
},
indexedItems: {
handler(value) {
this.dragCancel();
@@ -333,6 +344,7 @@ export default {
<div
ref="container"
class="drop-grid position-relative h-0"
:class="{'empty-tile-background':active}"
:style="gridStyle"
@touchmove="dragOver"
@touchend="dragCancel"
@@ -341,7 +353,7 @@ export default {
@mousemove="updateCursor"
@mouseleave="mouseLeave">
<grid-item
v-for="item in placedItems"
v-for="item in (mode == 0 && active? placedItems_withPlaceholders : placedItems)"
:key="item.id"
:item="item"
@start-move="startMove"
@@ -357,21 +369,26 @@ export default {
height: 'calc(' + item.h + ' * var(--fhc-dg-row-height))'
}">
<template v-slot="item">
<slot v-bind="item.data"></slot>
<slot v-bind="item.data" v-bind="item" :x="item.x" :y="item.y" ></slot>
</template>
</grid-item>
<div
v-if="showEmptyTileHover"
class="position-absolute d-flex justify-content-center align-items-center"
:style="{
cursor: 'pointer',
top: 'calc(' + y + ' * var(--fhc-dg-row-height))',
left: 'calc(' + x + ' * var(--fhc-dg-col-width))',
width: 'var(--fhc-dg-col-width)',
height: 'var(--fhc-dg-row-height)'
}"
@click="emptyTileClicked">
<slot v-bind="{x,y}" name="empty-tile-hover"></slot>
</div>
</div>`
}
/*
OLD VERSION - ON HOVER
<div
v-if="showEmptyTileHover"
class="position-absolute d-flex justify-content-center align-items-center"
:style="{
cursor: 'pointer',
top: 'calc(' + y + ' * var(--fhc-dg-row-height))',
left: 'calc(' + x + ' * var(--fhc-dg-col-width))',
width: 'var(--fhc-dg-col-width)',
height: 'var(--fhc-dg-row-height)'
}"
@click="emptyTileClicked">
<slot :x="x" :y="y" name="empty-tile-hover"></slot>
</div>
*/