npx-calendar
Version:
A customizable and feature-rich calendar component for Angular applications.
481 lines • 60.5 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Pipe, Input, ViewChild, Component } from '@angular/core';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
class NpxCalendarService {
constructor() { }
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: NpxCalendarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: NpxCalendarService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: NpxCalendarService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [] });
class StyleObjectPipe {
transform(value) {
const styles = {};
if (!value) {
return styles;
}
const styleRules = value.split(';');
styleRules.forEach(rule => {
const [property, value2] = rule.split(':');
if (property && value2) {
styles[property.trim()] = value2.trim();
}
});
return styles;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: StyleObjectPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.0", ngImport: i0, type: StyleObjectPipe, isStandalone: true, name: "styleObject" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: StyleObjectPipe, decorators: [{
type: Pipe,
args: [{
name: 'styleObject'
}]
}] });
class FilterEventsPipe {
transform(events, targetTime) {
return events.filter(event => event.time === targetTime);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: FilterEventsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.0", ngImport: i0, type: FilterEventsPipe, isStandalone: true, name: "filterEvents" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: FilterEventsPipe, decorators: [{
type: Pipe,
args: [{ name: 'filterEvents' }]
}] });
class CalendarComponent {
elementRef;
popover;
isPopoverOpen = false;
popoverDay = null;
daysOfTheWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
monthsOfTheYear = [
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
];
hours = [];
currentWeekDays = [];
years = [];
viewOptions = ["Month", "Work week", "Week"];
daysInMonth = [];
currentMonth = 0;
currentYear = 0;
currentDay = 0;
currentMonthName = '';
currentYearName = '';
currentDate = '';
firstDayOfWeek = 0;
isOpen = false;
isMonthPickerOpen = false;
isFilterOpen = false;
selectedView = 0;
isOffCanvasOpen = false;
weekDay = null;
selectedDay = 0;
selectedDayEvents = [];
showYearPicker = false;
selectedEventDetail = {
title: '',
time: '',
description: '',
start_time: '',
end_time: '',
style: '',
attendees: [],
location: '',
locationLink: '',
category: '',
categoryColor: ''
};
calendar_events = [];
calendar_themes = {
show_header: true,
show_arrow: true,
show_month_picker: true,
show_calendar_view_filter: true
};
constructor(elementRef) {
this.elementRef = elementRef;
this.selectedEventDetail.categoryColor = '#ff0000';
this.years = [];
for (let i = 2020; i <= new Date().getFullYear() + 10; i++) {
this.years.push(i);
}
}
/**
* Initialize the component.
*
* Gets the current month and year, then calls
* {@link generateCalender} to generate the calender.
*/
ngOnInit() {
this.currentMonth = new Date().getMonth();
this.currentYear = new Date().getFullYear();
this.generateCalender();
}
/**
* Generate the calender.
*
* This method generates the days of the month and the first day of the week.
* It also sets the current date.
*
* It is called on component initialization.
*/
generateCalender() {
this.currentDay = new Date().getDate();
this.currentMonthName = this.monthsOfTheYear[this.currentMonth];
this.currentYearName = this.currentYear.toString();
this.currentDate = this.currentDay + ' ' + this.currentMonthName + ' ' + this.currentYearName;
this.firstDayOfWeek = new Date(this.currentYear, this.currentMonth, 1).getDay();
const daysInMonth = new Date(this.currentYear, this.currentMonth + 1, 0).getDate();
this.daysInMonth = [];
for (let i = 1; i <= daysInMonth; i++) {
this.daysInMonth.push(i);
}
}
handleCalenderEvent(day) {
console.log(day);
}
/**
* Handle the next month button click event.
*
* This will add one to the current month, taking into account the wrap-around
* from December to January.
*
* If the current month is December (11), we should increment the current year.
*/
handleNextMonth() {
if (this.currentMonth === 11) {
this.currentYear++;
this.currentMonth = 0;
}
else {
this.currentMonth++;
}
this.generateCalender();
}
/**
* Handle the previous month button click event.
*
* This will subtract one from the current month, taking into account the wrap-around
* from December to January.
*
* If the current month is January (0), we should decrement the current year.
*/
handlePrevMonth() {
this.currentMonth = (this.currentMonth - 1 + 12) % 12;
if (this.currentMonth === 11)
this.currentYear--;
this.generateCalender();
}
/**
* Toggle the date picker dropdown.
*
* This method is called when the current month button is clicked. It toggles the
* {@link isOpen} property, which determines whether the date picker dropdown
* is visible or not.
*/
toggleDatePicker() {
this.isOpen = !this.isOpen;
}
/**
* Toggle the month picker dropdown.
*
* This method is called when the month button is clicked. It toggles the
* {@link isMonthPickerOpen} property, which determines whether the month
* picker dropdown is visible or not.
*/
toggleMonthPicker() {
this.isMonthPickerOpen = !this.isMonthPickerOpen;
}
/**
* Toggle the filter dropdown.
*
* This method is called when the filter button is clicked. It toggles the
* {@link isFilterOpen} property, which determines whether the filter dropdown
* is visible or not.
*/
toggleFilter() {
this.isFilterOpen = !this.isFilterOpen;
}
/**
* Handles the month change event.
*
* This method is called when a new month is selected from the month dropdown.
* It is called automatically whenever the user selects a new month from the
* month dropdown.
*
* The purpose of this method is to update the current month and regenerate
* the calender. This is necessary because the calender is rendered based on the
* current month and year, so if the user changes the month, we need to update
* the calender to reflect the new month.
*
* The method takes a single argument, `month`, which is the new month to be
* selected (0-11, January-December).
*
* The method does the following:
* 1. It updates the current month by setting the `currentMonth` property to
* the new month.
* 2. It closes the month dropdown by setting the `isOpen` property to false.
* 3. It regenerates the calender by calling the `generateCalender()` method.
*
* @param month The new month (0-11, January-December).
*/
onMonthChange(month) {
this.currentMonth = month;
this.isOpen = false;
this.generateCalender();
}
/************* ✨ Codeium Command 🌟 *************/
/**
* Handles the year change event.
*
* This method is called when a new year is selected from the year dropdown.
* It updates the current year and regenerates the calender by calling
* {@link generateCalender}.
*
* @param year The new year.
*/
onYearChange(year) {
this.currentYear = year;
this.isOpen = false;
this.generateCalender();
}
/****** a23a8126-489d-4240-8c98-4a4c397bedb5 *******/
/**
* Open the off-canvas menu.
*
* This method is called when a day is clicked in the calendar. It will open the
* off-canvas menu and set the week day label to the name of the day of the week
* of the selected date.
*
* @param day The day of the month that was clicked (1-31).
* @param event The list of events associated with the day that was clicked.
*/
openOffCanvas(day, event) {
this.selectedDay = day;
const date = new Date(this.currentYear, this.currentMonth, day);
const dayOfWeek = date.getDay();
this.weekDay = this.daysOfTheWeek[dayOfWeek];
this.selectedDayEvents = event;
this.isOffCanvasOpen = !this.isOffCanvasOpen;
this.isPopoverOpen = false;
}
/**
* Close the off-canvas menu.
*
* This method is called when the close button is clicked in the off-canvas
* menu. It sets the {@link isOffCanvasOpen} property to false, which will
* hide the off-canvas menu.
*/
closeOffCanvas() {
this.isOffCanvasOpen = false;
}
/**
* Opens the popover that displays the events for the selected day.
*
* This method is called when a day is clicked in the calendar. It will open the
* popover and position it at the location of the click event.
*
* @param event The mouse event that triggered this method.
* @param day The day of the month that was clicked (1-31).
*/
openPopover(event, day, eventDetail) {
this.selectedEventDetail = eventDetail;
this.selectedDay = day;
const date = new Date(this.currentYear, this.currentMonth, day);
const dayOfWeek = date.getDay();
this.weekDay = this.daysOfTheWeek[dayOfWeek];
this.isPopoverOpen = true;
this.popoverDay = day;
this.closeOffCanvas();
this.positionPopover(event);
}
/**
* Position the popover at the location of the click event.
*
* This function is called by the openPopover method, which is called when a day
* is clicked in the calendar. It will position the popover at the location of the
* click event.
*
* This function will wait for the popover to render before positioning it. This
* is done with setTimeout and a 0ms delay. This ensures that the popover has
* rendered and its width and height are available.
*
* It will check if the popover is too close to the edge of the screen and if so,
* will reposition it so it doesn't go off the screen.
*
* @param event The mouse event that triggered this method.
*/
positionPopover(event) {
setTimeout(() => {
const popoverEl = this.popover.nativeElement;
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const popoverRect = popoverEl.getBoundingClientRect();
let left = event.clientX;
let top = event.clientY + 10; // Default below cursor
if (left + popoverRect.width > viewportWidth) {
left = viewportWidth - popoverRect.width - 10;
}
if (top + popoverRect.height > viewportHeight) {
top = event.clientY - popoverRect.height - 10;
}
popoverEl.style.left = `${left}px`;
popoverEl.style.top = `${top + 5}px`;
}, 0);
}
/**
* Called when the user changes the calendar view.
*
* This function is called when the user changes the calendar view by clicking on
* one of the view options in the top right corner of the calendar. The view
* options are "Month", "Week", and "Day".
*
* When this function is called, it will update the selectedView property to the
* index of the view that was selected.
*
* @param view The index of the view that was selected (0, 1, or 2).
*/
onViewChange(view) {
this.selectedView = view;
this.getCurrentWeek(false);
}
/**
* Toggle the year picker dropdown.
*
* This function is called when the year button is clicked. It will toggle the
* {@link showYearPicker} property, which determines whether the year picker
* dropdown is visible or not.
*
* Also, it will stop the event from propagating up the DOM tree, so that the
* event doesn't bubble up and cause the calendar to be closed.
*
* @param event The mouse event that triggered this method.
*/
toggleYearPicker(event) {
this.showYearPicker = !this.showYearPicker;
event.stopPropagation();
}
/**
* Handles the previous year button click event.
*
* This method is called when the previous year button is clicked. It will
* decrement the current year by one and regenerate the calender by calling
* {@link generateCalender}.
*
* It will also stop the event from propagating up the DOM tree, so that the
* event doesn't bubble up and cause the calendar to be closed.
*
* @param event The mouse event that triggered this method.
*/
handlePrevYear(event) {
event.stopPropagation();
this.currentYear--;
this.generateCalender();
}
/**
* Handles the next year button click event.
*
* This method is called when the next year button is clicked. It will
* increment the current year by one and regenerate the calender by calling
* {@link generateCalender}.
*
* @param event The mouse event that triggered this method.
*/
handleNextYear(event) {
event.stopPropagation();
this.currentYear++;
this.generateCalender();
}
getCurrentWeek(startFromMonday = false) {
this.hours = [];
this.currentWeekDays = [];
this.daysOfTheWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const today = new Date();
const dayOfWeek = today.getDay(); // 0 (Sunday) to 6 (Saturday)
// Adjust for Monday as the start of the week if needed
const weekStart = new Date(today);
weekStart.setDate(today.getDate() - dayOfWeek + (startFromMonday ? (dayOfWeek === 0 ? -6 : 1) : 0));
const weekDates = [];
for (let i = 0; i < 7; i++) {
const date = new Date(weekStart);
date.setDate(weekStart.getDate() + i);
weekDates.push(date.getDate()); // Day of the month as 1, 2, 3, etc.
}
this.hours = Array.from({ length: 24 }, (_, i) => {
const suffix = i < 12 ? 'AM' : 'PM';
const hour = i % 12 === 0 ? 12 : i % 12;
return `${hour} ${suffix}`;
});
console.log("weekDates", weekDates);
if (this.viewOptions[this.selectedView] === 'Work week') {
this.currentWeekDays = weekDates.slice(1, weekDates.length - 1);
this.daysOfTheWeek = this.daysOfTheWeek.slice(1, this.daysOfTheWeek.length - 1);
}
else {
this.currentWeekDays = weekDates;
}
console.log(this.currentWeekDays, this.hours);
}
getEventHour(eventTime, extraMinutes) {
return eventTime.split(" ")[0] + ":" + extraMinutes + ' ' + eventTime.split(" ")[1]; // Extract hour + AM/PM
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: CalendarComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.0", type: CalendarComponent, isStandalone: true, selector: "lib-calendar", inputs: { calendar_events: "calendar_events", calendar_themes: "calendar_themes" }, viewQueries: [{ propertyName: "popover", first: true, predicate: ["popover"], descendants: true }], ngImport: i0, template: "<!-- Days of the week header (Sun, Mon, Tue, etc.) -->\n<div class=\"calendar-container\">\n <div class=\"header\" *ngIf=\"calendar_themes.show_header\" [ngStyle]=\"calendar_themes.header_style ?? ''| styleObject\">\n <div class=\"left-content\" style=\"display: flex; align-items: center;\">\n <div *ngIf=\"calendar_themes.show_arrow\">\n <span class=\"arrow-prev\" (click)=\"handlePrevMonth()\" [ngStyle]=\"calendar_themes.arrow_style ?? ''| styleObject\"><</span>\n <span class=\"arrow-next\" (click)=\"handleNextMonth()\" [ngStyle]=\"calendar_themes.arrow_style ?? ''| styleObject\">></span>\n </div>\n\n <div class=\"datepicker current-month\" (click)=\"toggleDatePicker()\" [ngClass]=\"{ 'active': isOpen }\">\n <div class=\"datepicker-header\">\n <span>{{ currentMonthName }} {{ currentYear }} ▼</span>\n </div>\n\n <div class=\"month-grid\" *ngIf=\"calendar_themes.show_month_picker\">\n <div class=\"arrow\"></div>\n <div class=\"year-container\">\n <div class=\"year\" (click)=\"toggleYearPicker($event)\">{{ currentYear }}{{ showYearPicker ? '-' + years[years.length - 1] : '' }}</div>\n <div class=\"year-filter-arrow\" style=\"margin: 8px;\">\n <span class=\"year-arrow\" (click)=\"handlePrevYear($event)\">↑</span>\n <span class=\"year-arrow\" style=\"margin-left:2px ;\" (click)=\"handleNextYear($event)\">↓</span>\n </div>\n </div>\n <div *ngFor=\"let month of monthsOfTheYear and let index = index\">\n <div *ngIf=\"!showYearPicker\" class=\"month\" [ngClass]=\"{ 'selected': index === currentMonth }\" (click)=\"onMonthChange(index)\">\n {{ month }}\n </div>\n </div>\n\n <div *ngFor=\"let year of years and let index = index\" style=\"min-width: 120px;\">\n <div *ngIf=\"showYearPicker\" class=\"month\" [ngClass]=\"{ 'selected': index === currentMonth }\" (click)=\"onYearChange(year)\">\n {{ year }}\n </div>\n </div>\n\n </div>\n </div>\n </div>\n\n <div class=\"right-content\" style=\"display: flex; align-items: center;\" *ngIf=\"calendar_themes.show_calendar_view_filter\">\n <div class=\"datepicker month-dropdown\" (click)=\"toggleMonthPicker()\" [ngClass]=\"{ 'active': isMonthPickerOpen }\">\n <div class=\"datepicker-header\">\n <span>{{viewOptions[selectedView]}} ▼</span>\n </div>\n\n <div class=\"view-options-grid\">\n <div class=\"view-arrow\"></div>\n <div *ngFor=\"let view of viewOptions and let index = index\" class=\"month\" [ngClass]=\"{ 'selected': index === selectedView }\" (click)=\"onViewChange(index)\">\n {{ view }}\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Calendar Weekdays -->\n <div class=\"calendar-weekdays\" *ngIf=\"viewOptions[selectedView] === 'Month'\">\n <span *ngFor=\"let day of daysOfTheWeek\" class=\"calendar-weekday\">{{ day }}</span>\n </div>\n <div [ngClass]=\"viewOptions[selectedView] === 'Work week' ? 'calendar-working-weekdays' : 'calendar-weekdays'\" *ngIf=\"viewOptions[selectedView] === 'Work week' || viewOptions[selectedView] === 'Week'\">\n <span *ngFor=\"let day of daysOfTheWeek and let index = index\" class=\"calendar-weekday\" [class.current-day-in-weekdays]=\"currentWeekDays[index] === currentDay\">\n <div>\n {{ day }}\n </div>\n {{currentWeekDays[index]}}\n </span>\n </div>\n\n <!-- Calendar Days -->\n <div class=\"calendar-days\" *ngIf=\"viewOptions[selectedView] === 'Month'\">\n <!-- Blank spaces before 1st day -->\n <div *ngFor=\"let blank of [].constructor(firstDayOfWeek)\">\n <div></div>\n </div>\n\n <!-- Calendar Days -->\n <div *ngFor=\"let day of daysInMonth\" class=\"calendar-day\" [class.current-day]=\"day === currentDay\" (click)=\"handleCalenderEvent(day)\">\n <div style=\"font-weight: bolder;\">\n {{ day }}\n </div>\n <div *ngFor=\"let eventDetails of calendar_events\">\n <div *ngIf=\"eventDetails.month - 1 === currentMonth\">\n <div *ngFor=\"let list of eventDetails.list\">\n <div *ngIf=\"list.day === day\">\n <div *ngFor=\"let event of list.events and let index = index\">\n <span class=\"events\" [ngStyle]=\"event.style | styleObject\" *ngIf=\"index < 2\" #trigger (click)=\"openPopover($event, day, event)()\">\n {{ event.title }} - {{ event.time }}\n </span>\n <div class=\"extra-events\" *ngIf=\"index===2\" (click)=\"openOffCanvas(day, list.events)\">+{{ list.events.length - 2 }}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"calendar-days\" style=\"display: flex; margin: 0;\" *ngIf=\"viewOptions[selectedView] === 'Work week' || viewOptions[selectedView] === 'Week'\">\n <div [ngClass]=\"viewOptions[selectedView] === 'Work week' ? 'calendar-week-days' : 'calendar-weekend-days'\" style=\"border: 1px solid #000;\">\n <div class=\"calendar-week-day\" *ngFor=\"let day of currentWeekDays; let index = index\" [class.current-day-in-weekdays]=\"currentWeekDays[index] === currentDay\">\n <div class=\"time-slot\" *ngFor=\"let hour of hours\">\n <div style=\"height: 100%;\" *ngFor=\"let eventDetails of calendar_events\">\n\n\n <ng-container *ngIf=\"eventDetails.month - 1 === currentMonth\">\n <div style=\"height: 50%; padding: 5px 0 2px 4px; width: 100%; overflow-y: auto;\">\n <div *ngIf=\"index === 0\">\n {{ hour }}\n </div>\n\n <div *ngFor=\"let list of eventDetails.list\">\n <ng-container *ngIf=\"list.day === day\">\n <ng-container *ngIf=\"(list.events | filterEvents:getEventHour(hour, '00')) as filteredEvents\">\n <ng-container *ngFor=\"let event of filteredEvents.slice(0, 2)\">\n <span class=\"week-events\" [ngStyle]=\"event.style | styleObject\" #trigger (click)=\"openPopover($event, day, event)\">\n {{ event.title }} - {{ event.time }}\n </span>\n </ng-container>\n <div *ngIf=\"filteredEvents.length > 2\" (click)=\"openOffCanvas(day, list.events)\" class=\"extra-week-events\">+{{ filteredEvents.length - 2 }}</div>\n </ng-container>\n </ng-container>\n </div>\n\n </div>\n <div style=\"border-top: 1px solid rgba(128, 128, 128, 0.486); min-height: 50%; padding: 5px 0 2px 4px; width: 100%; overflow-y: auto;\">\n\n <div *ngFor=\"let list of eventDetails.list\">\n <ng-container *ngIf=\"list.day === day\">\n <ng-container *ngIf=\"(list.events | filterEvents:getEventHour(hour, '30')) as filteredEvents\">\n <ng-container *ngFor=\"let event of filteredEvents.slice(0, 2)\">\n <span class=\"week-events\" [ngStyle]=\"event.style | styleObject\" #trigger (click)=\"openPopover($event, day, event)\">\n {{ event.title }} - {{ event.time }}\n </span>\n </ng-container>\n <div *ngIf=\"filteredEvents.length > 2\" (click)=\"openOffCanvas(day, list.events)\" class=\"extra-week-events\">+{{ filteredEvents.length - 2 }}</div>\n </ng-container>\n </ng-container>\n </div>\n\n </div>\n </ng-container>\n\n </div>\n </div>\n\n </div>\n </div>\n </div>\n\n\n</div>\n\n<div class=\"off-canvas\" [class.open]=\"isOffCanvasOpen\">\n <div class=\"off-canvas-header\">\n <h3>{{ weekDay?.slice(0, 3) }}, {{ currentMonthName.slice(0, 3) }} {{ selectedDay }}</h3>\n <button class=\"close-btn\" (click)=\"closeOffCanvas()\">\u00D7</button>\n </div>\n\n <div class=\"off-canvas-content\">\n <div *ngIf=\"selectedDayEvents.length; else noEvents\">\n <div *ngFor=\"let event of selectedDayEvents\" class=\"event-card\" [ngStyle]=\"event.style | styleObject\">\n <div class=\"event-header\">\n <h3 class=\"event-title\">{{ event.title }}</h3>\n </div>\n\n <div class=\"event-category\" [ngStyle]=\"{'background': event.categoryColor}\">\n {{ event.category || 'General' }}\n </div>\n\n <div class=\"popover-section\">\n <i class=\"icon-calendar\"></i>\n <p>{{ selectedDay }} {{ currentMonthName }} {{ weekDay?.slice(0, 3) }},\n {{ selectedEventDetail.start_time }} - {{ selectedEventDetail.end_time }}</p>\n </div>\n\n <div class=\"event-section\">\n <i class=\"icon-location\"></i>\n <p>\n {{ selectedEventDetail.location}}\n </p>\n </div>\n\n <div class=\"event-section attendees\" *ngIf=\"event.attendees?.length\">\n <i class=\"icon-users\"></i>\n <div class=\"attendees-list\">\n <div class=\"attendee\" *ngFor=\"let attendee of event.attendees.slice(0, 3)\">\n <img [src]=\"attendee.image\" [alt]=\"attendee.name\">\n <span class=\"attendee-name\">{{ attendee.name }}</span>\n </div>\n <span *ngIf=\"event.attendees.length > 3\" class=\"more-attendees\">\n +{{ event.attendees.length - 3 }} more\n </span>\n </div>\n </div>\n\n <div class=\"event-section\">\n <i class=\"icon-info\"></i>\n <p>{{ event.description }}</p>\n </div>\n </div>\n </div>\n\n <ng-template #noEvents>\n <p class=\"no-events\">No events scheduled for this day.</p>\n </ng-template>\n </div>\n</div>\n\n\n\n\n\n<div #popover class=\"popover-container\" [ngClass]=\"{ 'show': isPopoverOpen }\" [ngStyle]=\"selectedEventDetail.style | styleObject\">\n <div class=\"popover-content\">\n <h3 class=\"popover-title\">\n {{ selectedEventDetail.title }}\n </h3>\n\n <div class=\"event-category\" [ngStyle]=\"{'background': selectedEventDetail.categoryColor}\">\n {{ selectedEventDetail.category || 'General' }}\n </div>\n\n <div class=\"popover-section\">\n <i class=\"icon-calendar\"></i>\n <p>{{ selectedDay }} {{ currentMonthName }} {{ weekDay?.slice(0, 3) }},\n {{ selectedEventDetail.start_time }} - {{ selectedEventDetail.end_time }}</p>\n </div>\n\n <div class=\"event-section\" *ngIf=\"selectedEventDetail.location\">\n <i class=\"icon-location\"></i>\n <p>\n {{ selectedEventDetail.location }}\n </p>\n </div>\n\n <div class=\"event-section attendees\" *ngIf=\"selectedEventDetail.attendees?.length\">\n <i class=\"icon-users\"></i>\n <div class=\"attendees-list\">\n <div class=\"attendee\" *ngFor=\"let attendee of selectedEventDetail.attendees.slice(0, 3)\">\n <img [src]=\"attendee.image\" [alt]=\"attendee.name\">\n <span class=\"attendee-name\">{{ attendee.name }}</span>\n </div>\n <span *ngIf=\"selectedEventDetail.attendees.length > 3\" class=\"more-attendees\">\n +{{ selectedEventDetail.attendees.length - 3 }} more\n </span>\n </div>\n </div>\n\n <div class=\"popover-section\">\n <i class=\"icon-info\"></i>\n <p>{{ selectedEventDetail.description }}</p>\n </div>\n\n <button class=\"close-btn\" (click)=\"isPopoverOpen = false\">\u2716</button>\n </div>\n</div>\n", styles: [".calendar-container{display:flex;flex-direction:column;align-items:center;width:100%;margin:auto;padding:0 10px;box-sizing:border-box;min-height:100vh}.calendar-weekdays,.calendar-days{display:grid;grid-template-columns:repeat(7,minmax(50px,1fr));gap:5px;padding:10px;border:1px solid #000;width:100%}.calendar-working-weekdays{display:grid;grid-template-columns:repeat(5,minmax(50px,1fr));gap:5px;padding:10px;border:1px solid #000;width:100%}.calendar-weekday,.calendar-day{text-align:center;padding:8px;border-radius:5px;min-height:20px;cursor:pointer;border:1px solid #000;font-weight:bolder;font-size:14px}@media (max-width: 1024px){.calendar-weekdays,.calendar-days{grid-template-columns:repeat(7,minmax(40px,1fr))}.calendar-weekday,.calendar-day{font-size:12px;padding:5px}}@media (max-width: 768px){.calendar-weekdays,.calendar-days{grid-template-columns:repeat(7,minmax(35px,1fr))}.calendar-weekday,.calendar-day{font-size:11px;padding:4px}}@media (max-width: 480px){.calendar-weekdays,.calendar-days{grid-template-columns:repeat(7,minmax(30px,1fr))}.calendar-weekday,.calendar-day{font-size:10px;padding:3px}}.calendar-day{text-align:left;padding:10px;background-color:transparent;border-radius:5px;min-height:95px;align-content:flex-start;cursor:pointer;border:1px solid #000}.time-slot{height:50px;border-bottom:1px solid #333}.blank{background-color:transparent}.current-day{background-color:#0000008e;color:#fff;font-weight:700;border-radius:5px;align-content:center;cursor:pointer;border:1px solid #000;align-content:flex-start}.current-day-in-weekdays{background-color:#00000029;color:#fff;font-weight:700;align-content:center;cursor:pointer;align-content:flex-start}.header{padding:10px;border:1px solid #000;display:flex;justify-content:space-between;width:100%}.left-content,.right-content{padding:10px}.arrow-prev,.arrow-next,.current-month{font-weight:700;border:2px solid #000;padding:10px;border-radius:5px;cursor:pointer;background-color:#000;color:#fff}.arrow-prev,.month-dropdown,.arrow-next{margin-right:2px}.current-month{font-weight:700;padding:10px}.month-dropdown,.filter-dropdown{font-weight:700;border:2px solid #000;padding:10px;border-radius:5px;cursor:pointer;background-color:#000;color:#fff}.datepicker{background:#000;padding:10px;border-radius:8px;max-width:200px;position:relative}.datepicker-header{display:flex;justify-content:space-between;align-items:center;cursor:pointer;border-radius:6px}.datepicker-header span{font-size:14px}.month-grid{display:none;grid-template-columns:repeat(3,1fr);gap:3px 5px;padding:10px 5px;position:absolute;top:50px;left:0;background:#000;border-radius:8px;width:100%;box-shadow:0 4px 6px #0000004d;z-index:1}.year-container{grid-column-start:1;grid-column-end:4;padding:5px;display:grid;grid-template-columns:repeat(2,60%)}.year{text-align:center;padding:5px;border-radius:6px;cursor:pointer;color:#fff;border:1px solid #fff}.year-filter-arrow{text-align:center}.year-arrow{padding:5px;border:1px solid #fff;border-radius:6px;cursor:pointer;color:#fff;background:#000}.view-options-grid{display:none;grid-template-columns:repeat(1,1fr);gap:8px;padding:10px 5px;position:absolute;top:50px;left:0;background:#000;border-radius:8px;width:100%;z-index:1}.month{text-align:center;padding:5px;border-radius:6px;cursor:pointer;color:#fff;border:1px solid #fff}.month:hover,.selected{background:#fff;color:#000}.datepicker.active .month-grid,.datepicker.active .view-options-grid{display:grid;width:-webkit-max-content}.arrow{position:absolute;top:-8px;left:10%;transform:translate(-50%);width:0;height:0;border-left:8px solid transparent;border-right:8px solid transparent;border-bottom:8px solid #0d0d0d}.view-arrow,.view-arrow-popover{position:absolute;top:-8px;left:30%;transform:translate(-50%);width:0;height:0;border-left:8px solid transparent;border-right:8px solid transparent;border-bottom:8px solid #0d0d0d}.view-arrow-popover{border-bottom:8px solid #fff!important}.events{border:1px dotted #000;padding:2px;border-radius:5px;margin:5px 0;font-size:small;overflow:hidden;min-height:fit-content;white-space:nowrap;text-overflow:ellipsis;display:block;width:100%}.extra-events{background-color:#000;color:#fff;text-align:center;border-radius:5px;padding:2px;margin:5px 0;font-size:small;width:100%}.off-canvas{display:none;position:fixed;top:0;right:-320px;width:300px;height:100vh;background:#000c;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);color:#fff;padding:20px;transition:right .3s ease-in-out;box-shadow:-5px 0 10px #0000004d;overflow-y:auto}.off-canvas.open{display:block;right:0}.off-canvas-header{display:flex;justify-content:space-between;align-items:center;border-bottom:2px solid rgba(255,255,255,.2);padding-bottom:10px}.off-canvas-header h3{font-size:18px;font-weight:700}.close-btn{background:none;border:none;color:#fff;font-size:20px;cursor:pointer;opacity:.8;transition:opacity .2s ease}.off-canvas-content{margin-top:10px}.event-card{background:#ffffff1a;border-radius:8px;padding:12px;margin-bottom:10px;transition:transform .2s ease-in-out}.event-card:hover{transform:scale(1.05)}.event-header{display:flex;align-items:center;gap:12px}.event-icon img{width:40px;height:40px;border-radius:50%}.event-icon i{font-size:24px;color:#fff}.event-title{font-size:16px;font-weight:700}.event-category{padding:4px 10px;border-radius:5px;font-size:12px;text-align:center;color:#fff;margin:8px 0}.event-section{display:flex;align-items:center;gap:8px;font-size:14px}.icon-calendar:before{content:\"\\1f4c5\"}.icon-location:before{content:\"\\1f4cd\"}.icon-users:before{content:\"\\1f465\"}.icon-timer:before{content:\"\\23f3\"}.event-actions{display:flex;justify-content:space-between;margin-top:10px}.btn{border:none;padding:8px 10px;border-radius:5px;cursor:pointer;font-size:12px}.btn-primary{background:#4caf50;color:#fff}.btn-secondary{background:#2196f3;color:#fff}.btn-edit{background:#ffc107;color:#fff}.btn-delete{background:#f44336;color:#fff}.btn:hover{opacity:.8}.no-events{text-align:center;font-style:italic;opacity:.7}.attendees{display:flex;align-items:center;gap:8px}.attendees-list{display:flex;flex-wrap:wrap;gap:8px}.attendee{display:flex;align-items:center;gap:6px;background:#ffffff1a;padding:4px 8px;border-radius:5px}.attendee img{width:28px;height:28px;border-radius:50%;border:2px solid white}.attendee-name{font-size:14px;color:#fff}.more-attendees{font-size:14px;color:#ddd;background:#fff3;padding:4px 8px;border-radius:5px}.popover-container{display:none;position:absolute;background:#ffffff1a;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.2);border-radius:12px;padding:16px;width:250px;box-shadow:0 8px 16px #0003;opacity:0;transform:scale(.95);pointer-events:none;transition:opacity .3s ease-in-out,visibility .3s ease-in-out}.popover-container.show{visibility:visible;display:block;opacity:1;transform:scale(1);pointer-events:auto}.popover-content{display:flex;flex-direction:column;gap:10px;color:#fff}.popover-title{font-size:18px;font-weight:700;padding-bottom:8px;border-bottom:2px solid rgba(255,255,255,.3);text-align:center}.popover-section{display:flex;align-items:center;gap:8px;font-size:14px}.icon-calendar:before,.icon-info:before{content:\"\\1f4c5\";font-size:16px}.icon-info:before{content:\"\\2139\\fe0f\"}.close-btn{position:absolute;top:8px;left:88%;background:none;border:none;color:#fff;font-size:16px;cursor:pointer;opacity:.7;transition:opacity .2s ease}.close-btn:hover{opacity:1}.time-column{display:flex;flex-direction:column;align-items:flex-end;text-align:right;font-weight:700}.calendar-week-days{display:grid;grid-template-columns:repeat(5,1fr);border-left:1px solid #444;height:78vh;overflow-y:scroll;overflow-x:auto;width:100%}.calendar-weekend-days{display:grid;grid-template-columns:repeat(7,1fr);border-left:1px solid #444;height:78vh;overflow-y:scroll;overflow-x:auto;width:100%}.calendar-week-day{display:grid;grid-template-rows:repeat(24,120px);border-right:1px solid #444;width:100%}.time-slot{border-bottom:1px solid #333;height:120px;padding:5px 0;width:100%;box-sizing:border-box;position:relative}.time-divider{position:absolute;width:100%;border-bottom:1px solid #333;left:0}.week-events{border:1px dotted #000;border-radius:5px;margin:5px 0;font-size:small;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;display:block;width:92%;cursor:pointer}.extra-week-events{background-color:#000;color:#fff;text-align:center;border-radius:5px;padding:2px;margin:5px 0;font-size:small;width:92%;cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: StyleObjectPipe, name: "styleObject" }, { kind: "pipe", type: FilterEventsPipe, name: "filterEvents" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: CalendarComponent, decorators: [{
type: Component,
args: [{ selector: 'lib-calendar', imports: [CommonModule, StyleObjectPipe, FilterEventsPipe], template: "<!-- Days of the week header (Sun, Mon, Tue, etc.) -->\n<div class=\"calendar-container\">\n <div class=\"header\" *ngIf=\"calendar_themes.show_header\" [ngStyle]=\"calendar_themes.header_style ?? ''| styleObject\">\n <div class=\"left-content\" style=\"display: flex; align-items: center;\">\n <div *ngIf=\"calendar_themes.show_arrow\">\n <span class=\"arrow-prev\" (click)=\"handlePrevMonth()\" [ngStyle]=\"calendar_themes.arrow_style ?? ''| styleObject\"><</span>\n <span class=\"arrow-next\" (click)=\"handleNextMonth()\" [ngStyle]=\"calendar_themes.arrow_style ?? ''| styleObject\">></span>\n </div>\n\n <div class=\"datepicker current-month\" (click)=\"toggleDatePicker()\" [ngClass]=\"{ 'active': isOpen }\">\n <div class=\"datepicker-header\">\n <span>{{ currentMonthName }} {{ currentYear }} ▼</span>\n </div>\n\n <div class=\"month-grid\" *ngIf=\"calendar_themes.show_month_picker\">\n <div class=\"arrow\"></div>\n <div class=\"year-container\">\n <div class=\"year\" (click)=\"toggleYearPicker($event)\">{{ currentYear }}{{ showYearPicker ? '-' + years[years.length - 1] : '' }}</div>\n <div class=\"year-filter-arrow\" style=\"margin: 8px;\">\n <span class=\"year-arrow\" (click)=\"handlePrevYear($event)\">↑</span>\n <span class=\"year-arrow\" style=\"margin-left:2px ;\" (click)=\"handleNextYear($event)\">↓</span>\n </div>\n </div>\n <div *ngFor=\"let month of monthsOfTheYear and let index = index\">\n <div *ngIf=\"!showYearPicker\" class=\"month\" [ngClass]=\"{ 'selected': index === currentMonth }\" (click)=\"onMonthChange(index)\">\n {{ month }}\n </div>\n </div>\n\n <div *ngFor=\"let year of years and let index = index\" style=\"min-width: 120px;\">\n <div *ngIf=\"showYearPicker\" class=\"month\" [ngClass]=\"{ 'selected': index === currentMonth }\" (click)=\"onYearChange(year)\">\n {{ year }}\n </div>\n </div>\n\n </div>\n </div>\n </div>\n\n <div class=\"right-content\" style=\"display: flex; align-items: center;\" *ngIf=\"calendar_themes.show_calendar_view_filter\">\n <div class=\"datepicker month-dropdown\" (click)=\"toggleMonthPicker()\" [ngClass]=\"{ 'active': isMonthPickerOpen }\">\n <div class=\"datepicker-header\">\n <span>{{viewOptions[selectedView]}} ▼</span>\n </div>\n\n <div class=\"view-options-grid\">\n <div class=\"view-arrow\"></div>\n <div *ngFor=\"let view of viewOptions and let index = index\" class=\"month\" [ngClass]=\"{ 'selected': index === selectedView }\" (click)=\"onViewChange(index)\">\n {{ view }}\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Calendar Weekdays -->\n <div class=\"calendar-weekdays\" *ngIf=\"viewOptions[selectedView] === 'Month'\">\n <span *ngFor=\"let day of daysOfTheWeek\" class=\"calendar-weekday\">{{ day }}</span>\n </div>\n <div [ngClass]=\"viewOptions[selectedView] === 'Work week' ? 'calendar-working-weekdays' : 'calendar-weekdays'\" *ngIf=\"viewOptions[selectedView] === 'Work week' || viewOptions[selectedView] === 'Week'\">\n <span *ngFor=\"let day of daysOfTheWeek and let index = index\" class=\"calendar-weekday\" [class.current-day-in-weekdays]=\"currentWeekDays[index] === currentDay\">\n <div>\n {{ day }}\n </div>\n {{currentWeekDays[index]}}\n </span>\n </div>\n\n <!-- Calendar Days -->\n <div class=\"calendar-days\" *ngIf=\"viewOptions[selectedView] === 'Month'\">\n <!-- Blank spaces before 1st day -->\n <div *ngFor=\"let blank of [].constructor(firstDayOfWeek)\">\n <div></div>\n </div>\n\n <!-- Calendar Days -->\n <div *ngFor=\"let day of daysInMonth\" class=\"calendar-day\" [class.current-day]=\"day === currentDay\" (click)=\"handleCalenderEvent(day)\">\n <div style=\"font-weight: bolder;\">\n {{ day }}\n </div>\n <div *ngFor=\"let eventDetails of calendar_events\">\n <div *ngIf=\"eventDetails.month - 1 === currentMonth\">\n <div *ngFor=\"let list of eventDetails.list\">\n <div *ngIf=\"list.day === day\">\n <div *ngFor=\"let event of list.events and let index = index\">\n <span class=\"events\" [ngStyle]=\"event.style | styleObject\" *ngIf=\"index < 2\" #trigger (click)=\"openPopover($event, day, event)()\">\n {{ event.title }} - {{ event.time }}\n </span>\n <div class=\"extra-events\" *ngIf=\"index===2\" (click)=\"openOffCanvas(day, list.events)\">+{{ list.events.length - 2 }}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"calendar-days\" style=\"display: flex; margin: 0;\" *ngIf=\"viewOptions[selectedView] === 'Work week' || viewOptions[selectedView] === 'Week'\">\n <div [ngClass]=\"viewOptions[selectedView] === 'Work week' ? 'calendar-week-days' : 'calendar-weekend-days'\" style=\"border: 1px solid #000;\">\n <div class=\"calendar-week-day\" *ngFor=\"let day of currentWeekDays; let index = index\" [class.current-day-in-weekdays]=\"currentWeekDays[index] === currentDay\">\n <div class=\"time-slot\" *ngFor=\"let hour of hours\">\n <div style=\"height: 100%;\" *ngFor=\"let eventDetails of calendar_events\">\n\n\n <ng-container *ngIf=\"eventDetails.month - 1 === currentMonth\">\n <div style=\"height: 50%; padding: 5px 0 2px 4px; width: 100%; overflow-y: auto;\">\n <div *ngIf=\"index === 0\">\n {{ hour }}\n </div>\n\n <div *ngFor=\"let list of eventDetails.list\">\n <ng-container *ngIf=\"list.day === day\">\n <ng-container *ngIf=\"(list.events | filterEvents:getEventHour(hour, '00')) as filteredEvents\">\n <ng-container *ngFor=\"let event of filteredEvents.slice(0, 2)\">\n <span class=\"week-events\" [ngStyle]=\"event.style | styleObject\" #trigger (click)=\"openPopover($event, day, event)\">\n {{ event.title }} - {{ event.time }}\n </span>\n </ng-container>\n <div *ngIf=\"filteredEvents.length > 2\" (click)=\"openOffCanvas(day, list.events)\" class=\"extra-week-events\">+{{ filteredEvents.length - 2 }}</div>\n </ng-container>\n </ng-container>\n </div>\n\n </div>\n <div style=\"border-top: 1px solid rgba(128, 128, 128, 0.486); min-height: 50%; padding: 5px 0 2px 4px; width: 100%; overflow-y: auto;\">\n\n <div *ngFor=\"let list of eventDetails.list\">\n <ng-container *ngIf=\"list.day === day\">\n <ng-container *ngIf=\"(list.events | filterEvents:getEventHour(hour, '30')) as filteredEvents\">\n <ng-container *ngFor=\"let event of filteredEvents.slice(0, 2)\">\n <span class=\"week-events\" [ngStyle]=\"event.style | styleObject\" #trigger (click)=\"openPopover($event, day, event)\">\n {{ event.title }} - {{ event.time }}\n </span>\n </ng-container>\n <div *ngIf=\"filteredEvents.length > 2\" (click)=\"openOffCanvas(day, list.events)\" class=\"extra-week-events\">+{{ filteredEvents.length - 2 }}</div>\n </ng-container>\n </ng-container>\n </div>\n\n </div>\n </ng-container>\n\n </div>\n </div>\n\n </div>\n </div>\n </div>\n\n\n</div>\n\n<div class=\"off-canvas\" [class.open]=\"isOffCanvasOpen\">\n <div class=\"off-canvas-header\">\n <h3>{{ weekDay?.slice(0, 3) }}, {{ currentMonthName.slice(0, 3) }} {{ selectedDay }}</h3>\n <button class=\"close-btn\" (click)=\"closeOffCanvas()\">\u00D7</button>\n </div>\n\n <div class=\"off-canvas-content\">\n <div *ngIf=\"selectedDayEvents.length; else noEvents\">\n <div *ngFor=\"let event of selectedDayEvents\" class=\"event-card\" [ngStyle]=\"event.style | styleObject\">\n <div class=\"event-header\">\n <h3 class=\"event-title\">{{ event.title }}</h3>\n </div>\n\n <div class=\"event-category\" [ngStyle]=\"{'background': event.categoryColor}\">\n {{ event.category || 'General' }}\n </div>\n\n <div class=\"popover-section\">\n <i class=\"icon-calendar\"></i>\n <p>{{ selectedDay }} {{ currentMonthName }} {{ weekDay?.slice(0, 3) }},\n {{ selectedEventDetail.start_time }} - {{ selectedEventDetail.end_time }}</p>\n </div>\n\n <div class=\"event-section\">\n <i class=\"icon-location\"></i>\n <p>\n {{ selectedEventDetail.location}}\n </p>\n </div>\n\n <div class=\"event-section attendees\" *ngIf=\"event.attendees?.length\">\n <i class=\"icon-users\"></i>\n <div class=\"attendees-list\">\n <div class=\"attendee\" *ngFor=\"let attendee of event.attendees.slice(0, 3)\">\n <img [src]=\"attendee.image\" [alt]=\"attendee.name\">\n <span class=\"attendee-name\">{{ attendee.name }}</span>\n </div>\n <span *ngIf=\"event.attendees.length > 3\" class=\"more-attendees\">\n +{{ event.attendees.length - 3 }} more\n </span>\n </div>\n </div>\n\n <div class=\"event-section\">\n <i class=\"icon-info\"></i>\n <p>{{ event.description }}</p>\n </div>\n </div>\n </div>\n\n <ng-template #noEvents>\n <p class=\"no-events\">No events scheduled for this day.</p>\n </ng-template>\n </div>\n</div>\n\n\n\n\n\n<div #popover class=\"popover-container\" [ngClass]=\"{ 'show': isPopoverOpen }\" [ngStyle]=\"selectedEventDetail.style | styleObject\">\n <div class=\"popover-content\">\n <h3 class=\"popover-title\">\n {{ selectedEventDetail.title }}\n </h3>\n\n <div class=\"event-category\" [ngStyle]=\"{'background': selectedEventDetail.categoryColor}\">\n {{ selectedEventDetail.category || 'General' }}\n </div>\n\n <div class=\"popover-section\">\n <i class=\"icon-calendar\"></i>\n <p>{{ selectedDay }} {{ currentMonthName }} {{ weekDay?.slice(0, 3) }},\n {{ selectedEventDetail.start_time }} - {{ selectedEventDetail.end_time }}</p>\n </div>\n\n <div class=\"event-section\" *ngIf=\"selectedEventDetail.location\">\n <i class=\"icon-location\"></i>\n <p>\n {{ selectedEventDetail.location }}\n </p>\n </div>\n\n <div class=\"event-section attendees\" *ngIf=\"selectedEventDetail.attendees?.length\">\n <i class=\"icon-users\"></i>\n <div class=\"attendees-list\">\n <div class=\"attendee\" *ngFor=\"let attendee of selectedEventDetail.attendees.slice(0, 3)\">\n <img [src]=\"attendee.image\" [alt]=\"attendee.name\">\n <span class=\"attendee-name\">{{ attendee.name }}</span>\n </div>\n <span *ngIf=\"selectedEventDetail.attendees.length > 3\" class=\"more-attendees\">\n +{{ selectedEventDetail.attendees.length - 3 }} more\n </span>\n </div>\n </div>\n\n <div class=\"popover-section\">\n <i class=\"icon-info\"></i>\n <p>{{ selectedEventDetail.description }}</p>\n </div>\n\n <button class=\"close-btn\" (click)=\"isPopoverOpen = false\">\u2716</button>\n </div>\n</div>\n", styles: [".calendar-container{display:flex;flex-direction:column;align-items:center;width:100%;margin:auto;padding:0 10px;box-sizing:border-box;min-height:100vh}.calendar-weekdays,.calendar-days{display:grid;grid-template-columns:repeat(7,minmax(50px,1fr));gap:5px;padding:10px;border:1px solid #000;width:100%}.calendar-working-weekdays{display:grid;grid-template-columns:repeat(5,minmax(50px,1fr));gap:5px;padding:10px;border:1px solid #000;width:100%}.calendar-weekday,.calendar-day{text-align:center;padding:8px;border-radius:5px;min-height:20px;cursor:pointer;border:1px solid #000;font-weight:bolder;font-size:14px}@media (max-width: 1024px){.calendar-weekdays,.calendar-days{grid-template-columns:repeat(7,minmax(40px,1fr))}.calendar-weekday,.calendar-day{font-size:12px;padding:5px}}@media (max-width: 768px){.calendar-weekdays,.calendar-days{grid-template-columns:repeat(7,minmax(35px,1fr))}.calendar-weekday,.calendar-day{font-size:11px;padding:4px}}@media (max-width: 480px){.calendar-weekdays,.calendar-days{grid-template-columns:repeat(7,minmax(30px,1fr))}.calendar-weekday,.calendar-day{font-size:10px;padding:3px}}.calendar-day{text-align:left;padding:10px;background-color:transparent;border-radius:5px;min-height:95px;align-content:flex-start;cursor:pointer;border:1px solid #000}.time-slot{height:50px;border-bottom:1px solid #333}.blank{background-color:transparent}.current-day{background-color:#0000008e;color:#fff;font-weight:700;border-radius:5px;align-content:center;cursor:pointer;border:1px solid #000;align-content:flex-start}.current-day-in-weekdays{background-color:#00000029;color:#fff;font-weight:700;align-content:center;cursor:pointer;align-content:flex-start}.header{padding:10px;border:1px solid #000;display:flex;justify-content:space-between;width:100%}.left-content,.right-content{padding:10px}.arrow-prev,.arrow-next,.current-month{font-weight:700;border:2px solid #000;padding:10px;border-radius:5px;cursor:pointer;background-color:#000;color:#fff}.arrow-prev,.month-dropdown,.arrow-next{margin-right:2px}.current-month{font-weight:700;padding:10px}.month-dropdown,.filter-dropdown{font-weight:700;border:2px solid #000;padding:10px;border-radius:5px;cursor:pointer;background-color:#000;color:#fff}.datepicker{background:#000;padding:10px;border-radius:8px;max-width:200px;position:relative}.datepicker-header{display:flex;justify-content:space-between;align-items:center;cursor:pointer;border-radius:6px}.datepicker-header span{font-size:14px}.month-grid{display:none;grid-template-columns:repeat(3,1fr);gap:3px 5px;padding:10px 5px;position:absolute;top:50px;left:0;background:#000;border-radius:8px;width:100%;box-shadow:0 4px 6px #0000004d;z-index:1}.year-container{grid-column-start:1;grid-column-end:4;padding:5px;display:grid;grid-template-columns:repeat(2,60%)}.year{text-align:center;padding:5px;border-radius:6px;cursor:pointer;color:#fff;border:1px solid #fff}.year-filter-arrow{text-align:center}.year-arrow{padding:5px;border:1px solid #fff;border-radius:6px;cursor:pointer;color:#fff;background:#000}.view-options-grid{display:none;grid-template-columns:repeat(1,1fr);gap:8px;padding:10px 5px;position:absolute;top:50px;left:0;background:#000;border-radius:8px;width:100%;z-index:1}.month{text-align:center;padding:5px;border-radius:6px;cursor:pointer;color:#fff;border:1px solid #fff}.month:hover,.selected{background:#fff;color:#000}.datepicker.active .month-grid,.datepicker.active .view-options-grid{display:grid;width:-webkit-max-content}.arrow{position:absolute;top:-8px;left:10%;transform:translate(-50%);width:0;height:0;border-left:8px solid transparent;border-right:8px solid transparent;border-bottom:8px solid #0d0d0d}.view-arrow,.view-arrow-popover{position:absolute;top:-8px;left:30%;transform:translate(-50%);width:0;height:0;border-left:8px solid transparent;border-right:8px solid transparent;border-bottom:8px solid #0d0d0d}.view-arrow-popover{border-bottom:8px solid #fff!important}.events{border:1px dotted #000;padding:2px;border-radius:5px;margin:5px 0;font-size:small;overflow:hidden;min-height:fit-content;white-space:nowrap;text-overflow:ellipsis;display:block;width:100%}.extra-events{background-color:#000;color:#fff;text-align:center;border-radius:5px;padding:2px;margin:5px 0;font-size:small;width:100%}.off-canvas{display:none;position:fixed;top:0;right:-320px;width:300px;height:100vh;background:#000c;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);color:#fff;padding:20px;transition:right .3s ease-in-out;box-shadow:-5px 0 10px #0000004d;overflow-y:auto}.off-canvas.open{display:block;right:0}.off-canvas-header{display:flex;justify-content:space-between;align-items:center;border-bottom:2px solid rgba(255,255,255,.2);padding-bottom:10px}.off-canvas-header h3{font-size:18px;font-weight:700}.close-btn{background:none;border:none;color:#fff;font-size:20px;cursor:pointer;opacity:.8;transition:opacity .2s ease}.off-canvas-content{margin-top:10px}.event-card{background:#ffffff1a;border-radius:8px;padding:12px;margin-bottom:10px;transition:transform .2s ease-in-out}.event-card:hover{transform:scale(1.05)}.event-header{display:flex;align-items:center;gap:12px}.event-icon img{width:40px;height:40px;border-radius:50%}.event-icon i{font-size:24px;color:#fff}.event-title{font-size:16px;font-weight:700}.event-category{padding:4px 10px;border-radius:5px;font-size:12px;text-align:center;color:#fff;margin:8px 0}.event-section{display:flex;align-items:center;gap:8px;font-size:14px}.icon-calendar:before{content:\"\\1f4c5\"}.icon-location:before{content:\"\\1f4cd\"}.icon-users:before{content:\"\\1f465\"}.icon-timer:before{content:\"\\23f3\"}.event-actions{display:flex;justify-content:space-between;margin-top:10px}.btn{border:none;padding:8px 10px;border-radius:5px;cursor:pointer;font-size:12px}.btn-primary{background:#4caf50;color:#fff}.btn-secondary{background:#2196f3;color:#fff}.btn-edit{background:#ffc107;color:#fff}.btn-delete{background:#f44336;color:#fff}.btn:hover{opacity:.8}.no-events{text-align:center;font-style:italic;opacity:.7}.attendees{display:flex;align-items:center;gap:8px}.attendees-list{display:flex;flex-wrap:wrap;gap:8px}.attendee{display:flex;align-items:center;gap:6px;background:#ffffff1a;padding:4px 8px;border-radius:5px}.attendee img{width:28px;height:28px;border-radius:50%;border:2px solid white}.attendee-name{font-size:14px;color:#fff}.more-attendees{font-size:14px;color:#ddd;background:#fff3;padding:4px 8px;border-radius:5px}.popover-container{display:none;position:absolute;background:#ffffff1a;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.2);border-radius:12px;padding:16px;width:250px;box-shadow:0 8px 16px #0003;opacity:0;transform:scale(.95);pointer-events:none;transition:opacity .3s ease-in-out,visibility .3s ease-in-out}.popover-container.show{visibility:visible;display:block;opacity:1;transform:scale(1);pointer-events:auto}.popover-content{display:flex;flex-direction:column;gap:10px;color:#fff}.popover-title{font-size:18px;font-weight:700;padding-bottom:8px;border-bottom:2px solid rgba(255,255,255,.3);text-align:center}.popover-section{display:flex;align-items:center;gap:8px;font-size:14px}.icon-calendar:before,.icon-info:before{content:\"\\1f4c5\";font-size:16px}.icon-info:before{content:\"\\2139\\fe0f\"}.close-btn{position:absolute;top:8px;left:88%;background:none;border:none;color:#fff;font-size:16px;cursor:pointer;opacity:.7;transition:opacity .2s ease}.close-btn:hover{opacity:1}.time-column{display:flex;flex-direction:column;align-items:flex-end;text-align:right;font-weight:700}.calendar-week-days{display:grid;grid-template-columns:repeat(5,1fr);border-left:1px solid #444;height:78vh;overflow-y:scroll;overflow-x:auto;width:100%}.calendar-weekend-days{display:grid;grid-template-columns:repeat(7,1fr);border-left:1px solid #444;height:78vh;overflow-y:scroll;overflow-x:auto;width:100%}.calendar-week-day{display:grid;grid-template-rows:repeat(24,120px);border-right:1px solid #444;width:100%}.time-slot{border-bottom:1px solid #333;height:120px;padding:5px 0;width:100%;box-sizing:border-box;position:relative}.time-divider{position:absolute;width:100%;border-bottom:1px solid #333;left:0}.week-events{border:1px dotted #000;border-radius:5px;margin:5px 0;font-size:small;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;display:block;width:92%;cursor:pointer}.extra-week-events{background-color:#000;color:#fff;text-align:center;border-radius:5px;padding:2px;margin:5px 0;font-size:small;width:92%;cursor:pointer}\n"] }]
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { popover: [{
type: ViewChild,
args: ['popover']
}], calendar_events: [{
type: Input
}], calendar_themes: [{
type: Input
}] } });
class NpxCalendarComponent {
events = [];
options = {
show_header: true,
show_arrow: true,
show_month_picker: true,
show_calendar_view_filter: true
};
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: NpxCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.0", type: NpxCalendarComponent, isStandalone: true, selector: "npx-calendar", inputs: { events: "events", options: "options" }, ngImport: i0, template: `
<lib-calendar [calendar_events]="events" [calendar_themes]="options"></lib-calendar>
`, isInline: true, styles: [""], dependencies: [{ kind: "component", type: CalendarComponent, selector: "lib-calendar", inputs: ["calendar_events", "calendar_themes"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: NpxCalendarComponent, decorators: [{
type: Component,
args: [{ selector: 'npx-calendar', imports: [CalendarComponent], template: `
<lib-calendar [calendar_events]="events" [calendar_themes]="options"></lib-calendar>
` }]
}], propDecorators: { events: [{
type: Input
}], options: [{
type: Input
}] } });
/*
* Public API Surface of npx-calendar
*/
/**
* Generated bundle index. Do not edit.
*/
export { NpxCalendarComponent, NpxCalendarService };
//# sourceMappingURL=npx-calendar.mjs.map