mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-22 09:22:22 +00:00
deactivate old month page css for day number and events in favor of new computed style (can be redesigned but is being handled in js instead of css class); save & inject/provide observed resize from already existing ResizeObserver to be able to access concrete container width/height values we already had all the time anyway; added some comment to 2year old TODO concerning calendar breakpoints; check if navbar is showing before toggling programmatically; remove some unused code; week time line spawns in dayLane which is representing today to avoid caluclating left/right offsets -> WIP accurately retrieving lane width somehow else, currently approximated;
This commit is contained in:
@@ -131,19 +131,19 @@
|
||||
.fhc-calendar-md .fhc-calendar-month-page-day.active {
|
||||
border-color: var(--bs-secondary);
|
||||
}
|
||||
.fhc-calendar-lg .fhc-calendar-month-page-day .events,
|
||||
.fhc-calendar-md .fhc-calendar-month-page-day .events {
|
||||
display: block;
|
||||
overflow: auto;
|
||||
font-size: 0.7em;
|
||||
}
|
||||
.fhc-calendar-lg .fhc-calendar-month-page-day .events span,
|
||||
.fhc-calendar-md .fhc-calendar-month-page-day .events span {
|
||||
display: block;
|
||||
margin: 0.2em;
|
||||
padding: 0.1em 0.4em;
|
||||
border-radius: 0.1em;
|
||||
}
|
||||
/*.fhc-calendar-lg .fhc-calendar-month-page-day .events,*/
|
||||
/*.fhc-calendar-md .fhc-calendar-month-page-day .events {*/
|
||||
/* display: block;*/
|
||||
/* overflow: auto;*/
|
||||
/* font-size: 0.7em;*/
|
||||
/*}*/
|
||||
/*.fhc-calendar-lg .fhc-calendar-month-page-day .events span,*/
|
||||
/*.fhc-calendar-md .fhc-calendar-month-page-day .events span {*/
|
||||
/* display: block;*/
|
||||
/* margin: 0.2em;*/
|
||||
/* padding: 0.1em 0.4em;*/
|
||||
/* border-radius: 0.1em;*/
|
||||
/*}*/
|
||||
.fhc-calendar-lg .fhc-calendar-years .col-4,
|
||||
.fhc-calendar-md .fhc-calendar-years .col-4 {
|
||||
padding: 0.09375em 0;
|
||||
@@ -217,25 +217,25 @@
|
||||
background-color: rgba(var(--bs-secondary-rgb), 0.25);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.fhc-calendar-sm .fhc-calendar-month-page-day .no,
|
||||
.fhc-calendar-xs .fhc-calendar-month-page-day .no {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
margin: 10%;
|
||||
}
|
||||
.fhc-calendar-sm .fhc-calendar-month-page-day .events,
|
||||
.fhc-calendar-xs .fhc-calendar-month-page-day .events {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 10%;
|
||||
width: 80%;
|
||||
height: 10%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
}
|
||||
/*.fhc-calendar-sm .fhc-calendar-month-page-day .no,*/
|
||||
/*.fhc-calendar-xs .fhc-calendar-month-page-day .no {*/
|
||||
/* display: flex;*/
|
||||
/* align-items: center;*/
|
||||
/* justify-content: center;*/
|
||||
/* width: 80%;*/
|
||||
/* height: 80%;*/
|
||||
/* margin: 10%;*/
|
||||
/*}*/
|
||||
/*.fhc-calendar-sm .fhc-calendar-month-page-day .events,*/
|
||||
/*.fhc-calendar-xs .fhc-calendar-month-page-day .events {*/
|
||||
/* position: absolute;*/
|
||||
/* bottom: 0;*/
|
||||
/* left: 10%;*/
|
||||
/* width: 80%;*/
|
||||
/* height: 10%;*/
|
||||
/* overflow: hidden;*/
|
||||
/* display: flex;*/
|
||||
/*}*/
|
||||
.fhc-calendar-sm .fhc-calendar-month-page-day .events span,
|
||||
.fhc-calendar-xs .fhc-calendar-month-page-day .events span {
|
||||
overflow: hidden;
|
||||
|
||||
@@ -104,7 +104,9 @@ const app = Vue.createApp({
|
||||
event.preventDefault(); // Prevent browser navigation
|
||||
|
||||
if(this.isMobile) { // toggle the menu
|
||||
document.getElementById('nav-main-btn').click();
|
||||
const navMain = document.getElementById('nav-main');
|
||||
// fix unwanted toggle from off to on for some links on mobile
|
||||
if(navMain.classList.contains('show')) document.getElementById('nav-main-btn').click();
|
||||
}
|
||||
|
||||
this.$router.push(route);
|
||||
|
||||
@@ -28,7 +28,10 @@ export default {
|
||||
todayDate,
|
||||
date: this.date,
|
||||
focusDate: this.focusDate,
|
||||
size: Vue.computed({ get: () => this.size, set: v => this.size = v }),
|
||||
size: Vue.computed({ get: () => this.size }),
|
||||
calendarHeight: Vue.computed({ get: () => this.calendarHeight }),
|
||||
calendarWidth: Vue.computed({ get: () => this.calendarWidth }),
|
||||
|
||||
events: Vue.computed(() => this.eventsPerDay),
|
||||
filteredEvents: Vue.computed(() => this.filteredEvents),
|
||||
minimized: Vue.computed({ get: () => this.minimized, set: v => this.$emit('update:minimized', v) }),
|
||||
@@ -36,11 +39,9 @@ export default {
|
||||
noMonthView: this.noMonthView,
|
||||
noWeekView: this.noWeekView,
|
||||
eventsAreNull: Vue.computed(() => this.events === null),
|
||||
classHeader: this.classHeader,
|
||||
mode: Vue.computed(()=>this.mode),
|
||||
selectedEvent: Vue.computed(() => this.selectedEvent),
|
||||
setSelectedEvent: (event)=>{this.selectedEvent = event;},
|
||||
widget: this.widget
|
||||
};
|
||||
},
|
||||
props: {
|
||||
@@ -57,17 +58,9 @@ export default {
|
||||
type: String,
|
||||
default: 'month'
|
||||
},
|
||||
classHeader: {
|
||||
type: [String, Object, Array],
|
||||
default: ''
|
||||
},
|
||||
minimized: Boolean,
|
||||
noWeekView: Boolean,
|
||||
noMonthView: Boolean,
|
||||
widget: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
noMonthView: Boolean
|
||||
},
|
||||
watch:{
|
||||
selectedEvent:{
|
||||
@@ -110,11 +103,14 @@ export default {
|
||||
date: new CalendarDate(),
|
||||
focusDate: new CalendarDate(),
|
||||
size: 0,
|
||||
containerWidth: 0,
|
||||
containerHeight: 0,
|
||||
selectedEvent:null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
sizeClass() {
|
||||
sizeClass() {
|
||||
// mainly determines calendar font-size
|
||||
return 'fhc-calendar-' + ['xs', 'sm', 'md', 'lg'][this.size];
|
||||
},
|
||||
mode: {
|
||||
@@ -210,16 +206,25 @@ export default {
|
||||
if (this.$refs.container) {
|
||||
new ResizeObserver(entries => {
|
||||
for (const entry of entries) {
|
||||
let w = entry.contentBoxSize ? entry.contentBoxSize[0].inlineSize : entry.contentRect.width;
|
||||
// TODO(chris): rework sizing
|
||||
if (w > 600)
|
||||
const w = entry.contentBoxSize ? entry.contentBoxSize[0].inlineSize : entry.contentRect.width;
|
||||
const h = entry.contentBoxSize ? entry.contentBoxSize[0].blockSize : entry.contentRect.height;
|
||||
|
||||
// https://getbootstrap.com/docs/5.0/layout/breakpoints/
|
||||
// bootstrap breakpoints watch window size and this function monitors container size of calendar itself.
|
||||
// calendar is using bootstrap breakpoints which influence layout, which retriggers this function
|
||||
// -> some width constellations will loop so we dont use values around bs5 breakpoints
|
||||
// ['xs', 'sm', 'md', 'lg'][this.size]
|
||||
if (w >= 600)
|
||||
this.size = 3;
|
||||
else if (w > 350)
|
||||
else if (w >= 350)
|
||||
this.size = 2;
|
||||
else if (w > 250)
|
||||
else if (w >= 250)
|
||||
this.size = 1;
|
||||
else
|
||||
this.size = 0;
|
||||
|
||||
this.containerWidth = w
|
||||
this.containerHeight = h
|
||||
}
|
||||
}).observe(this.$refs.container);
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ export default {
|
||||
}
|
||||
},
|
||||
dayText(){
|
||||
if(!this.size || !this.day)return {};
|
||||
if(!this.day)return {};
|
||||
return {
|
||||
heading: this.day.toLocaleString(this.$p.user_locale.value, { dateStyle: 'short' }),
|
||||
tag: this.day.toLocaleString(this.$p.user_locale.value, { weekday: this.size < 2 ? 'narrow' : (this.size < 3 ? 'short' : 'long') }),
|
||||
|
||||
@@ -13,11 +13,9 @@ export default {
|
||||
inject: [
|
||||
'eventsAreNull',
|
||||
'size',
|
||||
'classHeader',
|
||||
'mode',
|
||||
'noWeekView',
|
||||
'noMonthView',
|
||||
'widget'
|
||||
],
|
||||
props: {
|
||||
title: String
|
||||
@@ -28,25 +26,8 @@ export default {
|
||||
'next',
|
||||
'click'
|
||||
],
|
||||
computed: {
|
||||
myClassHeader() {
|
||||
// TODO(chris): + {'btn-sm': !this.size}
|
||||
let c = this.classHeader;
|
||||
if (Array.isArray(c)) {
|
||||
if (!this.size)
|
||||
c.push('btn-sm');
|
||||
} else if (typeof c === 'string' || c instanceof String) {
|
||||
if (!this.size)
|
||||
c += ' btn-sm';
|
||||
} else {
|
||||
c['btn-sm'] = !this.size;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
},
|
||||
template: /*html*/`
|
||||
<div class="calendar-header card-header w-100" :class="classHeader">
|
||||
<div class="calendar-header card-header w-100">
|
||||
<div class="row align-items-center ">
|
||||
<div class=" col-12 col-md-3 d-flex justify-content-center justify-content-md-start align-items-center">
|
||||
<slot name="calendarDownloads"></slot>
|
||||
|
||||
@@ -8,7 +8,6 @@ export default {
|
||||
'size',
|
||||
'minimized',
|
||||
'date',
|
||||
'classHeader'
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -18,7 +18,7 @@ export default {
|
||||
'showWeeks',
|
||||
'noWeekView',
|
||||
'selectedEvent',
|
||||
'setSelectedEvent',
|
||||
'setSelectedEvent'
|
||||
],
|
||||
props: {
|
||||
year: Number,
|
||||
@@ -71,12 +71,9 @@ export default {
|
||||
const isNotThisMonth = day.getMonth() != this.month
|
||||
const isInThePast = day.getTime() < this.today // this.date is just the focusDate but not the initial Date
|
||||
|
||||
|
||||
|
||||
if(isHighlightedWeek) classstring += ' fhc-highlight-week'
|
||||
if(isHighlightedDay) classstring += ' fhc-highlight-day'
|
||||
|
||||
if(isThisDate) classstring += ' active'
|
||||
|
||||
if(isNotThisMonth) classstring += ' opacity-25'
|
||||
if(isInThePast) classstring += ' fhc-calendar-past'
|
||||
return classstring
|
||||
@@ -112,38 +109,29 @@ export default {
|
||||
},
|
||||
getNumberStyle(day) {
|
||||
|
||||
// TODO: move this to active css class in calendar.css
|
||||
const styleObj = {}
|
||||
// styleObj.display = 'inline-block';
|
||||
// styleObj.widt = '32px'; /* Adjust based on the calendar cell size */
|
||||
// styleObj.height = '32px';
|
||||
// styleObj['line-height'] = '32px';
|
||||
// styleObj['text-align'] = 'center';
|
||||
// styleObj['font-weight'] = 'bold';
|
||||
// styleObj['font-size'] = '14px';
|
||||
//
|
||||
// if(day.getDate() === this.todayDate.getDate()
|
||||
// && day.getMonth() === this.todayDate.getMonth()
|
||||
// && day.getFullYear() === this.todayDate.getFullYear()) {
|
||||
// styleObj['background-color'] = '#00649c'; // fh blau
|
||||
// styleObj.color = 'white';
|
||||
// } else {
|
||||
// // styleObj['background-color'] = '#ffffff'; // fh blau
|
||||
// // styleObj.color = 'white'; /* White text for contrast */
|
||||
// }
|
||||
styleObj.display = 'inline-block';
|
||||
styleObj.height = '32px';
|
||||
styleObj['line-height'] = '32px';
|
||||
styleObj['text-align'] = 'center';
|
||||
styleObj['font-weight'] = 'bold';
|
||||
styleObj['font-size'] = '14px';
|
||||
|
||||
if(day.getDate() === this.todayDate.getDate()
|
||||
&& day.getMonth() === this.todayDate.getMonth()
|
||||
&& day.getFullYear() === this.todayDate.getFullYear()) {
|
||||
styleObj['background-color'] = '#00649c'; // fh blau
|
||||
styleObj.color = 'white';
|
||||
}
|
||||
|
||||
return styleObj
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const container = document.getElementById("calendarContainer")
|
||||
if(container) container.style['overflow-y'] = 'scroll'
|
||||
if(container) container.style['overflow-y'] = 'auto'
|
||||
|
||||
},
|
||||
// unmounted() {
|
||||
// const container = document.getElementById("calendarContainer")
|
||||
// if(container) container.style['overflow-y'] = ''
|
||||
// },
|
||||
template: /*html*/`
|
||||
<div class="fhc-calendar-month-page" :class="{'show-weeks': showWeeks}">
|
||||
<div v-if="showWeeks" class=" bg-light fw-bold border-top border-bottom text-center"></div>
|
||||
@@ -173,5 +161,6 @@ export default {
|
||||
</span>
|
||||
</a>
|
||||
</template>
|
||||
</div>`
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ export default {
|
||||
'input',
|
||||
],
|
||||
computed: {
|
||||
laneWidth() {
|
||||
return this.width / this.days.length
|
||||
},
|
||||
curTime() {
|
||||
const now = new Date();
|
||||
return String(now.getHours()).padStart(2, '0') + ':' + String(now.getMinutes()).padStart(2, '0');
|
||||
@@ -137,10 +140,6 @@ export default {
|
||||
)
|
||||
},
|
||||
curIndicatorStyle() {
|
||||
const todayIndex = this.days.findIndex(d => d.getFullYear() === this.todayDate.getFullYear() &&
|
||||
d.getMonth() === this.todayDate.getMonth() &&
|
||||
d.getDate() === this.todayDate.getDate()
|
||||
)
|
||||
|
||||
return {
|
||||
'pointer-events': 'none',
|
||||
@@ -149,8 +148,7 @@ export default {
|
||||
'z-index': 2,
|
||||
'border-color': '#00649C!important',
|
||||
top: this.getDayTimePercent + '%',
|
||||
left: 'calc(('+this.width+'px + 3em) /'+this.days.length+'*'+todayIndex+')',
|
||||
right: 'calc(('+this.width+'px - 3em)/'+this.days.length+'*'+(this.days.length - 1 - todayIndex)+')',
|
||||
width: this.laneWidth + 'px' // todo: manage the real value of 1fr somehow
|
||||
}
|
||||
},
|
||||
getDayTimePercent() {
|
||||
@@ -314,16 +312,17 @@ export default {
|
||||
<span class="border border-top-0 px-2 bg-white">{{hourPositionTime}}</span>
|
||||
</div>
|
||||
</Transition>
|
||||
<Transition>
|
||||
<div v-if="lookingAtToday" class="position-absolute border-top small" :style="curIndicatorStyle">
|
||||
<span class="border border-top-0 px-2 bg-white">{{curTime}}</span>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<div class="events" :ref="'eventsRef'+week">
|
||||
<div class="hours">
|
||||
<div v-for="hour in hours" style="min-height:100px" :key="hour" class="text-muted text-end small" :ref="'hour' + hour">{{hour}}:00</div>
|
||||
</div>
|
||||
<div v-for="day in eventsPerDayAndHour" :key="day" class=" day border-start" :style="dayGridStyle(day)">
|
||||
<Transition>
|
||||
<div v-if="day.isToday" class="position-absolute border-top small" :style="curIndicatorStyle">
|
||||
<span class="border border-top-0 px-2 bg-white">{{curTime}}</span>
|
||||
</div>
|
||||
</Transition>
|
||||
<div v-for="event in day.events" :key="event" @click.prevent="weekPageClick(event.orig, day)"
|
||||
:selected="event.orig == selectedEvent"
|
||||
:style="eventGridStyle(day,event)"
|
||||
@@ -331,7 +330,7 @@ export default {
|
||||
v-contrast >
|
||||
<slot name="weekPage" :event="event" :day="day">
|
||||
<p>this is a placeholder which means that no template was passed to the Calendar Page slot</p>
|
||||
</slot>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -178,7 +178,7 @@ export default {
|
||||
<div v-if="events === null" class="d-flex h-100 justify-content-center align-items-center">
|
||||
<i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
|
||||
</div>
|
||||
<template ref="allWeek" v-else-if="allEventsGrouped.size" v-for="([key, value], index) in allEventsGrouped" :key="index" style="margin-top: 8px;">
|
||||
<template v-else-if="allEventsGrouped.size" v-for="([key, value], index) in allEventsGrouped" :key="index" style="margin-top: 8px;">
|
||||
<div class="card-header d-grid p-0">
|
||||
<button class="btn btn-link link-secondary text-decoration-none" @click="setCalendarMaximized">{{ key.format({dateStyle: "full"})}}</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user