Made "range mode" useable in tempus view

This commit is contained in:
Ivymaster
2026-10-19 16:19:21 +02:00
parent 0468e8a227
commit 2eef6fb620
9 changed files with 98 additions and 57 deletions
+4 -2
View File
@@ -2,12 +2,14 @@
@media (max-width: 991.98px) {
.responsive-calendar .fhc-calendar-mode-week .fhc-calendar-base-label-day .short,
.responsive-calendar .fhc-calendar-mode-week .fhc-calendar-base-label-dow .short,
.responsive-calendar .fhc-calendar-mode-month .fhc-calendar-base-label-dow .short {
.responsive-calendar .fhc-calendar-mode-month .fhc-calendar-base-label-dow .short,
.responsive-calendar .fhc-calendar-mode-range .fhc-calendar-base-label-day .short {
display: block;
}
.responsive-calendar .fhc-calendar-mode-week .fhc-calendar-base-label-day .long,
.responsive-calendar .fhc-calendar-mode-week .fhc-calendar-base-label-dow .long,
.responsive-calendar .fhc-calendar-mode-month .fhc-calendar-base-label-dow .long {
.responsive-calendar .fhc-calendar-mode-month .fhc-calendar-base-label-dow .long,
.responsive-calendar .fhc-calendar-mode-range .fhc-calendar-base-label-day .long {
display: none;
}
}
+9 -7
View File
@@ -13,7 +13,8 @@
}
.monthPageContainer .cis-renderer-feiertage-calendar-event,
.weekPageContainer .cis-renderer-feiertage-calendar-event,
.dayPageContainer .cis-renderer-feiertage-calendar-event {
.dayPageContainer .cis-renderer-feiertage-calendar-event,
.rangePageContainer .cis-renderer-feiertage-calendar-event {
display: grid;
grid-template-columns: auto 1fr;
justify-items: center;
@@ -28,6 +29,7 @@
}
.weekPageContainer .cis-renderer-feiertage-calendar-event .event-icon,
.dayPageContainer .cis-renderer-feiertage-calendar-event .event-icon,
.rangePageContainer .cis-renderer-feiertage-calendar-event .event-icon,
.listPageContainer .cis-renderer-feiertage-calendar-event .event-icon {
margin: .5rem;
}
@@ -50,21 +52,21 @@
justify-content: space-evenly;
align-items: center;
}
.weekPageContainer .calendar-event-default {
.weekPageContainer .calendar-event-default,
.rangePageContainer .calendar-event-default {
display: grid;
grid-template-columns: auto 1fr;
}
.weekPageContainer .calendar-event-default .event-time {
.weekPageContainer .calendar-event-default .event-time,
.rangePageContainer .calendar-event-default .event-time {
border-inline-end: solid 1px var(--bs-secondary);
align-self: stretch;
align-content: center;
padding: .25em .5em .25em .25em;
margin-inline-end: .25rem;
}
.rangePageContainer .calendar-event-default .event-time {
display: none !important;
}
.weekPageContainer .calendar-event-default .event-text {
.weekPageContainer .calendar-event-default .event-text,
.rangePageContainer .calendar-event-default .event-text {
display: flex;
flex-direction: column;
justify-content: space-evenly;
+16 -24
View File
@@ -7,11 +7,13 @@
}
.fhc-calendar-mode-day .fhc-calendar-base-grid-line,
.fhc-calendar-mode-week .fhc-calendar-base-grid-line {
.fhc-calendar-mode-week .fhc-calendar-base-grid-line,
.fhc-calendar-mode-range .fhc-calendar-base-grid-line,
padding: 0 var(--fhc-calendar-gap-events, var(--fhc-calendar-gap, 1px));
}
.fhc-calendar-mode-day .all-day-events .event,
.fhc-calendar-mode-week .all-day-events .event {
.fhc-calendar-mode-week .all-day-events .event,
.fhc-calendar-mode-range .all-day-events .event {
margin: var(--fhc-calendar-gap-events, var(--fhc-calendar-gap, 1px)) 0;
}
.fhc-calendar-mode-list .event {
@@ -19,7 +21,8 @@
}
/* Border */
.fhc-calendar-mode-day .grid-main .event > *,
.fhc-calendar-mode-week .grid-main .event > * {
.fhc-calendar-mode-week .grid-main .event > *,
.fhc-calendar-mode-range .grid-main .event > * {
border: solid 1px var(--fhc-calendar-border-event);
}
.fhc-calendar-mode-day .event {
@@ -31,20 +34,27 @@
.fhc-calendar-mode-month .event {
--event-radius: var(--fhc-calendar-radius-month-event, 0);
}
.fhc-calendar-mode-range .event {
--event-radius: var(--fhc-calendar-radius-list-event, 0);
}
.fhc-calendar-mode-list .event {
--event-radius: var(--fhc-calendar-radius-list-event, 0);
}
.fhc-calendar-mode-day .all-day-events .event > *,
.fhc-calendar-mode-week .all-day-events .event > *,
.fhc-calendar-mode-range .all-day-events .event > *,
.fhc-calendar-mode-day .event.event-begin > *,
.fhc-calendar-mode-week .event.event-begin > * {
.fhc-calendar-mode-week .event.event-begin > *,
.fhc-calendar-mode-range .event.event-begin > * {
border-top-left-radius: var(--event-radius);
border-top-right-radius: var(--event-radius);
}
.fhc-calendar-mode-day .all-day-events .event > *,
.fhc-calendar-mode-week .all-day-events .event > *,
.fhc-calendar-mode-range .all-day-events .event > *,
.fhc-calendar-mode-day .event.event-end > *,
.fhc-calendar-mode-week .event.event-end > * {
.fhc-calendar-mode-week .event.event-end > *,
.fhc-calendar-mode-range .event.event-end > * {
border-bottom-left-radius: var(--event-radius);
border-bottom-right-radius: var(--event-radius);
}
@@ -111,22 +121,4 @@
.fhc-calendar-mode-range .fhc-calendar-base-grid-line-event {
position: relative;
}
.fhc-calendar-mode-range .fhc-resize-bar {
position: absolute;
top: 0;
bottom: 0;
height: auto;
width: 15px;
margin: 0;
cursor: ew-resize;
}
.fhc-calendar-mode-range .fhc-resize-bar--left {
left: 0;
}
.fhc-calendar-mode-range .fhc-resize-bar--right {
right: 0;
}
}
+7 -3
View File
@@ -16,11 +16,13 @@
display: block;
}
.fhc-calendar-mode-day .fhc-calendar-base-label-day,
.fhc-calendar-mode-week .fhc-calendar-base-label-day {
.fhc-calendar-mode-week .fhc-calendar-base-label-day,
.fhc-calendar-mode-range .fhc-calendar-base-label-day {
font-size: .875em;
}
.fhc-calendar-mode-day .main-header,
.fhc-calendar-mode-week .main-header {
.fhc-calendar-mode-week .main-header,
.fhc-calendar-mode-range .main-header {
text-align: center;
}
.fhc-calendar-mode-month .fhc-calendar-base-label-week {
@@ -36,6 +38,7 @@
}
.fhc-calendar-mode-day .fhc-calendar-base-label-dow,
.fhc-calendar-mode-week .fhc-calendar-base-label-dow,
.fhc-calendar-mode-range .fhc-calendar-base-label-dow,
.fhc-calendar-base-label-day,
.fhc-calendar-base-label-week {
cursor: pointer;
@@ -184,7 +187,8 @@
color: var(--fhc-calendar-color-day-today);
}
/* Week */
.fhc-calendar-mode-week .today {
.fhc-calendar-mode-week .today,
.fhc-calendar-mode-range .today {
background-color: var(--fhc-calendar-bg-week-today);
color: var(--fhc-calendar-color-week-today);
}
@@ -101,7 +101,7 @@ export default {
this.$emit('resize-start', {
edge,
evt,
horizontal: this.mode === 'range',
horizontal: false,
el: this.$refs.eventEl,
event: this.event,
});
@@ -78,7 +78,6 @@ export default {
},
axisParts() {
if (this.timeGrid) {
// create {start, end} array
return this.timeGrid.map(tu => {
return {
start: luxon.Duration.fromISOTime(tu.start),
+15 -1
View File
@@ -16,6 +16,9 @@ export default {
rangeViewPresetsConfig: {
default: {},
},
rangeViewPreviewLink: {
default: null,
},
},
props: {
currentDate: {
@@ -109,10 +112,21 @@ export default {
{{ preset.name }}
</option>
</form-input>
<a
v-if="rangeViewPreviewLink"
:href="rangeViewPreviewLink"
target="_blank"
rel="noopener"
class="btn btn-outline-secondary"
aria-label="Vorschau öffnen"
title="Vorschau öffnen"
>
<i class="fa-solid fa-eye"></i>
</a>
</div>
<div class="flex-grow-1">
<base-slider ref="slider" v-slot="slot">
<range-view ref="view" v-bind="viewAttrs()">
<range-view ref="view" v-bind="viewAttrs(slot.offset)">
<template v-slot="slot"><slot v-bind="slot" mode="range" /></template>
</range-view>
</base-slider>
@@ -2,6 +2,7 @@ import CalendarGrid from "../../Base/Grid.js";
import LabelDay from "../../Base/Label/Day.js";
import LabelDow from "../../Base/Label/Dow.js";
import LabelTime from "../../Base/Label/Time.js";
import FormInput from "../../../Form/Input.js";
export default {
name: "RangeView",
@@ -10,11 +11,14 @@ export default {
LabelDay,
LabelDow,
LabelTime,
FormInput
},
inject: {
timeGrid: "timeGrid",
timezone: "timezone",
events: "events",
hoursPlan: { from: "hoursPlan", default: null },
isHeaderSticky: { from: "isHeaderSticky", default: true },
},
props: {
day: {
@@ -24,8 +28,13 @@ export default {
collapseEmptyDays: Boolean,
rangeLength: Number,
},
data() {
return {
visibleDays: JSON.parse(localStorage.getItem('fhc-calender-visible-days')) ?? [true, true, true, true, true, true, true],
}
},
computed: {
axisMainGroupedByWeek() {
daysGroupedByWeek() {
const focusDayStartOfWeek = this.$props.day.startOf("week");
const prefixedDaysCount = this.$props.day.weekday - 1;
let rangeLength = this.$props.rangeLength + prefixedDaysCount;
@@ -34,27 +43,28 @@ export default {
let axisMain = Array.from({ length: rangeLength }, (e, i) =>
focusDayStartOfWeek.plus({ days: i }),
);
return Object.groupBy(axisMain, (day) => {
return day.startOf("week").toISO().slice(0, 10);
});
},
weeks() {
return Object.keys(this.axisMainGroupedByWeek).sort();
weekStartDays() {
return Object.keys(this.daysGroupedByWeek).sort();
},
axisParts() {
timeAxisSegments() {
if (this.timeGrid) {
// create {start, end} array
return this.timeGrid.map((tu) => {
return this.timeGrid.map(tu => {
return {
start: luxon.Duration.fromISOTime(tu.start),
end: luxon.Duration.fromISOTime(tu.end),
end: luxon.Duration.fromISOTime(tu.end)
};
});
} else if (this.hoursPlan) {
const start = this.hoursPlan?.start ?? 7;
const end = this.hoursPlan?.end ?? 23;
return Array.from({ length: end - start + 1 }, (e, i) => luxon.Duration.fromObject({ hours: i + start }));
} else {
// create 07:00-23:00
return Array.from({ length: 17 }, (e, i) =>
luxon.Duration.fromObject({ hours: i + 7 }),
);
return Array.from({ length: 17 }, (e, i) => luxon.Duration.fromObject({ hours: i + 7 }));
}
},
eventsGroupedByWeek() {
@@ -65,6 +75,9 @@ export default {
},
);
},
dayVisibility() {
return this.daysGroupedByWeek[this.weekStartDays[0]].map(date => this.visibleDays[date.weekday -1])
},
},
methods: {
isToday(date) {
@@ -73,23 +86,31 @@ export default {
"day",
);
},
toggleDay(day)
{
this.visibleDays.splice(day, 1, !this.visibleDays[day])
localStorage.setItem('fhc-calender-visible-days', JSON.stringify(this.visibleDays))
//this.$nextTick(() => this.queueGridWidthSync('day visibility'));
},
},
template: /* html */ `
<div class="fhc-calendar-mode-range-view h-100 overflow-y-scroll">
<calendar-grid
v-for="week in weeks"
:key="week"
:axis-main="axisMainGroupedByWeek[week]"
:axis-parts="axisParts"
v-for="weekStartDay in weekStartDays"
:key="weekStartDay"
:axis-main="daysGroupedByWeek[weekStartDay]"
:axis-parts="timeAxisSegments"
:axis-main-collapsible="collapseEmptyDays"
:snap-to-grid="!!timeGrid"
:overwrittenEvents="
week in eventsGroupedByWeek ? eventsGroupedByWeek[week] : []
weekStartDay in eventsGroupedByWeek ? eventsGroupedByWeek[weekStartDay] : []
"
:shouldMatchParentHeight="false"
:day-visibility="dayVisibility"
:sticky-header="isHeaderSticky"
>
<template #main-header="{ date }">
<div :class="{ today: isToday(date) }">
<div :class="{ today: isToday(date) }" class="d-flex flex-column align-items-center">
<label-dow
v-bind="{ date }"
@cal-click="evt => evt.detail.source = 'day'"
@@ -97,6 +118,13 @@ export default {
<label-day
v-bind="{ date }"
/>
<form-input
type="checkbox"
:checked="visibleDays[date.weekday - 1]"
@change="toggleDay(date.weekday - 1)"
@click.stop
>
</form-input>
</div>
</template>
<template #part-header="{ part }">
+1 -1
View File
@@ -443,7 +443,7 @@ export default {
show-btns
:draggable-events="isEventDraggingEnabled"
:resizable-events="isEventResizingEnabled"
:on-drop="isEventDraggingEnabled && ['week', 'multipleWeeks'].includes(currentMode) ? ondrop : null"
:on-drop="isEventDraggingEnabled && ['week', 'multipleWeeks', 'range'].includes(currentMode) ? ondrop : null"
:on-resize="isEventResizingEnabled ? onresize : null"
@update:date="handleDateUpdate"
@update:mode="(newMode, newDate) => { currentMode = newMode; $emit('update:mode', newMode, newDate) }"