From b54b49704eb31bbe0fe4ffe05466538a4174d4dc Mon Sep 17 00:00:00 2001
From: Ron Lucke <lucke@elan-ev.de>
Date: Mon, 6 May 2024 08:38:40 +0000
Subject: [PATCH] fix #4033

Closes #4033

Merge request studip/studip!2900
---
 .../scss/courseware/blockadder.scss           |   2 +-
 .../stylesheets/scss/courseware/toolbar.scss  |  17 +-
 .../courseware/toolbar/CoursewareToolbar.vue  |  44 +++--
 .../toolbar/CoursewareToolbarBlocks.vue       | 170 ++++++++++--------
 .../toolbar/CoursewareToolbarClipboard.vue    |  14 +-
 5 files changed, 150 insertions(+), 97 deletions(-)

diff --git a/resources/assets/stylesheets/scss/courseware/blockadder.scss b/resources/assets/stylesheets/scss/courseware/blockadder.scss
index 93325dd32a2..b3f48344ac8 100644
--- a/resources/assets/stylesheets/scss/courseware/blockadder.scss
+++ b/resources/assets/stylesheets/scss/courseware/blockadder.scss
@@ -136,7 +136,7 @@
 }
 .cw-element-inserter-wrapper {
     display: grid;
-    grid-template-columns: repeat(auto-fit, minmax(225px, 1fr));
+    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
     grid-auto-rows: auto;
     grid-gap: 4px;
     margin-bottom: 8px;
diff --git a/resources/assets/stylesheets/scss/courseware/toolbar.scss b/resources/assets/stylesheets/scss/courseware/toolbar.scss
index fdabbf21802..0670486c91a 100644
--- a/resources/assets/stylesheets/scss/courseware/toolbar.scss
+++ b/resources/assets/stylesheets/scss/courseware/toolbar.scss
@@ -14,8 +14,7 @@
         min-height: 100%;
         border: solid thin var(--content-color-40);
         background-color: var(--white);
-        overflow-y: auto;
-        overflow-x: hidden;
+        overflow: hidden;
         position: relative;
         padding: 0 4px;
         top: 0;
@@ -33,6 +32,11 @@
             right: 0;
         }
 
+        .cw-toolbar-tool-content {
+            overflow-y: auto;
+            padding-right: 8px;
+        }
+
         .cw-toolbar-blocks {
             .input-group.files-search {
                 &.search {
@@ -96,6 +100,12 @@
             }
 
         }
+
+        .cw-toolbar-clipboard {
+            .cw-collapsible {
+                margin-bottom: 4px;
+            }
+        }
     }
     .cw-toolbar-folded-wrapper {
         display: flex;
@@ -124,6 +134,7 @@
 
         &.cw-toolbar-button-toggle {
             text-align: end;
+            flex-grow: 1;
         }
 
         &.active {
@@ -142,7 +153,7 @@
     .cw-toolbar-tools.hd {
         .cw-toolbar-button-wrapper {
             .cw-toolbar-button {
-                width: 128px;
+                min-width: 110px;
                 padding: 2px 16px 0 16px;
                 &.cw-toolbar-button-toggle {
                     text-align: end;
diff --git a/resources/vue/components/courseware/toolbar/CoursewareToolbar.vue b/resources/vue/components/courseware/toolbar/CoursewareToolbar.vue
index 8f82eac052c..dc70348f1fe 100644
--- a/resources/vue/components/courseware/toolbar/CoursewareToolbar.vue
+++ b/resources/vue/components/courseware/toolbar/CoursewareToolbar.vue
@@ -2,7 +2,7 @@
     <div class="cw-toolbar-wrapper">
         <div id="cw-toolbar" class="cw-toolbar" :style="toolbarStyle">
             <div v-if="showTools" class="cw-toolbar-tools" :class="{ unfold: unfold, hd: isHd, wqhd: isWqhd }">
-                <div class="cw-toolbar-button-wrapper">
+                <div id="cw-toolbar-nav" class="cw-toolbar-button-wrapper">
                     <button
                         class="cw-toolbar-button"
                         :class="{ active: activeTool === 'blockAdder' }"
@@ -35,9 +35,19 @@
                         <studip-icon shape="arr_2right" :size="24" />
                     </button>
                 </div>
-                <courseware-toolbar-blocks v-if="activeTool === 'blockAdder'" />
-                <courseware-toolbar-containers v-if="activeTool === 'containerAdder'" />
-                <courseware-toolbar-clipboard v-if="activeTool === 'clipboard'" />
+                <div class="cw-toolbar-tool-wrapper">
+                    <CoursewareToolbarBlocks
+                        v-if="activeTool === 'blockAdder'"
+                        :toolbarContentHeight="toolbarContentHeight"
+                    />
+                    <CoursewareToolbarContainers
+                        v-if="activeTool === 'containerAdder'"
+                    />
+                    <CoursewareToolbarClipboard
+                        v-if="activeTool === 'clipboard'"
+                        :toolbarContentHeight="toolbarContentHeight"
+                    />
+                </div>
             </div>
             <div v-else class="cw-toolbar-folded-wrapper">
                 <button
@@ -97,20 +107,26 @@ export default {
             toolbarActive: 'toolbarActive',
             hideEditLayout: 'hideEditLayout',
         }),
-        toolbarStyle() {
-            const scrollTopStyles = window.getComputedStyle(document.getElementById('scroll-to-top'));
+        scrollTopStyles() {
+            return window.getComputedStyle(document.getElementById('scroll-to-top'));
+        },
+        toolbarHeight() {
             const scrollTopHeight =
-                parseInt(scrollTopStyles['height'], 10) +
-                parseInt(scrollTopStyles['padding-top'], 10) +
-                parseInt(scrollTopStyles['padding-bottom'], 10) +
-                parseInt(scrollTopStyles['margin-bottom'], 10);
-            let height = parseInt(
+                parseInt(this.scrollTopStyles['height'], 10) +
+                parseInt(this.scrollTopStyles['padding-top'], 10) +
+                parseInt(this.scrollTopStyles['padding-bottom'], 10) +
+                parseInt(this.scrollTopStyles['margin-bottom'], 10);
+            return parseInt(
                 Math.min(this.windowInnerHeight * 0.9, this.windowInnerHeight - this.toolbarTop - scrollTopHeight)
             );
-
+        },
+        toolbarContentHeight() {
+            return this.toolbarHeight - 55;
+        },
+        toolbarStyle() {
             return {
-                height: height + 'px',
-                minHeight: height + 'px',
+                height: this.toolbarHeight + 'px',
+                minHeight: this.toolbarHeight + 'px',
                 top: this.toolbarTop + 'px',
             };
         },
diff --git a/resources/vue/components/courseware/toolbar/CoursewareToolbarBlocks.vue b/resources/vue/components/courseware/toolbar/CoursewareToolbarBlocks.vue
index 2795e62db25..ceda0f0dd30 100644
--- a/resources/vue/components/courseware/toolbar/CoursewareToolbarBlocks.vue
+++ b/resources/vue/components/courseware/toolbar/CoursewareToolbarBlocks.vue
@@ -1,85 +1,88 @@
 <template>
     <div class="cw-toolbar-blocks">
-        <form @submit.prevent="loadSearch">
-            <div class="input-group files-search search cw-block-search">
-                <input
-                    ref="searchBox"
-                    type="text"
-                    v-model="searchInput"
-                    @click.stop
-                    :label="$gettext('Geben Sie einen Suchbegriff mit mindestens 3 Zeichen ein.')"
-                />
-                <span class="input-group-append" @click.stop>
-                    <button
-                        v-if="searchInput"
-                        type="button"
-                        class="button reset-search"
-                        id="reset-search"
-                        :title="$gettext('Suche zurücksetzen')"
-                        @click="resetSearch"
-                    >
-                        <studip-icon shape="decline" :size="20"></studip-icon>
-                    </button>
-                    <button
-                        type="submit"
-                        class="button"
-                        id="search-btn"
-                        :title="$gettext('Suche starten')"
-                        @click="loadSearch"
-                    >
-                        <studip-icon shape="search" :size="20"></studip-icon>
-                    </button>
-                </span>
-            </div>
-        </form>
+        <div id="cw-toolbar-blocks-header" class="cw-toolbar-tool-header">
+            <form @submit.prevent="loadSearch">
+                <div class="input-group files-search search cw-block-search">
+                    <input
+                        ref="searchBox"
+                        type="text"
+                        v-model="searchInput"
+                        @click.stop
+                        :label="$gettext('Geben Sie einen Suchbegriff mit mindestens 3 Zeichen ein.')"
+                    />
+                    <span class="input-group-append" @click.stop>
+                        <button
+                            v-if="searchInput"
+                            type="button"
+                            class="button reset-search"
+                            id="reset-search"
+                            :title="$gettext('Suche zurücksetzen')"
+                            @click="resetSearch"
+                        >
+                            <studip-icon shape="decline" :size="20"></studip-icon>
+                        </button>
+                        <button
+                            type="submit"
+                            class="button"
+                            id="search-btn"
+                            :title="$gettext('Suche starten')"
+                            @click="loadSearch"
+                        >
+                            <studip-icon shape="search" :size="20"></studip-icon>
+                        </button>
+                    </span>
+                </div>
+            </form>
 
-        <div class="filterpanel">
-            <span class="sr-only">{{ $gettext('Kategorien-Filter') }}</span>
-            <button
-                v-for="category in blockCategories"
-                :key="category.type"
-                class="button"
-                :class="{ 'button-active': category.type === currentFilterCategory }"
-                :aria-pressed="category.type === currentFilterCategory ? 'true' : 'false'"
-                @click="selectCategory(category.type)"
-            >
-                {{ category.title }}
-            </button>
+            <div class="filterpanel">
+                <span class="sr-only">{{ $gettext('Kategorien-Filter') }}</span>
+                <button
+                    v-for="category in blockCategories"
+                    :key="category.type"
+                    class="button"
+                    :class="{ 'button-active': category.type === currentFilterCategory }"
+                    :aria-pressed="category.type === currentFilterCategory ? 'true' : 'false'"
+                    @click="selectCategory(category.type)"
+                >
+                    {{ category.title }}
+                </button>
+            </div>
         </div>
-
-        <div v-if="filteredBlockTypes.length > 0" class="cw-blockadder-item-list">
-            <draggable
-                v-if="filteredBlockTypes.length > 0"
-                class="cw-blockadder-item-list"
-                tag="div"
-                role="listbox"
-                v-model="filteredBlockTypes"
-                handle=".cw-sortable-handle-blockadder"
-                :group="{ name: 'blocks', pull: 'clone', put: 'false' }"
-                :clone="cloneBlock"
-                :sort="false"
-                :emptyInsertThreshold="20"
-                @start="dragBlockStart($event)"
-                @end="dropNewBlock($event)"
-                ref="sortables"
-                sectionId="0"
-            >
-                <courseware-blockadder-item
-                    v-for="(block, index) in filteredBlockTypes"
-                    :key="index"
-                    :title="block.title"
-                    :type="block.type"
-                    :data-blocktype="block.type"
-                    :description="block.description"
-                    @blockAdded="$emit('blockAdded')"
-                />
-            </draggable>
+        <div class="cw-toolbar-tool-content" :style="toolContentStyle">
+            <div v-if="filteredBlockTypes.length > 0" class="cw-blockadder-item-list">
+                <draggable
+                    v-if="filteredBlockTypes.length > 0"
+                    class="cw-blockadder-item-list"
+                    tag="div"
+                    role="listbox"
+                    v-model="filteredBlockTypes"
+                    handle=".cw-sortable-handle-blockadder"
+                    :group="{ name: 'blocks', pull: 'clone', put: 'false' }"
+                    :clone="cloneBlock"
+                    :sort="false"
+                    :emptyInsertThreshold="20"
+                    @start="dragBlockStart($event)"
+                    @end="dropNewBlock($event)"
+                    ref="sortables"
+                    sectionId="0"
+                >
+                    <courseware-blockadder-item
+                        v-for="(block, index) in filteredBlockTypes"
+                        :key="index"
+                        :title="block.title"
+                        :type="block.type"
+                        :data-blocktype="block.type"
+                        :description="block.description"
+                        @blockAdded="$emit('blockAdded')"
+                    />
+                </draggable>
+            </div>
+            <courseware-companion-box
+                v-else
+                :msgCompanion="$gettext('Es wurden keine passenden Blöcke gefunden.')"
+                mood="pointing"
+            />
         </div>
-        <courseware-companion-box
-            v-else
-            :msgCompanion="$gettext('Es wurden keine passenden Blöcke gefunden.')"
-            mood="pointing"
-        />
     </div>
 </template>
 
@@ -99,6 +102,12 @@ export default {
         CoursewareCompanionBox,
         draggable,
     },
+    props: {
+        toolbarContentHeight: {
+            type: Number,
+            required: true,
+        },
+    },
     data() {
         return {
             searchInput: '',
@@ -132,6 +141,13 @@ export default {
                 { title: this.$gettext('Biografie'), type: 'biography' },
             ];
         },
+        toolContentStyle() {
+            const height = this.toolbarContentHeight - 115;
+
+            return {
+                height: height + 'px',
+            };
+        },
     },
     methods: {
         ...mapActions({
diff --git a/resources/vue/components/courseware/toolbar/CoursewareToolbarClipboard.vue b/resources/vue/components/courseware/toolbar/CoursewareToolbarClipboard.vue
index 98cd5730b40..c6f1e920ddc 100644
--- a/resources/vue/components/courseware/toolbar/CoursewareToolbarClipboard.vue
+++ b/resources/vue/components/courseware/toolbar/CoursewareToolbarClipboard.vue
@@ -1,5 +1,5 @@
 <template>
-    <div class="cw-toolbar-clipboard">
+    <div class="cw-toolbar-clipboard cw-toolbar-tool-content" :style="toolContentStyle">
         <courseware-collapsible-box :title="$gettext('Blöcke')" :open="clipboardBlocks.length > 0">
             <template v-if="clipboardBlocks.length > 0">
                 <div class="cw-element-inserter-wrapper">
@@ -101,7 +101,12 @@ export default {
         StudipDialog,
         draggable,
     },
-
+    props: {
+        toolbarContentHeight: {
+            type: Number,
+            required: true,
+        },
+    },
     data() {
         return {
             showDeleteClipboardDialog: false,
@@ -143,6 +148,11 @@ export default {
             }
             return '';
         },
+        toolContentStyle() {
+            return {
+                height: this.toolbarContentHeight + 'px',
+            };
+        },
     },
     methods: {
         ...mapActions({
-- 
GitLab