fix: make dashboard widgets closable (#14)
CI / build-and-test (pull_request) Successful in 1m27s
CI / build-and-test (pull_request) Successful in 1m27s
Every GridStackItem now renders a close button next to its drag grip, mirroring the grip's hover affordance. Closing detaches the item server-side; grid-stack.ts already unregisters widgets via its MutationObserver, so the layout is persisted without an extra protocol. Closable is on by default and can be turned off per item with setClosable(false); GridStackItem.CloseEvent lets views react. The GridStackView "remove last" toolbar button is dropped — per-widget close replaces it, so the view no longer tracks a widget stack. Its counter now only grows, keeping a closed widget's id from being handed to a new widget (which would inherit the saved position). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ue9ZtWUBQF4SuSHpzZ3zwq
This commit is contained in:
@@ -176,9 +176,45 @@ vaadin-app-layout::part(content) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Touch devices never hover — keep the grip permanently visible there. */
|
||||
/* Close button (GridStackItem#setClosable): same affordance as the grip, in
|
||||
the outermost corner slot. The grip steps aside only when it is there, so a
|
||||
non-closable item keeps its grip flush with the corner. */
|
||||
.dialect-close-button {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
right: 16px;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 6px;
|
||||
color: var(--dialect-ink);
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
transition: opacity 120ms ease;
|
||||
}
|
||||
|
||||
.grid-stack-item:has(> .dialect-close-button) > .dialect-drag-handle {
|
||||
right: 48px;
|
||||
}
|
||||
|
||||
.grid-stack-item:hover > .dialect-close-button,
|
||||
.dialect-close-button:focus-visible {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.dialect-close-button:hover,
|
||||
.dialect-close-button:active {
|
||||
opacity: 1;
|
||||
color: var(--dialect-primary);
|
||||
}
|
||||
|
||||
/* Touch devices never hover — keep the corner controls permanently visible. */
|
||||
@media (pointer: coarse) {
|
||||
.dialect-drag-handle {
|
||||
.dialect-drag-handle,
|
||||
.dialect-close-button {
|
||||
opacity: 0.65;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,15 +24,15 @@ card.registration=Registrierung
|
||||
card.employees=Mitarbeiter
|
||||
card.gridstackHint=Bedienung
|
||||
|
||||
gridstack.hint=Karten am Griff oben rechts verschieben, an der unteren rechten Ecke die Größe ändern. Das Layout wird im Browser gespeichert und beim nächsten Besuch wiederhergestellt.
|
||||
gridstack.hint=Karten am Griff oben rechts verschieben, an der unteren rechten Ecke die Größe ändern, mit dem X oben rechts schließen. Das Layout wird im Browser gespeichert und beim nächsten Besuch wiederhergestellt.
|
||||
gridstack.addWidget=Widget hinzufügen
|
||||
gridstack.removeWidget=Letztes entfernen
|
||||
gridstack.reset=Layout zurücksetzen
|
||||
gridstack.status=Layout geändert – {0} Widgets
|
||||
gridstack.statusInitial=Layout unverändert
|
||||
gridstack.widget=Widget {0}
|
||||
gridstack.widgetText=Frei platzierbare Karte.
|
||||
gridstack.dragHandle=Verschieben
|
||||
gridstack.close=Schließen
|
||||
|
||||
chart.revenueSeries=Umsatz 2026
|
||||
chart.pointClick=Serie {0}, Punkt {1}
|
||||
|
||||
@@ -24,15 +24,15 @@ card.registration=Registration
|
||||
card.employees=Employees
|
||||
card.gridstackHint=How it works
|
||||
|
||||
gridstack.hint=Move cards with the grip in their top right corner, resize them from the bottom right corner. The layout is stored in your browser and restored on your next visit.
|
||||
gridstack.hint=Move cards with the grip in their top right corner, resize them from the bottom right corner, close them with the X in the top right corner. The layout is stored in your browser and restored on your next visit.
|
||||
gridstack.addWidget=Add widget
|
||||
gridstack.removeWidget=Remove last
|
||||
gridstack.reset=Reset layout
|
||||
gridstack.status=Layout changed – {0} widgets
|
||||
gridstack.statusInitial=Layout unchanged
|
||||
gridstack.widget=Widget {0}
|
||||
gridstack.widgetText=Freely placeable card.
|
||||
gridstack.dragHandle=Move
|
||||
gridstack.close=Close
|
||||
|
||||
chart.revenueSeries=Revenue 2026
|
||||
chart.pointClick=Series {0}, point {1}
|
||||
|
||||
@@ -24,15 +24,15 @@ card.registration=Registro
|
||||
card.employees=Empleados
|
||||
card.gridstackHint=Cómo funciona
|
||||
|
||||
gridstack.hint=Mueve las tarjetas con el asa de la esquina superior derecha y cambia su tamaño desde la esquina inferior derecha. El diseño se guarda en el navegador y se restaura en la próxima visita.
|
||||
gridstack.hint=Mueve las tarjetas con el asa de la esquina superior derecha, cambia su tamaño desde la esquina inferior derecha y ciérralas con la X de la esquina superior derecha. El diseño se guarda en el navegador y se restaura en la próxima visita.
|
||||
gridstack.addWidget=Añadir widget
|
||||
gridstack.removeWidget=Quitar el último
|
||||
gridstack.reset=Restablecer diseño
|
||||
gridstack.status=Diseño modificado – {0} widgets
|
||||
gridstack.statusInitial=Diseño sin cambios
|
||||
gridstack.widget=Widget {0}
|
||||
gridstack.widgetText=Tarjeta de colocación libre.
|
||||
gridstack.dragHandle=Mover
|
||||
gridstack.close=Cerrar
|
||||
|
||||
chart.revenueSeries=Ingresos 2026
|
||||
chart.pointClick=Serie {0}, punto {1}
|
||||
|
||||
Reference in New Issue
Block a user