Home.vue 20.9 KB
Newer Older
1
<template>
2
  <div class="home">
3
    <div id="grid">
4
      <div @mousedown="resizeVertical($event, rowIndex)" @mouseup="saveAndStopResizing()" :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
        <div @mousedown="resizeHorizontal($event, rowIndex, colIndex)" @mouseup="saveAndStopResizing()" :id="rowIndex+','+colIndex" class="col" v-show="!isDragged(rowIndex, colIndex)"
11
12
          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
  resizing: false,
59

60
61
62
63
  created() {
    this.loadLayout("isaac");  
  },

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

  methods: {
Johan Degn's avatar
Johan Degn committed
91
92
93
94
    addBlock() {
      this.layout.push({
        height: 300,
        blocks: [{ type: "ActiveCourses", width: 30 },{ type: "Feed", width: 70 }]
95
      });
96
      this.saveLayout("isaac");
97
98
    },

99
    blurRow(rowIndex) {
100
101
      const cols = document.getElementById(rowIndex).getElementsByClassName("col");
      for (const col of cols) {
102
        col.className = "col animate-blur-grey-out-zoom";
103
      }
104
    },
105

106
    slightlyBlurRow(rowIndex) {
107
108
109
110
111
      if(!this.deleting) {
        const cols = document.getElementById(rowIndex).getElementsByClassName("col");
        for (const col of cols) {
          col.className = "col animate-slight-blur-grey-out";
        }
112
113
114
      }
    },

115
    unblurRow(rowIndex) {
116
117
118
119
120
      if(!this.deleting) {
        const cols = document.getElementById(rowIndex).getElementsByClassName("col");
        for (const col of cols) {
          col.className = "col";
        }
121
      }
122
    },
123

124
    mightRemoveRow(rowIndex) {
125
126
127
128
129
      if(this.deleting) {
        this.cancelRemoveRow(rowIndex);
        return;
      }

130
      this.deleting = true;
131
132
      this.blurRow(rowIndex);

133
134
135
136
137
138
      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";
139
140
141
142
143
144

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

147
    removeRow(rowIndex) {
148
149
      this.cancelRemoveRow(rowIndex);
      this.layout.splice(rowIndex, 1);
150
      this.saveLayout("isaac");
151
    },
152

153
154
155
156
157
158
159
160
161
162
    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";
163
164
165
166
167
168

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

171
    resizeHorizontalMouseMove(event) {
172
173
      const deltaX = this.mouseDragPos.x - event.x;
      this.mouseDragPos.x = event.x;
Kent Nielsen's avatar
Kent Nielsen committed
174
175
176
      const row = this.horizontalResizeObject.row;
      const col = this.horizontalResizeObject.col;

Kent Nielsen's avatar
Kent Nielsen committed
177
      // Find index of select col in html document
Kent Nielsen's avatar
Kent Nielsen committed
178
179
180
181
182
183
184
      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
185
186
187
      
      // 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
188
189
      const contentWidth = leftCol.clientWidth + rigthCol.clientWidth + 40;
      
Kent Nielsen's avatar
Kent Nielsen committed
190
191
192
193
194
195
196
197
198
199
200
201
202
      // 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
203
      
Kent Nielsen's avatar
Kent Nielsen committed
204
205
206
      // Storing new style.
      this.layout[row].blocks[col -1].width = newFlexLeft;
      this.layout[row].blocks[col].width = newFlexRight;
207
208
    },

209
    resizeVerticalMouseMove(event) {
210
211
      const deltaY = this.mouseDragPos.y - event.y;
      this.mouseDragPos.y = event.y;
Kent Nielsen's avatar
Kent Nielsen committed
212
      this.layout[this.verticalResizeObject.index].height -= deltaY
213
214
    },

215
    resizeHorizontal(event, row, col) {
216
217
218
219
220
221
222
223
224
225
226
      const mobileMode = window.innerWidth < 992;
      if(event.offsetX >= 0 || mobileMode)
        return;

      this.mouseDragPos.x = event.x;
      this.horizontalResizeObject.row = row;
      this.horizontalResizeObject.col = col;
      document.addEventListener("mousemove", this.resizeHorizontalMouseMove, false);
      document.addEventListener("mouseup", this.eventRemover, false);
      document.getElementsByTagName("html")[0].classList.add("no-select");
      this.dragEnabled = false;
227
      this.resizing = true;
228
229
    },

230
231
232
    resizeVertical(event, index) {
      const mobileMode = window.innerWidth < 992;
      if(index == 0 || this.deleting || mobileMode)
233
        return;
234
      
235
      const clickTarget = event.target;
236
      if(clickTarget.className != "row")
237
238
        return;
      
239
      if(event.offsetY > this.layout[index].height)
240
        console.log(":After event")
241
      else
242
        index--;
243

244
245
246
247
248
      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");
249
      this.dragEnabled = false;
250
251
252
253
254
255
256
257
      this.resizing = true;
    },

    saveAndStopResizing() {
      if(this.resizing) {
        this.saveLayout("isaac");
      }
      this.resizing = false;
Kent Nielsen's avatar
Kent Nielsen committed
258
259
    },

260
    eventRemover() {
Kent Nielsen's avatar
Kent Nielsen committed
261
      document.removeEventListener("mousemove", this.resizeHorizontalMouseMove, false);
Kent Nielsen's avatar
Kent Nielsen committed
262
263
      document.removeEventListener("mousemove", this.resizeVerticalMouseMove, false);
      document.removeEventListener("mouseup", this.eventRemover, false);
264
      document.getElementsByTagName("html")[0].classList.remove("no-select");
265
      this.dragEnabled = true;
Kent Nielsen's avatar
Kent Nielsen committed
266
267
268
269
    },

    mobileLayoutResize(){
      const winWidth = window.innerWidth;
270
      if(this.prevWinWidth > 992 && winWidth > 992) {
Kent Nielsen's avatar
Kent Nielsen committed
271
272
        return;
      }
273
      if(this.prevWinWidth < 992 && winWidth < 992) {
Kent Nielsen's avatar
Kent Nielsen committed
274
275
        return;
      }
Kent Nielsen's avatar
Kent Nielsen committed
276
277
278
279
280
281
282
283

      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){
284
            col.style.flexGrow = 0;
Kent Nielsen's avatar
Kent Nielsen committed
285
286
287
288
289
          }else{
            col.style.flexGrow = this.layout[i].blocks[j].width;
          }
        }
        if(winWidth < 992){
290
          row.style.height = 'auto';
Kent Nielsen's avatar
Kent Nielsen committed
291
292
293
        }else{
          row.style.height = this.layout[i].height + 'px';
        }
Kent Nielsen's avatar
Kent Nielsen committed
294
295
      }
      this.prevWinWidth = winWidth;      
Kent Nielsen's avatar
Kent Nielsen committed
296
    },
297

298
299
300
    startDrag(event, row, col) {
      event.dataTransfer.effectAllowed = 'move';

301
302
303
      const colElement = document.getElementById(row + ',' + col);
      event.dataTransfer.setDragImage(colElement, colElement.offsetWidth/2, 20);

304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
      // 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
330
        for (const block of blocks)
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
          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';

363
      let position = this.getDropPosition(event, row);
364
365
366
367
368
369
370
371
372
373
374

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

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

    showDropPreview(row, position) {
375
376
377
378
      if (this.activePreview !== null)
        this.hidePreview();
      this.activePreview = row;

379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
      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) {
396
397
398
399
      // If events get processed in an unfortunate order
      if (this.draggedBlock === null)
        return;

400
      this.hidePreview();
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426

      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
427
        for (const block of origBlocks) {
428
429
430
431
432
          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
433
        for (const block of destBlocks) {
434
435
436
437
438
          block.width *= destScaleFactor;
        }
      }
      
      this.draggedBlock = null;
439
      this.saveLayout("isaac");
440
441
    },

442
443
444
445
446
    hidePreview() {
      if (this.activePreview === null)
        return;

      const targetRow = document.getElementById(this.activePreview.toString());
447
448
      const preview = targetRow.getElementsByClassName('col-preview')[0];
      preview.style.display = 'none';
449
      this.activePreview = null;
450
451
452
453
454
455
    },

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

456
    saveLayout(id) {
457
      const type = "save"
458
      const payload = "id=" + id + "&" + "data=" + JSON.stringify(this.layout);
459

460
      const request = sendServerRequest(type, payload);
461
462
463
      request.onload = () => {
        const response = request.response;
      }
464
465
466
    },

    loadLayout(id) {
467
468
      const type = "load"
      const payload = "id=" + id;
469

470
      const request = sendServerRequest(type, payload);
Anders B. Clausen's avatar
Anders B. Clausen committed
471
472
      request.onload = () => {
        const response = request.response;
473
        this.layout = [];
474
        Object.assign(this.layout, JSON.parse(response));
475
      }
476
    },
477
  },
478

Kent Nielsen's avatar
Kent Nielsen committed
479
480
  mounted(){
    this.mobileLayoutResize();
481
    this.prevWinWidth = window.innerWidth;
Kent Nielsen's avatar
Kent Nielsen committed
482
483
484
    window.addEventListener('resize', this.mobileLayoutResize);
  },

485
486
487
488
  updated(){
    this.mobileLayoutResize();
  },

489
490
491
492
493
494
495
496
497
498
499
500
  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;
    }
  },

501
502
503
504
505
506
507
508
  provide() {
    return {
      dragEnabled: computed(() => this.dragEnabled),
      startDrag: this.startDrag,
      stopDrag: this.stopDrag
    }
  },

509
510
  components: {
    ActiveCourses,
511
512
    Deadlines,
    Feed,
513
514
    Mail,
    Calendar
515
  }
516
517
}
</script>
518

519
<style lang="scss">
520
  $gap: $default-margin;
521
522
523

  #grid {
    width: 100%;
524
    padding: 0 $gap / 2 $gap;
525
526
527
528
  }

  .row {
    display: flex;
529
    padding-top: $gap / 2;
Kent Nielsen's avatar
Kent Nielsen committed
530
    flex-direction: column;
Kent Nielsen's avatar
Kent Nielsen committed
531
    position: relative;
Lasse Overgaard Møldrup's avatar
Lasse Overgaard Møldrup committed
532
    min-height: 150px;
533

534
535
536
    &.drag * {
      pointer-events: none;
    }
Kent Nielsen's avatar
Kent Nielsen committed
537
  }
538
    
539
  .col, .col-preview {
Johan Degn's avatar
Johan Degn committed
540
    flex-basis: 0; // a basis of 0px. very important!
541
    background-color: $light-green-theme-color;
Johan Degn's avatar
Johan Degn committed
542
    border-radius: 4px;
543
    border: 2px solid $theme-color;
544
545
546
547
    margin: 0 $gap / 2;
  }

  .col {
Kent Nielsen's avatar
Kent Nielsen committed
548
    position: relative;
549

550
    &:not(:last-of-type) {
Kent Nielsen's avatar
Kent Nielsen committed
551
      margin-bottom: $gap / 2;
552
553
    }
  }
Kent Nielsen's avatar
Kent Nielsen committed
554

555
556
557
  .col-preview {
    display: none;
    opacity: 0.5;
558
  }
559

560
561
562
563
564
565
  .add-block {
    width: 50px;
    height: 50px;
    border: none;
    background: none;
    padding: 0;
Kent Nielsen's avatar
Kent Nielsen committed
566
    display: none;
567
    margin-top: $gap;
568
569

    svg {
570
      fill: #777f80;
571
572
573
574
575
576
    }

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

      svg {
577
        fill: $darker-theme-color;
578
579
580
      }
    }
  }
Kent Nielsen's avatar
Kent Nielsen committed
581

582
  .remove-block {
583
584
    right: $gap - 5px + $gap / 2;
    order: 1000;
585
586
587
  }

  .cancel-remove {
588
589
    right: 2 * $gap - 5px + $gap / 2;
    order: 1000;
590
591

    svg {
592
      color: $red-theme-color;
593
594
595
596
    }
  }

  .confirm-remove {
597
598
    right: 3 * $gap - 10px + $gap / 2;
    order: 1000;
599
600

    svg {
601
      color: $green-theme-color;
Kent Nielsen's avatar
Kent Nielsen committed
602
    }
603
604
605
  }

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

608
    height: 30px;
609
    top: -$gap + 5px;
610
611
612
613
614

    border: none;
    background: none;
    
    padding: 0;
615
616
617
618
619

    svg {
      width: 0px;
      height: 0px;
    }
620
  }
621

622
623
624
625
626
627
628
629
630
631
632
633
634
635
  .visible-row-item {
    display: flex;
    position: relative;
    flex-direction: column;

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

    padding: 0;

636
    animation: slide-from-bot 0.4s;
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651

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

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

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

Anders B. Clausen's avatar
Anders B. Clausen committed
652
  .animate-blur-grey-out-zoom {
653
    animation: blur-grey-out-zoom 0.6s;
Anders B. Clausen's avatar
Anders B. Clausen committed
654
655
656
657

    filter: blur(2px) grayscale(0.5); 
    transform: scale(0.97);
    opacity: 0.3;
658
659
660
661
662
663
664

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

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

667
668
669
670
671
672
673
  .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
674
675
676
677
678
679
680
681
682
683
684
  @keyframes slide-from-bot {
    0% { 
      top: 10.5px;
      z-index: -1; 
    }
    99% { 
      top: -$gap + 5px; 
      z-index: -1; 
    }
    100% { z-index: inherit; }
  }
685

Anders B. Clausen's avatar
Anders B. Clausen committed
686
687
  @keyframes blur-grey-out-zoom {
    from { 
688
      filter: blur(1px) grayscale(0.5); 
Anders B. Clausen's avatar
Anders B. Clausen committed
689
      transform: scale(1.0);
690
      opacity: 0.7;
Anders B. Clausen's avatar
Anders B. Clausen committed
691
692
693
694
695
696
697
    }
    to { 
      filter: blur(2px) grayscale(0.5); 
      transform: scale(0.97);
      opacity: 0.3;
    }
  }
698
699
700
701
702
703
704
705
706
707
708
709

  @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;
    }
  }
710
711

  @media only screen and (min-width: $mobile-width-cutoff) {
Kent Nielsen's avatar
Kent Nielsen committed
712
713
    .row{
      flex-direction: row;
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
      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
741
742
    }

743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
    // Must be outside ".row" or else after affect children
    .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;
      }
    }

    .row:last-of-type{
      &::after{
        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
768
769
770
    .col{
      flex-grow: 0;

771
       &:not(:first-of-type) {
Kent Nielsen's avatar
Kent Nielsen committed
772
773
774
775
776
777
778
779
780
781
782
783
        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;
        }
      }
784

Kent Nielsen's avatar
Kent Nielsen committed
785
786
787
788
      &:not(:last-child) {
        margin-right: $gap / 2;
        margin-bottom: 0;
      }
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
    
      &: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
821
822
823
824
825
826
827
828
    }

    .add-block{
      display: initial;
    }

    // Must be outside ".row" or else after affect children
    .row::after{
829
830
831
832
833
834
835
      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
836
837
    }
  }
838
</style>