diff --git a/development/QalendarView.vue b/development/QalendarView.vue index ac1c4a60..73572a5a 100644 --- a/development/QalendarView.vue +++ b/development/QalendarView.vue @@ -20,6 +20,11 @@ @event-was-dragged="handleEventWasDragged" @interval-was-clicked="handleIntervalWasClicked" > + @@ -84,7 +89,7 @@ export default defineComponent({ config: { week: { startsOn: 'monday', - nDays: 5, + // nDays: 5, scrollToHour: 8, }, locale: 'de-DE', @@ -102,12 +107,13 @@ export default defineComponent({ }, }, defaultMode: 'week', + showCurrentTime: true, // disableModes: ['month'], isSilent: true, dayIntervals: { - // height: 50, - // length: 15, - // displayClickableInterval: true, + height: 100, + length: 15, + displayClickableInterval: true, // intervalStyles: { // color: '#fff', // backgroundColor: 'rgba(10, 10, 10, 0.9)', diff --git a/docs/index.md b/docs/index.md index 24d553f9..f29baf55 100644 --- a/docs/index.md +++ b/docs/index.md @@ -100,6 +100,7 @@ data() { defaultMode: 'day', // The silent flag can be added, to disable the development warnings. This will also bring a slight performance boost isSilent: true, + showCurrentTime: true, // Display a line indicating the current time } } } @@ -377,6 +378,17 @@ data() { When a clickable interval is clicked, the calendar emits the event `interval-was-clicked`, containing date-time strings for the start and end of the clicked interval. This can be useful, for letting the user add an event, based on where in a day the user clicks. +### Custom current-time line +As shown above under basic configuration, there is a `showCurrentTime` option for displaying a red line, marking what time of the day it is. If you, however, want to customize the looks of this line, use the `customCurrentTime` slot as shown below, **instead** of `showCurrentTime`. Qalendar takes care of the positioning, you just need to style the line as you wish. + +```vue + +``` + ### Disabling features Some features of the calendar can be disabled/hidden through configuration. diff --git a/src/Qalendar.vue b/src/Qalendar.vue index 0cc949b5..35e331ec 100644 --- a/src/Qalendar.vue +++ b/src/Qalendar.vue @@ -50,6 +50,10 @@ :close-event-dialog="p.closeEventDialog" > + +
+
+ +
+ +
+
+
+ @@ -400,5 +443,35 @@ export default defineComponent({ height: v-bind(weekHeight); overflow: hidden; } + + .current-time-line { + position: absolute; + left: 0; + width: 100%; + height: 2px; + z-index: 10000; + background-color: red; + + &__circle { + position: relative; + + &::before { + content: ''; + position: absolute; + transform: translate(-45%, -45%); + width: 10px; + height: 10px; + border-radius: 50%; + background-color: red; + } + } + } + + .custom-current-time { + position: absolute; + left: 0; + width: 100%; + z-index: 1; + } } diff --git a/src/helpers/EventPosition.ts b/src/helpers/EventPosition.ts index 93b30260..76492440 100644 --- a/src/helpers/EventPosition.ts +++ b/src/helpers/EventPosition.ts @@ -6,51 +6,16 @@ import {eventInterface} from '../typings/interfaces/event.interface'; import Time from './Time'; import {fullDayEventsWeek} from '../typings/interfaces/full-day-events-week.type'; import {dayInterface} from '../typings/interfaces/day.interface'; -// IMPORTANT: this instance of Time, should not be used for anything sensitive to "locale" or "firstDayOfWeekIs" -const TimeHelper = new Time() - -export default class EventPosition { - protected turnMinutesIntoPercentageOfHour(minutes: number): string { - const oneMinutePercentage = 100 / 60; - - const minutePoints = oneMinutePercentage * minutes; - - if (minutePoints < 10) return "0" + minutePoints; - - return minutePoints.toString(); - } - - /** - * Every hour between 'dayStart' and 'dayEnd' is 100, in this function referred to as 100 points - * If an event starts 30 minutes after 'dayStart', it should have 50 pointsIntoDay - * If a day consists of 4 hours (400 points), we then have to count - * (50 / 400) * 100 = 12.5 => event starts after 12.5 percent of the day - * - * Result is supposed to be a number between 0 and 100, and is used for setting the CSS- top- and height-attributes for events - * */ - getPercentageOfDayFromDateTimeString( - dateTimeString: string, - dayStart: number, - dayEnd: number - ) { - const pointsInDay = dayEnd - dayStart; - const hour = dateTimeString.substring(11, 13); - const minutes = dateTimeString.substring(14, 16); - const minutesPoints = this.turnMinutesIntoPercentageOfHour(+minutes); - const eventPoints = +(hour + minutesPoints); - const eventPointsIntoDay = eventPoints - dayStart; - - return (eventPointsIntoDay / pointsInDay) * 100; - } +export default class EventPosition extends Time { /** * Yields a full calendar week, with all full-day events positioned in it * */ positionFullDayEventsInWeek(weekStart: Date, weekEnd: Date, events: eventInterface[]) { // 1. add timeJS.start and timeJS.end to all objects const eventsWithJSDates = events.map((scheduleEvent: eventInterface) => { - const { year: startYear, month: startMonth, date: startDate } = TimeHelper.getAllVariablesFromDateTimeString(scheduleEvent.time.start) - const { year: endYear, month: endMonth, date: endDate } = TimeHelper.getAllVariablesFromDateTimeString(scheduleEvent.time.end) + const { year: startYear, month: startMonth, date: startDate } = this.getAllVariablesFromDateTimeString(scheduleEvent.time.start) + const { year: endYear, month: endMonth, date: endDate } = this.getAllVariablesFromDateTimeString(scheduleEvent.time.end) scheduleEvent.timeJS = { start: new Date(startYear, startMonth, startDate), end: new Date(endYear, endMonth, endDate), @@ -66,18 +31,18 @@ export default class EventPosition { // 2. create a week array, where each day is represented as an object with different levels, level1, level2, level3, level4 etc. // An event starts on a certain level, the first day when it occurs, and then blocks that level for the rest of its duration - const allDatesOfWeek = TimeHelper.getDatesBetweenTwoDates(weekStart, weekEnd) + const allDatesOfWeek = this.getDatesBetweenTwoDates(weekStart, weekEnd) const week: fullDayEventsWeek = allDatesOfWeek.map(d => ({ date: d })) for (const scheduleEvent of eventsWithJSDates) { for (const [dayIndex, day] of week.entries()) { - const thisDayDateString = TimeHelper.getDateStringFromDate(day.date) + const thisDayDateString = this.getDateStringFromDate(day.date) if ( // @ts-ignore - TimeHelper.getDateStringFromDate(scheduleEvent.timeJS.start) <= thisDayDateString + this.getDateStringFromDate(scheduleEvent.timeJS.start) <= thisDayDateString // @ts-ignore - && TimeHelper.getDateStringFromDate(scheduleEvent.timeJS.end) >= thisDayDateString + && this.getDateStringFromDate(scheduleEvent.timeJS.end) >= thisDayDateString ) { // 2A. Get the first free level of the day let levelToStartOn = 1 @@ -87,7 +52,7 @@ export default class EventPosition { // 2B. set the event on this day // @ts-ignore - let eventNDays = (Math.ceil((scheduleEvent.timeJS.end.getTime() - day.date.getTime()) / TimeHelper.MS_PER_DAY) + 1) // Get difference in days, plus the first day itself + let eventNDays = (Math.ceil((scheduleEvent.timeJS.end.getTime() - day.date.getTime()) / this.MS_PER_DAY) + 1) // Get difference in days, plus the first day itself const remainingDaysOfWeek = (week.length - dayIndex) if (eventNDays > remainingDaysOfWeek) eventNDays = remainingDaysOfWeek @@ -140,17 +105,17 @@ export default class EventPosition { return 0 }) - + for (const fullDayEvent of fullDayEvents) { - const { year: startYear, month: startMonth, date: startDate } = TimeHelper.getAllVariablesFromDateTimeString(fullDayEvent.time.start) - const { year: endYear, month: endMonth, date: endDate } = TimeHelper.getAllVariablesFromDateTimeString(fullDayEvent.time.end) - const allDatesOfEvent = TimeHelper.getDatesBetweenTwoDates( + const { year: startYear, month: startMonth, date: startDate } = this.getAllVariablesFromDateTimeString(fullDayEvent.time.start) + const { year: endYear, month: endMonth, date: endDate } = this.getAllVariablesFromDateTimeString(fullDayEvent.time.end) + const allDatesOfEvent = this.getDatesBetweenTwoDates( new Date(startYear, startMonth, startDate), new Date(endYear, endMonth, endDate), ) for (const date of allDatesOfEvent) { - const dateString = TimeHelper.getDateStringFromDate(date) + const dateString = this.getDateStringFromDate(date) const dateInMap = monthMap.get(dateString) if (dateInMap) monthMap.set(dateString, { diff --git a/src/helpers/Time.ts b/src/helpers/Time.ts index 1889aa41..8b638d8c 100644 --- a/src/helpers/Time.ts +++ b/src/helpers/Time.ts @@ -336,4 +336,37 @@ export default class Time { 999 ) } + + protected turnMinutesIntoPercentageOfHour(minutes: number): string { + const oneMinutePercentage = 100 / 60; + + const minutePoints = oneMinutePercentage * minutes; + + if (minutePoints < 10) return "0" + minutePoints; + + return minutePoints.toString(); + } + + /** + * Every hour between 'dayStart' and 'dayEnd' is 100, in this function referred to as 100 points + * If an event starts 30 minutes after 'dayStart', it should have 50 pointsIntoDay + * If a day consists of 4 hours (400 points), we then have to count + * (50 / 400) * 100 = 12.5 => event starts after 12.5 percent of the day + * + * Result is supposed to be a number between 0 and 100, and is used for setting the CSS- top- and height-attributes for events + * */ + getPercentageOfDayFromDateTimeString( + dateTimeString: string, + dayStart: number, + dayEnd: number + ) { + const pointsInDay = dayEnd - dayStart; + const hour = dateTimeString.substring(11, 13); + const minutes = dateTimeString.substring(14, 16); + const minutesPoints = this.turnMinutesIntoPercentageOfHour(+minutes); + const eventPoints = +(hour + minutesPoints); + const eventPointsIntoDay = eventPoints - dayStart; + + return (eventPointsIntoDay / pointsInDay) * 100; + } } diff --git a/src/typings/config.interface.ts b/src/typings/config.interface.ts index 98c1505f..f0f37eb0 100644 --- a/src/typings/config.interface.ts +++ b/src/typings/config.interface.ts @@ -65,4 +65,5 @@ export interface configInterface { isDisabled?: boolean; isCustom?: boolean; } + showCurrentTime?: boolean; } diff --git a/tests/unit/components/week/Week.test.ts b/tests/unit/components/week/Week.test.ts index b9dc02ea..fdb5c384 100644 --- a/tests/unit/components/week/Week.test.ts +++ b/tests/unit/components/week/Week.test.ts @@ -73,4 +73,26 @@ describe('Week.vue', () => { const days = wrapper.findAll('.calendar-week__day') expect(days).toHaveLength(5) }) -}) \ No newline at end of file + + test('Not showing the currentTimeLine', () => { + expect(() => wrapper.get('.current-time-line')).toThrow() + }) + + test('Showing the currentTimeLine', async () => { + wrapper = week({ + props: { + config: { showCurrentTime: true }, + time: new Time('sunday', 'en-US'), + period: { + selectedDate: new Date(), + start: new Date(), + end: new Date() + }, + nDays: 5, + } + }) + + await wrapper.vm.setDays() + expect(wrapper.get('.current-time-line')) + }) +})