Calendar: ResizeObserver for compact day mode

This commit is contained in:
chfhtw
2025-07-25 09:27:56 +02:00
parent 611a6204cd
commit d101b53d3d
4 changed files with 100 additions and 6 deletions
+13 -2
View File
@@ -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 */`
<div
ref="container"
class="fhc-calendar-mode-day-view d-flex h-100"
@cal-click-default.capture="handleClickDefaults"
>
+1 -2
View File
@@ -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
@@ -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
+85
View File
@@ -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 };
}