@smart-solutions-tech/smart-angular-calendar 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -55,6 +55,7 @@ const TRANSLATIONS = {
55
55
  fri: 'Friday',
56
56
  sat: 'Saturday',
57
57
  today: 'Today',
58
+ allDayEvents: 'All-day events',
58
59
  january: 'January',
59
60
  february: 'February',
60
61
  march: 'March',
@@ -79,6 +80,7 @@ const TRANSLATIONS = {
79
80
  fri: 'Viernes',
80
81
  sat: 'Sábado',
81
82
  today: 'Hoy',
83
+ allDayEvents: 'Eventos de todo el día',
82
84
  january: 'Enero',
83
85
  february: 'Febrero',
84
86
  march: 'Marzo',
@@ -186,6 +188,152 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
186
188
  type: Output
187
189
  }] } });
188
190
 
191
+ class CalendarComponent {
192
+ constructor() {
193
+ this.currentMonth = {
194
+ year: new Date().getFullYear(),
195
+ month: new Date().getMonth() + 1
196
+ };
197
+ this.events = [];
198
+ this.startAt = 'sunday';
199
+ this.dayCells = [];
200
+ this.weekDays = [
201
+ { tag: 'sun' },
202
+ { tag: 'mon' },
203
+ { tag: 'tue' },
204
+ { tag: 'wed' },
205
+ { tag: 'thu' },
206
+ { tag: 'fri' },
207
+ { tag: 'sat' },
208
+ ];
209
+ this.showMoreEventsModal = false;
210
+ this.moreEventsModalEvents = [];
211
+ this.resizeListener = () => {
212
+ this.setCalendarBodyHeight();
213
+ this.setMaxEventsInDayCell();
214
+ };
215
+ }
216
+ isToday(date) {
217
+ const today = new Date();
218
+ return date.getDate() === today.getDate() &&
219
+ date.getMonth() === today.getMonth() &&
220
+ date.getFullYear() === today.getFullYear();
221
+ }
222
+ getEventsForDay(date) {
223
+ return this.events.filter(event => {
224
+ const eventStart = new Date(event.start);
225
+ const eventEnd = event.end ? new Date(event.end) : eventStart;
226
+ return date >= new Date(eventStart.getFullYear(), eventStart.getMonth(), eventStart.getDate()) &&
227
+ date <= new Date(eventEnd.getFullYear(), eventEnd.getMonth(), eventEnd.getDate());
228
+ });
229
+ }
230
+ initDaysCells() {
231
+ const daysInMonth = new Date(this.currentMonth.year, this.currentMonth.month, 0).getDate();
232
+ const firstDayOfWeek = new Date(this.currentMonth.year, this.currentMonth.month - 1, 1).getDay();
233
+ const prevDaysCount = this.startAt === 'monday' ? (firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1) : firstDayOfWeek;
234
+ // const nextDaysCount = (7 - ((prevDaysCount + daysInMonth) % 7)) % 7;
235
+ const nextDaysCount = 42 - (prevDaysCount + daysInMonth); // Always show 6 weeks
236
+ this.dayCells = [];
237
+ for (let i = 0; i < prevDaysCount; i++) {
238
+ const date = new Date(this.currentMonth.year, this.currentMonth.month - 1, i - prevDaysCount + 1);
239
+ const _events = this.getEventsForDay(date);
240
+ this.dayCells.push({
241
+ date,
242
+ events: _events,
243
+ isOutsideMonth: true,
244
+ isToday: this.isToday(date)
245
+ });
246
+ }
247
+ for (let day = 1; day <= daysInMonth; day++) {
248
+ const date = new Date(this.currentMonth.year, this.currentMonth.month - 1, day);
249
+ const _events = this.getEventsForDay(date);
250
+ this.dayCells.push({
251
+ date,
252
+ events: _events,
253
+ isToday: this.isToday(date)
254
+ });
255
+ }
256
+ for (let i = 1; i <= nextDaysCount; i++) {
257
+ const date = new Date(this.currentMonth.year, this.currentMonth.month - 1, daysInMonth + i);
258
+ const _events = this.getEventsForDay(date);
259
+ this.dayCells.push({
260
+ date,
261
+ events: _events,
262
+ isOutsideMonth: true,
263
+ isToday: this.isToday(date)
264
+ });
265
+ }
266
+ }
267
+ setCalendarBodyHeight() {
268
+ this.calendarBodyHeight = this.calendarBodyRef.nativeElement.clientHeight;
269
+ }
270
+ setMaxEventsInDayCell() {
271
+ const element = document.getElementsByClassName('events-list')[0];
272
+ console.log(element);
273
+ if (element) {
274
+ const eventItemHeight = 22;
275
+ this.maxEventsInDayCell = Math.floor(element.clientHeight / eventItemHeight) - 1;
276
+ }
277
+ }
278
+ openMoreEventsModal(date, events) {
279
+ this.moreEventsModalDate = date;
280
+ this.moreEventsModalEvents = events;
281
+ this.showMoreEventsModal = true;
282
+ }
283
+ closeMoreEventsModal() {
284
+ this.showMoreEventsModal = false;
285
+ this.moreEventsModalDate = undefined;
286
+ this.moreEventsModalEvents = [];
287
+ }
288
+ ngOnInit() {
289
+ if (this.startAt === 'monday') {
290
+ this.weekDays = [
291
+ { tag: 'mon' },
292
+ { tag: 'tue' },
293
+ { tag: 'wed' },
294
+ { tag: 'thu' },
295
+ { tag: 'fri' },
296
+ { tag: 'sat' },
297
+ { tag: 'sun' },
298
+ ];
299
+ }
300
+ this.initDaysCells();
301
+ }
302
+ ngAfterViewInit() {
303
+ window.addEventListener('resize', this.resizeListener);
304
+ setTimeout(() => {
305
+ this.setCalendarBodyHeight();
306
+ this.setMaxEventsInDayCell();
307
+ });
308
+ }
309
+ ngOnChanges(changes) {
310
+ if (changes['currentMonth']) {
311
+ this.initDaysCells();
312
+ }
313
+ }
314
+ onDestroy() {
315
+ window.removeEventListener('resize', this.resizeListener);
316
+ }
317
+ }
318
+ CalendarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
319
+ CalendarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: CalendarComponent, selector: "lib-calendar", inputs: { currentMonth: "currentMonth", events: "events", startAt: "startAt" }, viewQueries: [{ propertyName: "calendarRef", first: true, predicate: ["calendar"], descendants: true }, { propertyName: "calendarBodyRef", first: true, predicate: ["calendarBody"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"calendar-component\">\r\n <div class=\"body\" #calendarBody>\r\n <div class=\"week-days\">\r\n <div class=\"week-day\" *ngFor=\"let day of weekDays\">\r\n {{ day.tag | translate | slice:0:3 }}\r\n </div>\r\n </div>\r\n\r\n <div class=\"days-grid\">\r\n <div class=\"day-cell\" *ngFor=\"let day of dayCells; let i = index\"\r\n [ngClass]=\"{'outside-month': day.isOutsideMonth, 'is-today': day.isToday}\">\r\n <div class=\"day-number\">\r\n {{ day.date.getDate() }}\r\n </div>\r\n\r\n <div class=\"events-list\">\r\n <lib-calendar-event *ngFor=\"let event of day.events | slice:0:maxEventsInDayCell\"\r\n [event]=\"event\"></lib-calendar-event>\r\n\r\n <div class=\"more-events\" *ngIf=\"day.events.length > (maxEventsInDayCell || 0)\"\r\n (click)=\"openMoreEventsModal(day.date, day.events)\">\r\n {{'nMoreEvents' | translate: {n:(day.events.length - (maxEventsInDayCell || 0))} }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"footer\">\r\n Footer\r\n </div>\r\n\r\n <lib-more-events-modal *ngIf=\"showMoreEventsModal && moreEventsModalDate\" [events]=\"moreEventsModalEvents\"\r\n [date]=\"moreEventsModalDate\" (close)=\"closeMoreEventsModal()\"\r\n (eventClick)=\"closeMoreEventsModal()\"></lib-more-events-modal>\r\n</div>", styles: ["*{box-sizing:border-box;margin:0;padding:0}.calendar-component{display:flex;flex-direction:column;width:100%;height:100%}.body{flex:1 1 0;display:flex;flex-direction:column;width:100%;min-height:0;height:100%}.week-days{flex-shrink:0;display:grid;grid-template-columns:repeat(7,1fr);width:100%;background-color:#f4f4f4}.week-day{display:flex;align-items:center;justify-content:center;padding:4px;background-color:#fff;font-size:14px;color:#00000080}.days-grid{flex:1 1 0;display:grid;grid-template-columns:repeat(7,1fr);gap:1px;grid-auto-rows:1fr;width:100%;padding:1px;background-color:#f4f4f4;min-height:0;height:100%}.day-cell{display:flex;flex-direction:column;gap:4px;padding:4px;background-color:#fff;overflow:hidden}.day-cell .day-number{display:flex;align-items:center;justify-content:center;width:fit-content;aspect-ratio:1;padding:2px;border-radius:50%;font-size:12px;line-height:16px;font-weight:600;-webkit-user-select:none;user-select:none}.day-cell.outside-month{background-color:#f8f8f8}.day-cell.is-today .day-number{background-color:#007bff;color:#fff}.day-cell .events-list{flex:1 1 auto;display:flex;flex-direction:column;gap:2px;overflow:hidden;min-height:0;max-height:100%}.day-cell .events-list .more-events{padding:2px 8px;border-radius:4px;font-size:12px;color:#555;cursor:pointer}.day-cell .events-list .more-events:hover{background-color:#eee}.footer{flex-shrink:0;background-color:#add8e6}\n"], dependencies: [{ 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: "component", type: CalendarEventComponent, selector: "lib-calendar-event", inputs: ["event"] }, { kind: "component", type: MoreEventsModalComponent, selector: "lib-more-events-modal", inputs: ["events", "date"], outputs: ["close", "eventClick"] }, { kind: "pipe", type: i1.SlicePipe, name: "slice" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
320
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CalendarComponent, decorators: [{
321
+ type: Component,
322
+ args: [{ selector: 'lib-calendar', template: "<div class=\"calendar-component\">\r\n <div class=\"body\" #calendarBody>\r\n <div class=\"week-days\">\r\n <div class=\"week-day\" *ngFor=\"let day of weekDays\">\r\n {{ day.tag | translate | slice:0:3 }}\r\n </div>\r\n </div>\r\n\r\n <div class=\"days-grid\">\r\n <div class=\"day-cell\" *ngFor=\"let day of dayCells; let i = index\"\r\n [ngClass]=\"{'outside-month': day.isOutsideMonth, 'is-today': day.isToday}\">\r\n <div class=\"day-number\">\r\n {{ day.date.getDate() }}\r\n </div>\r\n\r\n <div class=\"events-list\">\r\n <lib-calendar-event *ngFor=\"let event of day.events | slice:0:maxEventsInDayCell\"\r\n [event]=\"event\"></lib-calendar-event>\r\n\r\n <div class=\"more-events\" *ngIf=\"day.events.length > (maxEventsInDayCell || 0)\"\r\n (click)=\"openMoreEventsModal(day.date, day.events)\">\r\n {{'nMoreEvents' | translate: {n:(day.events.length - (maxEventsInDayCell || 0))} }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"footer\">\r\n Footer\r\n </div>\r\n\r\n <lib-more-events-modal *ngIf=\"showMoreEventsModal && moreEventsModalDate\" [events]=\"moreEventsModalEvents\"\r\n [date]=\"moreEventsModalDate\" (close)=\"closeMoreEventsModal()\"\r\n (eventClick)=\"closeMoreEventsModal()\"></lib-more-events-modal>\r\n</div>", styles: ["*{box-sizing:border-box;margin:0;padding:0}.calendar-component{display:flex;flex-direction:column;width:100%;height:100%}.body{flex:1 1 0;display:flex;flex-direction:column;width:100%;min-height:0;height:100%}.week-days{flex-shrink:0;display:grid;grid-template-columns:repeat(7,1fr);width:100%;background-color:#f4f4f4}.week-day{display:flex;align-items:center;justify-content:center;padding:4px;background-color:#fff;font-size:14px;color:#00000080}.days-grid{flex:1 1 0;display:grid;grid-template-columns:repeat(7,1fr);gap:1px;grid-auto-rows:1fr;width:100%;padding:1px;background-color:#f4f4f4;min-height:0;height:100%}.day-cell{display:flex;flex-direction:column;gap:4px;padding:4px;background-color:#fff;overflow:hidden}.day-cell .day-number{display:flex;align-items:center;justify-content:center;width:fit-content;aspect-ratio:1;padding:2px;border-radius:50%;font-size:12px;line-height:16px;font-weight:600;-webkit-user-select:none;user-select:none}.day-cell.outside-month{background-color:#f8f8f8}.day-cell.is-today .day-number{background-color:#007bff;color:#fff}.day-cell .events-list{flex:1 1 auto;display:flex;flex-direction:column;gap:2px;overflow:hidden;min-height:0;max-height:100%}.day-cell .events-list .more-events{padding:2px 8px;border-radius:4px;font-size:12px;color:#555;cursor:pointer}.day-cell .events-list .more-events:hover{background-color:#eee}.footer{flex-shrink:0;background-color:#add8e6}\n"] }]
323
+ }], ctorParameters: function () { return []; }, propDecorators: { currentMonth: [{
324
+ type: Input
325
+ }], events: [{
326
+ type: Input
327
+ }], startAt: [{
328
+ type: Input
329
+ }], calendarRef: [{
330
+ type: ViewChild,
331
+ args: ['calendar']
332
+ }], calendarBodyRef: [{
333
+ type: ViewChild,
334
+ args: ['calendarBody']
335
+ }] } });
336
+
189
337
  class TranslateMonthPipe {
190
338
  constructor(translationService) {
191
339
  this.translationService = translationService;
@@ -281,33 +429,157 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
281
429
  type: Input
282
430
  }] } });
283
431
 
284
- class CalendarComponent {
432
+ class DurationEventComponent {
433
+ constructor() {
434
+ this.isDarkColor = false;
435
+ this.topPosition = 0;
436
+ this.height = 0;
437
+ this.isEventStartInThisDay = false;
438
+ this.isEventEndInThisDay = false;
439
+ }
440
+ ngOnInit() {
441
+ this.isDarkColor = isDarkColor(this.event.color || '#000000');
442
+ this.isEventStartInThisDay = this.getIsEventStartInThisDay();
443
+ this.isEventEndInThisDay = this.getIsEventEndInThisDay();
444
+ this.topPosition = this.getTopPosition();
445
+ this.height = this.getEventHeight();
446
+ }
447
+ getIsEventStartInThisDay() {
448
+ return this.event.start.getDate() === this.date.getDate() && this.event.start.getMonth() === this.date.getMonth() && this.event.start.getFullYear() === this.date.getFullYear();
449
+ }
450
+ getIsEventEndInThisDay() {
451
+ return this.event.end.getDate() === this.date.getDate() && this.event.end.getMonth() === this.date.getMonth() && this.event.end.getFullYear() === this.date.getFullYear();
452
+ }
453
+ getTopPosition() {
454
+ if (!this.isEventStartInThisDay)
455
+ return 0;
456
+ return this.event.start.getHours() * 60 + this.event.start.getMinutes();
457
+ }
458
+ getEventHeight() {
459
+ const max_minutes_in_day = 24 * 60;
460
+ if (!this.isEventStartInThisDay && !this.isEventEndInThisDay)
461
+ return max_minutes_in_day;
462
+ const result = (this.event.end.getTime() - this.event.start.getTime()) / (1000 * 60);
463
+ if (result < 20)
464
+ return 20;
465
+ if (!this.isEventStartInThisDay)
466
+ return (this.event.end.getTime() - new Date(this.date.getFullYear(), this.date.getMonth(), this.date.getDate(), 0, 0, 0).getTime()) / (1000 * 60);
467
+ const startPosition = this.getTopPosition();
468
+ if (startPosition + result > max_minutes_in_day)
469
+ return max_minutes_in_day - startPosition;
470
+ return result;
471
+ }
472
+ }
473
+ DurationEventComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DurationEventComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
474
+ DurationEventComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: DurationEventComponent, selector: "lib-duration-event", inputs: { event: "event", date: "date" }, ngImport: i0, template: "<div class=\"duration-event-component\" style=\"--color: {{ event.color }};\" [style.top.px]=\"topPosition\"\n [style.height.px]=\"height\" [ngClass]=\"{'dark-color': isDarkColor}\" [title]=\"event.title\">\n <div class=\"event-title\">{{ event.title }}</div>\n</div>", styles: [".duration-event-component{position:absolute;left:0;z-index:1;width:100%;background-color:var(--color, rgba(0, 0, 0, .05));border-radius:4px;padding:2px 8px;cursor:pointer;-webkit-user-select:none;user-select:none;color:#212121}.duration-event-component.dark-color{color:#fafafa}.event-title{font-size:12px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
475
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DurationEventComponent, decorators: [{
476
+ type: Component,
477
+ args: [{ selector: 'lib-duration-event', template: "<div class=\"duration-event-component\" style=\"--color: {{ event.color }};\" [style.top.px]=\"topPosition\"\n [style.height.px]=\"height\" [ngClass]=\"{'dark-color': isDarkColor}\" [title]=\"event.title\">\n <div class=\"event-title\">{{ event.title }}</div>\n</div>", styles: [".duration-event-component{position:absolute;left:0;z-index:1;width:100%;background-color:var(--color, rgba(0, 0, 0, .05));border-radius:4px;padding:2px 8px;cursor:pointer;-webkit-user-select:none;user-select:none;color:#212121}.duration-event-component.dark-color{color:#fafafa}.event-title{font-size:12px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
478
+ }], ctorParameters: function () { return []; }, propDecorators: { event: [{
479
+ type: Input
480
+ }], date: [{
481
+ type: Input
482
+ }] } });
483
+
484
+ class DayComponent {
485
+ constructor() {
486
+ this.events = [];
487
+ this.hourBlocks = Array.from({ length: 24 }, (_, i) => i);
488
+ this.allDayEvents = [];
489
+ this.allDayHeight = 60;
490
+ this.eventCols = [];
491
+ this.resizing = false;
492
+ this.startY = 0;
493
+ this.startHeight = 0;
494
+ this.onResizeMouseMove = (event) => {
495
+ if (!this.resizing)
496
+ return;
497
+ const delta = event.clientY - this.startY;
498
+ const newHeight = this.startHeight + delta;
499
+ this.allDayHeight = Math.max(60, newHeight); // mínimo 80px
500
+ };
501
+ this.onResizeMouseUp = () => {
502
+ this.resizing = false;
503
+ document.removeEventListener('mousemove', this.onResizeMouseMove);
504
+ document.removeEventListener('mouseup', this.onResizeMouseUp);
505
+ };
506
+ }
507
+ ngOnInit() {
508
+ this.initEventCols();
509
+ }
510
+ findAvalailableColumn(event) {
511
+ for (let colIndex = 0; colIndex < this.eventCols.length; colIndex++) {
512
+ const col = this.eventCols[colIndex];
513
+ // conflict if event overlaps with any existing event in the column
514
+ const hasConflict = col.events.some(existingEvent => {
515
+ const startsDuringExisting = event.start < existingEvent.end && event.start >= existingEvent.start;
516
+ const endsDuringExisting = event.end > existingEvent.start && event.end <= existingEvent.end;
517
+ const spansExisting = event.start <= existingEvent.start && event.end >= existingEvent.end;
518
+ return startsDuringExisting || endsDuringExisting || spansExisting;
519
+ });
520
+ if (!hasConflict) {
521
+ return colIndex;
522
+ }
523
+ }
524
+ return this.eventCols.length;
525
+ }
526
+ addEventToEventCols(event) {
527
+ const colIndex = this.findAvalailableColumn(event);
528
+ if (colIndex === this.eventCols.length) {
529
+ this.eventCols.push({ events: [event] });
530
+ }
531
+ else {
532
+ this.eventCols[colIndex].events.push(event);
533
+ }
534
+ }
535
+ addEvent(event) {
536
+ if (event.allDay)
537
+ this.allDayEvents.push(event);
538
+ else
539
+ this.addEventToEventCols(event);
540
+ }
541
+ initEventCols() {
542
+ this.eventCols = [];
543
+ this.allDayEvents = [];
544
+ this.events.forEach(event => this.addEvent(event));
545
+ }
546
+ ngOnChanges(changes) {
547
+ if (changes['events']) {
548
+ this.initEventCols();
549
+ }
550
+ }
551
+ onResizeMouseDown(event) {
552
+ this.resizing = true;
553
+ this.startY = event.clientY;
554
+ this.startHeight = this.allDayHeight;
555
+ document.addEventListener('mousemove', this.onResizeMouseMove);
556
+ document.addEventListener('mouseup', this.onResizeMouseUp);
557
+ }
558
+ }
559
+ DayComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
560
+ DayComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: DayComponent, selector: "lib-day", inputs: { events: "events", date: "date" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"day-view-component\">\n <section class=\"all-day-events\" [style.height.px]=\"allDayHeight\">\n <div class=\"header\">\n {{'allDayEvents' | translate}}\n </div>\n\n <div class=\"events-container\">\n <lib-calendar-event *ngFor=\"let event of allDayEvents\" [event]=\"event\"></lib-calendar-event>\n </div>\n </section>\n\n <div class=\"resize-divider\" (mousedown)=\"onResizeMouseDown($event)\"></div>\n\n <section class=\"duration-events\">\n <div class=\"hour-blocks\">\n <div class=\"hour-block\" *ngFor=\"let hour of hourBlocks\">\n <span>{{ hour }}:00</span>\n </div>\n </div>\n\n <div class=\"events-wrapper\">\n <div class=\"time-blocks\">\n <div class=\"time-block\" *ngFor=\"let hour of hourBlocks\">\n <div class=\"time-block-middle\"></div>\n </div>\n </div>\n\n <div class=\"events-container\" [style.gridTemplateColumns]=\"'repeat(' + eventCols.length + ', 1fr)'\">\n <div class=\"event-column\" *ngFor=\"let col of eventCols\">\n\n <lib-duration-event *ngFor=\"let event of col.events\" [event]=\"event\"\n [date]=\"date\"></lib-duration-event>\n\n </div>\n </div>\n </div>\n </section>\n</div>", styles: ["*{box-sizing:border-box;margin:0;padding:0}.day-view-component{display:flex;flex-direction:column;width:100%;height:100%;max-height:100%;overflow:hidden}section.all-day-events{position:relative;flex-shrink:0;display:flex;flex-direction:column;width:100%;min-height:60px;border-top:1px solid rgba(0,0,0,.12);overflow:auto}section.all-day-events .header{position:sticky;top:0;left:0;z-index:2;width:100%;flex-shrink:0;padding:2px 8px;background-color:#fff;font-size:12px;color:#000000b3;-webkit-user-select:none;user-select:none}section.all-day-events .events-container{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:4px;padding:4px}section.duration-events{flex-grow:1;display:flex;width:100%;overflow:auto}section.duration-events .hour-blocks{display:flex;flex-direction:column;width:45px;-webkit-user-select:none;user-select:none}section.duration-events .hour-blocks .hour-block{flex-shrink:0;height:60px;padding:4px;border:1px solid rgba(0,0,0,.12);border-top:none;font-size:12px;color:#00000080}section.duration-events .events-wrapper{position:relative;flex-grow:1;width:100%}section.duration-events .events-wrapper .time-blocks{position:absolute;top:0;left:0;width:100%;height:100%;z-index:0;display:flex;flex-direction:column}section.duration-events .events-wrapper .time-blocks .time-block{flex-shrink:0;height:60px;padding:4px;border-bottom:1px solid rgba(0,0,0,.12);border-top:none;font-size:12px;color:#00000080}section.duration-events .events-wrapper .time-blocks .time-block .time-block-middle{width:100%;height:50%;border-bottom:1px dashed rgba(0,0,0,.12)}section.duration-events .events-wrapper .events-container{display:grid;column-gap:1px}section.duration-events .events-wrapper .events-container .event-column{position:relative}.resize-divider{flex-shrink:0;width:100%;height:4px;background-color:#0000001f;cursor:row-resize;transition:transform .2s ease}.resize-divider:hover{z-index:5;background:repeating-linear-gradient(45deg,rgba(0,0,0,.12),rgba(0,0,0,.12) 4px,#ffffff 4px,#ffffff 8px);background-color:#fff;background-size:22px 8px;animation:stripe-move 1s linear infinite;transform:scaleY(2)}@keyframes stripe-move{0%{background-position:0 0}to{background-position:22px 0}}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: CalendarEventComponent, selector: "lib-calendar-event", inputs: ["event"] }, { kind: "component", type: DurationEventComponent, selector: "lib-duration-event", inputs: ["event", "date"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
561
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DayComponent, decorators: [{
562
+ type: Component,
563
+ args: [{ selector: 'lib-day', template: "<div class=\"day-view-component\">\n <section class=\"all-day-events\" [style.height.px]=\"allDayHeight\">\n <div class=\"header\">\n {{'allDayEvents' | translate}}\n </div>\n\n <div class=\"events-container\">\n <lib-calendar-event *ngFor=\"let event of allDayEvents\" [event]=\"event\"></lib-calendar-event>\n </div>\n </section>\n\n <div class=\"resize-divider\" (mousedown)=\"onResizeMouseDown($event)\"></div>\n\n <section class=\"duration-events\">\n <div class=\"hour-blocks\">\n <div class=\"hour-block\" *ngFor=\"let hour of hourBlocks\">\n <span>{{ hour }}:00</span>\n </div>\n </div>\n\n <div class=\"events-wrapper\">\n <div class=\"time-blocks\">\n <div class=\"time-block\" *ngFor=\"let hour of hourBlocks\">\n <div class=\"time-block-middle\"></div>\n </div>\n </div>\n\n <div class=\"events-container\" [style.gridTemplateColumns]=\"'repeat(' + eventCols.length + ', 1fr)'\">\n <div class=\"event-column\" *ngFor=\"let col of eventCols\">\n\n <lib-duration-event *ngFor=\"let event of col.events\" [event]=\"event\"\n [date]=\"date\"></lib-duration-event>\n\n </div>\n </div>\n </div>\n </section>\n</div>", styles: ["*{box-sizing:border-box;margin:0;padding:0}.day-view-component{display:flex;flex-direction:column;width:100%;height:100%;max-height:100%;overflow:hidden}section.all-day-events{position:relative;flex-shrink:0;display:flex;flex-direction:column;width:100%;min-height:60px;border-top:1px solid rgba(0,0,0,.12);overflow:auto}section.all-day-events .header{position:sticky;top:0;left:0;z-index:2;width:100%;flex-shrink:0;padding:2px 8px;background-color:#fff;font-size:12px;color:#000000b3;-webkit-user-select:none;user-select:none}section.all-day-events .events-container{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:4px;padding:4px}section.duration-events{flex-grow:1;display:flex;width:100%;overflow:auto}section.duration-events .hour-blocks{display:flex;flex-direction:column;width:45px;-webkit-user-select:none;user-select:none}section.duration-events .hour-blocks .hour-block{flex-shrink:0;height:60px;padding:4px;border:1px solid rgba(0,0,0,.12);border-top:none;font-size:12px;color:#00000080}section.duration-events .events-wrapper{position:relative;flex-grow:1;width:100%}section.duration-events .events-wrapper .time-blocks{position:absolute;top:0;left:0;width:100%;height:100%;z-index:0;display:flex;flex-direction:column}section.duration-events .events-wrapper .time-blocks .time-block{flex-shrink:0;height:60px;padding:4px;border-bottom:1px solid rgba(0,0,0,.12);border-top:none;font-size:12px;color:#00000080}section.duration-events .events-wrapper .time-blocks .time-block .time-block-middle{width:100%;height:50%;border-bottom:1px dashed rgba(0,0,0,.12)}section.duration-events .events-wrapper .events-container{display:grid;column-gap:1px}section.duration-events .events-wrapper .events-container .event-column{position:relative}.resize-divider{flex-shrink:0;width:100%;height:4px;background-color:#0000001f;cursor:row-resize;transition:transform .2s ease}.resize-divider:hover{z-index:5;background:repeating-linear-gradient(45deg,rgba(0,0,0,.12),rgba(0,0,0,.12) 4px,#ffffff 4px,#ffffff 8px);background-color:#fff;background-size:22px 8px;animation:stripe-move 1s linear infinite;transform:scaleY(2)}@keyframes stripe-move{0%{background-position:0 0}to{background-position:22px 0}}\n"] }]
564
+ }], ctorParameters: function () { return []; }, propDecorators: { events: [{
565
+ type: Input
566
+ }], date: [{
567
+ type: Input
568
+ }] } });
569
+
570
+ class SmartCalendarComponent {
285
571
  constructor() {
572
+ this.mode = 'month';
286
573
  this.currentMonth = {
287
574
  year: new Date().getFullYear(),
288
575
  month: new Date().getMonth() + 1
289
576
  };
290
577
  this.events = [];
291
- this.startAt = 'sunday';
292
578
  this.monthChange = new EventEmitter();
293
- this.dayCells = [];
294
- this.weekDays = [
295
- { tag: 'sun' },
296
- { tag: 'mon' },
297
- { tag: 'tue' },
298
- { tag: 'wed' },
299
- { tag: 'thu' },
300
- { tag: 'fri' },
301
- { tag: 'sat' },
302
- ];
303
- this.showMoreEventsModal = false;
304
- this.moreEventsModalEvents = [];
305
- this.currentMonthTitle = ``;
579
+ this.dateChanged = new EventEmitter();
306
580
  this.showDateSelector = false;
307
- this.resizeListener = () => {
308
- this.setCalendarBodyHeight();
309
- this.setMaxEventsInDayCell();
310
- };
581
+ this.selectedDate = new Date();
582
+ this.selectedDateEvents = [];
311
583
  }
312
584
  onDocumentClick(event) {
313
585
  if (!this.showDateSelector)
@@ -318,176 +590,160 @@ class CalendarComponent {
318
590
  this.showDateSelector = false;
319
591
  }
320
592
  }
321
- isToday(date) {
322
- const today = new Date();
323
- return date.getDate() === today.getDate() &&
324
- date.getMonth() === today.getMonth() &&
325
- date.getFullYear() === today.getFullYear();
326
- }
327
- getEventsForDay(date) {
328
- return this.events.filter(event => {
329
- const eventStart = new Date(event.start);
330
- const eventEnd = event.end ? new Date(event.end) : eventStart;
331
- return date >= new Date(eventStart.getFullYear(), eventStart.getMonth(), eventStart.getDate()) &&
332
- date <= new Date(eventEnd.getFullYear(), eventEnd.getMonth(), eventEnd.getDate());
333
- });
334
- }
335
- initDaysCells() {
336
- const daysInMonth = new Date(this.currentMonth.year, this.currentMonth.month, 0).getDate();
337
- const firstDayOfWeek = new Date(this.currentMonth.year, this.currentMonth.month - 1, 1).getDay();
338
- const prevDaysCount = this.startAt === 'monday' ? (firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1) : firstDayOfWeek;
339
- // const nextDaysCount = (7 - ((prevDaysCount + daysInMonth) % 7)) % 7;
340
- const nextDaysCount = 42 - (prevDaysCount + daysInMonth); // Always show 6 weeks
341
- this.dayCells = [];
342
- for (let i = 0; i < prevDaysCount; i++) {
343
- const date = new Date(this.currentMonth.year, this.currentMonth.month - 1, i - prevDaysCount + 1);
344
- const _events = this.getEventsForDay(date);
345
- this.dayCells.push({
346
- date,
347
- events: _events,
348
- isOutsideMonth: true,
349
- isToday: this.isToday(date)
350
- });
351
- }
352
- for (let day = 1; day <= daysInMonth; day++) {
353
- const date = new Date(this.currentMonth.year, this.currentMonth.month - 1, day);
354
- const _events = this.getEventsForDay(date);
355
- this.dayCells.push({
356
- date,
357
- events: _events,
358
- isToday: this.isToday(date)
359
- });
360
- }
361
- for (let i = 1; i <= nextDaysCount; i++) {
362
- const date = new Date(this.currentMonth.year, this.currentMonth.month - 1, daysInMonth + i);
363
- const _events = this.getEventsForDay(date);
364
- this.dayCells.push({
365
- date,
366
- events: _events,
367
- isOutsideMonth: true,
368
- isToday: this.isToday(date)
369
- });
370
- }
371
- }
372
- setCalendarBodyHeight() {
373
- this.calendarBodyHeight = this.calendarBodyRef.nativeElement.clientHeight;
374
- }
375
- setMaxEventsInDayCell() {
376
- const element = document.getElementsByClassName('events-list')[0];
377
- console.log(element);
378
- if (element) {
379
- const eventItemHeight = 22;
380
- this.maxEventsInDayCell = Math.floor(element.clientHeight / eventItemHeight) - 1;
381
- }
593
+ ngOnInit() {
594
+ this.selectDate(new Date());
382
595
  }
383
- openMoreEventsModal(date, events) {
384
- this.moreEventsModalDate = date;
385
- this.moreEventsModalEvents = events;
386
- this.showMoreEventsModal = true;
596
+ toggleDateSelector() {
597
+ this.showDateSelector = !this.showDateSelector;
387
598
  }
388
- closeMoreEventsModal() {
389
- this.showMoreEventsModal = false;
390
- this.moreEventsModalDate = undefined;
391
- this.moreEventsModalEvents = [];
599
+ onMonthSelected(newMonth) {
600
+ const oldMonth = { ...this.currentMonth };
601
+ this.currentMonth = newMonth;
602
+ this.selectDate(new Date(this.currentMonth.year, this.currentMonth.month - 1, 1));
603
+ this.monthChange.emit({
604
+ newMonth: this.currentMonth,
605
+ oldMonth
606
+ });
607
+ this.showDateSelector = false;
392
608
  }
393
609
  nextMonth() {
394
610
  const oldMonth = { ...this.currentMonth };
395
611
  if (this.currentMonth.month === 12) {
396
- this.currentMonth.month = 1;
397
- this.currentMonth.year += 1;
612
+ this.currentMonth = {
613
+ year: this.currentMonth.year + 1,
614
+ month: 1
615
+ };
398
616
  }
399
617
  else {
400
- this.currentMonth.month += 1;
618
+ this.currentMonth = {
619
+ year: this.currentMonth.year,
620
+ month: this.currentMonth.month + 1
621
+ };
401
622
  }
402
- this.initDaysCells();
623
+ this.selectDate(new Date(this.currentMonth.year, this.currentMonth.month - 1, 1));
403
624
  this.monthChange.emit({
404
- newMonth: { ...this.currentMonth },
625
+ newMonth: this.currentMonth,
405
626
  oldMonth
406
627
  });
407
628
  }
408
629
  prevMonth() {
409
630
  const oldMonth = { ...this.currentMonth };
410
631
  if (this.currentMonth.month === 1) {
411
- this.currentMonth.month = 12;
412
- this.currentMonth.year -= 1;
632
+ this.currentMonth = {
633
+ year: this.currentMonth.year - 1,
634
+ month: 12
635
+ };
413
636
  }
414
637
  else {
415
- this.currentMonth.month -= 1;
638
+ this.currentMonth = {
639
+ year: this.currentMonth.year,
640
+ month: this.currentMonth.month - 1
641
+ };
416
642
  }
417
- this.initDaysCells();
643
+ this.selectDate(new Date(this.currentMonth.year, this.currentMonth.month - 1, 1));
418
644
  this.monthChange.emit({
419
- newMonth: { ...this.currentMonth },
645
+ newMonth: this.currentMonth,
420
646
  oldMonth
421
647
  });
422
648
  }
423
649
  goToToday() {
424
650
  const today = new Date();
425
651
  const oldMonth = { ...this.currentMonth };
426
- this.currentMonth.year = today.getFullYear();
427
- this.currentMonth.month = today.getMonth() + 1;
428
- this.initDaysCells();
429
- this.monthChange.emit({
430
- newMonth: { ...this.currentMonth },
431
- oldMonth
432
- });
433
- }
434
- toggleDateSelector() {
435
- this.showDateSelector = !this.showDateSelector;
652
+ this.currentMonth = {
653
+ year: today.getFullYear(),
654
+ month: today.getMonth() + 1
655
+ };
656
+ this.selectDate(today);
657
+ if (this.currentMonth.month !== oldMonth.month || this.currentMonth.year !== oldMonth.year)
658
+ this.monthChange.emit({
659
+ newMonth: this.currentMonth,
660
+ oldMonth
661
+ });
436
662
  }
437
- onMonthSelected(newMonth) {
663
+ nextDay() {
438
664
  const oldMonth = { ...this.currentMonth };
439
- this.currentMonth = newMonth;
440
- this.initDaysCells();
441
- this.monthChange.emit({
442
- newMonth: { ...this.currentMonth },
443
- oldMonth
444
- });
445
- this.showDateSelector = false;
665
+ const newDate = new Date(this.selectedDate);
666
+ newDate.setDate(newDate.getDate() + 1);
667
+ this.selectDate(newDate);
668
+ this.currentMonth = {
669
+ year: newDate.getFullYear(),
670
+ month: newDate.getMonth() + 1
671
+ };
672
+ if (this.currentMonth.month !== oldMonth.month || this.currentMonth.year !== oldMonth.year)
673
+ this.monthChange.emit({
674
+ newMonth: this.currentMonth,
675
+ oldMonth
676
+ });
446
677
  }
447
- ngOnInit() {
448
- if (this.startAt === 'monday') {
449
- this.weekDays = [
450
- { tag: 'mon' },
451
- { tag: 'tue' },
452
- { tag: 'wed' },
453
- { tag: 'thu' },
454
- { tag: 'fri' },
455
- { tag: 'sat' },
456
- { tag: 'sun' },
457
- ];
458
- }
459
- this.initDaysCells();
678
+ prevDay() {
679
+ const oldMonth = { ...this.currentMonth };
680
+ const newDate = new Date(this.selectedDate);
681
+ newDate.setDate(newDate.getDate() - 1);
682
+ this.selectDate(newDate);
683
+ this.currentMonth = {
684
+ year: newDate.getFullYear(),
685
+ month: newDate.getMonth() + 1
686
+ };
687
+ if (this.currentMonth.month !== oldMonth.month || this.currentMonth.year !== oldMonth.year)
688
+ this.monthChange.emit({
689
+ newMonth: this.currentMonth,
690
+ oldMonth
691
+ });
460
692
  }
461
- ngAfterViewInit() {
462
- window.addEventListener('resize', this.resizeListener);
463
- setTimeout(() => {
464
- this.setCalendarBodyHeight();
465
- this.setMaxEventsInDayCell();
693
+ onNext() {
694
+ if (this.mode === 'month')
695
+ this.nextMonth();
696
+ else if (this.mode === 'day')
697
+ this.nextDay();
698
+ }
699
+ onPrev() {
700
+ if (this.mode === 'month')
701
+ this.prevMonth();
702
+ else if (this.mode === 'day')
703
+ this.prevDay();
704
+ }
705
+ selectDate(date) {
706
+ this.selectedDate = date;
707
+ this.selectedDateEvents = this.events.filter(event => {
708
+ const eventDate = new Date(event.start);
709
+ // return events that starts, ends or spans the selected date
710
+ return (eventDate.getDate() === date.getDate() &&
711
+ eventDate.getMonth() === date.getMonth() &&
712
+ eventDate.getFullYear() === date.getFullYear()) ||
713
+ (event.end &&
714
+ event.end.getDate() === date.getDate() &&
715
+ event.end.getMonth() === date.getMonth() &&
716
+ event.end.getFullYear() === date.getFullYear()) ||
717
+ (event.start < date && event.end && event.end > date);
466
718
  });
467
- }
468
- onDestroy() {
469
- window.removeEventListener('resize', this.resizeListener);
719
+ const oldMonth = this.currentMonth;
720
+ this.currentMonth = {
721
+ year: date.getFullYear(),
722
+ month: date.getMonth() + 1
723
+ };
724
+ if (this.currentMonth.month !== oldMonth.month || this.currentMonth.year !== oldMonth.year)
725
+ this.monthChange.emit({
726
+ newMonth: this.currentMonth,
727
+ oldMonth
728
+ });
729
+ this.dateChanged.emit(this.selectedDate);
470
730
  }
471
731
  }
472
- CalendarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
473
- CalendarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: CalendarComponent, selector: "lib-calendar", inputs: { currentMonth: "currentMonth", events: "events", startAt: "startAt" }, outputs: { monthChange: "monthChange" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "calendarRef", first: true, predicate: ["calendar"], descendants: true }, { propertyName: "calendarBodyRef", first: true, predicate: ["calendarBody"], descendants: true }, { propertyName: "dateSelectorDropdown", first: true, predicate: ["dateSelectorDropdown"], descendants: true }], ngImport: i0, template: "<div class=\"calendar-component\">\r\n <div class=\"header\">\r\n <div class=\"nav-controls\">\r\n <button class=\"btn-prev\" (click)=\"prevMonth()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\r\n fill=\"currentColor\">\r\n <path d=\"M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z\" />\r\n </svg>\r\n </button>\r\n\r\n <button class=\"btn-today\" (click)=\"goToToday()\">{{'today' | translate}}</button>\r\n\r\n <button class=\"btn-next\" (click)=\"nextMonth()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\r\n fill=\"currentColor\">\r\n <path d=\"M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"spacer\"></div>\r\n\r\n <div class=\"date-selector-container\">\r\n <button class=\"btn-date-selector\" (click)=\"toggleDateSelector()\">\r\n <span>{{ currentMonth.month | translateMonth}} - {{ currentMonth.year }}</span>\r\n\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\r\n fill=\"currentColor\">\r\n <path d=\"M480-360 280-560h400L480-360Z\" />\r\n </svg>\r\n </button>\r\n\r\n <div class=\"date-selector-dropdown\" *ngIf=\"showDateSelector\" #dateSelectorDropdown>\r\n <lib-month-selector [selectedMonth]=\"currentMonth\"\r\n (monthSelected)=\"onMonthSelected($event)\"></lib-month-selector>\r\n </div>\r\n </div>\r\n\r\n <div class=\"spacer\"></div>\r\n\r\n <div class=\"view-selector\">\r\n <button class=\"btn-view active\">\r\n <!-- month view -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\r\n fill=\"currentColor\">\r\n <path\r\n d=\"M200-80q-33 0-56.5-23.5T120-160v-560q0-33 23.5-56.5T200-800h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840-720v560q0 33-23.5 56.5T760-80H200Zm0-80h560v-400H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Zm280 240q-17 0-28.5-11.5T440-440q0-17 11.5-28.5T480-480q17 0 28.5 11.5T520-440q0 17-11.5 28.5T480-400Zm-160 0q-17 0-28.5-11.5T280-440q0-17 11.5-28.5T320-480q17 0 28.5 11.5T360-440q0 17-11.5 28.5T320-400Zm320 0q-17 0-28.5-11.5T600-440q0-17 11.5-28.5T640-480q17 0 28.5 11.5T680-440q0 17-11.5 28.5T640-400ZM480-240q-17 0-28.5-11.5T440-280q0-17 11.5-28.5T480-320q17 0 28.5 11.5T520-280q0 17-11.5 28.5T480-240Zm-160 0q-17 0-28.5-11.5T280-280q0-17 11.5-28.5T320-320q17 0 28.5 11.5T360-280q0 17-11.5 28.5T320-240Zm320 0q-17 0-28.5-11.5T600-280q0-17 11.5-28.5T640-320q17 0 28.5 11.5T680-280q0 17-11.5 28.5T640-240Z\" />\r\n </svg>\r\n </button>\r\n\r\n <button class=\"btn-view\">\r\n <!-- week view -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\r\n fill=\"currentColor\">\r\n <path\r\n d=\"M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm360-80h100v-480H520v480Zm-180 0h100v-480H340v480Zm-180 0h100v-480H160v480Zm540 0h100v-480H700v480Z\" />\r\n </svg>\r\n </button>\r\n\r\n <button class=\"btn-view\">\r\n <!-- day view -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\r\n fill=\"currentColor\">\r\n <path\r\n d=\"M120-160v-80h720v80H120Zm0-560v-80h720v80H120Zm80 400q-33 0-56.5-23.5T120-400v-160q0-33 23.5-56.5T200-640h560q33 0 56.5 23.5T840-560v160q0 33-23.5 56.5T760-320H200Zm0-80h560v-160H200v160Zm0-160v160-160Z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"body\" #calendarBody>\r\n <div class=\"week-days\">\r\n <div class=\"week-day\" *ngFor=\"let day of weekDays\">\r\n {{ day.tag | translate | slice:0:3 }}\r\n </div>\r\n </div>\r\n\r\n <div class=\"days-grid\">\r\n <div class=\"day-cell\" *ngFor=\"let day of dayCells; let i = index\"\r\n [ngClass]=\"{'outside-month': day.isOutsideMonth, 'is-today': day.isToday}\">\r\n <div class=\"day-number\">\r\n {{ day.date.getDate() }}\r\n </div>\r\n\r\n <div class=\"events-list\">\r\n <lib-calendar-event *ngFor=\"let event of day.events | slice:0:maxEventsInDayCell\"\r\n [event]=\"event\"></lib-calendar-event>\r\n\r\n <div class=\"more-events\" *ngIf=\"day.events.length > (maxEventsInDayCell || 0)\"\r\n (click)=\"openMoreEventsModal(day.date, day.events)\">\r\n {{'nMoreEvents' | translate: {n:(day.events.length - (maxEventsInDayCell || 0))} }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"footer\">\r\n Footer\r\n </div>\r\n\r\n <lib-more-events-modal *ngIf=\"showMoreEventsModal && moreEventsModalDate\" [events]=\"moreEventsModalEvents\"\r\n [date]=\"moreEventsModalDate\" (close)=\"closeMoreEventsModal()\"\r\n (eventClick)=\"closeMoreEventsModal()\"></lib-more-events-modal>\r\n</div>", styles: ["*{box-sizing:border-box;margin:0;padding:0}.calendar-component{display:flex;flex-direction:column;width:100%;height:100%}.header{flex-shrink:0;display:flex;align-items:center;gap:16px;padding:2px 16px}.header .spacer{flex:1 1 auto}.header .nav-controls{display:flex;align-items:center}.header .nav-controls .btn-prev,.header .nav-controls .btn-next{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;background:none;border-radius:50%;cursor:pointer;-webkit-user-select:none;user-select:none}.header .nav-controls .btn-prev:hover,.header .nav-controls .btn-next:hover{background-color:#eee}.header .nav-controls .btn-today{display:flex;align-items:center;height:30px;padding:0 12px;border:none;background:none;border-radius:50px;cursor:pointer;font-weight:600;-webkit-user-select:none;user-select:none}.header .nav-controls .btn-today:hover{background-color:#eee}.header .view-selector{display:flex;align-items:center}.header .view-selector .btn-view{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border:1px solid #cccccc;background:none;cursor:pointer;-webkit-user-select:none;user-select:none}.header .view-selector .btn-view:first-child{border-top-left-radius:4px;border-bottom-left-radius:4px;border-right:none}.header .view-selector .btn-view:last-child{border-top-right-radius:4px;border-bottom-right-radius:4px;border-left:none}.header .view-selector .btn-view:hover{background-color:#eee}.header .view-selector .btn-view svg{width:22px;height:22px}.header .view-selector .btn-view.active{background-color:#0000001a}.header .date-selector-container{position:relative}.header .date-selector-container .date-selector-dropdown{position:absolute;top:100%;left:50%;transform:translate(-50%);background-color:#fff;border-radius:4px;box-shadow:0 2px 24px #0000004d;z-index:3}.header .date-selector-container .date-selector-dropdown:before{content:\"\";position:absolute;top:-6px;left:50%;transform:translate(-50%) rotate(45deg);width:12px;height:12px;background-color:#fff;border-radius:2px}.header .btn-date-selector{display:flex;align-items:center;gap:8px;height:30px;padding:0 8px 0 12px;border:none;background:none;border-radius:50px;cursor:pointer;font-weight:600;-webkit-user-select:none;user-select:none}.header .btn-date-selector:hover{background-color:#eee}.body{flex:1 1 0;display:flex;flex-direction:column;width:100%;min-height:0;height:100%}.week-days{flex-shrink:0;display:grid;grid-template-columns:repeat(7,1fr);width:100%;background-color:#f4f4f4}.week-day{display:flex;align-items:center;justify-content:center;padding:4px;background-color:#fff;font-size:14px;color:#00000080}.days-grid{flex:1 1 0;display:grid;grid-template-columns:repeat(7,1fr);gap:1px;grid-auto-rows:1fr;width:100%;padding:1px;background-color:#f4f4f4;min-height:0;height:100%}.day-cell{display:flex;flex-direction:column;gap:4px;padding:4px;background-color:#fff;overflow:hidden}.day-cell .day-number{display:flex;align-items:center;justify-content:center;width:fit-content;aspect-ratio:1;padding:2px;border-radius:50%;font-size:12px;line-height:16px;font-weight:600;-webkit-user-select:none;user-select:none}.day-cell.outside-month{background-color:#f8f8f8}.day-cell.is-today .day-number{background-color:#007bff;color:#fff}.day-cell .events-list{flex:1 1 auto;display:flex;flex-direction:column;gap:2px;overflow:hidden;min-height:0;max-height:100%}.day-cell .events-list .more-events{padding:2px 8px;border-radius:4px;font-size:12px;color:#555;cursor:pointer}.day-cell .events-list .more-events:hover{background-color:#eee}.footer{flex-shrink:0;background-color:#add8e6}\n"], dependencies: [{ 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: "component", type: CalendarEventComponent, selector: "lib-calendar-event", inputs: ["event"] }, { kind: "component", type: MoreEventsModalComponent, selector: "lib-more-events-modal", inputs: ["events", "date"], outputs: ["close", "eventClick"] }, { kind: "component", type: MonthSelectorComponent, selector: "lib-month-selector", inputs: ["selectedMonth"], outputs: ["monthSelected"] }, { kind: "pipe", type: i1.SlicePipe, name: "slice" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: TranslateMonthPipe, name: "translateMonth" }] });
474
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CalendarComponent, decorators: [{
732
+ SmartCalendarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SmartCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
733
+ SmartCalendarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: SmartCalendarComponent, selector: "smart-calendar", inputs: { mode: "mode", currentMonth: "currentMonth", events: "events" }, outputs: { monthChange: "monthChange", dateChanged: "dateChanged" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "dateSelectorDropdown", first: true, predicate: ["dateSelectorDropdown"], descendants: true }], ngImport: i0, template: "<div class=\"smart-calendar-component\">\n <div class=\"header\">\n <div class=\"nav-controls\">\n <button class=\"btn-prev\" (click)=\"onPrev()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\n fill=\"currentColor\">\n <path d=\"M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z\" />\n </svg>\n </button>\n\n <button class=\"btn-today\" (click)=\"goToToday()\">{{'today' | translate}}</button>\n\n <button class=\"btn-next\" (click)=\"onNext()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\n fill=\"currentColor\">\n <path d=\"M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z\" />\n </svg>\n </button>\n </div>\n\n <div class=\"spacer\"></div>\n\n <div class=\"date-selector-container\">\n <button class=\"btn-date-selector\" (click)=\"toggleDateSelector()\">\n <span *ngIf=\"mode === 'month'\">{{ currentMonth.month | translateMonth}} - {{ currentMonth.year }}</span>\n <span *ngIf=\"mode === 'day'\">{{ selectedDate.toDateString() }}</span>\n\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\n fill=\"currentColor\">\n <path d=\"M480-360 280-560h400L480-360Z\" />\n </svg>\n </button>\n\n <div class=\"date-selector-dropdown\" *ngIf=\"showDateSelector\" #dateSelectorDropdown>\n <lib-month-selector [selectedMonth]=\"currentMonth\"\n (monthSelected)=\"onMonthSelected($event)\"></lib-month-selector>\n </div>\n </div>\n\n <div class=\"spacer\"></div>\n\n <div class=\"view-selector\">\n <button class=\"btn-view\" [ngClass]=\"{active: mode === 'month'}\" (click)=\"mode = 'month'\">\n <!-- month view -->\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\n fill=\"currentColor\">\n <path\n d=\"M200-80q-33 0-56.5-23.5T120-160v-560q0-33 23.5-56.5T200-800h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840-720v560q0 33-23.5 56.5T760-80H200Zm0-80h560v-400H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Zm280 240q-17 0-28.5-11.5T440-440q0-17 11.5-28.5T480-480q17 0 28.5 11.5T520-440q0 17-11.5 28.5T480-400Zm-160 0q-17 0-28.5-11.5T280-440q0-17 11.5-28.5T320-480q17 0 28.5 11.5T360-440q0 17-11.5 28.5T320-400Zm320 0q-17 0-28.5-11.5T600-440q0-17 11.5-28.5T640-480q17 0 28.5 11.5T680-440q0 17-11.5 28.5T640-400ZM480-240q-17 0-28.5-11.5T440-280q0-17 11.5-28.5T480-320q17 0 28.5 11.5T520-280q0 17-11.5 28.5T480-240Zm-160 0q-17 0-28.5-11.5T280-280q0-17 11.5-28.5T320-320q17 0 28.5 11.5T360-280q0 17-11.5 28.5T320-240Zm320 0q-17 0-28.5-11.5T600-280q0-17 11.5-28.5T640-320q17 0 28.5 11.5T680-280q0 17-11.5 28.5T640-240Z\" />\n </svg>\n </button>\n\n <button class=\"btn-view\" [ngClass]=\"{active: mode === 'week'}\" (click)=\"mode = 'week'\">\n <!-- week view -->\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\n fill=\"currentColor\">\n <path\n d=\"M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm360-80h100v-480H520v480Zm-180 0h100v-480H340v480Zm-180 0h100v-480H160v480Zm540 0h100v-480H700v480Z\" />\n </svg>\n </button>\n\n <button class=\"btn-view\" [ngClass]=\"{active: mode === 'day'}\" (click)=\"mode = 'day'\">\n <!-- day view -->\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\n fill=\"currentColor\">\n <path\n d=\"M120-160v-80h720v80H120Zm0-560v-80h720v80H120Zm80 400q-33 0-56.5-23.5T120-400v-160q0-33 23.5-56.5T200-640h560q33 0 56.5 23.5T840-560v160q0 33-23.5 56.5T760-320H200Zm0-80h560v-160H200v160Zm0-160v160-160Z\" />\n </svg>\n </button>\n </div>\n </div>\n\n <div class=\"view-container\">\n <lib-calendar [events]=\"events\" [currentMonth]=\"currentMonth\" *ngIf=\"mode === 'month'\"></lib-calendar>\n\n <lib-day *ngIf=\"mode === 'day'\" [date]=\"selectedDate\" [events]=\"selectedDateEvents\"></lib-day>\n </div>\n\n</div>", styles: ["*{box-sizing:border-box;margin:0;padding:0}.smart-calendar-component{display:flex;flex-direction:column;width:100%;height:100%;background-color:#fff}.header{flex-shrink:0;display:flex;align-items:center;gap:16px;padding:2px 16px}.header .spacer{flex:1 1 auto}.header .nav-controls{display:flex;align-items:center}.header .nav-controls .btn-prev,.header .nav-controls .btn-next{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;background:none;border-radius:50%;cursor:pointer;-webkit-user-select:none;user-select:none}.header .nav-controls .btn-prev:hover,.header .nav-controls .btn-next:hover{background-color:#eee}.header .nav-controls .btn-today{display:flex;align-items:center;height:30px;padding:0 12px;border:none;background:none;border-radius:50px;cursor:pointer;font-weight:600;-webkit-user-select:none;user-select:none}.header .nav-controls .btn-today:hover{background-color:#eee}.header .view-selector{display:flex;align-items:center}.header .view-selector .btn-view{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border:1px solid #cccccc;background:none;cursor:pointer;-webkit-user-select:none;user-select:none}.header .view-selector .btn-view:first-child{border-top-left-radius:4px;border-bottom-left-radius:4px;border-right:none}.header .view-selector .btn-view:last-child{border-top-right-radius:4px;border-bottom-right-radius:4px;border-left:none}.header .view-selector .btn-view:hover{background-color:#eee}.header .view-selector .btn-view svg{width:22px;height:22px}.header .view-selector .btn-view.active{background-color:#0000001a}.header .date-selector-container{position:relative}.header .date-selector-container .date-selector-dropdown{position:absolute;top:100%;left:50%;transform:translate(-50%);background-color:#fff;border-radius:4px;box-shadow:0 2px 24px #0000004d;z-index:3}.header .date-selector-container .date-selector-dropdown:before{content:\"\";position:absolute;top:-6px;left:50%;transform:translate(-50%) rotate(45deg);width:12px;height:12px;background-color:#fff;border-radius:2px}.header .btn-date-selector{display:flex;align-items:center;gap:8px;height:30px;padding:0 8px 0 12px;border:none;background:none;border-radius:50px;cursor:pointer;font-weight:600;-webkit-user-select:none;user-select:none}.header .btn-date-selector:hover{background-color:#eee}.view-container{flex:1 1 auto;overflow:hidden}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: CalendarComponent, selector: "lib-calendar", inputs: ["currentMonth", "events", "startAt"] }, { kind: "component", type: MonthSelectorComponent, selector: "lib-month-selector", inputs: ["selectedMonth"], outputs: ["monthSelected"] }, { kind: "component", type: DayComponent, selector: "lib-day", inputs: ["events", "date"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: TranslateMonthPipe, name: "translateMonth" }] });
734
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SmartCalendarComponent, decorators: [{
475
735
  type: Component,
476
- args: [{ selector: 'lib-calendar', template: "<div class=\"calendar-component\">\r\n <div class=\"header\">\r\n <div class=\"nav-controls\">\r\n <button class=\"btn-prev\" (click)=\"prevMonth()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\r\n fill=\"currentColor\">\r\n <path d=\"M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z\" />\r\n </svg>\r\n </button>\r\n\r\n <button class=\"btn-today\" (click)=\"goToToday()\">{{'today' | translate}}</button>\r\n\r\n <button class=\"btn-next\" (click)=\"nextMonth()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\r\n fill=\"currentColor\">\r\n <path d=\"M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"spacer\"></div>\r\n\r\n <div class=\"date-selector-container\">\r\n <button class=\"btn-date-selector\" (click)=\"toggleDateSelector()\">\r\n <span>{{ currentMonth.month | translateMonth}} - {{ currentMonth.year }}</span>\r\n\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\r\n fill=\"currentColor\">\r\n <path d=\"M480-360 280-560h400L480-360Z\" />\r\n </svg>\r\n </button>\r\n\r\n <div class=\"date-selector-dropdown\" *ngIf=\"showDateSelector\" #dateSelectorDropdown>\r\n <lib-month-selector [selectedMonth]=\"currentMonth\"\r\n (monthSelected)=\"onMonthSelected($event)\"></lib-month-selector>\r\n </div>\r\n </div>\r\n\r\n <div class=\"spacer\"></div>\r\n\r\n <div class=\"view-selector\">\r\n <button class=\"btn-view active\">\r\n <!-- month view -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\r\n fill=\"currentColor\">\r\n <path\r\n d=\"M200-80q-33 0-56.5-23.5T120-160v-560q0-33 23.5-56.5T200-800h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840-720v560q0 33-23.5 56.5T760-80H200Zm0-80h560v-400H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Zm280 240q-17 0-28.5-11.5T440-440q0-17 11.5-28.5T480-480q17 0 28.5 11.5T520-440q0 17-11.5 28.5T480-400Zm-160 0q-17 0-28.5-11.5T280-440q0-17 11.5-28.5T320-480q17 0 28.5 11.5T360-440q0 17-11.5 28.5T320-400Zm320 0q-17 0-28.5-11.5T600-440q0-17 11.5-28.5T640-480q17 0 28.5 11.5T680-440q0 17-11.5 28.5T640-400ZM480-240q-17 0-28.5-11.5T440-280q0-17 11.5-28.5T480-320q17 0 28.5 11.5T520-280q0 17-11.5 28.5T480-240Zm-160 0q-17 0-28.5-11.5T280-280q0-17 11.5-28.5T320-320q17 0 28.5 11.5T360-280q0 17-11.5 28.5T320-240Zm320 0q-17 0-28.5-11.5T600-280q0-17 11.5-28.5T640-320q17 0 28.5 11.5T680-280q0 17-11.5 28.5T640-240Z\" />\r\n </svg>\r\n </button>\r\n\r\n <button class=\"btn-view\">\r\n <!-- week view -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\r\n fill=\"currentColor\">\r\n <path\r\n d=\"M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm360-80h100v-480H520v480Zm-180 0h100v-480H340v480Zm-180 0h100v-480H160v480Zm540 0h100v-480H700v480Z\" />\r\n </svg>\r\n </button>\r\n\r\n <button class=\"btn-view\">\r\n <!-- day view -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\r\n fill=\"currentColor\">\r\n <path\r\n d=\"M120-160v-80h720v80H120Zm0-560v-80h720v80H120Zm80 400q-33 0-56.5-23.5T120-400v-160q0-33 23.5-56.5T200-640h560q33 0 56.5 23.5T840-560v160q0 33-23.5 56.5T760-320H200Zm0-80h560v-160H200v160Zm0-160v160-160Z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"body\" #calendarBody>\r\n <div class=\"week-days\">\r\n <div class=\"week-day\" *ngFor=\"let day of weekDays\">\r\n {{ day.tag | translate | slice:0:3 }}\r\n </div>\r\n </div>\r\n\r\n <div class=\"days-grid\">\r\n <div class=\"day-cell\" *ngFor=\"let day of dayCells; let i = index\"\r\n [ngClass]=\"{'outside-month': day.isOutsideMonth, 'is-today': day.isToday}\">\r\n <div class=\"day-number\">\r\n {{ day.date.getDate() }}\r\n </div>\r\n\r\n <div class=\"events-list\">\r\n <lib-calendar-event *ngFor=\"let event of day.events | slice:0:maxEventsInDayCell\"\r\n [event]=\"event\"></lib-calendar-event>\r\n\r\n <div class=\"more-events\" *ngIf=\"day.events.length > (maxEventsInDayCell || 0)\"\r\n (click)=\"openMoreEventsModal(day.date, day.events)\">\r\n {{'nMoreEvents' | translate: {n:(day.events.length - (maxEventsInDayCell || 0))} }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"footer\">\r\n Footer\r\n </div>\r\n\r\n <lib-more-events-modal *ngIf=\"showMoreEventsModal && moreEventsModalDate\" [events]=\"moreEventsModalEvents\"\r\n [date]=\"moreEventsModalDate\" (close)=\"closeMoreEventsModal()\"\r\n (eventClick)=\"closeMoreEventsModal()\"></lib-more-events-modal>\r\n</div>", styles: ["*{box-sizing:border-box;margin:0;padding:0}.calendar-component{display:flex;flex-direction:column;width:100%;height:100%}.header{flex-shrink:0;display:flex;align-items:center;gap:16px;padding:2px 16px}.header .spacer{flex:1 1 auto}.header .nav-controls{display:flex;align-items:center}.header .nav-controls .btn-prev,.header .nav-controls .btn-next{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;background:none;border-radius:50%;cursor:pointer;-webkit-user-select:none;user-select:none}.header .nav-controls .btn-prev:hover,.header .nav-controls .btn-next:hover{background-color:#eee}.header .nav-controls .btn-today{display:flex;align-items:center;height:30px;padding:0 12px;border:none;background:none;border-radius:50px;cursor:pointer;font-weight:600;-webkit-user-select:none;user-select:none}.header .nav-controls .btn-today:hover{background-color:#eee}.header .view-selector{display:flex;align-items:center}.header .view-selector .btn-view{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border:1px solid #cccccc;background:none;cursor:pointer;-webkit-user-select:none;user-select:none}.header .view-selector .btn-view:first-child{border-top-left-radius:4px;border-bottom-left-radius:4px;border-right:none}.header .view-selector .btn-view:last-child{border-top-right-radius:4px;border-bottom-right-radius:4px;border-left:none}.header .view-selector .btn-view:hover{background-color:#eee}.header .view-selector .btn-view svg{width:22px;height:22px}.header .view-selector .btn-view.active{background-color:#0000001a}.header .date-selector-container{position:relative}.header .date-selector-container .date-selector-dropdown{position:absolute;top:100%;left:50%;transform:translate(-50%);background-color:#fff;border-radius:4px;box-shadow:0 2px 24px #0000004d;z-index:3}.header .date-selector-container .date-selector-dropdown:before{content:\"\";position:absolute;top:-6px;left:50%;transform:translate(-50%) rotate(45deg);width:12px;height:12px;background-color:#fff;border-radius:2px}.header .btn-date-selector{display:flex;align-items:center;gap:8px;height:30px;padding:0 8px 0 12px;border:none;background:none;border-radius:50px;cursor:pointer;font-weight:600;-webkit-user-select:none;user-select:none}.header .btn-date-selector:hover{background-color:#eee}.body{flex:1 1 0;display:flex;flex-direction:column;width:100%;min-height:0;height:100%}.week-days{flex-shrink:0;display:grid;grid-template-columns:repeat(7,1fr);width:100%;background-color:#f4f4f4}.week-day{display:flex;align-items:center;justify-content:center;padding:4px;background-color:#fff;font-size:14px;color:#00000080}.days-grid{flex:1 1 0;display:grid;grid-template-columns:repeat(7,1fr);gap:1px;grid-auto-rows:1fr;width:100%;padding:1px;background-color:#f4f4f4;min-height:0;height:100%}.day-cell{display:flex;flex-direction:column;gap:4px;padding:4px;background-color:#fff;overflow:hidden}.day-cell .day-number{display:flex;align-items:center;justify-content:center;width:fit-content;aspect-ratio:1;padding:2px;border-radius:50%;font-size:12px;line-height:16px;font-weight:600;-webkit-user-select:none;user-select:none}.day-cell.outside-month{background-color:#f8f8f8}.day-cell.is-today .day-number{background-color:#007bff;color:#fff}.day-cell .events-list{flex:1 1 auto;display:flex;flex-direction:column;gap:2px;overflow:hidden;min-height:0;max-height:100%}.day-cell .events-list .more-events{padding:2px 8px;border-radius:4px;font-size:12px;color:#555;cursor:pointer}.day-cell .events-list .more-events:hover{background-color:#eee}.footer{flex-shrink:0;background-color:#add8e6}\n"] }]
477
- }], ctorParameters: function () { return []; }, propDecorators: { currentMonth: [{
736
+ args: [{ selector: 'smart-calendar', template: "<div class=\"smart-calendar-component\">\n <div class=\"header\">\n <div class=\"nav-controls\">\n <button class=\"btn-prev\" (click)=\"onPrev()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\n fill=\"currentColor\">\n <path d=\"M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z\" />\n </svg>\n </button>\n\n <button class=\"btn-today\" (click)=\"goToToday()\">{{'today' | translate}}</button>\n\n <button class=\"btn-next\" (click)=\"onNext()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\n fill=\"currentColor\">\n <path d=\"M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z\" />\n </svg>\n </button>\n </div>\n\n <div class=\"spacer\"></div>\n\n <div class=\"date-selector-container\">\n <button class=\"btn-date-selector\" (click)=\"toggleDateSelector()\">\n <span *ngIf=\"mode === 'month'\">{{ currentMonth.month | translateMonth}} - {{ currentMonth.year }}</span>\n <span *ngIf=\"mode === 'day'\">{{ selectedDate.toDateString() }}</span>\n\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\n fill=\"currentColor\">\n <path d=\"M480-360 280-560h400L480-360Z\" />\n </svg>\n </button>\n\n <div class=\"date-selector-dropdown\" *ngIf=\"showDateSelector\" #dateSelectorDropdown>\n <lib-month-selector [selectedMonth]=\"currentMonth\"\n (monthSelected)=\"onMonthSelected($event)\"></lib-month-selector>\n </div>\n </div>\n\n <div class=\"spacer\"></div>\n\n <div class=\"view-selector\">\n <button class=\"btn-view\" [ngClass]=\"{active: mode === 'month'}\" (click)=\"mode = 'month'\">\n <!-- month view -->\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\n fill=\"currentColor\">\n <path\n d=\"M200-80q-33 0-56.5-23.5T120-160v-560q0-33 23.5-56.5T200-800h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840-720v560q0 33-23.5 56.5T760-80H200Zm0-80h560v-400H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Zm280 240q-17 0-28.5-11.5T440-440q0-17 11.5-28.5T480-480q17 0 28.5 11.5T520-440q0 17-11.5 28.5T480-400Zm-160 0q-17 0-28.5-11.5T280-440q0-17 11.5-28.5T320-480q17 0 28.5 11.5T360-440q0 17-11.5 28.5T320-400Zm320 0q-17 0-28.5-11.5T600-440q0-17 11.5-28.5T640-480q17 0 28.5 11.5T680-440q0 17-11.5 28.5T640-400ZM480-240q-17 0-28.5-11.5T440-280q0-17 11.5-28.5T480-320q17 0 28.5 11.5T520-280q0 17-11.5 28.5T480-240Zm-160 0q-17 0-28.5-11.5T280-280q0-17 11.5-28.5T320-320q17 0 28.5 11.5T360-280q0 17-11.5 28.5T320-240Zm320 0q-17 0-28.5-11.5T600-280q0-17 11.5-28.5T640-320q17 0 28.5 11.5T680-280q0 17-11.5 28.5T640-240Z\" />\n </svg>\n </button>\n\n <button class=\"btn-view\" [ngClass]=\"{active: mode === 'week'}\" (click)=\"mode = 'week'\">\n <!-- week view -->\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\n fill=\"currentColor\">\n <path\n d=\"M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm360-80h100v-480H520v480Zm-180 0h100v-480H340v480Zm-180 0h100v-480H160v480Zm540 0h100v-480H700v480Z\" />\n </svg>\n </button>\n\n <button class=\"btn-view\" [ngClass]=\"{active: mode === 'day'}\" (click)=\"mode = 'day'\">\n <!-- day view -->\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\"\n fill=\"currentColor\">\n <path\n d=\"M120-160v-80h720v80H120Zm0-560v-80h720v80H120Zm80 400q-33 0-56.5-23.5T120-400v-160q0-33 23.5-56.5T200-640h560q33 0 56.5 23.5T840-560v160q0 33-23.5 56.5T760-320H200Zm0-80h560v-160H200v160Zm0-160v160-160Z\" />\n </svg>\n </button>\n </div>\n </div>\n\n <div class=\"view-container\">\n <lib-calendar [events]=\"events\" [currentMonth]=\"currentMonth\" *ngIf=\"mode === 'month'\"></lib-calendar>\n\n <lib-day *ngIf=\"mode === 'day'\" [date]=\"selectedDate\" [events]=\"selectedDateEvents\"></lib-day>\n </div>\n\n</div>", styles: ["*{box-sizing:border-box;margin:0;padding:0}.smart-calendar-component{display:flex;flex-direction:column;width:100%;height:100%;background-color:#fff}.header{flex-shrink:0;display:flex;align-items:center;gap:16px;padding:2px 16px}.header .spacer{flex:1 1 auto}.header .nav-controls{display:flex;align-items:center}.header .nav-controls .btn-prev,.header .nav-controls .btn-next{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;background:none;border-radius:50%;cursor:pointer;-webkit-user-select:none;user-select:none}.header .nav-controls .btn-prev:hover,.header .nav-controls .btn-next:hover{background-color:#eee}.header .nav-controls .btn-today{display:flex;align-items:center;height:30px;padding:0 12px;border:none;background:none;border-radius:50px;cursor:pointer;font-weight:600;-webkit-user-select:none;user-select:none}.header .nav-controls .btn-today:hover{background-color:#eee}.header .view-selector{display:flex;align-items:center}.header .view-selector .btn-view{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border:1px solid #cccccc;background:none;cursor:pointer;-webkit-user-select:none;user-select:none}.header .view-selector .btn-view:first-child{border-top-left-radius:4px;border-bottom-left-radius:4px;border-right:none}.header .view-selector .btn-view:last-child{border-top-right-radius:4px;border-bottom-right-radius:4px;border-left:none}.header .view-selector .btn-view:hover{background-color:#eee}.header .view-selector .btn-view svg{width:22px;height:22px}.header .view-selector .btn-view.active{background-color:#0000001a}.header .date-selector-container{position:relative}.header .date-selector-container .date-selector-dropdown{position:absolute;top:100%;left:50%;transform:translate(-50%);background-color:#fff;border-radius:4px;box-shadow:0 2px 24px #0000004d;z-index:3}.header .date-selector-container .date-selector-dropdown:before{content:\"\";position:absolute;top:-6px;left:50%;transform:translate(-50%) rotate(45deg);width:12px;height:12px;background-color:#fff;border-radius:2px}.header .btn-date-selector{display:flex;align-items:center;gap:8px;height:30px;padding:0 8px 0 12px;border:none;background:none;border-radius:50px;cursor:pointer;font-weight:600;-webkit-user-select:none;user-select:none}.header .btn-date-selector:hover{background-color:#eee}.view-container{flex:1 1 auto;overflow:hidden}\n"] }]
737
+ }], ctorParameters: function () { return []; }, propDecorators: { mode: [{
478
738
  type: Input
479
- }], events: [{
739
+ }], currentMonth: [{
480
740
  type: Input
481
- }], startAt: [{
741
+ }], events: [{
482
742
  type: Input
483
743
  }], monthChange: [{
484
744
  type: Output
485
- }], calendarRef: [{
486
- type: ViewChild,
487
- args: ['calendar']
488
- }], calendarBodyRef: [{
489
- type: ViewChild,
490
- args: ['calendarBody']
745
+ }], dateChanged: [{
746
+ type: Output
491
747
  }], dateSelectorDropdown: [{
492
748
  type: ViewChild,
493
749
  args: ['dateSelectorDropdown', { static: false }]
@@ -496,22 +752,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
496
752
  args: ['document:click', ['$event']]
497
753
  }] } });
498
754
 
499
- class SmartCalendarComponent {
500
- constructor() {
501
- this.events = [];
502
- }
503
- ngOnInit() {
504
- }
505
- }
506
- SmartCalendarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SmartCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
507
- SmartCalendarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: SmartCalendarComponent, selector: "smart-calendar", inputs: { events: "events" }, ngImport: i0, template: "<div class=\"smart-calendar-component\">\n <lib-calendar [events]=\"events\"></lib-calendar>\n</div>", styles: [".smart-calendar-component{width:100%;height:100%;background-color:#fff;border:1px solid #dddddd}\n"], dependencies: [{ kind: "component", type: CalendarComponent, selector: "lib-calendar", inputs: ["currentMonth", "events", "startAt"], outputs: ["monthChange"] }] });
508
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SmartCalendarComponent, decorators: [{
509
- type: Component,
510
- args: [{ selector: 'smart-calendar', template: "<div class=\"smart-calendar-component\">\n <lib-calendar [events]=\"events\"></lib-calendar>\n</div>", styles: [".smart-calendar-component{width:100%;height:100%;background-color:#fff;border:1px solid #dddddd}\n"] }]
511
- }], ctorParameters: function () { return []; }, propDecorators: { events: [{
512
- type: Input
513
- }] } });
514
-
515
755
  class SmartAngularCalendarModule {
516
756
  }
517
757
  SmartAngularCalendarModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SmartAngularCalendarModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
@@ -521,7 +761,9 @@ SmartAngularCalendarModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.
521
761
  CalendarEventComponent,
522
762
  MoreEventsModalComponent,
523
763
  TranslateMonthPipe,
524
- MonthSelectorComponent], imports: [CommonModule], exports: [SmartCalendarComponent] });
764
+ MonthSelectorComponent,
765
+ DayComponent,
766
+ DurationEventComponent], imports: [CommonModule], exports: [SmartCalendarComponent] });
525
767
  SmartAngularCalendarModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SmartAngularCalendarModule, imports: [CommonModule] });
526
768
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SmartAngularCalendarModule, decorators: [{
527
769
  type: NgModule,
@@ -533,7 +775,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
533
775
  CalendarEventComponent,
534
776
  MoreEventsModalComponent,
535
777
  TranslateMonthPipe,
536
- MonthSelectorComponent
778
+ MonthSelectorComponent,
779
+ DayComponent,
780
+ DurationEventComponent
537
781
  ],
538
782
  imports: [
539
783
  CommonModule