Enhance drag-and-drop functionality in Dashboard: Update styles for dragging state in DashboardWidget, including opacity and box-shadow adjustments. Improve LoggedInView by adding drop indicators for better user experience during widget rearrangement. Refactor drag-and-drop logic to maintain visual cues and ensure smoother interactions.
This commit is contained in:
@@ -264,10 +264,13 @@ export default {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 1px 3px rgba(0,0,0,0.06);
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
transition: opacity 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
}
|
}
|
||||||
.dashboard-widget.is-dragging {
|
.dashboard-widget.is-dragging {
|
||||||
opacity: 0.7;
|
opacity: 0.5;
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
box-shadow: 0 8px 24px rgba(0,0,0,0.25);
|
||||||
|
transform: rotate(2deg);
|
||||||
|
cursor: grabbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-widget__titlebar {
|
.dashboard-widget__titlebar {
|
||||||
|
|||||||
@@ -63,9 +63,19 @@
|
|||||||
@drop="onGridDrop"
|
@drop="onGridDrop"
|
||||||
>
|
>
|
||||||
<template v-for="(w, index) in widgets" :key="w.id">
|
<template v-for="(w, index) in widgets" :key="w.id">
|
||||||
|
<!-- Platzhalter vor dem Widget, wenn hier eingefügt werden soll -->
|
||||||
|
<div
|
||||||
|
v-if="dragOverIndex === index && draggedIndex !== null && draggedIndex !== index"
|
||||||
|
class="dashboard-grid-cell dashboard-drop-indicator"
|
||||||
|
>
|
||||||
|
<div class="drop-indicator-line"></div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="dashboard-grid-cell"
|
class="dashboard-grid-cell"
|
||||||
:class="{ 'drop-target': dragOverIndex === index && draggedIndex !== index }"
|
:class="{
|
||||||
|
'drop-target': dragOverIndex === index && draggedIndex !== index,
|
||||||
|
'drag-source': draggedIndex === index
|
||||||
|
}"
|
||||||
@dragover.prevent="() => setDropTarget(index)"
|
@dragover.prevent="() => setDropTarget(index)"
|
||||||
@dragleave="clearDropTarget"
|
@dragleave="clearDropTarget"
|
||||||
@drop="onDrop(index)"
|
@drop="onDrop(index)"
|
||||||
@@ -77,7 +87,7 @@
|
|||||||
:endpoint="effectiveEndpoint(w)"
|
:endpoint="effectiveEndpoint(w)"
|
||||||
:request-counter="widgetRequestCounter(index)"
|
:request-counter="widgetRequestCounter(index)"
|
||||||
@drag-start="() => (draggedIndex = index)"
|
@drag-start="() => (draggedIndex = index)"
|
||||||
@drag-end="() => (draggedIndex = null)"
|
@drag-end="() => onDragEnd()"
|
||||||
/>
|
/>
|
||||||
<div v-else class="dashboard-widget-edit">
|
<div v-else class="dashboard-widget-edit">
|
||||||
<div class="widget-edit-fields">
|
<div class="widget-edit-fields">
|
||||||
@@ -98,6 +108,13 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Platzhalter am Ende, wenn dort eingefügt werden soll -->
|
||||||
|
<div
|
||||||
|
v-if="dragOverIndex === widgets.length && draggedIndex !== null"
|
||||||
|
class="dashboard-grid-cell dashboard-drop-indicator"
|
||||||
|
>
|
||||||
|
<div class="drop-indicator-line"></div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -240,13 +257,18 @@ export default {
|
|||||||
await this.saveConfig();
|
await this.saveConfig();
|
||||||
},
|
},
|
||||||
setDropTarget(index) {
|
setDropTarget(index) {
|
||||||
|
if (this.draggedIndex !== null && this.draggedIndex !== index) {
|
||||||
this.dragOverIndex = index;
|
this.dragOverIndex = index;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
clearDropTarget() {
|
clearDropTarget() {
|
||||||
this.dragOverIndex = null;
|
// Nicht sofort löschen, damit der Indikator sichtbar bleibt
|
||||||
|
// Wird beim Drop oder Drag-End gelöscht
|
||||||
},
|
},
|
||||||
onGridDragover() {
|
onGridDragover() {
|
||||||
|
if (this.draggedIndex !== null) {
|
||||||
this.dragOverIndex = this.widgets.length;
|
this.dragOverIndex = this.widgets.length;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async onGridDrop() {
|
async onGridDrop() {
|
||||||
if (this.draggedIndex == null) return;
|
if (this.draggedIndex == null) return;
|
||||||
@@ -277,6 +299,10 @@ export default {
|
|||||||
this.draggedIndex = null;
|
this.draggedIndex = null;
|
||||||
this.dragOverIndex = null;
|
this.dragOverIndex = null;
|
||||||
await this.saveConfig();
|
await this.saveConfig();
|
||||||
|
},
|
||||||
|
onDragEnd() {
|
||||||
|
this.draggedIndex = null;
|
||||||
|
this.dragOverIndex = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -374,7 +400,7 @@ export default {
|
|||||||
.dashboard-grid {
|
.dashboard-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||||
grid-auto-rows: 200px;
|
grid-auto-rows: 420px;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,6 +408,7 @@ export default {
|
|||||||
min-height: 0;
|
min-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-grid-cell > * {
|
.dashboard-grid-cell > * {
|
||||||
@@ -395,6 +422,38 @@ export default {
|
|||||||
outline: 2px dashed #0d6efd;
|
outline: 2px dashed #0d6efd;
|
||||||
outline-offset: 4px;
|
outline-offset: 4px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
background-color: rgba(13, 110, 253, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-grid-cell.drag-source {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-drop-indicator {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drop-indicator-line {
|
||||||
|
width: 100%;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg, transparent, #0d6efd, transparent);
|
||||||
|
border-radius: 2px;
|
||||||
|
animation: pulse-drop-indicator 1.5s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-drop-indicator {
|
||||||
|
0%, 100% {
|
||||||
|
opacity: 0.5;
|
||||||
|
transform: scaleX(0.8);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-widget-edit {
|
.dashboard-widget-edit {
|
||||||
|
|||||||
Reference in New Issue
Block a user