diff --git a/public/js/components/Calendar/Mode/Day/View.js b/public/js/components/Calendar/Mode/Day/View.js
index 09738f1d0..cd953f33a 100644
--- a/public/js/components/Calendar/Mode/Day/View.js
+++ b/public/js/components/Calendar/Mode/Day/View.js
@@ -3,6 +3,8 @@ import LabelDay from '../../Base/Label/Day.js';
import LabelDow from '../../Base/Label/Dow.js';
import LabelTime from '../../Base/Label/Time.js';
+import { useResizeObserver } from '../../../../composables/Responsive.js';
+
export default {
name: "DayView",
components: {
@@ -22,8 +24,7 @@ export default {
required: true
},
emptyMessage: String,
- emptyMessageDetails: String,
- compact: Boolean
+ emptyMessageDetails: String
},
emits: [
"requestModalOpen",
@@ -104,11 +105,21 @@ export default {
}
}
},
+ setup() {
+ const container = Vue.ref(null); // use useTemplateRef when updating to Vue 3.5
+ const { compact } = useResizeObserver(container, 750);
+
+ return {
+ container, // must be exposed or it won't be set in Vue < 3.5
+ compact
+ };
+ },
mounted() {
this.gridMainRef = this.$refs.grid.$refs.main;
},
template: /* html */`
diff --git a/public/js/components/Cis/LvPlan/LvPlan.js b/public/js/components/Cis/LvPlan/LvPlan.js
index cdb2c38c1..4fbb7c871 100644
--- a/public/js/components/Cis/LvPlan/LvPlan.js
+++ b/public/js/components/Cis/LvPlan/LvPlan.js
@@ -34,8 +34,7 @@ export default {
modeOptions: {
day: {
emptyMessage: Vue.computed(() => this.$p.t('lehre/noLvFound')),
- emptyMessageDetails: Vue.computed(() => this.$p.t('lehre/noLvFound')),
- compact: false
+ emptyMessageDetails: Vue.computed(() => this.$p.t('lehre/noLvFound'))
},
week: {
collapseEmptyDays: false
diff --git a/public/js/components/Cis/Mylv/RoomInformation.js b/public/js/components/Cis/Mylv/RoomInformation.js
index ac02a9d51..0f4fa0603 100644
--- a/public/js/components/Cis/Mylv/RoomInformation.js
+++ b/public/js/components/Cis/Mylv/RoomInformation.js
@@ -32,8 +32,7 @@ export default {
modeOptions: {
day: {
emptyMessage: Vue.computed(() => this.$p.t('rauminfo/keineRaumReservierung')),
- emptyMessageDetails: Vue.computed(() => this.$p.t('rauminfo/keineRaumReservierung')),
- compact: false
+ emptyMessageDetails: Vue.computed(() => this.$p.t('rauminfo/keineRaumReservierung'))
},
week: {
collapseEmptyDays: false
diff --git a/public/js/composables/Responsive.js b/public/js/composables/Responsive.js
new file mode 100644
index 000000000..f1761d870
--- /dev/null
+++ b/public/js/composables/Responsive.js
@@ -0,0 +1,85 @@
+/**
+ * size returns the key of smallest threshold array (integer converts to
+ * { compact: threshold }) entry that is bigger than the current width of
+ * the element or 'full' if none is found.
+ * compact is true if the smallest threshold array entry is bigger than the
+ * current width or false otherwise.
+ *
+ * @param DOMElement|VueTemplateRef element
+ * @param object|array|integer threshold
+ * @return object { compact:Boolean, size:String }
+ */
+export function useResizeObserver(element, threshold) {
+ /* Result Vars */
+ const compact = Vue.ref(false);
+ const size = Vue.ref(false);
+
+ /* Helper Vars */
+ const mounted = Vue.ref(false);
+ const elementRef = Vue.computed(() => {
+ if (!Vue.isRef(element))
+ return element;
+
+ if (!element.value)
+ return element.value;
+
+ if (element.value.$el) // Maybe there is a better test
+ return element.value.$el;
+
+ return element.value;
+ });
+ const compareArray = Vue.computed(() => {
+ const input = Vue.isRef(threshold) ? threshold.value : threshold;
+ if (Number.isInteger(input))
+ return [['compact', input]];
+ if (Array.isArray(input))
+ return input.map((value, key) => [key, value]).sort((a, b) => a[1]-b[1]);
+ return Object.entries(input).sort((a, b) => a[1]-b[1]);
+ });
+
+ /* Helper Functions */
+ function updateResultVars() {
+ const compare = threshold.value || threshold;
+ if (elementRef.value.offsetWidth === undefined)
+ return;
+
+ const found = compareArray.value.find(compare => compare[1] > elementRef.value.offsetWidth);
+
+ size.value = found ? found[0] : 'full';
+ compact.value = (size.value == compareArray.value[0][0]);
+ }
+
+ /* Observer */
+ const observer = new ResizeObserver(() => {
+ if (elementRef.value) {
+ updateResultVars();
+ }
+ });
+ /* Observer Helper Functions */
+ function addObserver() {
+ if (!elementRef.value)
+ return;
+
+ updateResultVars();
+ observer.observe(elementRef.value);
+ mounted.value = true;
+ }
+ function removeObserver() {
+ if (mounted.value) {
+ observer.disconnect()
+ }
+ }
+
+ /* Main Logic */
+ Vue.onMounted(addObserver);
+ Vue.onUnmounted(removeObserver);
+
+ Vue.watchEffect(() => {
+ if (elementRef.value) {
+ removeObserver();
+ addObserver();
+ }
+ });
+
+ return { compact, size };
+}
\ No newline at end of file