diff --git a/public/css/Studentenverwaltung.css b/public/css/Studentenverwaltung.css index cb4b8f2e9..b0285a628 100644 --- a/public/css/Studentenverwaltung.css +++ b/public/css/Studentenverwaltung.css @@ -2,6 +2,7 @@ @import './SvgIcons.css'; @import './components/searchbar/searchbar.css'; @import './components/verticalsplit.css'; +@import './components/horizontalsplit.css'; @import './components/FilterComponent.css'; @import './components/Tabs.css'; @import './components/Notiz.css'; diff --git a/public/css/components/horizontalsplit.css b/public/css/components/horizontalsplit.css new file mode 100644 index 000000000..0db03b2b4 --- /dev/null +++ b/public/css/components/horizontalsplit.css @@ -0,0 +1,73 @@ +:root { + --fhc-horizontalsplit-hsplitter-bg-color: var(--fhc-background, #eee); + --fhc-horizontalsplit-hsplitter-border-color: var(--fhc-border, #eee); + --fhc-horizontalsplit-hsplitter-splitactions-color: var(--fhc-dark, #000); +} + +.horizontalsplit-container { + display: flex; + flex-direction: row; + overflow: hidden; + max-height: 100%; + padding: 0px; +} + +.horizontalsplitted { + overflow: auto; + flex-shrink: 0; +} + +.horizontalsplitter { + flex-shrink: 0; + width: 8px; + cursor: col-resize; + user-select: none; + display: flex; + align-items: center; + justify-content: center; +} + +.horizontalsplitter.left { + border-left: solid 3px var(--fhc-horizontalsplit-hsplitter-border-color); +} + +.horizontalsplitter.right { + border-right: solid 3px var(--fhc-horizontalsplit-hsplitter-border-color); +} + +.splitactions.horizontal { + background-color: var(--fhc-horizontalsplit-hsplitter-bg-color); + color: var(--fhc-horizontalsplit-hsplitter-splitactions-color); + display: flex; + flex-direction: column; + padding: 5px 0 5px 0; +} + +.splitactions.horizontal.left { + border-radius: 0 40% 40% 0; +} + +.splitactions.horizontal.right { + border-radius: 40% 0 0 40%; +} + +.splitactions.horizontal .splitaction { + width: auto; + height: 28px; + display: flex; + align-items: center; + justify-content: center; +} + +.splitactions.horizontal .splitaction.resize { + cursor: col-resize; +} + +#content { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +#content > div:first-child { + margin-top: 30px; +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung.js b/public/js/components/Stv/Studentenverwaltung.js index 66ff7f891..4c57c56f9 100644 --- a/public/js/components/Stv/Studentenverwaltung.js +++ b/public/js/components/Stv/Studentenverwaltung.js @@ -18,6 +18,7 @@ import CoreSearchbar from "../searchbar/searchbar.js"; import NavLanguage from "../navigation/Language.js"; import VerticalSplit from "../verticalsplit/verticalsplit.js"; +import HorizontalSplit from "../horizontalsplit/horizontalsplit.js"; import AppMenu from "../AppMenu.js"; import AppConfig from "../AppConfig.js"; import StvVerband from "./Studentenverwaltung/Verband.js"; @@ -37,6 +38,7 @@ export default { CoreSearchbar, NavLanguage, VerticalSplit, + HorizontalSplit, AppMenu, AppConfig, StvVerband, @@ -235,6 +237,10 @@ export default { } } } + }, + sidebarCollapsed(newVal) { + if(newVal) this.$refs.hSplit.collapseLeft() + else this.$refs.hSplit.showBoth() } }, methods: { @@ -632,23 +638,30 @@ export default { - -
- - - - -
+ + + + + diff --git a/public/js/components/horizontalsplit/horizontalsplit.js b/public/js/components/horizontalsplit/horizontalsplit.js new file mode 100644 index 000000000..2d91cc6a9 --- /dev/null +++ b/public/js/components/horizontalsplit/horizontalsplit.js @@ -0,0 +1,147 @@ +export default { + name: 'HorizontalSplit', + props: { + defaultRatio: { + type: Array, + default: () => [50, 50] + } + }, + data: function () { + return { + availWidth: 0, + leftwidth: 0, + rightwidth: 0, + mousePosX: 0, + resize: false, + hsplitterOffset: 0, + selfOffsetLeft: 0 + }; + }, + template: ` +
+
+ +

Left Panel

+
+
+
+
+ + + + + + + + + +
+
+
+ +

+ +

+
+ `, + mounted: function () { + this.calcWidths(); + this.trackHorizontalSplitterOffsetLeft(); + window.addEventListener('resize', this.calcWidths); + }, + updated: function () { + this.trackHorizontalSplitterOffsetLeft(); + }, + beforeDestroy: function () { + window.removeEventListener('resize', this.calcWidths); + }, + methods: { + calcWidths: function () { + var oldavailWidth = this.availWidth; + this.selfOffsetLeft = this.$refs.horizontalsplit.offsetLeft; + this.availWidth = this.$refs.horizontalsplit.offsetWidth - this.$refs.hsplitter.offsetWidth; + + if ((this.leftwidth === 0 && this.rightwidth === 0) || oldavailWidth === 0) { + this.leftwidth = Math.floor(this.availWidth * (this.defaultRatio[0] / 100)); + } else { + this.leftwidth = Math.floor(((this.leftwidth * 100) / oldavailWidth) / 100 * this.availWidth); + } + this.rightwidth = this.availWidth - this.leftwidth; + }, + collapseLeft: function () { + this.calcWidths(); + this.leftwidth = 0; + this.rightwidth = this.availWidth; + }, + collapseRight: function () { + this.calcWidths(); + this.leftwidth = this.availWidth; + this.rightwidth = 0; + }, + showBoth: function () { + this.leftwidth = Math.floor(this.availWidth * (this.defaultRatio[0] / 100)); + this.rightwidth = this.availWidth - this.leftwidth; + }, + isCollapsed: function () { + if (this.leftwidth === 0) { + return 'left'; + } else if (this.rightwidth === 0) { + return 'right'; + } else { + return false; + } + }, + dragStart: function (e) { + e.preventDefault(); + e.stopPropagation(); + window.addEventListener('mouseup', this.dragEnd); + window.addEventListener('mousemove', this.drag); + this.resize = true; + this.mousePosX = e.clientX; + }, + drag: function (e) { + if (!this.resize) { + return; + } + e.preventDefault(); + e.stopPropagation(); + var offsetX = e.clientX - this.mousePosX; + this.leftwidth = this.leftwidth + offsetX; + if (this.leftwidth < 0) { + this.leftwidth = 0; + } + if (this.leftwidth > this.availWidth) { + this.leftwidth = this.availWidth; + } + this.rightwidth = this.availWidth - this.leftwidth; + this.mousePosX = e.clientX; + }, + dragEnd: function (e) { + e.preventDefault(); + e.stopPropagation(); + window.removeEventListener('mousemove', this.drag); + window.removeEventListener('mouseup', this.dragEnd); + this.resize = false; + this.mousePosX = e.clientX; + }, + trackHorizontalSplitterOffsetLeft: function () { + this.hsplitterOffset = this.$refs.hsplitter.offsetLeft; + } + }, + computed: { + leftOrRightClass: function () { + return ((this.hsplitterOffset - this.selfOffsetLeft) <= Math.floor(this.availWidth / 2)) + ? 'left' + : 'right'; + }, + leftwidthcss: function () { + return this.leftwidth + 'px'; + }, + rightwidthcss: function () { + return this.rightwidth + 'px'; + } + } +}; \ No newline at end of file diff --git a/public/js/components/verticalsplit/verticalsplit.js b/public/js/components/verticalsplit/verticalsplit.js index e712d1ecb..91561a1d3 100644 --- a/public/js/components/verticalsplit/verticalsplit.js +++ b/public/js/components/verticalsplit/verticalsplit.js @@ -1,5 +1,11 @@ export default { name: 'VerticalSplit', + props: { + defaultRatio: { + type: Array, + default: () => [50, 50] + } + }, data: function() { return { availHeight: 0, @@ -50,17 +56,22 @@ export default { updated: function() { this.trackVerticalSplitterOffsetTop(); }, + beforeDestroy: function () { + window.removeEventListener('resize', this.calcHeights); + }, methods: { calcHeights: function() { var windowheight = window.innerHeight; var oldavailHeight = this.availHeight; this.selfOffsetTop = this.$refs.verticalsplit.offsetTop; this.availHeight = windowheight - this.selfOffsetTop - this.$refs.vsplitter.offsetHeight; + if( (this.topheight === 0 && this.bottomheight === 0) || oldavailHeight === 0 ) { - this.topheight = Math.floor(this.availHeight/2); + this.topheight = Math.floor(this.availHeight * (this.defaultRatio[0] / 100)); } else { this.topheight = Math.floor( ((((this.topheight * 100) / oldavailHeight) / 100) * this.availHeight) ); } + this.bottomheight = this.availHeight - this.topheight; }, collapseTop: function() { @@ -74,8 +85,8 @@ export default { this.bottomheight = 0; }, showBoth: function() { - this.topheight = Math.floor(this.availHeight/2); - this.bottomheight = Math.floor(this.availHeight/2); + this.topheight = Math.floor(this.availHeight * (this.defaultRatio[0] / 100)); + this.bottomheight = this.availHeight - this.topheight }, isCollapsed: function() { if( this.topheight === 0 ) {