Browse code

Improve grid selection UX

Benjamin Roth authored on03/03/2025 19:52:31
Showing4 changed files
... ...
@@ -50,6 +50,10 @@
50 50
   height: 30px;
51 51
   border: 1px solid #ccc;
52 52
   cursor: pointer;
53
+  position: relative;
54
+  display: flex;
55
+  justify-content: center;
56
+  align-items: center;
53 57
 }
54 58
 .grid-cell:hover {
55 59
   background-color: rgba(var(--gp-primary-rgb), 0.3);
... ...
@@ -57,3 +61,31 @@
57 61
 .grid-cell.selected {
58 62
   background-color: var(--gp-primary);
59 63
 }
64
+.grid-cell.selected:hover::after {
65
+  content: "";
66
+  background-color: var(--red);
67
+  -webkit-mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E");
68
+  mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E");
69
+  -webkit-mask-size: contain;
70
+  mask-size: contain;
71
+  -webkit-mask-repeat: no-repeat;
72
+  mask-repeat: no-repeat;
73
+  width: 16px;
74
+  height: 16px;
75
+  position: absolute;
76
+  z-index: 2;
77
+}
78
+.grid-cell.selectable:not(.selected):hover::before {
79
+  content: "+";
80
+  -webkit-mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' y1='5' x2='12' y2='19'/%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3C/svg%3E");
81
+  mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' y1='5' x2='12' y2='19'/%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3C/svg%3E");
82
+  -webkit-mask-size: contain;
83
+  mask-size: contain;
84
+  -webkit-mask-repeat: no-repeat;
85
+  mask-repeat: no-repeat;
86
+  background-color: var(--green);
87
+  width: 16px;
88
+  height: 16px;
89
+  position: absolute;
90
+  z-index: 1;
91
+}
... ...
@@ -1 +1 @@
1
-:root{--gp-primary:#c1c1c1;--gp-primary-rgb:193, 193, 193}.vr--grid-pos-container{margin:3px 0;display:grid;grid-template-columns:repeat(6,1fr);grid-gap:5px}.vr--grid-pos-container[data-cols="1"]{grid-template-columns:repeat(1,1fr)}.vr--grid-pos-container[data-cols="2"]{grid-template-columns:repeat(2,1fr)}.vr--grid-pos-container[data-cols="3"]{grid-template-columns:repeat(3,1fr)}.vr--grid-pos-container[data-cols="4"]{grid-template-columns:repeat(4,1fr)}.vr--grid-pos-container[data-cols="5"]{grid-template-columns:repeat(5,1fr)}.vr--grid-pos-container[data-cols="6"]{grid-template-columns:repeat(6,1fr)}.vr--grid-pos-container[data-cols="7"]{grid-template-columns:repeat(7,1fr)}.vr--grid-pos-container[data-cols="8"]{grid-template-columns:repeat(8,1fr)}.vr--grid-pos-container[data-cols="9"]{grid-template-columns:repeat(9,1fr)}.vr--grid-pos-container[data-cols="10"]{grid-template-columns:repeat(10,1fr)}.vr--grid-pos-container[data-cols="11"]{grid-template-columns:repeat(11,1fr)}.vr--grid-pos-container[data-cols="12"]{grid-template-columns:repeat(12,1fr)}.grid-cell{height:30px;border:1px solid #ccc;cursor:pointer}.grid-cell:hover{background-color:rgba(var(--gp-primary-rgb),.3)}.grid-cell.selected{background-color:var(--gp-primary)}
2 1
\ No newline at end of file
2
+:root{--gp-primary:#c1c1c1;--gp-primary-rgb:193, 193, 193}.vr--grid-pos-container{margin:3px 0;display:grid;grid-template-columns:repeat(6,1fr);grid-gap:5px}.vr--grid-pos-container[data-cols="1"]{grid-template-columns:repeat(1,1fr)}.vr--grid-pos-container[data-cols="2"]{grid-template-columns:repeat(2,1fr)}.vr--grid-pos-container[data-cols="3"]{grid-template-columns:repeat(3,1fr)}.vr--grid-pos-container[data-cols="4"]{grid-template-columns:repeat(4,1fr)}.vr--grid-pos-container[data-cols="5"]{grid-template-columns:repeat(5,1fr)}.vr--grid-pos-container[data-cols="6"]{grid-template-columns:repeat(6,1fr)}.vr--grid-pos-container[data-cols="7"]{grid-template-columns:repeat(7,1fr)}.vr--grid-pos-container[data-cols="8"]{grid-template-columns:repeat(8,1fr)}.vr--grid-pos-container[data-cols="9"]{grid-template-columns:repeat(9,1fr)}.vr--grid-pos-container[data-cols="10"]{grid-template-columns:repeat(10,1fr)}.vr--grid-pos-container[data-cols="11"]{grid-template-columns:repeat(11,1fr)}.vr--grid-pos-container[data-cols="12"]{grid-template-columns:repeat(12,1fr)}.grid-cell{height:30px;border:1px solid #ccc;cursor:pointer;position:relative;display:flex;justify-content:center;align-items:center}.grid-cell:hover{background-color:rgba(var(--gp-primary-rgb),.3)}.grid-cell.selected{background-color:var(--gp-primary)}.grid-cell.selected:hover::after{content:"";background-color:var(--red);-webkit-mask-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E");-webkit-mask-size:contain;mask-size:contain;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;width:16px;height:16px;position:absolute;z-index:2}.grid-cell.selectable:not(.selected):hover::before{content:"+";-webkit-mask-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' y1='5' x2='12' y2='19'/%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' y1='5' x2='12' y2='19'/%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3C/svg%3E");-webkit-mask-size:contain;mask-size:contain;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;background-color:var(--green);width:16px;height:16px;position:absolute;z-index:1}
3 3
\ No newline at end of file
... ...
@@ -21,11 +21,51 @@
21 21
   border: 1px solid #ccc;
22 22
   cursor: pointer;
23 23
 
24
+  position: relative; // Macht es möglich, Symbole absolut zu positionieren
25
+  display: flex;
26
+  justify-content: center;
27
+  align-items: center;
28
+
29
+
24 30
   &:hover {
25 31
     background-color: rgba(var(--gp-primary-rgb),.3);
26 32
   }
27 33
 
28 34
   &.selected {
29 35
     background-color: var(--gp-primary);
36
+
37
+    &:hover::after {
38
+      content: '';
39
+      background-color: var(--red);
40
+      -webkit-mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E");
41
+      mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E");
42
+      -webkit-mask-size: contain;
43
+      mask-size: contain;
44
+      -webkit-mask-repeat: no-repeat;
45
+      mask-repeat: no-repeat;
46
+      width: 16px;
47
+      height: 16px;
48
+      position: absolute;
49
+      z-index: 2;
50
+    }
51
+
30 52
   }
53
+
54
+  &.selectable {
55
+    &:not(.selected):hover::before {
56
+      content: '+'; // Plus-Symbol
57
+      -webkit-mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' y1='5' x2='12' y2='19'/%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3C/svg%3E");
58
+      mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' y1='5' x2='12' y2='19'/%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3C/svg%3E");
59
+      -webkit-mask-size: contain;
60
+      mask-size: contain;
61
+      -webkit-mask-repeat: no-repeat;
62
+      mask-repeat: no-repeat;
63
+      background-color: var(--green);
64
+      width: 16px;
65
+      height: 16px;
66
+      position: absolute;
67
+      z-index: 1;
68
+    }
69
+  }
70
+
31 71
 }
... ...
@@ -131,7 +131,7 @@ function init() {
131 131
   /**
132 132
    * Aktualisiert die visuelle Darstellung des Grids
133 133
    */
134
-  function updateGrid(gridContainer) {
134
+  function nupdateGrid(gridContainer) {
135 135
     // Entferne die "selected"-Klasse von allen Zellen
136 136
     gridContainer.querySelectorAll('.grid-cell').forEach(cell => {
137 137
       cell.classList.remove('selected');
... ...
@@ -145,6 +145,22 @@ function init() {
145 145
     });
146 146
   }
147 147
 
148
+  function updateGrid(gridContainer) {
149
+    const cells = gridContainer.querySelectorAll('.grid-cell');
150
+    const { selectedIndices, gridCols } = gridContainer;
151
+
152
+    cells.forEach((cell, index) => {
153
+      cell.classList.remove('selected', 'selectable');
154
+
155
+      if (selectedIndices.includes(index)) {
156
+        cell.classList.add('selected'); // Markiere ausgewählte Zellen
157
+      } else {
158
+        cell.classList.add('selectable'); // Markiere verfügbare Zellen
159
+      }
160
+    });
161
+  }
162
+
163
+
148 164
   /**
149 165
    * Speichert die Auswahl in einem versteckten Eingabeelement
150 166
    */