Home.vue 20.6 KB
Newer Older
1
<template>
2
  <div class="home">
3
    <div id="grid">
4
      <div @mousedown="resizeVertical($event, rowIndex)" :id="rowIndex" class="row" :class="{ drag: draggedBlock !== null }"
5
        v-for="(rowBlock, rowIndex) in layout" :key="rowIndex" :style="{ height: rowBlock.height + 'px' }" @mouseleave="cancelRemoveRow(rowIndex)"
6
        @dragover="dragHover($event, rowIndex)" @dragleave="hidePreview()" @drop="drop($event, rowIndex)">
7
8
9
        <span class="col-preview">
          <component :is="previewType"></component>
        </span>
10
11
12
        <div @mousedown="resizeHorizontal($event, rowIndex, colIndex)" :id="rowIndex+','+colIndex" class="col" v-show="!isDragged(rowIndex, colIndex)"
          v-for="(colBlock, colIndex) in rowBlock.blocks" :key="colIndex" :style="{ 'flex-grow': colBlock.width, 'order': colIndex }">
          <component :is="colBlock.type" :row="rowIndex" :col="colIndex"></component>
Anders B. Clausen's avatar
Anders B. Clausen committed
13
14
15
          <button class="hidden-row-item pencil">
            <img v-svg-inline class="icon" src="@/assets/pencil.svg"/>
          </button>
16
        </div>
17
        <button class="hidden-row-item remove-block" @mouseover="slightlyBlurRow(rowIndex)" @mouseleave="unblurRow(rowIndex)" @click="mightRemoveRow(rowIndex)">
18
19
          <img v-svg-inline class="icon" src="@/assets/trashcan.svg"/>
        </button>
20
21
22
23
24
25
        <button class="hidden-row-item cancel-remove" @click="cancelRemoveRow(rowIndex)">
          <img v-svg-inline class="icon" src="@/assets/draw-cross.svg"/>
        </button>
        <button class="hidden-row-item confirm-remove" @click="removeRow(rowIndex)">
          <img v-svg-inline class="icon" src="@/assets/draw-tick.svg"/>
        </button>
26
      </div>
Johan Degn's avatar
Johan Degn committed
27
28
29
      <button class="add-block" @click="addBlock()">
        <img v-svg-inline class="icon" src="@/assets/collapse-plus.svg"/>
      </button>
30
    </div>
31
32
33
34
  </div>
</template>

<script>
35
import { computed } from 'vue';
36
37
38
39
import ActiveCourses from "@/components/blocks/ActiveCourses";
import Deadlines from "@/components/blocks/Deadlines";
import Feed from "@/components/blocks/Feed";
import Mail from "@/components/blocks/Mail";
40
import Calendar from "@/components/blocks/Calendar";
41

Anders B. Clausen's avatar
Anders B. Clausen committed
42
const sendServerRequest = (type, payload) => {
43
44
45
46
47
48
49
50
51
  const xhr = new XMLHttpRequest();
  const url = "/persistence";

  xhr.open("GET", url + "?type=" + type + "&" + payload);
  xhr.send();

  return xhr;
}

52
53
54
// Maximum number of blocks allowed in a row
const maxBlocks = 3;

55
56
export default {
  name: 'Home',
57
  deleting: false,
58
59
60

  data() {
    return {
Johan Degn's avatar
WIP    
Johan Degn committed
61
      layout: [
62
        {
Johan Degn's avatar
Johan Degn committed
63
64
          height: 400,
          blocks: [{type: "Calendar", width: 75}, {type: "ActiveCourses", width: 25}]
65
66
        },
        {
Johan Degn's avatar
Johan Degn committed
67
68
          height: 250,
          blocks: [{type: "Deadlines", width: 100}]
69
70
        },
        {
Johan Degn's avatar
Johan Degn committed
71
72
          height: 300,
          blocks: [{type: "Feed", width: 50}, {type: "Mail", width: 25}, {type: "Mail", width: 25}]
Johan Degn's avatar
WIP    
Johan Degn committed
73
        }
74
      ],
75
      mouseDragPos: {x: 0, y: 0},
Kent Nielsen's avatar
Kent Nielsen committed
76
      verticalResizeObject: {index: 0},
Kent Nielsen's avatar
Kent Nielsen committed
77
      horizontalResizeObject: {row: 0, col: 0},
78
      prevWinWidth: 1000,
79
      draggedBlock: null,
80
      activePreview: null,
81
      dragEnabled: true
82
83
84
85
    }
  },

  methods: {
Johan Degn's avatar
Johan Degn committed
86
87
88
89
    addBlock() {
      this.layout.push({
        height: 300,
        blocks: [{ type: "ActiveCourses", width: 30 },{ type: "Feed", width: 70 }]
90
      });
91
92
    },

93
    blurRow(rowIndex) {
94
95
      const cols = document.getElementById(rowIndex).getElementsByClassName("col");
      for (const col of cols) {
96
        col.className = "col animate-blur-grey-out-zoom";
97
      }
98
    },
99

100
    slightlyBlurRow(rowIndex) {
101
102
103
104
105
      if(!this.deleting) {
        const cols = document.getElementById(rowIndex).getElementsByClassName("col");
        for (const col of cols) {
          col.className = "col animate-slight-blur-grey-out";
        }
106
107
108
      }
    },

109
    unblurRow(rowIndex) {
110
111
112
113
114
      if(!this.deleting) {
        const cols = document.getElementById(rowIndex).getElementsByClassName("col");
        for (const col of cols) {
          col.className = "col";
        }
115
      }
116
    },
117

118
    mightRemoveRow(rowIndex) {
119
120
121
122
123
      if(this.deleting) {
        this.cancelRemoveRow(rowIndex);
        return;
      }

124
      this.deleting = true;
125
126
      this.blurRow(rowIndex);

127
128
129
130
131
132
      const row = document.getElementById(rowIndex);
      const cross = row.getElementsByClassName("cancel-remove")[0];
      const tick = row.getElementsByClassName("confirm-remove")[0];

      cross.className = "visible-row-item cancel-remove";
      tick.className = "visible-row-item confirm-remove";
133
134
135
136
137
138

      // toggle off pencil on hover for cols
      const pens = row.getElementsByClassName("pencil")
      for (const pen of pens) {
        pen.style.display = "none";
      }
139
    },
140

141
    removeRow(rowIndex) {
142
143
      this.cancelRemoveRow(rowIndex);
      this.layout.splice(rowIndex, 1);
144
    },
145

146
147
148
149
150
151
152
153
154
155
    cancelRemoveRow(rowIndex) {
      this.deleting = false;
      this.unblurRow(rowIndex);

      const row = document.getElementById(rowIndex);
      const cross = row.getElementsByClassName("cancel-remove")[0];
      const tick = row.getElementsByClassName("confirm-remove")[0];

      cross.className = "hidden-row-item cancel-remove";
      tick.className = "hidden-row-item confirm-remove";
156
157
158
159
160
161

      // toggle on pencil on hover for cols
      const pens = row.getElementsByClassName("pencil")
      for (const pen of pens) {
        pen.style.display = "block";
      }
162
163
    },

164
    resizeHorizontalMouseMove(event) {
165
166
      const deltaX = this.mouseDragPos.x - event.x;
      this.mouseDragPos.x = event.x;
Kent Nielsen's avatar
Kent Nielsen committed
167
168
169
      const row = this.horizontalResizeObject.row;
      const col = this.horizontalResizeObject.col;

Kent Nielsen's avatar
Kent Nielsen committed
170
      // Find index of select col in html document
Kent Nielsen's avatar
Kent Nielsen committed
171
172
173
174
175
176
177
      let colIndex = col;
      for (let i = 0; i < row; i++) {
        const element = this.layout[i];
        colIndex += element.blocks.length;
      }
      const leftCol = document.getElementsByClassName("col")[colIndex - 1];
      const rigthCol = document.getElementsByClassName("col")[colIndex];
Kent Nielsen's avatar
Kent Nielsen committed
178
179
180
      
      // Total flex allowed from layout
      const totalFlex = this.layout[row].blocks[col -1].width + this.layout[row].blocks[col].width;
Kent Nielsen's avatar
Kent Nielsen committed
181
182
      const contentWidth = leftCol.clientWidth + rigthCol.clientWidth + 40;
      
Kent Nielsen's avatar
Kent Nielsen committed
183
184
185
186
187
188
189
190
191
192
193
194
195
      // Resized size
      const newLeftWidth = leftCol.clientWidth - deltaX;
      const newRightWidth = rigthCol.clientWidth + deltaX;

      // Calculating new flexGrow value
      // This is not normalized to 100"%"
      let newFlexRight = contentWidth/newRightWidth;
      let newFlexLeft = (newLeftWidth * parseFloat(newFlexRight))/newRightWidth;

      // Normalizing flewGrow to 100"%"
      const preAdjustedTotalFlex = newFlexRight+newFlexLeft;
      newFlexRight = (newFlexRight/preAdjustedTotalFlex)*totalFlex;
      newFlexLeft = (newFlexLeft/preAdjustedTotalFlex)*totalFlex;
Kent Nielsen's avatar
Kent Nielsen committed
196
      
Kent Nielsen's avatar
Kent Nielsen committed
197
198
199
      // Storing new style.
      this.layout[row].blocks[col -1].width = newFlexLeft;
      this.layout[row].blocks[col].width = newFlexRight;
200
201
    },

202
    resizeVerticalMouseMove(event) {
203
204
      const deltaY = this.mouseDragPos.y - event.y;
      this.mouseDragPos.y = event.y;
Kent Nielsen's avatar
Kent Nielsen committed
205
      this.layout[this.verticalResizeObject.index].height -= deltaY
206
207
    },

208
    resizeHorizontal(event, row, col) {
209
      if(event.offsetX < 0){
210
        this.mouseDragPos.x = event.x;
Kent Nielsen's avatar
Kent Nielsen committed
211
212
        this.horizontalResizeObject.row = row;
        this.horizontalResizeObject.col = col;
213
        document.addEventListener("mousemove", this.resizeHorizontalMouseMove, false);
Kent Nielsen's avatar
Kent Nielsen committed
214
        document.addEventListener("mouseup", this.eventRemover, false);
215
        document.getElementsByTagName("html")[0].classList.add("no-select");
216
        this.dragEnabled = false;
217
      }
218
219
    },

Kent Nielsen's avatar
Kent Nielsen committed
220
    resizeVertical(event, index){
221
222
223
224
225
226
      if(index == 0 || this.deleting){
        return;
      }
      const clickTarget = event.target;
      if(clickTarget.className != "row"){
        return;
227
      }
228
      
Kent Nielsen's avatar
Kent Nielsen committed
229
      if(event.offsetY > this.layout[index].height){
230
231
232
        console.log(":After event")
      } else {
        index--;
233
      }
234
235
236
237
238
      this.mouseDragPos.y = event.y;
      this.verticalResizeObject.index = index; 
      document.addEventListener("mousemove", this.resizeVerticalMouseMove, false);
      document.addEventListener("mouseup", this.eventRemover, false);
      document.getElementsByTagName("html")[0].classList.add("no-select");
239
      this.dragEnabled = false;
Kent Nielsen's avatar
Kent Nielsen committed
240
241
    },

242
    eventRemover() {
Kent Nielsen's avatar
Kent Nielsen committed
243
      document.removeEventListener("mousemove", this.resizeHorizontalMouseMove, false);
Kent Nielsen's avatar
Kent Nielsen committed
244
245
      document.removeEventListener("mousemove", this.resizeVerticalMouseMove, false);
      document.removeEventListener("mouseup", this.eventRemover, false);
246
      document.getElementsByTagName("html")[0].classList.remove("no-select");
247
      this.dragEnabled = true;
Kent Nielsen's avatar
Kent Nielsen committed
248
249
250
251
    },

    mobileLayoutResize(){
      const winWidth = window.innerWidth;
Kent Nielsen's avatar
Kent Nielsen committed
252
253
254
255
256
257
      if((this.prevWinWidth - 992) > 0 && (winWidth - 992) > 0){
        return;
      }
      if((this.prevWinWidth - 992) < 0 && (winWidth - 992) < 0){
        return;
      }
Kent Nielsen's avatar
Kent Nielsen committed
258
259
260
261
262
263
264
265

      const rows = document.getElementsByClassName("row");
      for (let i = 0; i < rows.length; i++) {
        const row = rows[i];
        const cols = row.getElementsByClassName("col");
        for (let j = 0; j < cols.length; j++) {
          const col = cols[j];
          if(winWidth < 992){
266
            col.style.flexGrow = 0;
Kent Nielsen's avatar
Kent Nielsen committed
267
268
269
270
271
          }else{
            col.style.flexGrow = this.layout[i].blocks[j].width;
          }
        }
        if(winWidth < 992){
272
          row.style.height = 'auto';
Kent Nielsen's avatar
Kent Nielsen committed
273
274
275
        }else{
          row.style.height = this.layout[i].height + 'px';
        }
Kent Nielsen's avatar
Kent Nielsen committed
276
277
      }
      this.prevWinWidth = winWidth;      
Kent Nielsen's avatar
Kent Nielsen committed
278
    },
279

280
281
282
    startDrag(event, row, col) {
      event.dataTransfer.effectAllowed = 'move';

283
284
285
      const colElement = document.getElementById(row + ',' + col);
      event.dataTransfer.setDragImage(colElement, colElement.offsetWidth/2, 20);

286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
      // Workaround for a bug in Chrome causing dragend
      // to be fired immediately if the timeout is not used
      setTimeout(() => {
        this.draggedBlock = { row, col };

        this.showDropPreview(row, col);
      }, 10);
    },

    stopDrag() {
      this.draggedBlock = null;
    },

    getDropPosition(event, row) {
      // Copy blocks
      const blocks = JSON.parse(JSON.stringify(this.layout[row].blocks));

      const origRow = this.draggedBlock.row;
      const origCol = this.draggedBlock.col;
      const origBlock = this.layout[origRow].blocks[origCol];

      // Don't take into account the block we are dragging when calculating the preview
      if (origRow === row) {
        const missingWidth = origBlock.width / (blocks.length - 1);
        blocks.splice(origCol, 1);

Lasse Overgaard Møldrup's avatar
Lasse Overgaard Møldrup committed
312
        for (const block of blocks)
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
          block.width += missingWidth;
      }

      // No drop position if row is full
      if (blocks.length === maxBlocks)
        return null;

      const targetRow = document.getElementById(row.toString());
      const rowWidth = targetRow.offsetWidth;
      const x = event.x - targetRow.offsetLeft;

      let position = blocks.length;
      let cutoff = 0;
      for (let i = 0; i < blocks.length; i++) {
        const block = blocks[i];
        cutoff += block.width / 2;

        if (x <= rowWidth * cutoff / 100) {
          position = i;
          break;
        }

        cutoff += block.width / 2;
      }

      return position;
    },

    // Shows a preview upon dragging a block over a row
    dragHover(event, row) {
      event.dataTransfer.dropEffect = 'move';

345
      let position = this.getDropPosition(event, row);
346
347
348
349
350
351
352
353
354
355
356

      // Don't show preview if row is full
      if (position === null)
        return;

      this.showDropPreview(row, position);
      
      event.preventDefault();
    },

    showDropPreview(row, position) {
357
358
359
360
      if (this.activePreview !== null)
        this.hidePreview();
      this.activePreview = row;

361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
      const origRow = this.draggedBlock.row;
      const origCol = this.draggedBlock.col;
      const origBlock = this.layout[origRow].blocks[origCol];

      // Fix cases when dragging to own row
      if (origRow === row && position >= origCol) {
        position++;
      }

      const targetRow = document.getElementById(row.toString());
      const preview = targetRow.getElementsByClassName('col-preview')[0];
      preview.style.order = position;
      preview.style.flexGrow = origBlock.width;
      preview.style.display = 'block';
    },

    drop(event, row) {
378
379
380
381
      // If events get processed in an unfortunate order
      if (this.draggedBlock === null)
        return;

382
      this.hidePreview();
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408

      const position = this.getDropPosition(event, row);

      // Do nothing if row full
      if (position == null)
        return;

      const origRow = this.draggedBlock.row;
      const origCol = this.draggedBlock.col;
      const origBlock = this.layout[origRow].blocks[origCol];

      // Delete at origin
      const origBlocks = this.layout[origRow].blocks;
      origBlocks.splice(origCol, 1);

      // Insert at destination
      const destBlocks = this.layout[row].blocks;
      destBlocks.splice(position, 0, origBlock);

      if (origBlocks.length == 0)
        this.layout.splice(origRow, 1);
      
      // Normalize rows to 100 total width
      if (origRow !== row) {
        const origTotalWidth = origBlocks.reduce((total, block) => total + block.width, 0);
        const origScaleFactor = 100 / origTotalWidth;
Lasse Overgaard Møldrup's avatar
Lasse Overgaard Møldrup committed
409
        for (const block of origBlocks) {
410
411
412
413
414
          block.width *= origScaleFactor;
        }

        const destTotalWidth = destBlocks.reduce((total, block) => total + block.width, 0);
        const destScaleFactor = 100 / destTotalWidth;
Lasse Overgaard Møldrup's avatar
Lasse Overgaard Møldrup committed
415
        for (const block of destBlocks) {
416
417
418
419
420
421
422
          block.width *= destScaleFactor;
        }
      }
      
      this.draggedBlock = null;
    },

423
424
425
426
427
    hidePreview() {
      if (this.activePreview === null)
        return;

      const targetRow = document.getElementById(this.activePreview.toString());
428
429
      const preview = targetRow.getElementsByClassName('col-preview')[0];
      preview.style.display = 'none';
430
      this.activePreview = null;
431
432
433
434
435
436
    },

    isDragged(row, col) {
      return row === this.draggedBlock?.row && col === this.draggedBlock?.col;
    },

437
    saveLayout(id) {
438
      const type = "save"
Anders B. Clausen's avatar
Anders B. Clausen committed
439
      const payload = "id=" + id + "&" + "data=" + JSON.stringify(this.$data);
440

441
      const request = sendServerRequest(type, payload);
442
443
444
445
      request.onload = () => {
        const response = request.response;
        console.log(response);
      }
446
447
448
    },

    loadLayout(id) {
449
450
      const type = "load"
      const payload = "id=" + id;
451

452
      const request = sendServerRequest(type, payload);
Anders B. Clausen's avatar
Anders B. Clausen committed
453
454
      request.onload = () => {
        const response = request.response;
455
        Object.assign(this.$data, JSON.parse(response));
456
      }
457
    },
458
  },
459

Kent Nielsen's avatar
Kent Nielsen committed
460
461
  mounted(){
    this.mobileLayoutResize();
462
    this.prevWinWidth = window.innerWidth;
Kent Nielsen's avatar
Kent Nielsen committed
463
464
465
    window.addEventListener('resize', this.mobileLayoutResize);
  },

466
467
468
469
  updated(){
    this.mobileLayoutResize();
  },

470
471
472
473
474
475
476
477
478
479
480
481
  computed: {
    previewType() {
      if (this.draggedBlock == null)
        return null;

      const origRow = this.draggedBlock.row;
      const origCol = this.draggedBlock.col;

      return this.layout[origRow].blocks[origCol].type;
    }
  },

482
483
484
485
486
487
488
489
  provide() {
    return {
      dragEnabled: computed(() => this.dragEnabled),
      startDrag: this.startDrag,
      stopDrag: this.stopDrag
    }
  },

490
491
  components: {
    ActiveCourses,
492
493
    Deadlines,
    Feed,
494
495
    Mail,
    Calendar
496
  }
497
498
}
</script>
499

500
<style lang="scss">
501
  $gap: $default-margin;
502
503
504

  #grid {
    width: 100%;
505
    padding: 0 $gap / 2 $gap;
506
507
508
509
  }

  .row {
    display: flex;
510
    padding-top: $gap / 2;
Kent Nielsen's avatar
Kent Nielsen committed
511
    flex-direction: column;
Kent Nielsen's avatar
Kent Nielsen committed
512
    position: relative;
Lasse Overgaard Møldrup's avatar
Lasse Overgaard Møldrup committed
513
    min-height: 150px;
514

515
516
517
    &.drag * {
      pointer-events: none;
    }
Kent Nielsen's avatar
Kent Nielsen committed
518
519
  }

Kent Nielsen's avatar
Kent Nielsen committed
520
  // Must be outside ".row" or else after affect children
521
522
523
524
525
526
527
528
529
530
  .row:not(:first-of-type){
    &::before{
      content: " ";
      background-color: rgba(0, 0, 0, 0);
      position: absolute;
      top: 0;
      width: 100%;
      height: $gap;
      cursor: n-resize;
    }
531
  }
532

533
534
535
536
537
538
539
540
541
542
  .row:last-of-type{
    &::after{
      content: " ";
      background-color: rgba(0, 0, 0, 0);
      position: absolute;
      bottom: -$gap;
      width: 100%;
      height: $gap;
      cursor: n-resize;
    }
543
  }
544
    
545
  .col, .col-preview {
Johan Degn's avatar
Johan Degn committed
546
    flex-basis: 0; // a basis of 0px. very important!
547
    background-color: $light-green-theme-color;
Johan Degn's avatar
Johan Degn committed
548
    border-radius: 4px;
549
    border: 2px solid $theme-color;
550
551
552
553
    margin: 0 $gap / 2;
  }

  .col {
Kent Nielsen's avatar
Kent Nielsen committed
554
    position: relative;
555

556
    &:not(:last-of-type) {
Kent Nielsen's avatar
Kent Nielsen committed
557
      margin-bottom: $gap / 2;
558
    }
559

560
561
562
563
564
565
566
567
    &:not(:first-of-type)::before{
      content: " ";
      background-color: rgba(0, 0, 0, 0);
      position: absolute;
      left: - $gap - 2px;
      width: $gap;
      height: 100%;
      cursor: w-resize;
568
569
    }
  }
Kent Nielsen's avatar
Kent Nielsen committed
570

571
572
573
  .col-preview {
    display: none;
    opacity: 0.5;
574
  }
575

576
577
578
579
580
581
  .add-block {
    width: 50px;
    height: 50px;
    border: none;
    background: none;
    padding: 0;
Kent Nielsen's avatar
Kent Nielsen committed
582
    display: none;
583
    margin-top: $gap;
584
585

    svg {
586
      fill: #777f80;
587
588
589
590
591
592
    }

    &:hover, &:focus {
      cursor: pointer;

      svg {
593
        fill: $darker-theme-color;
594
595
596
      }
    }
  }
Kent Nielsen's avatar
Kent Nielsen committed
597

598
  .remove-block {
599
600
    right: $gap - 5px + $gap / 2;
    order: 1000;
601
602
603
  }

  .cancel-remove {
604
605
    right: 2 * $gap - 5px + $gap / 2;
    order: 1000;
606
607

    svg {
608
      color: $red-theme-color;
609
610
611
612
    }
  }

  .confirm-remove {
613
614
    right: 3 * $gap - 10px + $gap / 2;
    order: 1000;
615
616

    svg {
617
      color: $green-theme-color;
Kent Nielsen's avatar
Kent Nielsen committed
618
    }
619
620
621
  }

  .hidden-row-item {
622
    display: none;
Kent Nielsen's avatar
Kent Nielsen committed
623

624
    height: 30px;
625
    top: -$gap + 5px;
626
627
628
629
630

    border: none;
    background: none;
    
    padding: 0;
631
632
633
634
635

    svg {
      width: 0px;
      height: 0px;
    }
636
  }
637

638
639
640
641
642
643
644
645
646
647
648
649
650
651
  .visible-row-item {
    display: flex;
    position: relative;
    flex-direction: column;

    width: 0px;
    height: 30px;
    top: -$gap + 5px;
    
    border: none;
    background: none;

    padding: 0;

652
    animation: slide-from-bot 0.4s;
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667

    svg {
      width: 28px;
      height: 28px;
    }

    &:hover, &:focus {
      cursor: pointer;

      svg {
        color: $darker-theme-color;
      }
    }
  }

Anders B. Clausen's avatar
Anders B. Clausen committed
668
  .animate-blur-grey-out-zoom {
669
    animation: blur-grey-out-zoom 0.6s;
Anders B. Clausen's avatar
Anders B. Clausen committed
670
671
672
673

    filter: blur(2px) grayscale(0.5); 
    transform: scale(0.97);
    opacity: 0.3;
674
675
676
677
678
679
680

    pointer-events: none !important;
    @include no-select;

    * {
      pointer-events: none !important;
    }
Anders B. Clausen's avatar
Anders B. Clausen committed
681
682
  }

683
684
685
686
687
688
689
  .animate-slight-blur-grey-out {
    animation: slight-blur-grey-out 0.6s;

    filter: blur(1px) grayscale(0.5); 
    opacity: 0.7;
  }

Anders B. Clausen's avatar
Anders B. Clausen committed
690
691
692
693
694
695
696
697
698
699
700
  @keyframes slide-from-bot {
    0% { 
      top: 10.5px;
      z-index: -1; 
    }
    99% { 
      top: -$gap + 5px; 
      z-index: -1; 
    }
    100% { z-index: inherit; }
  }
701

Anders B. Clausen's avatar
Anders B. Clausen committed
702
703
  @keyframes blur-grey-out-zoom {
    from { 
704
      filter: blur(1px) grayscale(0.5); 
Anders B. Clausen's avatar
Anders B. Clausen committed
705
      transform: scale(1.0);
706
      opacity: 0.7;
Anders B. Clausen's avatar
Anders B. Clausen committed
707
708
709
710
711
712
713
    }
    to { 
      filter: blur(2px) grayscale(0.5); 
      transform: scale(0.97);
      opacity: 0.3;
    }
  }
714
715
716
717
718
719
720
721
722
723
724
725

  @keyframes slight-blur-grey-out {
    from { 
      filter: blur(0px) grayscale(0); 
      transform: scale(1.0);
      opacity: 1;
    }
    to { 
      filter: blur(1px) grayscale(0.5); 
      opacity: 0.7;
    }
  }
726
727

  @media only screen and (min-width: $mobile-width-cutoff) {
Kent Nielsen's avatar
Kent Nielsen committed
728
729
    .row{
      flex-direction: row;
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
      padding-top: $gap;

      &:hover {
        .remove-block {
          width: 0;

          display: block;
          position: relative;

          animation: slide-from-bot 0.4s;

          svg {
            color: $theme-color;

            width: 28px;
            height: 28px;
          }

          &:hover, &:focus {
            cursor: pointer;

            svg {
              color: $darker-theme-color;
            }
          }
        }
      }
Kent Nielsen's avatar
Kent Nielsen committed
757
758
759
760
761
    }

    .col{
      flex-grow: 0;

762
       &:not(:first-of-type) {
Kent Nielsen's avatar
Kent Nielsen committed
763
764
765
766
767
768
769
770
771
772
773
774
        margin-left: $gap / 2;
        
        &::before{
          content: " ";
          background-color: rgba(0, 0, 0, 0);
          position: absolute;
          left: - $gap - 2px;
          width: $gap;
          height: 100%;
          cursor: w-resize;
        }
      }
775

Kent Nielsen's avatar
Kent Nielsen committed
776
777
778
779
      &:not(:last-child) {
        margin-right: $gap / 2;
        margin-bottom: 0;
      }
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
    
      &:hover {
        .pencil {
          display: block;
          position: relative;
          float: right;

          width: 30px;
          height: 30px;
          right: 10px;
          top: -100%; 

          padding-top: 10px;

          z-index: inherit;

          svg {
            fill: $lighter-theme-color;

            width: 28px;
            height: 28px;
          }

          &:hover, &:focus {
            cursor: pointer;

            svg {
              fill: $light-theme-color;
            }
          }
        }
      }
Kent Nielsen's avatar
Kent Nielsen committed
812
813
814
815
816
817
818
819
    }

    .add-block{
      display: initial;
    }

    // Must be outside ".row" or else after affect children
    .row::after{
820
821
822
823
824
825
826
      content: " ";
      background-color: rgba(0, 0, 0, 0);
      position: absolute;
      bottom: - $gap;
      width: 100%;
      height: $gap;
      cursor: n-resize;
Kent Nielsen's avatar
Kent Nielsen committed
827
828
    }
  }
829
</style>