use a drag handle with icon

This commit is contained in:
2023-03-12 17:02:40 +01:00
parent e42c00cc08
commit add30a5ee9
9 changed files with 194 additions and 141 deletions

2
liquibase.properties Normal file
View File

@@ -0,0 +1,2 @@
liquibase.hub.mode=off

View File

@@ -33,6 +33,8 @@ import { DashboardPageComponent } from './dashboard-page/dashboard-page.componen
import { NewDashboardComponent } from './dashboard-page/new-dashboard/new-dashboard.component'; import { NewDashboardComponent } from './dashboard-page/new-dashboard/new-dashboard.component';
import { MatDialogModule, MAT_DIALOG_DEFAULT_OPTIONS } from '@angular/material/dialog'; import { MatDialogModule, MAT_DIALOG_DEFAULT_OPTIONS } from '@angular/material/dialog';
import {MatTableModule} from '@angular/material/table'; import {MatTableModule} from '@angular/material/table';
import {MatGridListModule} from '@angular/material/grid-list';
import {MatCardModule} from '@angular/material/card';
import {MatBadgeModule} from '@angular/material/badge'; import {MatBadgeModule} from '@angular/material/badge';
import { DashboardComponent } from './dashboard-page/dashboard/dashboard.component'; import { DashboardComponent } from './dashboard-page/dashboard/dashboard.component';
import { AddTextDialogComponent } from './dashboard-page/dashboard/add-text-dialog/add-text-dialog.component'; import { AddTextDialogComponent } from './dashboard-page/dashboard/add-text-dialog/add-text-dialog.component';
@@ -83,9 +85,11 @@ import { FocusDirective } from './focus.directive';
MatAutocompleteModule, MatAutocompleteModule,
MatBadgeModule, MatBadgeModule,
MatButtonModule, MatButtonModule,
MatCardModule,
MatCheckboxModule, MatCheckboxModule,
MatDialogModule, MatDialogModule,
MatFormFieldModule, MatFormFieldModule,
MatGridListModule,
MatInputModule, MatInputModule,
MatRadioModule, MatRadioModule,
MatProgressBarModule, MatProgressBarModule,

View File

@@ -1,121 +1,58 @@
<style> <style>
.customizable-grid { .grid-container {
width: 100%; margin: 10px;
display: flex;
flex-wrap: wrap;
}
.draggable {
flex-shrink: 0;
padding: 0.5rem;
border: solid 1px;
border-collapse: collapse;
}
.draggable-small {
width: 300px;
height: 300px;
background-color: rgb(158, 240, 189);
}
.draggable-middle {
width: 600px;
height: 300px;
background-color: darksalmon;
}
.example-container {
width: 400px;
max-width: 100%;
margin: 0 25px 25px 0;
display: inline-block;
vertical-align: top;
} }
.example-list { .dashboard-card {
border: solid 1px #ccc; position: absolute;
min-height: 60px; top: 0px;
background: white; left: 0px;
border-radius: 4px; right: 0px;
overflow: hidden; bottom: 0px;
display: block;
} }
.example-box { .more-button {
padding: 20px 10px; float: right;
border-bottom: solid 1px #ccc; font-size: 2em;
color: rgba(0, 0, 0, 0.87);
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
cursor: move;
background: white;
font-size: 14px;
} }
.dashboard-card-content {
text-align: center;
}
.cdk-drop-list {
height: 100%;
width: 100%;
}
.cdk-drag-preview { .cdk-drag-preview {
box-sizing: border-box; box-sizing: border-box;
border-radius: 4px; opacity: 0.5;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
.cdk-drag-placeholder {
opacity: 0;
} }
.cdk-drag-animating { .cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); transition: unset;
} }
.example-box:last-child { .cdk-drag-placeholder {
border: none; display: none;
} }
.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
</style> </style>
<!-- <div class="grid-container" style="height: 615px; overflow: hidden;">
<div class="customizable-grid"> <mat-grid-list cols="8" rowHeight="1:1" gutterSize="15px">
<div class="draggable draggable-small"></div> <mat-grid-tile *ngFor="let card of cards; let i = index;"
<div class="draggable draggable-middle"></div> [colspan]="card.cols" [rowspan]="card.rows">
<div class="draggable draggable-small"></div> <cdk-drop-list [cdkDropListConnectedTo]="drops" [cdkDropListData]="i" >
<div class="draggable draggable-middle"></div> <mat-card cdkDrag (cdkDragEntered)="entered($event)" [cdkDragData]="i"
</div> class="dashboard-card" [style.backgroundColor]="card.color">
--> <mat-icon cdkDragHandle class="more-button">drag_handle</mat-icon>
<mat-card-content class="dashboard-card-content">
<div class="example-container"> <h1>{{card.title}}</h1>
<h2>To do</h2> </mat-card-content>
</mat-card>
<div </cdk-drop-list>
cdkDropList </mat-grid-tile>
#todoList="cdkDropList" </mat-grid-list>
[cdkDropListData]="todo" </div>
[cdkDropListConnectedTo]="[doneList]"
class="example-list"
(cdkDropListDropped)="drop($event)">
<div class="example-box" *ngFor="let item of todo" cdkDrag>{{item}}</div>
</div>
</div>
<div class="example-container">
<h2>Done</h2>
<div
cdkDropList
#doneList="cdkDropList"
[cdkDropListData]="done"
[cdkDropListConnectedTo]="[todoList]"
class="example-list"
(cdkDropListDropped)="drop($event)">
<div class="example-box" *ngFor="let item of done" cdkDrag>{{item}}</div>
</div>
</div>

View File

@@ -1,24 +1,111 @@
import { Component } from '@angular/core'; import { Component, QueryList, ViewChildren } from '@angular/core';
import {CdkDragDrop, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop'; import {CdkDragDrop, CdkDragEnter, CdkDropList, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop';
const COLORS = [
'#ea4335',
'#4285f4',
'#fbbc04',
'#34a853',
'#fa7b17',
'#f538a0',
'#a142f4',
'#24c1e0',
'#9aa0a6',
'#5195ea',
'#e25142',
'#f5c518',
'#41af6a',
'#f6aea9',
'#a50e0e',
'#aecbfa',
'#174ea6',
'#fde293',
'#a8dab5',
'#0d652d',
'#fdc69c',
'#fba9d6',
'#c92786',
'#d7aefb',
'#8430ce',
'#a1e4f2',
'#007b83',
'#e8eaed',
'#b9d4f6',
'#f3b9b3',
'#fbe7a2',
'#b3dfc3',
]
function getColor() {
return COLORS[Math.floor(Math.random() * 32)];
}
@Component({ @Component({
selector: 'app-customizable-grid', selector: 'app-customizable-grid',
templateUrl: './customizable-grid.component.html' templateUrl: './customizable-grid.component.html'
}) })
export class CustomizableGridComponent { export class CustomizableGridComponent {
todo = ['Get to work', 'Pick up groceries', 'Go home', 'Fall asleep']; entered($event: CdkDragEnter) {
done = ['Get up', 'Brush teeth', 'Take a shower', 'Check e-mail', 'Walk dog']; console.log($event.item.data, $event.container.data);
moveItemInArray(this.cards, $event.item.data, $event.container.data);
drop(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex,
);
}
} }
entered2($event: CdkDragEnter) {
console.log($event.item.data, $event.container.data);
moveItemInArray(this.cards, $event.item.data, $event.container.data);
}
drop(event: CdkDragDrop<any[]>) {
}
done(){
}
@ViewChildren(CdkDropList) dropsQuery!: QueryList<CdkDropList>;
drops!: CdkDropList[];
ngAfterViewInit() {
this.dropsQuery.changes.subscribe(() => {
this.drops = this.dropsQuery.toArray()
})
Promise.resolve().then(() => {
this.drops = this.dropsQuery.toArray();
console.log(this.drops);
})
}
/** Based on the screen size, switch from standard to one column per row */
cards = [
{ title: 'Card 1', cols: 2, rows: 2, color: getColor()},
{ title: 'Card 2', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 3', cols: 3, rows: 1, color: getColor() },
{ title: 'Card 4', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 5', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 6', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 7', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 8', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 9', cols: 1, rows: 3, color: getColor() },
{ title: 'Card 10', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 11', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 12', cols: 2, rows: 1, color: getColor() },
{ title: 'Card 13', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 14', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 15', cols: 1, rows: 2, color: getColor() },
{ title: 'Card 16', cols: 2, rows: 1, color: getColor() },
{ title: 'Card 17', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 18', cols: 2, rows: 1, color: getColor() },
{ title: 'Card 19', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 20', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 21', cols: 1, rows: 1, color: getColor()},
/* { title: 'Card 22', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 23', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 24', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 25', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 26', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 27', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 28', cols: 1, rows: 1, color: getColor() },
{ title: 'Card 29', cols: 1, rows: 1, color: getColor() } */
];
} }

View File

@@ -2,7 +2,6 @@
:host { :host {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.center { .center {
position: absolute; position: absolute;
@@ -26,19 +25,19 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.editable .editable-hovered {
visibility: hidden;
}
.editable:hover .editable-hovered {
visibility: visible;
}
.handle { .handle {
display: block;
height: 1.5em; height: 1.5em;
visibility: hidden;
width: fit-content;
}
[cdkDrag] {
position: relative;
} }
[cdkDrag]:hover .handle, .cdk-drop-list-dragging .handle { [cdkDrag]:hover .handle, .cdk-drop-list-dragging .handle {
background-color: #f3f3f3;
border-radius: 3px;
cursor: grab; cursor: grab;
visibility: visible;
} }
</style> </style>
@@ -71,7 +70,7 @@
cdkDrag cdkDrag
*ngFor="let id of column" *ngFor="let id of column"
[attr.widget-id]="id"> [attr.widget-id]="id">
<div cdkDragHandle class="handle"></div> <div cdkDragHandle class="handle"><img src="/assets/img/drag_handle.svg" class="icon-small"/></div>
<app-text-widget <app-text-widget
*ngIf="isTextWidget(id)" *ngIf="isTextWidget(id)"
[data]="getTextWidget(id)!" (deleted)="delete($event)"></app-text-widget> [data]="getTextWidget(id)!" (deleted)="delete($event)"></app-text-widget>

View File

@@ -20,7 +20,13 @@
cursor: zoom-in; cursor: zoom-in;
} }
.editable-hovered { .top-left {
position: absolute;
left: 0;
top: 0;
}
.top-right {
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: 0;
@@ -34,7 +40,7 @@
} }
</style> </style>
<div class="dashboard-card" [ngClass]="{'size-medium' : true}"> <div class="dashboard-card" [ngClass]="{'size-medium' : true}">
<div class="editable-hovered"> <div class="editable-hovered top-right">
<button mat-icon-button (click)="edit()" ><img src="/assets/img/edit-outline.svg"/></button> <button mat-icon-button (click)="edit()" ><img src="/assets/img/edit-outline.svg"/></button>
<button mat-icon-button (click)="delete()"><img src="/assets/img/recycle-bin-line.svg"/></button> <button mat-icon-button (click)="delete()"><img src="/assets/img/recycle-bin-line.svg"/></button>
</div> </div>

View File

@@ -4,7 +4,7 @@
} }
.text-widget { .text-widget {
position: relative; position: relative;
padding: 1em 0; padding-bottom: 1em;
} }
.text-widget:hover { .text-widget:hover {
/*outline: solid 1px black;/**/ /*outline: solid 1px black;/**/

View File

@@ -0,0 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 32 32">
<g transform="translate(0.5,0.5)" style="fill:black">
<circle cx="4" cy="9" r="2"/>
<circle cx="12" cy="9" r="2"/>
<circle cx="20" cy="9" r="2"/>
<circle cx="28" cy="9" r="2"/>
<circle cx="4" cy="15" r="2"/>
<circle cx="12" cy="15" r="2"/>
<circle cx="20" cy="15" r="2"/>
<circle cx="28" cy="15" r="2"/>
<circle cx="4" cy="21" r="2"/>
<circle cx="12" cy="21" r="2"/>
<circle cx="20" cy="21" r="2"/>
<circle cx="28" cy="21" r="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 534 B

View File

@@ -114,22 +114,21 @@ button.save-button:disabled {
background-color: inherit; background-color: inherit;
} }
.icon-tiny {
width: 1em;
height: 1em;
}
.icon-small { .icon-small {
width: 1.5em; width: 1.5em;
height: 1.5em; height: 1.5em;
} }
.icon-small:hover {
background-color: #eee;
}
.icon-middle { .icon-middle {
width: 2.5em; width: 2.5em;
height: 2.5em; height: 2.5em;
margin: 0.2em; margin: 0.2em;
} }
.icon-middle:hover {
background-color: #eee;
}
.icon-large { .icon-large {
width: 8em; width: 8em;
@@ -148,8 +147,6 @@ button.save-button:disabled {
vertical-align: text-bottom; vertical-align: text-bottom;
} }
a ,a:visited { a ,a:visited {
color: blue; color: blue;
text-decoration: none; text-decoration: none;