@acorex/modules 19.4.13 → 19.4.15
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.
- package/assets/images/weather/cloudy-day-1.svg +175 -0
- package/assets/images/weather/cloudy-day-2.svg +176 -0
- package/assets/images/weather/cloudy-day-3.svg +175 -0
- package/assets/images/weather/cloudy-night-1.svg +198 -0
- package/assets/images/weather/cloudy-night-2.svg +198 -0
- package/assets/images/weather/cloudy-night-3.svg +198 -0
- package/assets/images/weather/cloudy.svg +500 -0
- package/assets/images/weather/day.svg +521 -0
- package/assets/images/weather/night.svg +503 -0
- package/assets/images/weather/rainy-1.svg +157 -0
- package/assets/images/weather/rainy-2.svg +133 -0
- package/assets/images/weather/rainy-3.svg +157 -0
- package/assets/images/weather/rainy-4.svg +66 -0
- package/assets/images/weather/rainy-5.svg +90 -0
- package/assets/images/weather/rainy-6.svg +91 -0
- package/assets/images/weather/rainy-7.svg +91 -0
- package/assets/images/weather/snowy-1.svg +230 -0
- package/assets/images/weather/snowy-2.svg +237 -0
- package/assets/images/weather/snowy-3.svg +268 -0
- package/assets/images/weather/snowy-4.svg +94 -0
- package/assets/images/weather/snowy-5.svg +166 -0
- package/assets/images/weather/snowy-6.svg +225 -0
- package/assets/images/weather/thunder.svg +268 -0
- package/assets/images/weather/weather-sprite.svg +1245 -0
- package/assets/images/weather/weather.svg +1245 -0
- package/assets/images/weather/weather_sagittarius.svg +9 -0
- package/assets/images/weather/weather_sunset.svg +14 -0
- package/content-management/index.d.ts +2 -0
- package/content-management/lib/entities/index.d.ts +1 -0
- package/content-management/lib/entities/promotion/index.d.ts +5 -0
- package/content-management/lib/features/index.d.ts +1 -0
- package/content-management/lib/features/promotion/components/index.d.ts +1 -0
- package/content-management/lib/features/promotion/index.d.ts +1 -0
- package/conversation/lib/features/chat/components/chat-preview/chat-preview.component.d.ts +0 -1
- package/conversation/lib/features/index.d.ts +1 -0
- package/conversation/lib/features/widget/share/comment/comment-widget-view.component.d.ts +66 -0
- package/conversation/lib/features/widget/share/comment/comment-widget.config.d.ts +2 -0
- package/conversation/lib/features/widget/share/comment/index.d.ts +2 -0
- package/dashboard-management/lib/features/home-dashboard/dashboard-popups/index.d.ts +3 -0
- package/dashboard-management/lib/features/home-dashboard/index.d.ts +3 -0
- package/dashboard-management/lib/features/home-dashboard/setrting.keys.d.ts +3 -0
- package/dashboard-management/lib/features/home-dashboard/widget-wrapper/index.d.ts +1 -0
- package/dashboard-management/lib/features/shared/widgets/analog-clock/analog-clock-widget-view.component.d.ts +9 -0
- package/dashboard-management/lib/features/shared/widgets/analog-clock/analog-clock-widget.config.d.ts +7 -0
- package/dashboard-management/lib/features/shared/widgets/analog-clock/analog-clock.component.d.ts +28 -0
- package/dashboard-management/lib/features/shared/widgets/analog-clock/index.d.ts +3 -0
- package/dashboard-management/lib/features/shared/widgets/index.d.ts +1 -0
- package/dashboard-management/lib/features/shared/widgets/weather/advanced-weather/advanced-weather.component.d.ts +32 -0
- package/dashboard-management/lib/features/shared/widgets/weather/advanced-weather/advanced-weather.config.d.ts +14 -0
- package/dashboard-management/lib/features/shared/widgets/weather/advanced-weather/index.d.ts +2 -0
- package/dashboard-management/lib/features/shared/widgets/weather/index.d.ts +2 -0
- package/dashboard-management/lib/features/shared/widgets/weather/minimal-weather/index.d.ts +2 -0
- package/dashboard-management/lib/features/shared/widgets/weather/minimal-weather/minimal-weather.component.d.ts +22 -0
- package/dashboard-management/lib/features/shared/widgets/weather/minimal-weather/minimal-weather.config.d.ts +14 -0
- package/dashboard-management/lib/features/shared/widgets/weather/weather-services/weather-api.abstract.d.ts +19 -0
- package/dashboard-management/lib/features/shared/widgets/weather/weather-widget.component.d.ts +5 -5
- package/fesm2022/{acorex-modules-application-management-module-designer.component-BJp8imYd.mjs → acorex-modules-application-management-module-designer.component-ZKzHxJ0D.mjs} +2 -2
- package/fesm2022/{acorex-modules-application-management-module-designer.component-BJp8imYd.mjs.map → acorex-modules-application-management-module-designer.component-ZKzHxJ0D.mjs.map} +1 -1
- package/fesm2022/acorex-modules-application-management.mjs +1 -1
- package/fesm2022/acorex-modules-content-management.mjs +1288 -1
- package/fesm2022/acorex-modules-content-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-conversation.mjs +476 -15
- package/fesm2022/acorex-modules-conversation.mjs.map +1 -1
- package/fesm2022/acorex-modules-dashboard-management.mjs +1224 -30
- package/fesm2022/acorex-modules-dashboard-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-notification-management.mjs +7 -7
- package/fesm2022/acorex-modules-notification-management.mjs.map +1 -1
- package/fesm2022/{acorex-modules-platform-management-acorex-modules-platform-management-B8aACrqL.mjs → acorex-modules-platform-management-acorex-modules-platform-management-CGGoHpYi.mjs} +132 -54
- package/fesm2022/acorex-modules-platform-management-acorex-modules-platform-management-CGGoHpYi.mjs.map +1 -0
- package/fesm2022/{acorex-modules-platform-management-list-version.component-DhSicYd3.mjs → acorex-modules-platform-management-list-version.component-CGxYFnd9.mjs} +2 -2
- package/fesm2022/{acorex-modules-platform-management-list-version.component-DhSicYd3.mjs.map → acorex-modules-platform-management-list-version.component-CGxYFnd9.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-platform-management-settings.provider-CnGAUpof.mjs → acorex-modules-platform-management-settings.provider-CHAI3QHV.mjs} +2 -2
- package/fesm2022/{acorex-modules-platform-management-settings.provider-CnGAUpof.mjs.map → acorex-modules-platform-management-settings.provider-CHAI3QHV.mjs.map} +1 -1
- package/fesm2022/acorex-modules-platform-management.mjs +1 -1
- package/fesm2022/acorex-modules-project-management.mjs +95 -21
- package/fesm2022/acorex-modules-project-management.mjs.map +1 -1
- package/fesm2022/{acorex-modules-security-management-permissions-editor.component-Ccx0_9L_.mjs → acorex-modules-security-management-permissions-editor.component-B2OIvMs7.mjs} +2 -2
- package/fesm2022/{acorex-modules-security-management-permissions-editor.component-Ccx0_9L_.mjs.map → acorex-modules-security-management-permissions-editor.component-B2OIvMs7.mjs.map} +1 -1
- package/fesm2022/acorex-modules-security-management.mjs +1 -1
- package/package.json +1 -1
- package/platform-management/lib/entities/data-source/datasource-provider.dynamic.d.ts +2 -0
- package/platform-management/lib/features/common/regional/data-source.provider.d.ts +1 -0
- package/fesm2022/acorex-modules-content-management-acorex-modules-content-management-C23PlUCn.mjs +0 -392
- package/fesm2022/acorex-modules-content-management-acorex-modules-content-management-C23PlUCn.mjs.map +0 -1
- package/fesm2022/acorex-modules-content-management-promotion.entity-D3qRwZhQ.mjs +0 -892
- package/fesm2022/acorex-modules-content-management-promotion.entity-D3qRwZhQ.mjs.map +0 -1
- package/fesm2022/acorex-modules-platform-management-acorex-modules-platform-management-B8aACrqL.mjs.map +0 -1
@@ -1,11 +1,13 @@
|
|
1
1
|
import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
|
2
2
|
import { createAllQueryView, AXPEntityCommandScope, AXPEntityQueryType, AXP_HOME_PAGES, AXP_MENU_PROVIDER, AXP_HOME_PAGE_DEFAULT_KEY, AXPSettingService } from '@acorex/platform/common';
|
3
3
|
import * as i3$1 from '@acorex/platform/layout/builder';
|
4
|
-
import { AXPWidgetsCatalog,
|
4
|
+
import { AXPWidgetsCatalog, AXPLayoutWidgetComponent, AXPWidgetGroupEnum, AXPValueWidgetComponent, cloneProperty, AXPLayoutBuilderModule, AXPWidgetRendererDirective } from '@acorex/platform/layout/builder';
|
5
5
|
import { AXMEntityCrudServiceImpl, AXPEntityService, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
|
6
|
-
import { AXP_APPEARANCE_PROPERTY_GROUP, AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_BEHAVIOR_PROPERTY_GROUP, AXP_BG_COLOR_PROPERTY, plainTextDefaultProperty,
|
6
|
+
import { AXP_DATA_PROPERTY_GROUP, AXP_APPEARANCE_PROPERTY_GROUP, AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_BEHAVIOR_PROPERTY_GROUP, AXP_BG_COLOR_PROPERTY, plainTextDefaultProperty, AXP_COLOR_PROPERTY, AXPWidgetsModule } from '@acorex/platform/widgets';
|
7
7
|
import * as i0 from '@angular/core';
|
8
|
-
import { Injectable, inject, Injector, computed, ChangeDetectionStrategy, Component, ChangeDetectorRef,
|
8
|
+
import { Injectable, inject, Injector, input, signal, computed, effect, ChangeDetectionStrategy, Component, ChangeDetectorRef, viewChild, ElementRef, HostListener, output, InjectionToken, HostBinding, NgModule, contentChild, afterNextRender, model, ViewEncapsulation } from '@angular/core';
|
9
|
+
import * as i1 from '@angular/common';
|
10
|
+
import { CommonModule, DatePipe } from '@angular/common';
|
9
11
|
import { AXBarChartComponent } from '@acorex/charts/bar-chart';
|
10
12
|
import * as i2$2 from '@acorex/components/decorators';
|
11
13
|
import { AXDecoratorModule } from '@acorex/components/decorators';
|
@@ -13,9 +15,7 @@ import { AXTagModule } from '@acorex/components/tag';
|
|
13
15
|
import { AXDateTimeModule } from '@acorex/core/date-time';
|
14
16
|
import * as i2 from '@acorex/core/format';
|
15
17
|
import { AXFormatModule } from '@acorex/core/format';
|
16
|
-
import
|
17
|
-
import { CommonModule, DatePipe } from '@angular/common';
|
18
|
-
import { interval, map, Observable, catchError, throwError, switchMap, firstValueFrom } from 'rxjs';
|
18
|
+
import { interval, map, Observable, catchError, throwError, of, finalize, switchMap, firstValueFrom } from 'rxjs';
|
19
19
|
import { AXDonutChartComponent } from '@acorex/charts/donut-chart';
|
20
20
|
import { AXGaugeChartComponent } from '@acorex/charts/gauge-chart';
|
21
21
|
import { AXLineChartComponent } from '@acorex/charts/line-chart';
|
@@ -40,6 +40,9 @@ import { AXLabelModule } from '@acorex/components/label';
|
|
40
40
|
import { AXTabsModule } from '@acorex/components/tabs';
|
41
41
|
import * as i2$3 from '@acorex/core/translation';
|
42
42
|
import { AXTranslationModule, AXTranslationService } from '@acorex/core/translation';
|
43
|
+
import * as i2$4 from '@acorex/components/skeleton';
|
44
|
+
import { AXSkeletonModule } from '@acorex/components/skeleton';
|
45
|
+
import { AXTooltipModule } from '@acorex/components/tooltip';
|
43
46
|
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
44
47
|
import { AXPopupService } from '@acorex/components/popup';
|
45
48
|
import { AXP_GLOBAL_SEARCH_CONFIG_TOKEN } from '@acorex/modules/common';
|
@@ -56,7 +59,7 @@ import { AXPWidgetPropertyViewerComponent, AXPWidgetPickerService, AXPDesignerSe
|
|
56
59
|
import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageLayoutBase } from '@acorex/platform/layout/views';
|
57
60
|
import { AXPLayoutThemeService } from '@acorex/platform/themes/shared';
|
58
61
|
import { AXPThemeLayoutBlockComponent } from '@acorex/platform/layout/components';
|
59
|
-
import * as i2$
|
62
|
+
import * as i2$5 from '@acorex/components/loading';
|
60
63
|
import { AXLoadingModule } from '@acorex/components/loading';
|
61
64
|
import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
|
62
65
|
import { AXBasePageComponent } from '@acorex/components/page';
|
@@ -449,6 +452,320 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
|
|
449
452
|
type: Injectable
|
450
453
|
}] });
|
451
454
|
|
455
|
+
class AXMAnalogClockComponent {
|
456
|
+
constructor() {
|
457
|
+
this.timezone = input();
|
458
|
+
this.showNumbers = input(true);
|
459
|
+
this.currentTime = signal(new Date());
|
460
|
+
this.timeParts = signal({ hours: 0, minutes: 0, seconds: 0 });
|
461
|
+
this.hourHandTransform = computed(() => {
|
462
|
+
const { hours, minutes } = this.timeParts();
|
463
|
+
const hoursAngle = (hours % 12) * 30 + minutes * 0.5;
|
464
|
+
return `translateX(-50%) rotate(${hoursAngle}deg)`;
|
465
|
+
});
|
466
|
+
this.minuteHandTransform = computed(() => {
|
467
|
+
const { minutes, seconds } = this.timeParts();
|
468
|
+
const minutesAngle = minutes * 6 + seconds * 0.1;
|
469
|
+
return `translateX(-50%) rotate(${minutesAngle}deg)`;
|
470
|
+
});
|
471
|
+
this.secondHandTransform = computed(() => {
|
472
|
+
const { seconds } = this.timeParts();
|
473
|
+
const secondsAngle = seconds * 6;
|
474
|
+
return `translateX(-50%) rotate(${secondsAngle}deg)`;
|
475
|
+
});
|
476
|
+
this.hourLines = [];
|
477
|
+
this.hourNumbers = [];
|
478
|
+
this.dots = [];
|
479
|
+
effect(() => {
|
480
|
+
const now = this.currentTime();
|
481
|
+
const tz = this.timezone();
|
482
|
+
let hours, minutes, seconds;
|
483
|
+
if (tz) {
|
484
|
+
try {
|
485
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
486
|
+
timeZone: tz,
|
487
|
+
hour12: false,
|
488
|
+
hour: 'numeric',
|
489
|
+
minute: 'numeric',
|
490
|
+
second: 'numeric',
|
491
|
+
});
|
492
|
+
const parts = formatter.formatToParts(now);
|
493
|
+
hours = parseInt(parts.find((p) => p.type === 'hour')?.value ?? '0', 10);
|
494
|
+
minutes = parseInt(parts.find((p) => p.type === 'minute')?.value ?? '0', 10);
|
495
|
+
seconds = parseInt(parts.find((p) => p.type === 'second')?.value ?? '0', 10);
|
496
|
+
}
|
497
|
+
catch (e) {
|
498
|
+
console.error(`Invalid timezone provided: "${tz}". Falling back to local time.`);
|
499
|
+
hours = now.getHours();
|
500
|
+
minutes = now.getMinutes();
|
501
|
+
seconds = now.getSeconds();
|
502
|
+
}
|
503
|
+
}
|
504
|
+
else {
|
505
|
+
hours = now.getHours();
|
506
|
+
minutes = now.getMinutes();
|
507
|
+
seconds = now.getSeconds();
|
508
|
+
}
|
509
|
+
this.timeParts.set({ hours, minutes, seconds });
|
510
|
+
});
|
511
|
+
}
|
512
|
+
ngOnInit() {
|
513
|
+
this.createClockMarks();
|
514
|
+
this.timerId = window.setInterval(() => {
|
515
|
+
this.currentTime.set(new Date());
|
516
|
+
}, 1000);
|
517
|
+
}
|
518
|
+
ngOnDestroy() {
|
519
|
+
if (this.timerId) {
|
520
|
+
clearInterval(this.timerId);
|
521
|
+
}
|
522
|
+
}
|
523
|
+
createClockMarks() {
|
524
|
+
const majorHours = [12, 3, 6, 9];
|
525
|
+
// Hour Lines
|
526
|
+
this.hourLines = [];
|
527
|
+
for (let i = 1; i <= 12; i++) {
|
528
|
+
this.hourLines.push({
|
529
|
+
transform: `translateX(-50%) rotate(${i * 30}deg)`,
|
530
|
+
});
|
531
|
+
}
|
532
|
+
// Hour Numbers
|
533
|
+
this.hourNumbers = [];
|
534
|
+
for (const hour of majorHours) {
|
535
|
+
const angleRad = (hour * 30 - 90) * (Math.PI / 180);
|
536
|
+
this.hourNumbers.push({
|
537
|
+
value: hour,
|
538
|
+
top: `calc(50% + ${33 * Math.sin(angleRad)}%)`,
|
539
|
+
left: `calc(50% + ${33 * Math.cos(angleRad)}%)`,
|
540
|
+
});
|
541
|
+
}
|
542
|
+
// Dots
|
543
|
+
this.dots = [];
|
544
|
+
for (let i = 1; i <= 60; i++) {
|
545
|
+
if (i % 5 !== 0) {
|
546
|
+
this.dots.push({
|
547
|
+
transform: `translateX(-50%) rotate(${i * 6}deg)`,
|
548
|
+
});
|
549
|
+
}
|
550
|
+
}
|
551
|
+
}
|
552
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXMAnalogClockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
553
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXMAnalogClockComponent, isStandalone: true, selector: "axm-analog-clock", inputs: { timezone: { classPropertyName: "timezone", publicName: "timezone", isSignal: true, isRequired: false, transformFunction: null }, showNumbers: { classPropertyName: "showNumbers", publicName: "showNumbers", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
554
|
+
<div class="axm-analog-clock-container">
|
555
|
+
<div class="axm-analog-clock-face">
|
556
|
+
<div class="axm-analog-clock-marks-container">
|
557
|
+
@for (line of hourLines; track $index) {
|
558
|
+
<div class="axm-analog-clock-hour-line" [style.transform]="line.transform">
|
559
|
+
<div class="axm-analog-clock-hour-line-inner"></div>
|
560
|
+
</div>
|
561
|
+
}
|
562
|
+
@for (dot of dots; track $index) {
|
563
|
+
<div class="axm-analog-clock-dot-line" [style.transform]="dot.transform">
|
564
|
+
<div class="axm-analog-clock-dot-line-inner"></div>
|
565
|
+
</div>
|
566
|
+
}
|
567
|
+
</div>
|
568
|
+
|
569
|
+
@if (showNumbers()) {
|
570
|
+
<div class="axm-analog-clock-numbers-container">
|
571
|
+
@for (num of hourNumbers; track num.value) {
|
572
|
+
<div class="axm-analog-clock-hour-number" [style.top]="num.top" [style.left]="num.left">
|
573
|
+
{{ num.value }}
|
574
|
+
</div>
|
575
|
+
}
|
576
|
+
</div>
|
577
|
+
}
|
578
|
+
<div class="axm-analog-clock-hands">
|
579
|
+
<div class="axm-analog-clock-hand axm-analog-clock-hour-hand" [style.transform]="hourHandTransform()"></div>
|
580
|
+
<div
|
581
|
+
class="axm-analog-clock-hand axm-analog-clock-minute-hand"
|
582
|
+
[style.transform]="minuteHandTransform()"
|
583
|
+
></div>
|
584
|
+
<div
|
585
|
+
class="axm-analog-clock-hand axm-analog-clock-second-hand"
|
586
|
+
[style.transform]="secondHandTransform()"
|
587
|
+
></div>
|
588
|
+
<div class="axm-analog-clock-center-point"></div>
|
589
|
+
</div>
|
590
|
+
</div>
|
591
|
+
</div>
|
592
|
+
`, isInline: true, styles: [":host{display:grid;width:100%;height:100%;place-items:center}.axm-analog-clock-container{position:relative;max-height:100%;width:100%;aspect-ratio:1;container-type:inline-size}.axm-analog-clock-face{position:relative;height:100%;width:100%}.axm-analog-clock-marks-container,.axm-analog-clock-numbers-container,.axm-analog-clock-hands{position:absolute;top:0;right:0;bottom:0;left:0}.axm-analog-clock-hour-line,.axm-analog-clock-dot-line{position:absolute;bottom:50%;left:50%;height:50%;transform-origin:bottom}.axm-analog-clock-hour-line{width:1.8cqw}.axm-analog-clock-dot-line{width:2.4cqw}.axm-analog-clock-hour-line-inner{position:absolute;top:6cqw;left:50%;height:5.5cqw;width:100%;--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));--tw-bg-opacity: 1;background-color:rgb(156 163 175 / var(--tw-bg-opacity, 1))}.axm-analog-clock-dot-line-inner{position:absolute;top:6cqw;left:50%;height:2.4cqw;width:100%;--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));border-radius:9999px;--tw-bg-opacity: 1;background-color:rgb(209 213 219 / var(--tw-bg-opacity, 1))}.axm-analog-clock-hour-number{position:absolute;--tw-translate-x: -50%;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));font-size:12cqw;font-weight:500;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.axm-analog-clock-hand{position:absolute;bottom:50%;left:50%;transform-origin:bottom;border-top-left-radius:.5rem;border-top-right-radius:.5rem}.axm-analog-clock-hand:after{content:\"\";position:absolute;left:0;width:100%}.axm-analog-clock-hour-hand{z-index:20;height:25%;width:2.7cqw;--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.axm-analog-clock-hour-hand:after{bottom:-20%;height:20%;--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.axm-analog-clock-minute-hand{z-index:30;height:35%;width:2.1cqw;--tw-bg-opacity: 1;background-color:rgb(156 163 175 / var(--tw-bg-opacity, 1))}.axm-analog-clock-minute-hand:after{bottom:-20%;height:20%;--tw-bg-opacity: 1;background-color:rgb(156 163 175 / var(--tw-bg-opacity, 1))}.axm-analog-clock-second-hand{z-index:40;height:42%;width:1.5cqw;--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.axm-analog-clock-second-hand:after{bottom:-20%;height:20%;--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.axm-analog-clock-center-point{position:absolute;top:50%;left:50%;z-index:50;height:9cqw;width:9cqw;--tw-translate-x: -50%;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));border-radius:9999px;border-width:1.8cqw;--tw-border-opacity: 1;border-color:rgb(0 0 0 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
593
|
+
}
|
594
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXMAnalogClockComponent, decorators: [{
|
595
|
+
type: Component,
|
596
|
+
args: [{ selector: 'axm-analog-clock', standalone: true, imports: [CommonModule], template: `
|
597
|
+
<div class="axm-analog-clock-container">
|
598
|
+
<div class="axm-analog-clock-face">
|
599
|
+
<div class="axm-analog-clock-marks-container">
|
600
|
+
@for (line of hourLines; track $index) {
|
601
|
+
<div class="axm-analog-clock-hour-line" [style.transform]="line.transform">
|
602
|
+
<div class="axm-analog-clock-hour-line-inner"></div>
|
603
|
+
</div>
|
604
|
+
}
|
605
|
+
@for (dot of dots; track $index) {
|
606
|
+
<div class="axm-analog-clock-dot-line" [style.transform]="dot.transform">
|
607
|
+
<div class="axm-analog-clock-dot-line-inner"></div>
|
608
|
+
</div>
|
609
|
+
}
|
610
|
+
</div>
|
611
|
+
|
612
|
+
@if (showNumbers()) {
|
613
|
+
<div class="axm-analog-clock-numbers-container">
|
614
|
+
@for (num of hourNumbers; track num.value) {
|
615
|
+
<div class="axm-analog-clock-hour-number" [style.top]="num.top" [style.left]="num.left">
|
616
|
+
{{ num.value }}
|
617
|
+
</div>
|
618
|
+
}
|
619
|
+
</div>
|
620
|
+
}
|
621
|
+
<div class="axm-analog-clock-hands">
|
622
|
+
<div class="axm-analog-clock-hand axm-analog-clock-hour-hand" [style.transform]="hourHandTransform()"></div>
|
623
|
+
<div
|
624
|
+
class="axm-analog-clock-hand axm-analog-clock-minute-hand"
|
625
|
+
[style.transform]="minuteHandTransform()"
|
626
|
+
></div>
|
627
|
+
<div
|
628
|
+
class="axm-analog-clock-hand axm-analog-clock-second-hand"
|
629
|
+
[style.transform]="secondHandTransform()"
|
630
|
+
></div>
|
631
|
+
<div class="axm-analog-clock-center-point"></div>
|
632
|
+
</div>
|
633
|
+
</div>
|
634
|
+
</div>
|
635
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:grid;width:100%;height:100%;place-items:center}.axm-analog-clock-container{position:relative;max-height:100%;width:100%;aspect-ratio:1;container-type:inline-size}.axm-analog-clock-face{position:relative;height:100%;width:100%}.axm-analog-clock-marks-container,.axm-analog-clock-numbers-container,.axm-analog-clock-hands{position:absolute;top:0;right:0;bottom:0;left:0}.axm-analog-clock-hour-line,.axm-analog-clock-dot-line{position:absolute;bottom:50%;left:50%;height:50%;transform-origin:bottom}.axm-analog-clock-hour-line{width:1.8cqw}.axm-analog-clock-dot-line{width:2.4cqw}.axm-analog-clock-hour-line-inner{position:absolute;top:6cqw;left:50%;height:5.5cqw;width:100%;--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));--tw-bg-opacity: 1;background-color:rgb(156 163 175 / var(--tw-bg-opacity, 1))}.axm-analog-clock-dot-line-inner{position:absolute;top:6cqw;left:50%;height:2.4cqw;width:100%;--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));border-radius:9999px;--tw-bg-opacity: 1;background-color:rgb(209 213 219 / var(--tw-bg-opacity, 1))}.axm-analog-clock-hour-number{position:absolute;--tw-translate-x: -50%;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));font-size:12cqw;font-weight:500;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.axm-analog-clock-hand{position:absolute;bottom:50%;left:50%;transform-origin:bottom;border-top-left-radius:.5rem;border-top-right-radius:.5rem}.axm-analog-clock-hand:after{content:\"\";position:absolute;left:0;width:100%}.axm-analog-clock-hour-hand{z-index:20;height:25%;width:2.7cqw;--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.axm-analog-clock-hour-hand:after{bottom:-20%;height:20%;--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.axm-analog-clock-minute-hand{z-index:30;height:35%;width:2.1cqw;--tw-bg-opacity: 1;background-color:rgb(156 163 175 / var(--tw-bg-opacity, 1))}.axm-analog-clock-minute-hand:after{bottom:-20%;height:20%;--tw-bg-opacity: 1;background-color:rgb(156 163 175 / var(--tw-bg-opacity, 1))}.axm-analog-clock-second-hand{z-index:40;height:42%;width:1.5cqw;--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.axm-analog-clock-second-hand:after{bottom:-20%;height:20%;--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.axm-analog-clock-center-point{position:absolute;top:50%;left:50%;z-index:50;height:9cqw;width:9cqw;--tw-translate-x: -50%;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));border-radius:9999px;border-width:1.8cqw;--tw-border-opacity: 1;border-color:rgb(0 0 0 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}\n"] }]
|
636
|
+
}], ctorParameters: () => [] });
|
637
|
+
|
638
|
+
class AXMClockWidgetViewComponent extends AXPLayoutWidgetComponent {
|
639
|
+
constructor() {
|
640
|
+
super(...arguments);
|
641
|
+
this.timezone = computed(() => this.options()?.timezone);
|
642
|
+
this.others = computed(() => (this.options()?.others ?? []));
|
643
|
+
}
|
644
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXMClockWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
645
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXMClockWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: `
|
646
|
+
<div class="ax-size-full ax-p-4">
|
647
|
+
<div class="ax-flex ax-items-center ax-justify-center ax-gap-4 ax-w-full ax-flex-wrap">
|
648
|
+
<div class="ax-flex-1 ax-max-w-[50%] ax-min-w-[110px] ax-aspect-square">
|
649
|
+
<axm-analog-clock [timezone]="timezone()?.iana"></axm-analog-clock>
|
650
|
+
</div>
|
651
|
+
@if (timezone()?.abbr) {
|
652
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-justify-center">
|
653
|
+
<span class="ax-text-xl">{{ timezone()?.code }}</span>
|
654
|
+
<span class="ax-text-3xl">{{ timezone()?.abbr }}</span>
|
655
|
+
</div>
|
656
|
+
}
|
657
|
+
</div>
|
658
|
+
|
659
|
+
<div class="ax-w-full ax-flex ax-gap-2 ax-items-start ax-justify-center ax-flex-wrap ax-pt-8">
|
660
|
+
@for (clock of others(); track clock.code) {
|
661
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-gap-1">
|
662
|
+
<div class="ax-w-full ax-aspect-square" style="min-width: 75px; max-width: 150px;">
|
663
|
+
<axm-analog-clock [timezone]="clock.iana" [showNumbers]="false"></axm-analog-clock>
|
664
|
+
</div>
|
665
|
+
@if (clock.abbr) {
|
666
|
+
<span class="ax-text-xl ax-text-center">{{ clock.abbr }}</span>
|
667
|
+
}
|
668
|
+
</div>
|
669
|
+
}
|
670
|
+
</div>
|
671
|
+
</div>
|
672
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXMAnalogClockComponent, selector: "axm-analog-clock", inputs: ["timezone", "showNumbers"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
673
|
+
}
|
674
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXMClockWidgetViewComponent, decorators: [{
|
675
|
+
type: Component,
|
676
|
+
args: [{ template: `
|
677
|
+
<div class="ax-size-full ax-p-4">
|
678
|
+
<div class="ax-flex ax-items-center ax-justify-center ax-gap-4 ax-w-full ax-flex-wrap">
|
679
|
+
<div class="ax-flex-1 ax-max-w-[50%] ax-min-w-[110px] ax-aspect-square">
|
680
|
+
<axm-analog-clock [timezone]="timezone()?.iana"></axm-analog-clock>
|
681
|
+
</div>
|
682
|
+
@if (timezone()?.abbr) {
|
683
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-justify-center">
|
684
|
+
<span class="ax-text-xl">{{ timezone()?.code }}</span>
|
685
|
+
<span class="ax-text-3xl">{{ timezone()?.abbr }}</span>
|
686
|
+
</div>
|
687
|
+
}
|
688
|
+
</div>
|
689
|
+
|
690
|
+
<div class="ax-w-full ax-flex ax-gap-2 ax-items-start ax-justify-center ax-flex-wrap ax-pt-8">
|
691
|
+
@for (clock of others(); track clock.code) {
|
692
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-gap-1">
|
693
|
+
<div class="ax-w-full ax-aspect-square" style="min-width: 75px; max-width: 150px;">
|
694
|
+
<axm-analog-clock [timezone]="clock.iana" [showNumbers]="false"></axm-analog-clock>
|
695
|
+
</div>
|
696
|
+
@if (clock.abbr) {
|
697
|
+
<span class="ax-text-xl ax-text-center">{{ clock.abbr }}</span>
|
698
|
+
}
|
699
|
+
</div>
|
700
|
+
}
|
701
|
+
</div>
|
702
|
+
</div>
|
703
|
+
`, standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXMAnalogClockComponent], styles: [":host{display:block;width:100%;height:100%}\n"] }]
|
704
|
+
}] });
|
705
|
+
|
706
|
+
var analogClockWidgetView_component = /*#__PURE__*/Object.freeze({
|
707
|
+
__proto__: null,
|
708
|
+
AXMClockWidgetViewComponent: AXMClockWidgetViewComponent
|
709
|
+
});
|
710
|
+
|
711
|
+
const AXPAnalogClockWidget = {
|
712
|
+
name: 'analog-clock',
|
713
|
+
title: 'Analog Clock',
|
714
|
+
description: '',
|
715
|
+
type: 'view',
|
716
|
+
categories: [],
|
717
|
+
groups: [AXPWidgetGroupEnum.DashboardWidget],
|
718
|
+
icon: 'fa-solid fa-square',
|
719
|
+
properties: [
|
720
|
+
{
|
721
|
+
name: 'timezone',
|
722
|
+
title: '@dashboard:widgets.analog-clock.timezone',
|
723
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
724
|
+
schema: {
|
725
|
+
dataType: 'object',
|
726
|
+
interface: {
|
727
|
+
name: 'timezone',
|
728
|
+
path: 'options.timezone',
|
729
|
+
type: AXPWidgetsCatalog.select,
|
730
|
+
options: {
|
731
|
+
dataSource: 'timezones',
|
732
|
+
textField: 'title',
|
733
|
+
valueField: 'code',
|
734
|
+
},
|
735
|
+
},
|
736
|
+
},
|
737
|
+
visible: true,
|
738
|
+
order: 1,
|
739
|
+
},
|
740
|
+
{
|
741
|
+
name: 'others',
|
742
|
+
title: '@dashboard:widgets.analog-clock.other-timezones',
|
743
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
744
|
+
schema: {
|
745
|
+
dataType: 'object',
|
746
|
+
interface: {
|
747
|
+
name: 'others',
|
748
|
+
path: 'options.others',
|
749
|
+
type: AXPWidgetsCatalog.select,
|
750
|
+
options: {
|
751
|
+
multiple: true,
|
752
|
+
dataSource: 'timezones',
|
753
|
+
textField: 'title',
|
754
|
+
valueField: 'code',
|
755
|
+
},
|
756
|
+
},
|
757
|
+
},
|
758
|
+
visible: true,
|
759
|
+
order: 2,
|
760
|
+
},
|
761
|
+
],
|
762
|
+
components: {
|
763
|
+
view: {
|
764
|
+
component: () => Promise.resolve().then(function () { return analogClockWidgetView_component; }).then((c) => c.AXMClockWidgetViewComponent),
|
765
|
+
},
|
766
|
+
},
|
767
|
+
};
|
768
|
+
|
452
769
|
/**
|
453
770
|
* Bar Chart Widget Component
|
454
771
|
* Renders data as vertical bars with interactive hover effects and animations
|
@@ -2372,7 +2689,7 @@ class AXPTaskListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
2372
2689
|
return Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
2373
2690
|
}
|
2374
2691
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPTaskListWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
2375
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXPTaskListWidgetViewComponent, isStandalone: true, selector: "ng-component", outputs: { taskClick: "taskClick", taskCompleted: "taskCompleted" }, providers: [DatePipe], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-size-full ax-p-4 ax-flex ax-flex-col\">\n <!-- Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <h3 class=\"ax-text-lg ax-font-semibold ax-flex ax-items-center ax-gap-2\">\n <ax-icon class=\"ax-text-primary-500\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n {{ 'tasklist.title' | translate: { scope: 'dashboard' } | async }}\n </h3>\n <div class=\"ax-flex ax-gap-2\">\n @if (getPendingTaskCount() > 0) {\n <ax-badge\n [text]=\"getPendingTaskCount() + ' ' + ('tasklist.pending' | translate: { scope: 'dashboard' } | async)\"\n [color]=\"'warning'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n @if (getCompletedTaskCount() > 0) {\n <ax-badge\n [text]=\"getCompletedTaskCount() + ' ' + ('tasklist.completed' | translate: { scope: 'dashboard' } | async)\"\n [color]=\"'success'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"ax-space-y-4 ax-my-4 ax-px-1 ax-overflow-auto ax-grow\">\n @if (showCategories() && hasCategories()) {\n <!-- Categorized Tasks -->\n @for (category of getCategories(); track category) {\n <div class=\"ax-mb-5\">\n <!-- Category Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3 ax-h-5\">\n <h4 class=\"ax-font-medium category-header\">{{ category }}</h4>\n @if (getCategoryTaskCount(category)) {\n <ax-badge\n [text]=\"getCategoryTaskCount(category).toString()\"\n [color]=\"'primary'\"\n size=\"sm\"\n class=\"ax-rounded-full\"\n ></ax-badge>\n }\n </div>\n <!-- Tasks in Category -->\n <div class=\"ax-space-y-2\">\n @for (task of getTasksByCategory(category); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n }\n </div>\n </div>\n }\n } @else {\n <!-- Uncategorized Tasks -->\n <div class=\"ax-space-y-2\">\n @for (task of taskItems(); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n } @empty {\n <!-- Empty State -->\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-14 ax-px-4 ax-text-gray-400 empty-state\"\n >\n <ax-icon class=\"ax-text-5xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n <p class=\"ax-text-center ax-font-medium\">\n {{ 'tasklist.noTasks' | translate: { scope: 'dashboard' } | async }}\n </p>\n <p class=\"ax-text-center ax-text-sm ax-mt-2\">\n {{ 'tasklist.addTask' | translate: { scope: 'dashboard' } | async }}\n </p>\n </div>\n }\n </div>\n }\n </div>\n</div>\n\n<!-- Task Item Template -->\n<ng-template #taskItemTemplateRef let-task>\n <div\n class=\"ax-flex ax-gap-3 ax-items-start ax-p-3
|
2692
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXPTaskListWidgetViewComponent, isStandalone: true, selector: "ng-component", outputs: { taskClick: "taskClick", taskCompleted: "taskCompleted" }, providers: [DatePipe], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-size-full ax-p-4 ax-flex ax-flex-col\">\n <!-- Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <h3 class=\"ax-text-lg ax-font-semibold ax-flex ax-items-center ax-gap-2\">\n <ax-icon class=\"ax-text-primary-500\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n {{ 'tasklist.title' | translate: { scope: 'dashboard' } | async }}\n </h3>\n <div class=\"ax-flex ax-gap-2\">\n @if (getPendingTaskCount() > 0) {\n <ax-badge\n [text]=\"getPendingTaskCount() + ' ' + ('tasklist.pending' | translate: { scope: 'dashboard' } | async)\"\n [color]=\"'warning'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n @if (getCompletedTaskCount() > 0) {\n <ax-badge\n [text]=\"getCompletedTaskCount() + ' ' + ('tasklist.completed' | translate: { scope: 'dashboard' } | async)\"\n [color]=\"'success'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"ax-space-y-4 ax-my-4 ax-px-1 ax-overflow-auto ax-grow\">\n @if (showCategories() && hasCategories()) {\n <!-- Categorized Tasks -->\n @for (category of getCategories(); track category) {\n <div class=\"ax-mb-5\">\n <!-- Category Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3 ax-h-5\">\n <h4 class=\"ax-font-medium category-header\">{{ category }}</h4>\n @if (getCategoryTaskCount(category)) {\n <ax-badge\n [text]=\"getCategoryTaskCount(category).toString()\"\n [color]=\"'primary'\"\n size=\"sm\"\n class=\"ax-rounded-full\"\n ></ax-badge>\n }\n </div>\n <!-- Tasks in Category -->\n <div class=\"ax-space-y-2\">\n @for (task of getTasksByCategory(category); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n }\n </div>\n </div>\n }\n } @else {\n <!-- Uncategorized Tasks -->\n <div class=\"ax-space-y-2\">\n @for (task of taskItems(); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n } @empty {\n <!-- Empty State -->\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-14 ax-px-4 ax-text-gray-400 empty-state\"\n >\n <ax-icon class=\"ax-text-5xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n <p class=\"ax-text-center ax-font-medium\">\n {{ 'tasklist.noTasks' | translate: { scope: 'dashboard' } | async }}\n </p>\n <p class=\"ax-text-center ax-text-sm ax-mt-2\">\n {{ 'tasklist.addTask' | translate: { scope: 'dashboard' } | async }}\n </p>\n </div>\n }\n </div>\n }\n </div>\n</div>\n\n<!-- Task Item Template -->\n<ng-template #taskItemTemplateRef let-task>\n <div\n class=\"ax-flex ax-gap-3 ax-items-start ax-p-3 task-item\"\n [class.priority-high]=\"task.priority === 'high'\"\n [class.priority-medium]=\"task.priority === 'medium'\"\n [class.priority-low]=\"task.priority === 'low'\"\n >\n <!-- Checkbox -->\n <ax-check-box\n class=\"ax-flex-shrink-0 ax-mt-1 task-checkbox\"\n [value]=\"task.completed\"\n [disabled]=\"!allowMarkComplete()\"\n (valueChange)=\"onTaskCompletionChange(task, $event)\"\n >\n </ax-check-box>\n\n <!-- Task Details -->\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\" (click)=\"onTaskClick(task)\">\n <!-- Title and Priority -->\n <div class=\"ax-flex ax-items-center ax-gap-2\">\n <h6 class=\"ax-font-medium ax-truncate ax-pb-1\" [title]=\"task.title\" [class.task-completed]=\"task.completed\">\n {{ task.title }}\n </h6>\n @if (showPriority() && task.priority) {\n <ax-badge\n [color]=\"getPriorityColor(task.priority)\"\n [text]=\"task.priority\"\n size=\"sm\"\n class=\"ax-ml-1 ax-rounded-full\"\n ></ax-badge>\n }\n </div>\n\n <!-- Metadata -->\n <div class=\"ax-flex ax-flex-wrap ax-gap-x-3 ax-gap-y-1 ax-mt-2 ax-text-xs ax-text-gray-500\">\n @if (showDate() && task.dueDate) {\n <span\n class=\"ax-flex ax-items-center ax-gap-1 due-date\"\n [class.ax-text-danger-500]=\"getDaysDifference(task.dueDate) < 0\"\n [class.overdue]=\"getDaysDifference(task.dueDate) < 0\"\n >\n <ax-icon><i class=\"fa-light fa-calendar\"></i></ax-icon>\n {{ formatDueDate(task.dueDate) }}\n </span>\n }\n @if (showAssignee() && task.assignedTo) {\n <span class=\"ax-flex ax-items-center ax-gap-1\">\n @if (task.assignedTo.image) {\n <ax-icon class=\"ax-bg-primary-100 ax-text-primary-500 ax-rounded-full ax-p-1\">\n <i class=\"fa-light fa-user\"></i>\n </ax-icon>\n } @else {\n <ax-icon><i class=\"fa-light fa-user\"></i></ax-icon>\n }\n {{ task.assignedTo.name }}\n </span>\n }\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block;height:100%;width:100%}.task-item{transition:all .2s ease-in-out;border-left:3px solid transparent}.task-item:hover{background-color:rgba(var(--ax-sys-color-on-surface),.1);transform:translateY(-2px);box-shadow:0 2px 8px rgba(0,0,0,.05)}.task-item.priority-high{border-left-color:rgb(var(--ax-sys-color-danger-500))}.task-item.priority-medium{border-left-color:rgb(var(--ax-sys-color-warning-500))}.task-item.priority-low{border-left-color:rgb(var(--ax-sys-color-success-500))}.task-item:active{transform:translateY(0);box-shadow:0 1px 3px rgba(0,0,0,.05)}.task-completed{text-decoration:line-through;color:var(--ax-text-secondary);opacity:.7;transition:all .3s ease}.category-header{position:relative}.category-header:after{content:\"\";position:absolute;bottom:-8px;left:0;width:40px;height:3px;background-color:var(--ax-primary-500);border-radius:3px;transition:width .3s ease}.category-header:hover:after{width:60px}.empty-state{animation:fadeIn .5s ease}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.task-checkbox ::ng-deep .ax-checkbox{transition:all .2s ease}.task-checkbox ::ng-deep .ax-checkbox:hover{transform:scale(1.1)}.due-date.overdue{animation:pulse 2s infinite}@keyframes pulse{0%{opacity:.7}50%{opacity:1}to{opacity:.7}}.ax-space-y-2>*{animation:slideInRight .3s ease forwards;opacity:0}.ax-space-y-2>*:nth-child(1){animation-delay:.05s}.ax-space-y-2>*:nth-child(2){animation-delay:.1s}.ax-space-y-2>*:nth-child(3){animation-delay:.15s}.ax-space-y-2>*:nth-child(4){animation-delay:.2s}.ax-space-y-2>*:nth-child(5){animation-delay:.25s}.ax-space-y-2>*:nth-child(6){animation-delay:.3s}.ax-space-y-2>*:nth-child(7){animation-delay:.35s}.ax-space-y-2>*:nth-child(8){animation-delay:.4s}.ax-space-y-2>*:nth-child(9){animation-delay:.45s}.ax-space-y-2>*:nth-child(10){animation-delay:.5s}@keyframes slideInRight{0%{opacity:0;transform:translate(10px)}to{opacity:1;transform:translate(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTabsModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i3.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "text", "look"] }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "ngmodule", type: AXImageModule }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i4.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "checked", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXLabelModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i2$3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
2376
2693
|
}
|
2377
2694
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPTaskListWidgetViewComponent, decorators: [{
|
2378
2695
|
type: Component,
|
@@ -2387,7 +2704,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
|
|
2387
2704
|
AXCheckBoxModule,
|
2388
2705
|
AXLabelModule,
|
2389
2706
|
AXTranslationModule,
|
2390
|
-
], providers: [DatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-size-full ax-p-4 ax-flex ax-flex-col\">\n <!-- Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <h3 class=\"ax-text-lg ax-font-semibold ax-flex ax-items-center ax-gap-2\">\n <ax-icon class=\"ax-text-primary-500\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n {{ 'tasklist.title' | translate: { scope: 'dashboard' } | async }}\n </h3>\n <div class=\"ax-flex ax-gap-2\">\n @if (getPendingTaskCount() > 0) {\n <ax-badge\n [text]=\"getPendingTaskCount() + ' ' + ('tasklist.pending' | translate: { scope: 'dashboard' } | async)\"\n [color]=\"'warning'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n @if (getCompletedTaskCount() > 0) {\n <ax-badge\n [text]=\"getCompletedTaskCount() + ' ' + ('tasklist.completed' | translate: { scope: 'dashboard' } | async)\"\n [color]=\"'success'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"ax-space-y-4 ax-my-4 ax-px-1 ax-overflow-auto ax-grow\">\n @if (showCategories() && hasCategories()) {\n <!-- Categorized Tasks -->\n @for (category of getCategories(); track category) {\n <div class=\"ax-mb-5\">\n <!-- Category Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3 ax-h-5\">\n <h4 class=\"ax-font-medium category-header\">{{ category }}</h4>\n @if (getCategoryTaskCount(category)) {\n <ax-badge\n [text]=\"getCategoryTaskCount(category).toString()\"\n [color]=\"'primary'\"\n size=\"sm\"\n class=\"ax-rounded-full\"\n ></ax-badge>\n }\n </div>\n <!-- Tasks in Category -->\n <div class=\"ax-space-y-2\">\n @for (task of getTasksByCategory(category); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n }\n </div>\n </div>\n }\n } @else {\n <!-- Uncategorized Tasks -->\n <div class=\"ax-space-y-2\">\n @for (task of taskItems(); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n } @empty {\n <!-- Empty State -->\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-14 ax-px-4 ax-text-gray-400 empty-state\"\n >\n <ax-icon class=\"ax-text-5xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n <p class=\"ax-text-center ax-font-medium\">\n {{ 'tasklist.noTasks' | translate: { scope: 'dashboard' } | async }}\n </p>\n <p class=\"ax-text-center ax-text-sm ax-mt-2\">\n {{ 'tasklist.addTask' | translate: { scope: 'dashboard' } | async }}\n </p>\n </div>\n }\n </div>\n }\n </div>\n</div>\n\n<!-- Task Item Template -->\n<ng-template #taskItemTemplateRef let-task>\n <div\n class=\"ax-flex ax-gap-3 ax-items-start ax-p-3
|
2707
|
+
], providers: [DatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-size-full ax-p-4 ax-flex ax-flex-col\">\n <!-- Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <h3 class=\"ax-text-lg ax-font-semibold ax-flex ax-items-center ax-gap-2\">\n <ax-icon class=\"ax-text-primary-500\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n {{ 'tasklist.title' | translate: { scope: 'dashboard' } | async }}\n </h3>\n <div class=\"ax-flex ax-gap-2\">\n @if (getPendingTaskCount() > 0) {\n <ax-badge\n [text]=\"getPendingTaskCount() + ' ' + ('tasklist.pending' | translate: { scope: 'dashboard' } | async)\"\n [color]=\"'warning'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n @if (getCompletedTaskCount() > 0) {\n <ax-badge\n [text]=\"getCompletedTaskCount() + ' ' + ('tasklist.completed' | translate: { scope: 'dashboard' } | async)\"\n [color]=\"'success'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"ax-space-y-4 ax-my-4 ax-px-1 ax-overflow-auto ax-grow\">\n @if (showCategories() && hasCategories()) {\n <!-- Categorized Tasks -->\n @for (category of getCategories(); track category) {\n <div class=\"ax-mb-5\">\n <!-- Category Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3 ax-h-5\">\n <h4 class=\"ax-font-medium category-header\">{{ category }}</h4>\n @if (getCategoryTaskCount(category)) {\n <ax-badge\n [text]=\"getCategoryTaskCount(category).toString()\"\n [color]=\"'primary'\"\n size=\"sm\"\n class=\"ax-rounded-full\"\n ></ax-badge>\n }\n </div>\n <!-- Tasks in Category -->\n <div class=\"ax-space-y-2\">\n @for (task of getTasksByCategory(category); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n }\n </div>\n </div>\n }\n } @else {\n <!-- Uncategorized Tasks -->\n <div class=\"ax-space-y-2\">\n @for (task of taskItems(); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n } @empty {\n <!-- Empty State -->\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-14 ax-px-4 ax-text-gray-400 empty-state\"\n >\n <ax-icon class=\"ax-text-5xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n <p class=\"ax-text-center ax-font-medium\">\n {{ 'tasklist.noTasks' | translate: { scope: 'dashboard' } | async }}\n </p>\n <p class=\"ax-text-center ax-text-sm ax-mt-2\">\n {{ 'tasklist.addTask' | translate: { scope: 'dashboard' } | async }}\n </p>\n </div>\n }\n </div>\n }\n </div>\n</div>\n\n<!-- Task Item Template -->\n<ng-template #taskItemTemplateRef let-task>\n <div\n class=\"ax-flex ax-gap-3 ax-items-start ax-p-3 task-item\"\n [class.priority-high]=\"task.priority === 'high'\"\n [class.priority-medium]=\"task.priority === 'medium'\"\n [class.priority-low]=\"task.priority === 'low'\"\n >\n <!-- Checkbox -->\n <ax-check-box\n class=\"ax-flex-shrink-0 ax-mt-1 task-checkbox\"\n [value]=\"task.completed\"\n [disabled]=\"!allowMarkComplete()\"\n (valueChange)=\"onTaskCompletionChange(task, $event)\"\n >\n </ax-check-box>\n\n <!-- Task Details -->\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\" (click)=\"onTaskClick(task)\">\n <!-- Title and Priority -->\n <div class=\"ax-flex ax-items-center ax-gap-2\">\n <h6 class=\"ax-font-medium ax-truncate ax-pb-1\" [title]=\"task.title\" [class.task-completed]=\"task.completed\">\n {{ task.title }}\n </h6>\n @if (showPriority() && task.priority) {\n <ax-badge\n [color]=\"getPriorityColor(task.priority)\"\n [text]=\"task.priority\"\n size=\"sm\"\n class=\"ax-ml-1 ax-rounded-full\"\n ></ax-badge>\n }\n </div>\n\n <!-- Metadata -->\n <div class=\"ax-flex ax-flex-wrap ax-gap-x-3 ax-gap-y-1 ax-mt-2 ax-text-xs ax-text-gray-500\">\n @if (showDate() && task.dueDate) {\n <span\n class=\"ax-flex ax-items-center ax-gap-1 due-date\"\n [class.ax-text-danger-500]=\"getDaysDifference(task.dueDate) < 0\"\n [class.overdue]=\"getDaysDifference(task.dueDate) < 0\"\n >\n <ax-icon><i class=\"fa-light fa-calendar\"></i></ax-icon>\n {{ formatDueDate(task.dueDate) }}\n </span>\n }\n @if (showAssignee() && task.assignedTo) {\n <span class=\"ax-flex ax-items-center ax-gap-1\">\n @if (task.assignedTo.image) {\n <ax-icon class=\"ax-bg-primary-100 ax-text-primary-500 ax-rounded-full ax-p-1\">\n <i class=\"fa-light fa-user\"></i>\n </ax-icon>\n } @else {\n <ax-icon><i class=\"fa-light fa-user\"></i></ax-icon>\n }\n {{ task.assignedTo.name }}\n </span>\n }\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block;height:100%;width:100%}.task-item{transition:all .2s ease-in-out;border-left:3px solid transparent}.task-item:hover{background-color:rgba(var(--ax-sys-color-on-surface),.1);transform:translateY(-2px);box-shadow:0 2px 8px rgba(0,0,0,.05)}.task-item.priority-high{border-left-color:rgb(var(--ax-sys-color-danger-500))}.task-item.priority-medium{border-left-color:rgb(var(--ax-sys-color-warning-500))}.task-item.priority-low{border-left-color:rgb(var(--ax-sys-color-success-500))}.task-item:active{transform:translateY(0);box-shadow:0 1px 3px rgba(0,0,0,.05)}.task-completed{text-decoration:line-through;color:var(--ax-text-secondary);opacity:.7;transition:all .3s ease}.category-header{position:relative}.category-header:after{content:\"\";position:absolute;bottom:-8px;left:0;width:40px;height:3px;background-color:var(--ax-primary-500);border-radius:3px;transition:width .3s ease}.category-header:hover:after{width:60px}.empty-state{animation:fadeIn .5s ease}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.task-checkbox ::ng-deep .ax-checkbox{transition:all .2s ease}.task-checkbox ::ng-deep .ax-checkbox:hover{transform:scale(1.1)}.due-date.overdue{animation:pulse 2s infinite}@keyframes pulse{0%{opacity:.7}50%{opacity:1}to{opacity:.7}}.ax-space-y-2>*{animation:slideInRight .3s ease forwards;opacity:0}.ax-space-y-2>*:nth-child(1){animation-delay:.05s}.ax-space-y-2>*:nth-child(2){animation-delay:.1s}.ax-space-y-2>*:nth-child(3){animation-delay:.15s}.ax-space-y-2>*:nth-child(4){animation-delay:.2s}.ax-space-y-2>*:nth-child(5){animation-delay:.25s}.ax-space-y-2>*:nth-child(6){animation-delay:.3s}.ax-space-y-2>*:nth-child(7){animation-delay:.35s}.ax-space-y-2>*:nth-child(8){animation-delay:.4s}.ax-space-y-2>*:nth-child(9){animation-delay:.45s}.ax-space-y-2>*:nth-child(10){animation-delay:.5s}@keyframes slideInRight{0%{opacity:0;transform:translate(10px)}to{opacity:1;transform:translate(0)}}\n"] }]
|
2391
2708
|
}] });
|
2392
2709
|
|
2393
2710
|
var tasklistWidget_component = /*#__PURE__*/Object.freeze({
|
@@ -2549,60 +2866,70 @@ class AXPWeatherApiAbstract {
|
|
2549
2866
|
id: 'sunny',
|
2550
2867
|
name: 'Sunny',
|
2551
2868
|
icon: 'fa-solid fa-sun',
|
2869
|
+
svgIcon: 'day.svg',
|
2552
2870
|
color: '#ff9d00',
|
2553
2871
|
},
|
2554
2872
|
clearNight: {
|
2555
2873
|
id: 'clearNight',
|
2556
2874
|
name: 'Clear Night',
|
2557
2875
|
icon: 'fa-solid fa-moon',
|
2876
|
+
svgIcon: 'night.svg',
|
2558
2877
|
color: '#5d639e',
|
2559
2878
|
},
|
2560
2879
|
partlyCloudy: {
|
2561
2880
|
id: 'partlyCloudy',
|
2562
2881
|
name: 'Partly Cloudy',
|
2563
2882
|
icon: 'fa-solid fa-cloud-sun',
|
2883
|
+
svgIcon: 'cloudy-day-3.svg',
|
2564
2884
|
color: '#6ba4e8',
|
2565
2885
|
},
|
2566
2886
|
partlyCloudyNight: {
|
2567
2887
|
id: 'partlyCloudyNight',
|
2568
2888
|
name: 'Partly Cloudy Night',
|
2569
2889
|
icon: 'fa-solid fa-cloud-moon',
|
2890
|
+
svgIcon: 'cloudy-night-3.svg',
|
2570
2891
|
color: '#5d639e',
|
2571
2892
|
},
|
2572
2893
|
cloudy: {
|
2573
2894
|
id: 'cloudy',
|
2574
2895
|
name: 'Cloudy',
|
2575
2896
|
icon: 'fa-solid fa-cloud',
|
2897
|
+
svgIcon: 'cloudy.svg',
|
2576
2898
|
color: '#72869d',
|
2577
2899
|
},
|
2578
2900
|
rain: {
|
2579
2901
|
id: 'rain',
|
2580
2902
|
name: 'Rain',
|
2581
2903
|
icon: 'fa-solid fa-cloud-rain',
|
2904
|
+
svgIcon: 'rainy-6.svg',
|
2582
2905
|
color: '#3a74ad',
|
2583
2906
|
},
|
2584
2907
|
showers: {
|
2585
2908
|
id: 'showers',
|
2586
2909
|
name: 'Showers',
|
2587
2910
|
icon: 'fa-solid fa-cloud-showers-heavy',
|
2911
|
+
svgIcon: 'rainy-7.svg',
|
2588
2912
|
color: '#2c5d8c',
|
2589
2913
|
},
|
2590
2914
|
thunderstorm: {
|
2591
2915
|
id: 'thunderstorm',
|
2592
2916
|
name: 'Thunderstorm',
|
2593
2917
|
icon: 'fa-solid fa-bolt-lightning',
|
2918
|
+
svgIcon: 'thunder.svg',
|
2594
2919
|
color: '#8834af',
|
2595
2920
|
},
|
2596
2921
|
snow: {
|
2597
2922
|
id: 'snow',
|
2598
2923
|
name: 'Snow',
|
2599
2924
|
icon: 'fa-solid fa-snowflake',
|
2925
|
+
svgIcon: 'snowy-6.svg',
|
2600
2926
|
color: '#68a9cd',
|
2601
2927
|
},
|
2602
2928
|
mist: {
|
2603
2929
|
id: 'mist',
|
2604
2930
|
name: 'Mist',
|
2605
2931
|
icon: 'fa-solid fa-smog',
|
2932
|
+
svgIcon: 'cloudy.svg',
|
2606
2933
|
color: '#94a3b8',
|
2607
2934
|
},
|
2608
2935
|
};
|
@@ -2642,6 +2969,7 @@ class AXPWeatherApiAbstract {
|
|
2642
2969
|
id: 'unknown',
|
2643
2970
|
name: 'Unknown',
|
2644
2971
|
icon: 'fa-solid fa-question',
|
2972
|
+
svgIcon: 'weather.svg',
|
2645
2973
|
color: '#999999',
|
2646
2974
|
};
|
2647
2975
|
}
|
@@ -2890,6 +3218,7 @@ class AXPWeatherApiMockService extends AXPWeatherApiAbstract {
|
|
2890
3218
|
maxTempF,
|
2891
3219
|
minTempC,
|
2892
3220
|
minTempF,
|
3221
|
+
hour: [],
|
2893
3222
|
};
|
2894
3223
|
});
|
2895
3224
|
return { ...data, forecast };
|
@@ -3051,6 +3380,13 @@ class AXPWeatherApiService extends AXPWeatherApiAbstract {
|
|
3051
3380
|
maxTempF: day.day?.maxtemp_f || 0,
|
3052
3381
|
minTempC: day.day?.mintemp_c || 0,
|
3053
3382
|
minTempF: day.day?.mintemp_f || 0,
|
3383
|
+
hour: day.hour.map((hour) => ({
|
3384
|
+
time: hour.time,
|
3385
|
+
condition: hour.condition.code,
|
3386
|
+
iconUrl: hour.condition.icon,
|
3387
|
+
tempC: hour.temp_c,
|
3388
|
+
tempF: hour.temp_f,
|
3389
|
+
})),
|
3054
3390
|
};
|
3055
3391
|
});
|
3056
3392
|
return weatherData;
|
@@ -3062,6 +3398,847 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
|
|
3062
3398
|
type: Injectable
|
3063
3399
|
}] });
|
3064
3400
|
|
3401
|
+
class AXPAdvancedWeatherViewComponent extends AXPValueWidgetComponent {
|
3402
|
+
constructor() {
|
3403
|
+
super();
|
3404
|
+
this.weatherService = inject(AXPWeatherApiAbstract);
|
3405
|
+
this.weatherData = signal(null);
|
3406
|
+
this.isLoading = signal(true);
|
3407
|
+
this.hasError = signal(false);
|
3408
|
+
this.errorMessage = signal('');
|
3409
|
+
this.city = computed(() => this.options()['city'] || 'New York');
|
3410
|
+
this.temperatureUnit = computed(() => this.options()['temperatureUnit']?.id || '°C');
|
3411
|
+
this.forecastDays = computed(() => (this.options()['forecastDays'] ?? 2) + 1);
|
3412
|
+
this.forecastHours = computed(() => this.options()['forecastHours'] ?? 5);
|
3413
|
+
this.iconCache = new Map();
|
3414
|
+
this.displayedForecast = computed(() => {
|
3415
|
+
this.forecastDays();
|
3416
|
+
const weatherData = this.weatherData();
|
3417
|
+
if (!weatherData?.forecast)
|
3418
|
+
return [];
|
3419
|
+
// Skip today's forecast for the bottom row display
|
3420
|
+
return weatherData.forecast.slice(1, this.forecastDays());
|
3421
|
+
});
|
3422
|
+
this.displayedHourlyForecast = computed(() => {
|
3423
|
+
this.forecastHours();
|
3424
|
+
const weatherData = this.weatherData();
|
3425
|
+
if (!weatherData?.forecast?.[0]?.hour)
|
3426
|
+
return [];
|
3427
|
+
const now = new Date();
|
3428
|
+
const currentHour = now.getHours();
|
3429
|
+
const todayHours = weatherData.forecast[0].hour;
|
3430
|
+
// Get hours after current hour for today
|
3431
|
+
const remainingTodayHours = todayHours.filter((hour) => {
|
3432
|
+
const hourTime = new Date(hour.time);
|
3433
|
+
return hourTime.getHours() > currentHour;
|
3434
|
+
});
|
3435
|
+
// If we need more hours, get from tomorrow
|
3436
|
+
let result = [...remainingTodayHours];
|
3437
|
+
if (result.length < this.forecastHours() && weatherData.forecast.length > 1) {
|
3438
|
+
const tomorrowHours = weatherData.forecast[1].hour;
|
3439
|
+
const neededFromTomorrow = this.forecastHours() - result.length;
|
3440
|
+
result = [...result, ...tomorrowHours.slice(0, neededFromTomorrow)];
|
3441
|
+
}
|
3442
|
+
// Limit to requested number of hours
|
3443
|
+
return result.slice(0, this.forecastHours());
|
3444
|
+
});
|
3445
|
+
effect(() => {
|
3446
|
+
if (this.options()) {
|
3447
|
+
this.loadWeatherData();
|
3448
|
+
}
|
3449
|
+
});
|
3450
|
+
}
|
3451
|
+
loadWeatherData() {
|
3452
|
+
if (!this.city()) {
|
3453
|
+
this.isLoading.set(false);
|
3454
|
+
return;
|
3455
|
+
}
|
3456
|
+
this.isLoading.set(true);
|
3457
|
+
this.hasError.set(false);
|
3458
|
+
this.errorMessage.set('');
|
3459
|
+
const requestOptions = {
|
3460
|
+
location: this.city(),
|
3461
|
+
tempUnit: this.temperatureUnit(),
|
3462
|
+
days: this.forecastDays(),
|
3463
|
+
};
|
3464
|
+
this.weatherService
|
3465
|
+
.getForecast(requestOptions)
|
3466
|
+
.pipe(catchError((error) => {
|
3467
|
+
this.handleError(error);
|
3468
|
+
return of(null);
|
3469
|
+
}), finalize(() => this.isLoading.set(false)))
|
3470
|
+
.subscribe((data) => {
|
3471
|
+
if (data) {
|
3472
|
+
this.weatherData.set(data);
|
3473
|
+
}
|
3474
|
+
});
|
3475
|
+
}
|
3476
|
+
handleError(error) {
|
3477
|
+
console.error('Advanced weather widget error:', error);
|
3478
|
+
this.hasError.set(true);
|
3479
|
+
this.errorMessage.set(error.message || 'Failed to load weather data');
|
3480
|
+
}
|
3481
|
+
getConditionIcon(conditionId) {
|
3482
|
+
if (!conditionId) {
|
3483
|
+
return '';
|
3484
|
+
}
|
3485
|
+
if (this.iconCache.has(conditionId)) {
|
3486
|
+
return this.iconCache.get(conditionId);
|
3487
|
+
}
|
3488
|
+
const svgIcon = this.weatherService.getCondition(conditionId).svgIcon;
|
3489
|
+
const iconPath = `assets/images/weather/${svgIcon}`;
|
3490
|
+
this.iconCache.set(conditionId, iconPath);
|
3491
|
+
return iconPath;
|
3492
|
+
}
|
3493
|
+
getConditionName(conditionId) {
|
3494
|
+
if (!conditionId) {
|
3495
|
+
return 'Unknown';
|
3496
|
+
}
|
3497
|
+
const condition = this.weatherService.getCondition(conditionId);
|
3498
|
+
return condition?.name || 'Unknown';
|
3499
|
+
}
|
3500
|
+
getCurrentTemperature() {
|
3501
|
+
if (!this.weatherData())
|
3502
|
+
return 0;
|
3503
|
+
return this.temperatureUnit() === '°C' ? this.weatherData().current.tempC : this.weatherData().current.tempF;
|
3504
|
+
}
|
3505
|
+
getMaxTemp() {
|
3506
|
+
if (!this.weatherData()?.forecast?.[0])
|
3507
|
+
return 0;
|
3508
|
+
return this.temperatureUnit() === '°C'
|
3509
|
+
? this.weatherData().forecast[0].maxTempC
|
3510
|
+
: this.weatherData().forecast[0].maxTempF;
|
3511
|
+
}
|
3512
|
+
getMinTemp() {
|
3513
|
+
if (!this.weatherData()?.forecast?.[0])
|
3514
|
+
return 0;
|
3515
|
+
return this.temperatureUnit() === '°C'
|
3516
|
+
? this.weatherData().forecast[0].minTempC
|
3517
|
+
: this.weatherData().forecast[0].minTempF;
|
3518
|
+
}
|
3519
|
+
getForecastDayTemp(day) {
|
3520
|
+
if (!day)
|
3521
|
+
return 0;
|
3522
|
+
return this.temperatureUnit() === '°C' ? day.maxTempC : day.maxTempF;
|
3523
|
+
}
|
3524
|
+
parseDate(dateStr) {
|
3525
|
+
return new Date(dateStr);
|
3526
|
+
}
|
3527
|
+
getDayName(date) {
|
3528
|
+
const today = new Date();
|
3529
|
+
today.setHours(0, 0, 0, 0);
|
3530
|
+
const tomorrow = new Date(today);
|
3531
|
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
3532
|
+
const checkDate = new Date(date);
|
3533
|
+
checkDate.setHours(0, 0, 0, 0);
|
3534
|
+
if (checkDate.getTime() === today.getTime()) {
|
3535
|
+
return 'Today';
|
3536
|
+
}
|
3537
|
+
if (checkDate.getTime() === tomorrow.getTime()) {
|
3538
|
+
return 'Tomorrow';
|
3539
|
+
}
|
3540
|
+
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
3541
|
+
return days[checkDate.getDay()];
|
3542
|
+
}
|
3543
|
+
getHourLabel(timeStr) {
|
3544
|
+
const time = new Date(timeStr);
|
3545
|
+
return time.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false });
|
3546
|
+
}
|
3547
|
+
getHourTemp(hour) {
|
3548
|
+
return this.temperatureUnit() === '°C' ? hour.tempC : hour.tempF;
|
3549
|
+
}
|
3550
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPAdvancedWeatherViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
3551
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXPAdvancedWeatherViewComponent, isStandalone: true, selector: "ng-component", providers: [
|
3552
|
+
{
|
3553
|
+
provide: AXPWeatherApiAbstract,
|
3554
|
+
useClass: AXPWeatherApiService,
|
3555
|
+
},
|
3556
|
+
], usesInheritance: true, ngImport: i0, template: `
|
3557
|
+
<div class="ax-size-full ax-p-6">
|
3558
|
+
@if (weatherData() && !isLoading() && !hasError()) {
|
3559
|
+
<div class="ax-flex ax-h-full ax-flex-col ax-gap-4 ax-justify-around">
|
3560
|
+
<div class="ax-flex ax-items-start ax-justify-around ax-w-full ax-gap-4">
|
3561
|
+
<div class="ax-flex ax-items-center ax-shrink-0">
|
3562
|
+
<img
|
3563
|
+
[src]="getConditionIcon(weatherData()!.current.condition)"
|
3564
|
+
class="ax-w-20 ax-h-20 ax-scale-[1.5]"
|
3565
|
+
[alt]="getConditionName(weatherData()!.current.condition)"
|
3566
|
+
loading="lazy"
|
3567
|
+
/>
|
3568
|
+
<div class="ax-flex ax-flex-col ax-gap-1 ax-items-start">
|
3569
|
+
<span class="ax-text-lg ax-font-medium ax-text-muted">{{
|
3570
|
+
getConditionName(weatherData()!.current.condition)
|
3571
|
+
}}</span>
|
3572
|
+
<span class="ax-text-5xl" style="text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.3)"
|
3573
|
+
>{{ getCurrentTemperature() | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
3574
|
+
>
|
3575
|
+
</div>
|
3576
|
+
</div>
|
3577
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-gap-1 ax-pe-4">
|
3578
|
+
<span class="ax-text-2xl ax-font-bold ax-capitalize">{{ city() }}</span>
|
3579
|
+
<div class="ax-flex ax-gap-4 ax-font-semibold ax-text-muted">
|
3580
|
+
<span
|
3581
|
+
>H: {{ getMaxTemp() | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
3582
|
+
>
|
3583
|
+
<span
|
3584
|
+
>L: {{ getMinTemp() | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
3585
|
+
>
|
3586
|
+
</div>
|
3587
|
+
</div>
|
3588
|
+
</div>
|
3589
|
+
|
3590
|
+
<div class="ax-flex ax-w-full ax-gap-1 ax-items-center ax-justify-around ax-overflow-x-auto ax-shrink-0">
|
3591
|
+
@for (hour of displayedHourlyForecast(); track hour.time) {
|
3592
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-p-2 ax-cursor-default ax-min-w-16">
|
3593
|
+
<span class="ax-text-sm ax-font-medium ax-text-muted">{{ getHourLabel(hour.time) }}</span>
|
3594
|
+
<img
|
3595
|
+
[src]="getConditionIcon(weatherData()!.forecast[0].condition)"
|
3596
|
+
class="ax-w-10 ax-h-10"
|
3597
|
+
[alt]="getConditionName(weatherData()!.forecast[0].condition)"
|
3598
|
+
/>
|
3599
|
+
<span class="ax-text-lg ax-font-semibold"
|
3600
|
+
>{{ getHourTemp(hour) | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
3601
|
+
>
|
3602
|
+
</div>
|
3603
|
+
}
|
3604
|
+
</div>
|
3605
|
+
|
3606
|
+
<div class="ax-mt-2 ax-w-full">
|
3607
|
+
<div
|
3608
|
+
class="ax-grid ax-grid-cols-[1fr_auto_auto_auto] ax-gap-x-4 ax-gap-y-2 ax-items-center ax-justify-items-start"
|
3609
|
+
>
|
3610
|
+
@for (day of displayedForecast(); track day.date) {
|
3611
|
+
<span class="ax-font-medium">{{ getDayName(parseDate(day.date)) }}</span>
|
3612
|
+
<div class="ax-flex ax-items-center ax-justify-center">
|
3613
|
+
<img
|
3614
|
+
[src]="getConditionIcon(day.condition)"
|
3615
|
+
class="ax-w-8 ax-h-8 ax-scale-[2]"
|
3616
|
+
[alt]="getConditionName(day.condition)"
|
3617
|
+
/>
|
3618
|
+
</div>
|
3619
|
+
<span class="ax-font-semibold"
|
3620
|
+
>{{ getForecastDayTemp(day) | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
3621
|
+
>
|
3622
|
+
<span class="ax-text-muted"
|
3623
|
+
>{{ day.minTempC | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
3624
|
+
>
|
3625
|
+
} @empty {
|
3626
|
+
<span class="ax-text-muted">No forecast data available</span>
|
3627
|
+
}
|
3628
|
+
</div>
|
3629
|
+
</div>
|
3630
|
+
</div>
|
3631
|
+
} @else {
|
3632
|
+
<div class="ax-flex ax-size-full ax-flex-col ax-gap-6" [attr.aria-busy]="isLoading()">
|
3633
|
+
@if (isLoading()) {
|
3634
|
+
<!-- Current weather skeleton -->
|
3635
|
+
<div class="ax-flex ax-items-start ax-justify-around ax-w-full ax-gap-4">
|
3636
|
+
<div class="ax-flex ax-items-center ax-gap-4">
|
3637
|
+
<ax-skeleton class="ax-w-20 ax-h-20 ax-rounded-full"></ax-skeleton>
|
3638
|
+
<div class="ax-flex ax-flex-col ax-gap-2">
|
3639
|
+
<ax-skeleton class="ax-w-24 ax-h-6 ax-rounded"></ax-skeleton>
|
3640
|
+
<ax-skeleton class="ax-w-32 ax-h-12 ax-rounded"></ax-skeleton>
|
3641
|
+
</div>
|
3642
|
+
</div>
|
3643
|
+
<div class="ax-flex ax-flex-col ax-items-end ax-gap-2">
|
3644
|
+
<ax-skeleton class="ax-w-28 ax-h-8 ax-rounded"></ax-skeleton>
|
3645
|
+
<div class="ax-flex ax-gap-2">
|
3646
|
+
<ax-skeleton class="ax-w-12 ax-h-6 ax-rounded"></ax-skeleton>
|
3647
|
+
<ax-skeleton class="ax-w-12 ax-h-6 ax-rounded"></ax-skeleton>
|
3648
|
+
</div>
|
3649
|
+
</div>
|
3650
|
+
</div>
|
3651
|
+
|
3652
|
+
<!-- Hourly forecast skeleton -->
|
3653
|
+
<div class="ax-flex ax-w-full ax-gap-2 ax-items-center ax-justify-around">
|
3654
|
+
@for (i of [1, 2, 3, 4, 5]; track i) {
|
3655
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-gap-2 ax-min-w-16">
|
3656
|
+
<ax-skeleton class="ax-w-12 ax-h-4 ax-rounded"></ax-skeleton>
|
3657
|
+
<ax-skeleton class="ax-w-10 ax-h-10 ax-rounded-full ax-my-1"></ax-skeleton>
|
3658
|
+
<ax-skeleton class="ax-w-10 ax-h-6 ax-rounded"></ax-skeleton>
|
3659
|
+
</div>
|
3660
|
+
}
|
3661
|
+
</div>
|
3662
|
+
|
3663
|
+
<!-- Daily forecast skeleton -->
|
3664
|
+
<div class="ax-mt-2 ax-w-full">
|
3665
|
+
<div class="ax-grid ax-grid-cols-[1fr_auto_auto_auto] ax-gap-x-4 ax-gap-y-4 ax-items-center">
|
3666
|
+
@for (i of [1, 2]; track i) {
|
3667
|
+
<ax-skeleton class="ax-w-20 ax-h-6 ax-rounded"></ax-skeleton>
|
3668
|
+
<ax-skeleton class="ax-w-8 ax-h-8 ax-rounded-full"></ax-skeleton>
|
3669
|
+
<ax-skeleton class="ax-w-10 ax-h-6 ax-rounded"></ax-skeleton>
|
3670
|
+
<ax-skeleton class="ax-w-10 ax-h-6 ax-rounded"></ax-skeleton>
|
3671
|
+
}
|
3672
|
+
</div>
|
3673
|
+
</div>
|
3674
|
+
} @else if (hasError()) {
|
3675
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-gap-3">
|
3676
|
+
<i class="fa-solid fa-cloud-bolt fa-3x ax-text-danger"></i>
|
3677
|
+
<span class="ax-text-danger ax-text-lg">{{ errorMessage() }}</span>
|
3678
|
+
<button
|
3679
|
+
class="ax-btn ax-btn-md ax-btn-outline-primary ax-mt-2"
|
3680
|
+
(click)="loadWeatherData()"
|
3681
|
+
aria-label="Retry loading weather data"
|
3682
|
+
>
|
3683
|
+
<i class="fa-solid fa-rotate-right ax-me-2"></i> Retry
|
3684
|
+
</button>
|
3685
|
+
</div>
|
3686
|
+
}
|
3687
|
+
</div>
|
3688
|
+
}
|
3689
|
+
</div>
|
3690
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.ax-text-muted{color:gray}sup{font-weight:300;position:relative;top:-.3em;font-size:.6em;margin-left:.1em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXTooltipModule }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i2$4.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
3691
|
+
}
|
3692
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPAdvancedWeatherViewComponent, decorators: [{
|
3693
|
+
type: Component,
|
3694
|
+
args: [{ template: `
|
3695
|
+
<div class="ax-size-full ax-p-6">
|
3696
|
+
@if (weatherData() && !isLoading() && !hasError()) {
|
3697
|
+
<div class="ax-flex ax-h-full ax-flex-col ax-gap-4 ax-justify-around">
|
3698
|
+
<div class="ax-flex ax-items-start ax-justify-around ax-w-full ax-gap-4">
|
3699
|
+
<div class="ax-flex ax-items-center ax-shrink-0">
|
3700
|
+
<img
|
3701
|
+
[src]="getConditionIcon(weatherData()!.current.condition)"
|
3702
|
+
class="ax-w-20 ax-h-20 ax-scale-[1.5]"
|
3703
|
+
[alt]="getConditionName(weatherData()!.current.condition)"
|
3704
|
+
loading="lazy"
|
3705
|
+
/>
|
3706
|
+
<div class="ax-flex ax-flex-col ax-gap-1 ax-items-start">
|
3707
|
+
<span class="ax-text-lg ax-font-medium ax-text-muted">{{
|
3708
|
+
getConditionName(weatherData()!.current.condition)
|
3709
|
+
}}</span>
|
3710
|
+
<span class="ax-text-5xl" style="text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.3)"
|
3711
|
+
>{{ getCurrentTemperature() | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
3712
|
+
>
|
3713
|
+
</div>
|
3714
|
+
</div>
|
3715
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-gap-1 ax-pe-4">
|
3716
|
+
<span class="ax-text-2xl ax-font-bold ax-capitalize">{{ city() }}</span>
|
3717
|
+
<div class="ax-flex ax-gap-4 ax-font-semibold ax-text-muted">
|
3718
|
+
<span
|
3719
|
+
>H: {{ getMaxTemp() | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
3720
|
+
>
|
3721
|
+
<span
|
3722
|
+
>L: {{ getMinTemp() | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
3723
|
+
>
|
3724
|
+
</div>
|
3725
|
+
</div>
|
3726
|
+
</div>
|
3727
|
+
|
3728
|
+
<div class="ax-flex ax-w-full ax-gap-1 ax-items-center ax-justify-around ax-overflow-x-auto ax-shrink-0">
|
3729
|
+
@for (hour of displayedHourlyForecast(); track hour.time) {
|
3730
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-p-2 ax-cursor-default ax-min-w-16">
|
3731
|
+
<span class="ax-text-sm ax-font-medium ax-text-muted">{{ getHourLabel(hour.time) }}</span>
|
3732
|
+
<img
|
3733
|
+
[src]="getConditionIcon(weatherData()!.forecast[0].condition)"
|
3734
|
+
class="ax-w-10 ax-h-10"
|
3735
|
+
[alt]="getConditionName(weatherData()!.forecast[0].condition)"
|
3736
|
+
/>
|
3737
|
+
<span class="ax-text-lg ax-font-semibold"
|
3738
|
+
>{{ getHourTemp(hour) | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
3739
|
+
>
|
3740
|
+
</div>
|
3741
|
+
}
|
3742
|
+
</div>
|
3743
|
+
|
3744
|
+
<div class="ax-mt-2 ax-w-full">
|
3745
|
+
<div
|
3746
|
+
class="ax-grid ax-grid-cols-[1fr_auto_auto_auto] ax-gap-x-4 ax-gap-y-2 ax-items-center ax-justify-items-start"
|
3747
|
+
>
|
3748
|
+
@for (day of displayedForecast(); track day.date) {
|
3749
|
+
<span class="ax-font-medium">{{ getDayName(parseDate(day.date)) }}</span>
|
3750
|
+
<div class="ax-flex ax-items-center ax-justify-center">
|
3751
|
+
<img
|
3752
|
+
[src]="getConditionIcon(day.condition)"
|
3753
|
+
class="ax-w-8 ax-h-8 ax-scale-[2]"
|
3754
|
+
[alt]="getConditionName(day.condition)"
|
3755
|
+
/>
|
3756
|
+
</div>
|
3757
|
+
<span class="ax-font-semibold"
|
3758
|
+
>{{ getForecastDayTemp(day) | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
3759
|
+
>
|
3760
|
+
<span class="ax-text-muted"
|
3761
|
+
>{{ day.minTempC | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
3762
|
+
>
|
3763
|
+
} @empty {
|
3764
|
+
<span class="ax-text-muted">No forecast data available</span>
|
3765
|
+
}
|
3766
|
+
</div>
|
3767
|
+
</div>
|
3768
|
+
</div>
|
3769
|
+
} @else {
|
3770
|
+
<div class="ax-flex ax-size-full ax-flex-col ax-gap-6" [attr.aria-busy]="isLoading()">
|
3771
|
+
@if (isLoading()) {
|
3772
|
+
<!-- Current weather skeleton -->
|
3773
|
+
<div class="ax-flex ax-items-start ax-justify-around ax-w-full ax-gap-4">
|
3774
|
+
<div class="ax-flex ax-items-center ax-gap-4">
|
3775
|
+
<ax-skeleton class="ax-w-20 ax-h-20 ax-rounded-full"></ax-skeleton>
|
3776
|
+
<div class="ax-flex ax-flex-col ax-gap-2">
|
3777
|
+
<ax-skeleton class="ax-w-24 ax-h-6 ax-rounded"></ax-skeleton>
|
3778
|
+
<ax-skeleton class="ax-w-32 ax-h-12 ax-rounded"></ax-skeleton>
|
3779
|
+
</div>
|
3780
|
+
</div>
|
3781
|
+
<div class="ax-flex ax-flex-col ax-items-end ax-gap-2">
|
3782
|
+
<ax-skeleton class="ax-w-28 ax-h-8 ax-rounded"></ax-skeleton>
|
3783
|
+
<div class="ax-flex ax-gap-2">
|
3784
|
+
<ax-skeleton class="ax-w-12 ax-h-6 ax-rounded"></ax-skeleton>
|
3785
|
+
<ax-skeleton class="ax-w-12 ax-h-6 ax-rounded"></ax-skeleton>
|
3786
|
+
</div>
|
3787
|
+
</div>
|
3788
|
+
</div>
|
3789
|
+
|
3790
|
+
<!-- Hourly forecast skeleton -->
|
3791
|
+
<div class="ax-flex ax-w-full ax-gap-2 ax-items-center ax-justify-around">
|
3792
|
+
@for (i of [1, 2, 3, 4, 5]; track i) {
|
3793
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-gap-2 ax-min-w-16">
|
3794
|
+
<ax-skeleton class="ax-w-12 ax-h-4 ax-rounded"></ax-skeleton>
|
3795
|
+
<ax-skeleton class="ax-w-10 ax-h-10 ax-rounded-full ax-my-1"></ax-skeleton>
|
3796
|
+
<ax-skeleton class="ax-w-10 ax-h-6 ax-rounded"></ax-skeleton>
|
3797
|
+
</div>
|
3798
|
+
}
|
3799
|
+
</div>
|
3800
|
+
|
3801
|
+
<!-- Daily forecast skeleton -->
|
3802
|
+
<div class="ax-mt-2 ax-w-full">
|
3803
|
+
<div class="ax-grid ax-grid-cols-[1fr_auto_auto_auto] ax-gap-x-4 ax-gap-y-4 ax-items-center">
|
3804
|
+
@for (i of [1, 2]; track i) {
|
3805
|
+
<ax-skeleton class="ax-w-20 ax-h-6 ax-rounded"></ax-skeleton>
|
3806
|
+
<ax-skeleton class="ax-w-8 ax-h-8 ax-rounded-full"></ax-skeleton>
|
3807
|
+
<ax-skeleton class="ax-w-10 ax-h-6 ax-rounded"></ax-skeleton>
|
3808
|
+
<ax-skeleton class="ax-w-10 ax-h-6 ax-rounded"></ax-skeleton>
|
3809
|
+
}
|
3810
|
+
</div>
|
3811
|
+
</div>
|
3812
|
+
} @else if (hasError()) {
|
3813
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-gap-3">
|
3814
|
+
<i class="fa-solid fa-cloud-bolt fa-3x ax-text-danger"></i>
|
3815
|
+
<span class="ax-text-danger ax-text-lg">{{ errorMessage() }}</span>
|
3816
|
+
<button
|
3817
|
+
class="ax-btn ax-btn-md ax-btn-outline-primary ax-mt-2"
|
3818
|
+
(click)="loadWeatherData()"
|
3819
|
+
aria-label="Retry loading weather data"
|
3820
|
+
>
|
3821
|
+
<i class="fa-solid fa-rotate-right ax-me-2"></i> Retry
|
3822
|
+
</button>
|
3823
|
+
</div>
|
3824
|
+
}
|
3825
|
+
</div>
|
3826
|
+
}
|
3827
|
+
</div>
|
3828
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXDecoratorModule, AXTooltipModule, AXSkeletonModule], providers: [
|
3829
|
+
{
|
3830
|
+
provide: AXPWeatherApiAbstract,
|
3831
|
+
useClass: AXPWeatherApiService,
|
3832
|
+
},
|
3833
|
+
], styles: [":host{display:block;width:100%;height:100%}.ax-text-muted{color:gray}sup{font-weight:300;position:relative;top:-.3em;font-size:.6em;margin-left:.1em}\n"] }]
|
3834
|
+
}], ctorParameters: () => [] });
|
3835
|
+
|
3836
|
+
var advancedWeather_component = /*#__PURE__*/Object.freeze({
|
3837
|
+
__proto__: null,
|
3838
|
+
AXPAdvancedWeatherViewComponent: AXPAdvancedWeatherViewComponent
|
3839
|
+
});
|
3840
|
+
|
3841
|
+
/**
|
3842
|
+
* Weather Widget Configuration
|
3843
|
+
* Provides customization options for displaying weather data and forecast
|
3844
|
+
*/
|
3845
|
+
const AXPAdvancedWeatherWidget = {
|
3846
|
+
name: 'advanced-weather',
|
3847
|
+
title: 'Advanced Weather Widget',
|
3848
|
+
categories: [AXP_WIDGETS_UTILITY_CATEGORY],
|
3849
|
+
groups: [AXPWidgetGroupEnum.DashboardWidget],
|
3850
|
+
type: 'dashboard',
|
3851
|
+
icon: 'fa-light fa-cloud-sun',
|
3852
|
+
properties: [
|
3853
|
+
{
|
3854
|
+
name: 'temperatureUnit',
|
3855
|
+
title: '@dashboard:widgets.weather.temperature-unit',
|
3856
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
3857
|
+
schema: {
|
3858
|
+
defaultValue: '°C',
|
3859
|
+
dataType: 'string',
|
3860
|
+
interface: {
|
3861
|
+
name: 'temperatureUnit',
|
3862
|
+
path: 'options.temperatureUnit',
|
3863
|
+
type: AXPWidgetsCatalog.select,
|
3864
|
+
options: {
|
3865
|
+
dataSource: ['°C', '°F'],
|
3866
|
+
},
|
3867
|
+
},
|
3868
|
+
},
|
3869
|
+
visible: true,
|
3870
|
+
},
|
3871
|
+
{
|
3872
|
+
name: 'city',
|
3873
|
+
title: '@dashboard:widgets.weather.city',
|
3874
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
3875
|
+
schema: {
|
3876
|
+
defaultValue: 'New York',
|
3877
|
+
dataType: 'string',
|
3878
|
+
interface: {
|
3879
|
+
name: 'city',
|
3880
|
+
path: 'options.city',
|
3881
|
+
type: AXPWidgetsCatalog.text,
|
3882
|
+
},
|
3883
|
+
},
|
3884
|
+
visible: true,
|
3885
|
+
},
|
3886
|
+
{
|
3887
|
+
name: 'forecastHours',
|
3888
|
+
title: '@dashboard:widgets.weather.forecast-hours',
|
3889
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
3890
|
+
schema: {
|
3891
|
+
defaultValue: 5,
|
3892
|
+
dataType: 'number',
|
3893
|
+
interface: {
|
3894
|
+
name: 'forecastHours',
|
3895
|
+
path: 'options.forecastHours',
|
3896
|
+
type: AXPWidgetsCatalog.number,
|
3897
|
+
options: {
|
3898
|
+
minValue: 1,
|
3899
|
+
maxValue: 8,
|
3900
|
+
step: 1,
|
3901
|
+
},
|
3902
|
+
},
|
3903
|
+
},
|
3904
|
+
visible: true,
|
3905
|
+
},
|
3906
|
+
{
|
3907
|
+
name: 'forecastDays',
|
3908
|
+
title: '@dashboard:widgets.weather.forecast-days',
|
3909
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
3910
|
+
schema: {
|
3911
|
+
defaultValue: 2,
|
3912
|
+
dataType: 'number',
|
3913
|
+
interface: {
|
3914
|
+
name: 'forecastDays',
|
3915
|
+
path: 'options.forecastDays',
|
3916
|
+
type: AXPWidgetsCatalog.number,
|
3917
|
+
options: {
|
3918
|
+
minValue: 1,
|
3919
|
+
maxValue: 2,
|
3920
|
+
step: 1,
|
3921
|
+
},
|
3922
|
+
},
|
3923
|
+
},
|
3924
|
+
visible: true,
|
3925
|
+
},
|
3926
|
+
],
|
3927
|
+
components: {
|
3928
|
+
view: {
|
3929
|
+
component: () => Promise.resolve().then(function () { return advancedWeather_component; }).then((c) => c.AXPAdvancedWeatherViewComponent),
|
3930
|
+
},
|
3931
|
+
},
|
3932
|
+
meta: {
|
3933
|
+
dimensions: {
|
3934
|
+
width: 3,
|
3935
|
+
height: 5,
|
3936
|
+
minWidth: 3,
|
3937
|
+
minHeight: 5,
|
3938
|
+
maxWidth: 5,
|
3939
|
+
maxHeight: 7,
|
3940
|
+
},
|
3941
|
+
},
|
3942
|
+
};
|
3943
|
+
|
3944
|
+
class AXPMinimalWeatherViewComponent extends AXPValueWidgetComponent {
|
3945
|
+
constructor() {
|
3946
|
+
super();
|
3947
|
+
this.weatherService = inject(AXPWeatherApiAbstract);
|
3948
|
+
this.weatherData = signal(null);
|
3949
|
+
this.isLoading = signal(true);
|
3950
|
+
this.hasError = signal(false);
|
3951
|
+
this.errorMessage = signal('');
|
3952
|
+
this.city = computed(() => this.options()['city'] || 'New York');
|
3953
|
+
this.temperatureUnit = computed(() => this.options()['temperatureUnit']?.id || '°C');
|
3954
|
+
this.iconCache = new Map();
|
3955
|
+
effect(() => {
|
3956
|
+
if (this.options()) {
|
3957
|
+
this.loadWeatherData();
|
3958
|
+
}
|
3959
|
+
});
|
3960
|
+
}
|
3961
|
+
loadWeatherData() {
|
3962
|
+
if (!this.city()) {
|
3963
|
+
this.isLoading.set(false);
|
3964
|
+
return;
|
3965
|
+
}
|
3966
|
+
this.isLoading.set(true);
|
3967
|
+
this.hasError.set(false);
|
3968
|
+
this.errorMessage.set('');
|
3969
|
+
const requestOptions = {
|
3970
|
+
location: this.city(),
|
3971
|
+
tempUnit: this.temperatureUnit(),
|
3972
|
+
days: 1,
|
3973
|
+
};
|
3974
|
+
this.weatherService
|
3975
|
+
.getForecast(requestOptions)
|
3976
|
+
.pipe(catchError((error) => {
|
3977
|
+
this.handleError(error);
|
3978
|
+
return of(null);
|
3979
|
+
}), finalize(() => this.isLoading.set(false)))
|
3980
|
+
.subscribe((data) => {
|
3981
|
+
if (data) {
|
3982
|
+
this.weatherData.set(data);
|
3983
|
+
}
|
3984
|
+
});
|
3985
|
+
}
|
3986
|
+
handleError(error) {
|
3987
|
+
console.error('Minimal weather widget error:', error);
|
3988
|
+
this.hasError.set(true);
|
3989
|
+
this.errorMessage.set(error.message || 'Failed to load weather data');
|
3990
|
+
}
|
3991
|
+
getConditionIcon() {
|
3992
|
+
const conditionId = this.weatherData()?.current.condition || 'unknown';
|
3993
|
+
if (this.iconCache.has(conditionId)) {
|
3994
|
+
return this.iconCache.get(conditionId);
|
3995
|
+
}
|
3996
|
+
const svgIcon = this.weatherService.getCondition(conditionId).svgIcon;
|
3997
|
+
const iconPath = `assets/images/weather/${svgIcon}`;
|
3998
|
+
this.iconCache.set(conditionId, iconPath);
|
3999
|
+
return iconPath;
|
4000
|
+
}
|
4001
|
+
getCurrentTemperature() {
|
4002
|
+
if (!this.weatherData())
|
4003
|
+
return 0;
|
4004
|
+
return this.temperatureUnit() === '°C' ? this.weatherData().current.tempC : this.weatherData().current.tempF;
|
4005
|
+
}
|
4006
|
+
getMaxTemp() {
|
4007
|
+
if (!this.weatherData()?.forecast?.[0])
|
4008
|
+
return 0;
|
4009
|
+
return this.temperatureUnit() === '°C'
|
4010
|
+
? this.weatherData().forecast[0].maxTempC
|
4011
|
+
: this.weatherData().forecast[0].maxTempF;
|
4012
|
+
}
|
4013
|
+
getMinTemp() {
|
4014
|
+
if (!this.weatherData()?.forecast?.[0])
|
4015
|
+
return 0;
|
4016
|
+
return this.temperatureUnit() === '°C'
|
4017
|
+
? this.weatherData().forecast[0].minTempC
|
4018
|
+
: this.weatherData().forecast[0].minTempF;
|
4019
|
+
}
|
4020
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPMinimalWeatherViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
4021
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXPMinimalWeatherViewComponent, isStandalone: true, selector: "ng-component", providers: [
|
4022
|
+
{
|
4023
|
+
provide: AXPWeatherApiAbstract,
|
4024
|
+
useClass: AXPWeatherApiService,
|
4025
|
+
},
|
4026
|
+
], usesInheritance: true, ngImport: i0, template: `
|
4027
|
+
@if (weatherData() && !isLoading() && !hasError()) {
|
4028
|
+
<div
|
4029
|
+
class="ax-flex ax-size-full ax-flex-col ax-items-start ax-p-2 ax-gap-6 weather-container ax-overflow-hidden"
|
4030
|
+
style="container-type: inline-size"
|
4031
|
+
[attr.aria-label]="'Current weather for ' + city()"
|
4032
|
+
>
|
4033
|
+
<div class="weather-top ax-flex ax-items-center ax-w-full ax-pt-4">
|
4034
|
+
<img
|
4035
|
+
[src]="getConditionIcon()"
|
4036
|
+
class="ax-h-[180%]"
|
4037
|
+
[alt]="weatherData()?.current?.condition + ' weather icon'"
|
4038
|
+
loading="lazy"
|
4039
|
+
/>
|
4040
|
+
<span
|
4041
|
+
class="-ax-ms-2 temperature"
|
4042
|
+
style="font-size: max(20px, calc(32cqw - 25px)); text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.3)"
|
4043
|
+
aria-live="polite"
|
4044
|
+
>{{ getCurrentTemperature() | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
4045
|
+
>
|
4046
|
+
</div>
|
4047
|
+
<div class="ax-text-start ax-ps-6">
|
4048
|
+
<div style="font-size: max(16px, calc(19cqw - 25px))" class="ax-mt-1">
|
4049
|
+
<span class="ax-font-bold ax-capitalize">{{ city() }}</span>
|
4050
|
+
</div>
|
4051
|
+
<div style="font-size: max(12px, calc(14cqw - 25px))" class="ax-pt-2 ax-flex ax-gap-4 ax-opacity-75">
|
4052
|
+
<span aria-label="High temperature">
|
4053
|
+
H: {{ getMaxTemp() | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup>
|
4054
|
+
</span>
|
4055
|
+
<span aria-label="Low temperature">
|
4056
|
+
L: {{ getMinTemp() | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup>
|
4057
|
+
</span>
|
4058
|
+
</div>
|
4059
|
+
</div>
|
4060
|
+
</div>
|
4061
|
+
} @else {
|
4062
|
+
<div class="ax-flex ax-size-full ax-flex-col ax-p-2 ax-gap-4" [attr.aria-busy]="isLoading()">
|
4063
|
+
@if (isLoading()) {
|
4064
|
+
<!-- Weather icon and temperature skeleton -->
|
4065
|
+
<div class="ax-flex ax-items-center ax-w-full ax-pt-4 ax-gap-8">
|
4066
|
+
<ax-skeleton class="ax-w-16 ax-h-16 ax-rounded-full"></ax-skeleton>
|
4067
|
+
<ax-skeleton class="ax-w-24 ax-h-12 ax-rounded -ax-ms-2"></ax-skeleton>
|
4068
|
+
</div>
|
4069
|
+
|
4070
|
+
<!-- City and temperature range skeleton -->
|
4071
|
+
<div class="ax-text-start ax-ps-6 ax-w-full">
|
4072
|
+
<div class="ax-mt-1">
|
4073
|
+
<ax-skeleton class="ax-w-24 ax-h-6 ax-rounded"></ax-skeleton>
|
4074
|
+
</div>
|
4075
|
+
<div class="ax-pt-2 ax-flex ax-gap-4">
|
4076
|
+
<ax-skeleton class="ax-w-12 ax-h-4 ax-rounded"></ax-skeleton>
|
4077
|
+
<ax-skeleton class="ax-w-12 ax-h-4 ax-rounded"></ax-skeleton>
|
4078
|
+
</div>
|
4079
|
+
</div>
|
4080
|
+
} @else if (hasError()) {
|
4081
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-gap-2">
|
4082
|
+
<span class="ax-text-danger">{{ errorMessage() }}</span>
|
4083
|
+
<button
|
4084
|
+
class="ax-btn ax-btn-sm ax-btn-outline-primary"
|
4085
|
+
(click)="loadWeatherData()"
|
4086
|
+
aria-label="Retry loading weather data"
|
4087
|
+
>
|
4088
|
+
<i class="fa-solid fa-rotate-right"></i> Retry
|
4089
|
+
</button>
|
4090
|
+
</div>
|
4091
|
+
}
|
4092
|
+
</div>
|
4093
|
+
}
|
4094
|
+
`, isInline: true, styles: [":host{width:100%;height:100%}.weather-container{container-type:inline-size;transition:opacity .3s ease-in-out}.temperature{font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums}@container (max-width: 130px){.weather-top{flex-direction:column!important;align-items:center!important;text-align:center}.temperature{margin-top:.5rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXTooltipModule }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i2$4.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
4095
|
+
}
|
4096
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPMinimalWeatherViewComponent, decorators: [{
|
4097
|
+
type: Component,
|
4098
|
+
args: [{ template: `
|
4099
|
+
@if (weatherData() && !isLoading() && !hasError()) {
|
4100
|
+
<div
|
4101
|
+
class="ax-flex ax-size-full ax-flex-col ax-items-start ax-p-2 ax-gap-6 weather-container ax-overflow-hidden"
|
4102
|
+
style="container-type: inline-size"
|
4103
|
+
[attr.aria-label]="'Current weather for ' + city()"
|
4104
|
+
>
|
4105
|
+
<div class="weather-top ax-flex ax-items-center ax-w-full ax-pt-4">
|
4106
|
+
<img
|
4107
|
+
[src]="getConditionIcon()"
|
4108
|
+
class="ax-h-[180%]"
|
4109
|
+
[alt]="weatherData()?.current?.condition + ' weather icon'"
|
4110
|
+
loading="lazy"
|
4111
|
+
/>
|
4112
|
+
<span
|
4113
|
+
class="-ax-ms-2 temperature"
|
4114
|
+
style="font-size: max(20px, calc(32cqw - 25px)); text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.3)"
|
4115
|
+
aria-live="polite"
|
4116
|
+
>{{ getCurrentTemperature() | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup></span
|
4117
|
+
>
|
4118
|
+
</div>
|
4119
|
+
<div class="ax-text-start ax-ps-6">
|
4120
|
+
<div style="font-size: max(16px, calc(19cqw - 25px))" class="ax-mt-1">
|
4121
|
+
<span class="ax-font-bold ax-capitalize">{{ city() }}</span>
|
4122
|
+
</div>
|
4123
|
+
<div style="font-size: max(12px, calc(14cqw - 25px))" class="ax-pt-2 ax-flex ax-gap-4 ax-opacity-75">
|
4124
|
+
<span aria-label="High temperature">
|
4125
|
+
H: {{ getMaxTemp() | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup>
|
4126
|
+
</span>
|
4127
|
+
<span aria-label="Low temperature">
|
4128
|
+
L: {{ getMinTemp() | number: '1.0-0' }}<sup>{{ temperatureUnit() }}</sup>
|
4129
|
+
</span>
|
4130
|
+
</div>
|
4131
|
+
</div>
|
4132
|
+
</div>
|
4133
|
+
} @else {
|
4134
|
+
<div class="ax-flex ax-size-full ax-flex-col ax-p-2 ax-gap-4" [attr.aria-busy]="isLoading()">
|
4135
|
+
@if (isLoading()) {
|
4136
|
+
<!-- Weather icon and temperature skeleton -->
|
4137
|
+
<div class="ax-flex ax-items-center ax-w-full ax-pt-4 ax-gap-8">
|
4138
|
+
<ax-skeleton class="ax-w-16 ax-h-16 ax-rounded-full"></ax-skeleton>
|
4139
|
+
<ax-skeleton class="ax-w-24 ax-h-12 ax-rounded -ax-ms-2"></ax-skeleton>
|
4140
|
+
</div>
|
4141
|
+
|
4142
|
+
<!-- City and temperature range skeleton -->
|
4143
|
+
<div class="ax-text-start ax-ps-6 ax-w-full">
|
4144
|
+
<div class="ax-mt-1">
|
4145
|
+
<ax-skeleton class="ax-w-24 ax-h-6 ax-rounded"></ax-skeleton>
|
4146
|
+
</div>
|
4147
|
+
<div class="ax-pt-2 ax-flex ax-gap-4">
|
4148
|
+
<ax-skeleton class="ax-w-12 ax-h-4 ax-rounded"></ax-skeleton>
|
4149
|
+
<ax-skeleton class="ax-w-12 ax-h-4 ax-rounded"></ax-skeleton>
|
4150
|
+
</div>
|
4151
|
+
</div>
|
4152
|
+
} @else if (hasError()) {
|
4153
|
+
<div class="ax-flex ax-flex-col ax-items-center ax-gap-2">
|
4154
|
+
<span class="ax-text-danger">{{ errorMessage() }}</span>
|
4155
|
+
<button
|
4156
|
+
class="ax-btn ax-btn-sm ax-btn-outline-primary"
|
4157
|
+
(click)="loadWeatherData()"
|
4158
|
+
aria-label="Retry loading weather data"
|
4159
|
+
>
|
4160
|
+
<i class="fa-solid fa-rotate-right"></i> Retry
|
4161
|
+
</button>
|
4162
|
+
</div>
|
4163
|
+
}
|
4164
|
+
</div>
|
4165
|
+
}
|
4166
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXDecoratorModule, AXTooltipModule, AXSkeletonModule], providers: [
|
4167
|
+
{
|
4168
|
+
provide: AXPWeatherApiAbstract,
|
4169
|
+
useClass: AXPWeatherApiService,
|
4170
|
+
},
|
4171
|
+
], styles: [":host{width:100%;height:100%}.weather-container{container-type:inline-size;transition:opacity .3s ease-in-out}.temperature{font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums}@container (max-width: 130px){.weather-top{flex-direction:column!important;align-items:center!important;text-align:center}.temperature{margin-top:.5rem}}\n"] }]
|
4172
|
+
}], ctorParameters: () => [] });
|
4173
|
+
|
4174
|
+
var minimalWeather_component = /*#__PURE__*/Object.freeze({
|
4175
|
+
__proto__: null,
|
4176
|
+
AXPMinimalWeatherViewComponent: AXPMinimalWeatherViewComponent
|
4177
|
+
});
|
4178
|
+
|
4179
|
+
/**
|
4180
|
+
* Weather Widget Configuration
|
4181
|
+
* Provides customization options for displaying weather data and forecast
|
4182
|
+
*/
|
4183
|
+
const AXPMinimalWeatherWidget = {
|
4184
|
+
name: 'minimal-weather',
|
4185
|
+
title: 'Minimal Weather Widget',
|
4186
|
+
categories: [AXP_WIDGETS_UTILITY_CATEGORY],
|
4187
|
+
groups: [AXPWidgetGroupEnum.DashboardWidget],
|
4188
|
+
type: 'dashboard',
|
4189
|
+
icon: 'fa-light fa-cloud-sun',
|
4190
|
+
properties: [
|
4191
|
+
{
|
4192
|
+
name: 'temperatureUnit',
|
4193
|
+
title: '@dashboard:widgets.weather.temperature-unit',
|
4194
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
4195
|
+
schema: {
|
4196
|
+
defaultValue: '°C',
|
4197
|
+
dataType: 'string',
|
4198
|
+
interface: {
|
4199
|
+
name: 'temperatureUnit',
|
4200
|
+
path: 'options.temperatureUnit',
|
4201
|
+
type: AXPWidgetsCatalog.select,
|
4202
|
+
options: {
|
4203
|
+
dataSource: ['°C', '°F'],
|
4204
|
+
},
|
4205
|
+
},
|
4206
|
+
},
|
4207
|
+
visible: true,
|
4208
|
+
},
|
4209
|
+
{
|
4210
|
+
name: 'city',
|
4211
|
+
title: '@dashboard:widgets.weather.city',
|
4212
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
4213
|
+
schema: {
|
4214
|
+
defaultValue: 'New York',
|
4215
|
+
dataType: 'string',
|
4216
|
+
interface: {
|
4217
|
+
name: 'city',
|
4218
|
+
path: 'options.city',
|
4219
|
+
type: AXPWidgetsCatalog.text,
|
4220
|
+
},
|
4221
|
+
},
|
4222
|
+
visible: true,
|
4223
|
+
},
|
4224
|
+
],
|
4225
|
+
components: {
|
4226
|
+
view: {
|
4227
|
+
component: () => Promise.resolve().then(function () { return minimalWeather_component; }).then((c) => c.AXPMinimalWeatherViewComponent),
|
4228
|
+
},
|
4229
|
+
},
|
4230
|
+
meta: {
|
4231
|
+
dimensions: {
|
4232
|
+
width: 2,
|
4233
|
+
height: 2,
|
4234
|
+
minWidth: 1,
|
4235
|
+
minHeight: 2,
|
4236
|
+
maxWidth: 4,
|
4237
|
+
maxHeight: 5,
|
4238
|
+
},
|
4239
|
+
},
|
4240
|
+
};
|
4241
|
+
|
3065
4242
|
/**
|
3066
4243
|
* Weather Widget Component
|
3067
4244
|
* Displays current weather conditions and optional forecast data
|
@@ -3272,18 +4449,21 @@ class AXPWeatherWidgetViewComponent extends AXPValueWidgetComponent {
|
|
3272
4449
|
return new Date(this.weatherData().current.lastUpdated).toLocaleTimeString();
|
3273
4450
|
}
|
3274
4451
|
/**
|
3275
|
-
* Gets the icon class for a weather condition
|
3276
|
-
* @param conditionId
|
3277
|
-
* @returns Font Awesome icon class
|
4452
|
+
* Gets the appropriate icon class for a weather condition
|
4453
|
+
* @param conditionId The ID of the weather condition
|
4454
|
+
* @returns The Font Awesome icon class string
|
3278
4455
|
*/
|
3279
4456
|
getConditionIcon(conditionId) {
|
3280
|
-
|
3281
|
-
|
4457
|
+
if (!conditionId) {
|
4458
|
+
conditionId = 'unknown';
|
4459
|
+
}
|
4460
|
+
const svgIcon = this.weatherService.getCondition(conditionId).svgIcon;
|
4461
|
+
return `assets/images/weather/${svgIcon}`;
|
3282
4462
|
}
|
3283
4463
|
/**
|
3284
4464
|
* Gets the display name for a weather condition
|
3285
|
-
* @param conditionId
|
3286
|
-
* @returns
|
4465
|
+
* @param conditionId The ID of the weather condition
|
4466
|
+
* @returns The translated display name
|
3287
4467
|
*/
|
3288
4468
|
getConditionName(conditionId) {
|
3289
4469
|
const condition = this.weatherService.getCondition(conditionId);
|
@@ -3353,7 +4533,7 @@ class AXPWeatherWidgetViewComponent extends AXPValueWidgetComponent {
|
|
3353
4533
|
provide: AXPWeatherApiAbstract,
|
3354
4534
|
useClass: AXPWeatherApiService,
|
3355
4535
|
},
|
3356
|
-
], viewQueries: [{ propertyName: "containerEl", first: true, predicate: ["containerElement"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Weather Widget Component Template -->\n<div class=\"axp-weather-container\" #containerElement>\n <!-- Loading indicator -->\n @if (isLoading()) {\n <div class=\"axp-weather-loading-overlay\">\n <div class=\"axp-weather-loading-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>{{ 'weather.loading' | translate: { scope: 'dashboard' } | async }}</span>\n </div>\n </div>\n }\n\n <!-- Error message -->\n @if (hasError()) {\n <div class=\"axp-weather-error-overlay\">\n <div class=\"axp-weather-error-message\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage() | translate: { scope: 'dashboard' } | async }}</span>\n <button class=\"axp-weather-retry-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.retry' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n </div>\n }\n\n <!-- Weather content - only show when we have data -->\n @if (weatherData()) {\n <!-- Background decorations based on weather condition -->\n <div class=\"axp-weather-background-decorations\">\n <div class=\"axp-weather-decoration\" [ngClass]=\"weatherData()?.current?.condition?.toLowerCase()\"></div>\n <div class=\"axp-weather-gradient-overlay\"></div>\n </div>\n\n <div class=\"axp-weather-inner\">\n <!-- Location information section -->\n <div class=\"axp-weather-location-info\">\n <div class=\"axp-weather-location-icon\">\n <i class=\"fa-solid fa-location-dot\"></i>\n </div>\n <div class=\"axp-weather-location-text\">\n <h2 class=\"axp-weather-location-name\">{{ city() }}</h2>\n </div>\n </div>\n\n <!-- Current weather conditions section -->\n <div class=\"axp-weather-current-weather\">\n <!-- Weather icon and condition name -->\n @if (showCurrentCondition()) {\n <div class=\"axp-weather-condition\">\n <div class=\"axp-weather-icon-wrapper\">\n <div class=\"axp-weather-icon\">\n <i\n [class]=\"getConditionIcon(weatherData()?.current?.condition || '')\"\n [style.color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></i>\n </div>\n <div\n class=\"axp-weather-icon-glow\"\n [style.background-color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></div>\n </div>\n <div class=\"axp-weather-condition-name\">\n {{ getCurrentCondition() | translate: { scope: 'dashboard' } | async }}\n </div>\n </div>\n }\n\n <!-- Temperature display -->\n @if (showTemperature()) {\n <div class=\"axp-weather-temperature\">\n <span class=\"axp-weather-temperature-value\">{{ getCurrentTemperature() }}</span>\n <span class=\"axp-weather-temperature-unit\">{{\n getTemperatureUnit() | translate: { scope: 'dashboard' } | async\n }}</span>\n </div>\n }\n </div>\n\n <!-- Weather details section (humidity and wind) -->\n @if (showHumidity() || showWind()) {\n <div class=\"axp-weather-details\">\n <!-- Humidity information -->\n @if (showHumidity()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-droplet\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">\n {{ 'weather.humidity' | translate: { scope: 'dashboard' } | async }}\n </div>\n <div class=\"axp-weather-detail-value\">{{ getHumidity() }}%</div>\n </div>\n </div>\n }\n\n <!-- Wind speed information -->\n @if (showWind()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-wind\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">\n {{ 'weather.wind' | translate: { scope: 'dashboard' } | async }}\n </div>\n <div class=\"axp-weather-detail-value\">\n {{ getWindSpeed() }} {{ getWindSpeedUnit() | translate: { scope: 'dashboard' } | async }}\n </div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Weather forecast section -->\n @if (showForecast() && weatherData()?.forecast) {\n <div class=\"axp-weather-forecast\">\n <div class=\"axp-weather-forecast-header\">\n <h3 class=\"axp-weather-forecast-title\">\n <i class=\"fa-solid fa-calendar-days\"></i>\n <span class=\"ax-px-1\">{{ 'weather.forecast' | translate: { scope: 'dashboard' } | async }}</span>\n </h3>\n </div>\n <!-- Loading indicator for forecast -->\n <!-- @if (isForecastLoading()) {\n <div class=\"axp-weather-forecast-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>{{ 'weather.loading-forecast' | translate: { scope: 'dashboard' } | async }}</span>\n </div>\n } -->\n <!-- Scrollable forecast days display -->\n <div class=\"axp-weather-forecast-items\">\n @for (day of displayedForecast(); track day.day) {\n <div class=\"axp-weather-forecast-day\">\n <div class=\"axp-weather-forecast-day-name\">\n {{ getDayName(parseDate(day.date)) | translate: { scope: 'dashboard' } | async }}\n </div>\n <div\n class=\"axp-weather-forecast-icon\"\n [title]=\"getConditionName(day.condition) | translate: { scope: 'dashboard' } | async\"\n >\n <i [class]=\"getConditionIcon(day.condition)\" [style.color]=\"getConditionColor(day.condition)\"></i>\n </div>\n <div class=\"axp-weather-forecast-temps\">\n <span class=\"axp-weather-forecast-low\">\n {{ temperatureUnit() === '\u00B0C' ? day.minTempC : day.minTempF\n }}{{ getTemperatureUnit() | translate: { scope: 'dashboard' } | async }}\n </span>\n <span class=\"axp-weather-forecast-high\">\n {{ temperatureUnit() === '\u00B0C' ? day.maxTempC : day.maxTempF\n }}{{ getTemperatureUnit() | translate: { scope: 'dashboard' } | async }}\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Last updated timestamp -->\n <div class=\"axp-weather-last-updated\">\n <span>{{ 'weather.last-updated' | translate: { scope: 'dashboard' } | async }}: {{ getLastUpdated() }}</span>\n </div>\n\n <!-- Manual refresh button -->\n <div class=\"axp-weather-refresh-action\">\n <button\n class=\"axp-weather-refresh-button\"\n (click)=\"refreshWeather()\"\n [attr.aria-label]=\"'weather.refresh' | translate: { scope: 'dashboard' } | async\"\n [title]=\"'weather.refresh' | translate: { scope: 'dashboard' } | async\"\n >\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.refresh' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n </div>\n } @else if (!isLoading() && !hasError()) {\n <!-- No data state (not loading, no error) -->\n <div class=\"axp-weather-no-data-state\">\n <i class=\"fa-solid fa-cloud-sun\"></i>\n <p>{{ 'weather.no-data' | translate: { scope: 'dashboard' } | async }}</p>\n <button class=\"axp-weather-refresh-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.load-data' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%;--primary-gradient-start: #2196f3;--primary-gradient-end: #1976d2;--shadow-color: rgba(0, 0, 0, .2);--glass-bg: rgba(255, 255, 255, .15);--glass-border: rgba(255, 255, 255, .2);--text-primary: rgba(255, 255, 255, .95);--text-secondary: rgba(255, 255, 255, .75);--transition-speed: .3s}.axp-weather-container{width:100%;height:100%;overflow:hidden;position:relative;box-shadow:0 4px 8px rgba(0,0,0,.1);color:#fff;min-height:300px;background-color:#2c3e50}.axp-weather-loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(44,62,80,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-loading-spinner{text-align:center}.axp-weather-loading-spinner i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-loading-spinner span{display:block;color:#fff;font-size:1rem}.axp-weather-error-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(189,54,47,.85);display:flex;justify-content:center;align-items:center}.axp-weather-error-message{text-align:center;padding:1rem}.axp-weather-error-message i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-error-message span{display:block;color:#fff;font-size:1.1rem;margin-bottom:1rem}.axp-weather-error-message .axp-weather-retry-button{color:#bd362f;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-error-message .axp-weather-retry-button:hover{transform:translateY(-1px)}.axp-weather-no-data-state{display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%;padding:2rem;text-align:center}.axp-weather-no-data-state i{font-size:3rem;margin-bottom:1rem;color:rgba(255,255,255,.8)}.axp-weather-no-data-state p{margin-bottom:1.5rem;font-size:1.1rem}.axp-weather-no-data-state .axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-no-data-state .axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-background-decorations{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.axp-weather-decoration{position:absolute;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:center}.axp-weather-decoration.sunny{background:linear-gradient(135deg,#ff7e00,#f7d358)}.axp-weather-decoration.partlyCloudy{background:linear-gradient(135deg,#7ba2e7,#b4d2f7)}.axp-weather-decoration.cloudy{background:linear-gradient(135deg,#717e8c,#919eab)}.axp-weather-decoration.rain{background:linear-gradient(135deg,#6a8caf,#567a9e)}.axp-weather-decoration.snow{background:linear-gradient(135deg,#99b3cc,#c6d4e1)}.axp-weather-decoration.thunder{background:linear-gradient(135deg,#425777,#2c3e50)}.axp-weather-decoration.mist{background:linear-gradient(135deg,#94a3b8,#cbd5e1)}.axp-weather-gradient-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(rgba(0,0,0,.2),rgba(0,0,0,.5))}.axp-weather-inner{position:relative;z-index:2;height:100%;padding:1.5rem;display:flex;flex-direction:column;justify-content:space-between}.axp-weather-location-info{display:flex;align-items:center;margin-bottom:1.5rem}.axp-weather-location-icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;background-color:rgba(255,255,255,.2);border-radius:50%;margin-right:.75rem}.axp-weather-location-icon i{color:#fff}.axp-weather-location-name{margin:0;font-size:1.5rem;font-weight:500;text-shadow:1px 1px 3px rgba(0,0,0,.2);text-transform:capitalize}.axp-weather-current-weather{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap}.axp-weather-condition{display:flex;flex-direction:column;align-items:center}.axp-weather-icon-wrapper{position:relative;margin-bottom:.5rem}.axp-weather-icon{position:relative;z-index:2}.axp-weather-icon i{font-size:2.75rem;filter:drop-shadow(0 0 8px rgba(0,0,0,.3))}.axp-weather-icon-glow{position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);width:45px;height:45px;border-radius:50%;filter:blur(15px);opacity:.75}.axp-weather-condition-name{font-size:1.1rem;text-align:center;text-shadow:1px 1px 2px rgba(0,0,0,.2)}.axp-weather-temperature{display:flex;align-items:flex-start;text-shadow:1px 1px 3px rgba(0,0,0,.3)}.axp-weather-temperature-value{font-size:3.5rem;font-weight:500;line-height:1}.axp-weather-temperature-unit{font-size:1.5rem;margin-top:.25rem}.axp-weather-details{display:flex;flex-wrap:wrap;gap:1.5rem;margin-bottom:1rem;padding:1rem;background-color:rgba(0,0,0,.15);border-radius:8px}.axp-weather-detail-item{display:flex;align-items:center;flex:1;min-width:120px}.axp-weather-detail-icon{width:40px;height:40px;border-radius:50%;background-color:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;margin-right:.75rem}.axp-weather-detail-icon i{font-size:1.25rem}.axp-weather-detail-info{display:flex;padding-inline:.25rem;flex-direction:column}.axp-weather-detail-label{font-size:.875rem;color:rgba(255,255,255,.8);margin-bottom:.25rem}.axp-weather-detail-value{font-size:1.125rem;font-weight:500}.axp-weather-forecast{margin-bottom:.5rem;background-color:rgba(0,0,0,.15);border-radius:8px;padding:1rem}.axp-weather-forecast-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.axp-weather-forecast-title{margin:0;font-size:1.125rem;font-weight:500;display:flex;align-items:center}.axp-weather-forecast-title i{margin-right:.5rem;opacity:.8}.axp-weather-scroll-indicator{color:rgba(255,255,255,.6)}.axp-weather-forecast-items{display:flex;overflow-x:auto;gap:.75rem;padding-bottom:.5rem}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.3);border-radius:4px}.axp-weather-forecast-items::-webkit-scrollbar-track{background-color:rgba(0,0,0,.1);border-radius:4px}.axp-weather-forecast-day{min-width:90px;display:flex;flex-direction:column;align-items:center;padding:.75rem .5rem;background-color:rgba(255,255,255,.1);border-radius:6px;transition:all .3s ease}.axp-weather-forecast-day:hover{background-color:rgba(255,255,255,.15);transform:translateY(-2px)}.axp-weather-forecast-day-name{font-size:.875rem;margin-bottom:.5rem;font-weight:500}.axp-weather-forecast-icon{font-size:1.5rem;margin-bottom:.5rem}.axp-weather-forecast-icon i{filter:drop-shadow(0 0 5px rgba(0,0,0,.2))}.axp-weather-forecast-temps{display:flex;flex-direction:row;gap:.75rem;align-items:center;font-size:.775rem}.axp-weather-last-updated{text-align:center;font-size:.75rem;opacity:.7;margin-bottom:.5rem}.axp-weather-refresh-action{text-align:center}.axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:.875rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-refresh-button i{font-size:.875rem}@media (max-width: 576px){.axp-weather-inner{padding:.8rem;gap:.4rem}.axp-weather-location-name{font-size:1.1rem;padding-inline:.25rem}.axp-weather-temperature{font-size:2.5rem}.axp-weather-temperature-unit{font-size:1.1rem}.axp-weather-weather-details{flex-direction:column;gap:.5rem}.axp-weather-forecast-items{flex-wrap:nowrap;overflow-x:auto;padding-bottom:.5rem;margin:0 -.4rem;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scrollbar-width:thin;mask-image:linear-gradient(to right,#000 95%,rgba(0,0,0,0));-webkit-mask-image:linear-gradient(to right,rgb(0,0,0) 95%,rgba(0,0,0,0))}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.2);border-radius:4px}.axp-weather-forecast-day{min-width:60px;flex:0 0 auto;padding:.4rem .6rem}.axp-weather-forecast-day-name{font-size:.7rem}.axp-weather-forecast-icon{padding:.3rem;height:1.6rem}.axp-weather-forecast-temps{font-size:.7rem}.axp-weather-scroll-indicator{display:block}}:host-context(.theme-dark){--glass-bg: rgba(0, 0, 0, .3);--glass-border: rgba(255, 255, 255, .1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "ngmodule", type: HttpClientModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i2$3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
4536
|
+
], viewQueries: [{ propertyName: "containerEl", first: true, predicate: ["containerElement"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Weather Widget Component Template -->\n<div class=\"axp-weather-container\" #containerElement>\n <!-- Loading indicator -->\n @if (isLoading()) {\n <div class=\"axp-weather-loading-overlay\">\n <div class=\"axp-weather-loading-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>{{ 'weather.loading' | translate: { scope: 'dashboard' } | async }}</span>\n </div>\n </div>\n }\n\n <!-- Error message -->\n @if (hasError()) {\n <div class=\"axp-weather-error-overlay\">\n <div class=\"axp-weather-error-message\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage() | translate: { scope: 'dashboard' } | async }}</span>\n <button class=\"axp-weather-retry-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.retry' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n </div>\n }\n\n <!-- Weather content - only show when we have data -->\n @if (weatherData()) {\n <!-- Background decorations based on weather condition -->\n <div class=\"axp-weather-background-decorations\">\n <div class=\"axp-weather-decoration\" [ngClass]=\"weatherData()?.current?.condition?.toLowerCase()\"></div>\n <div class=\"axp-weather-gradient-overlay\"></div>\n </div>\n\n <div class=\"axp-weather-inner\">\n <!-- Location information section -->\n <div class=\"axp-weather-location-info\">\n <div class=\"axp-weather-location-icon\">\n <i class=\"fa-solid fa-location-dot\"></i>\n </div>\n <div class=\"axp-weather-location-text\">\n <h2 class=\"axp-weather-location-name\">{{ city() }}</h2>\n </div>\n </div>\n\n <!-- Current weather conditions section -->\n <div class=\"axp-weather-current-weather\">\n <!-- Weather icon and condition name -->\n @if (showCurrentCondition()) {\n <div class=\"axp-weather-condition\">\n <div class=\"axp-weather-icon-wrapper\">\n <div class=\"axp-weather-icon\">\n <img [src]=\"getConditionIcon(weatherData()?.current?.condition || '')\" />\n </div>\n <div\n class=\"axp-weather-icon-glow\"\n [style.background-color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></div>\n </div>\n <div class=\"axp-weather-condition-name\">\n {{ getCurrentCondition() | translate: { scope: 'dashboard' } | async }}\n </div>\n </div>\n }\n\n <!-- Temperature display -->\n @if (showTemperature()) {\n <div class=\"axp-weather-temperature\">\n <span class=\"axp-weather-temperature-value\">{{ getCurrentTemperature() }}</span>\n <span class=\"axp-weather-temperature-unit\">{{\n getTemperatureUnit() | translate: { scope: 'dashboard' } | async\n }}</span>\n </div>\n }\n </div>\n\n <!-- Weather details section (humidity and wind) -->\n @if (showHumidity() || showWind()) {\n <div class=\"axp-weather-details\">\n <!-- Humidity information -->\n @if (showHumidity()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-droplet\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">\n {{ 'weather.humidity' | translate: { scope: 'dashboard' } | async }}\n </div>\n <div class=\"axp-weather-detail-value\">{{ getHumidity() }}%</div>\n </div>\n </div>\n }\n\n <!-- Wind speed information -->\n @if (showWind()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-wind\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">\n {{ 'weather.wind' | translate: { scope: 'dashboard' } | async }}\n </div>\n <div class=\"axp-weather-detail-value\">\n {{ getWindSpeed() }} {{ getWindSpeedUnit() | translate: { scope: 'dashboard' } | async }}\n </div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Weather forecast section -->\n @if (showForecast() && weatherData()?.forecast) {\n <div class=\"axp-weather-forecast\">\n <div class=\"axp-weather-forecast-header\">\n <h3 class=\"axp-weather-forecast-title\">\n <i class=\"fa-solid fa-calendar-days\"></i>\n <span class=\"ax-px-1\">{{ 'weather.forecast' | translate: { scope: 'dashboard' } | async }}</span>\n </h3>\n </div>\n <!-- Loading indicator for forecast -->\n <!-- @if (isForecastLoading()) {\n <div class=\"axp-weather-forecast-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>{{ 'weather.loading-forecast' | translate: { scope: 'dashboard' } | async }}</span>\n </div>\n } -->\n <!-- Scrollable forecast days display -->\n <div class=\"axp-weather-forecast-items\">\n @for (day of displayedForecast(); track day.day) {\n <div class=\"axp-weather-forecast-day\">\n <div class=\"axp-weather-forecast-day-name\">\n {{ getDayName(parseDate(day.date)) | translate: { scope: 'dashboard' } | async }}\n </div>\n <div\n class=\"axp-weather-forecast-icon\"\n [title]=\"getConditionName(day.condition) | translate: { scope: 'dashboard' } | async\"\n >\n <img [src]=\"getConditionIcon(day.condition || '')\" />\n </div>\n <div class=\"axp-weather-forecast-temps\">\n <span class=\"axp-weather-forecast-low\">\n {{ temperatureUnit() === '\u00B0C' ? day.minTempC : day.minTempF\n }}{{ getTemperatureUnit() | translate: { scope: 'dashboard' } | async }}\n </span>\n <span class=\"axp-weather-forecast-high\">\n {{ temperatureUnit() === '\u00B0C' ? day.maxTempC : day.maxTempF\n }}{{ getTemperatureUnit() | translate: { scope: 'dashboard' } | async }}\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Last updated timestamp -->\n <div class=\"axp-weather-last-updated\">\n <span>{{ 'weather.last-updated' | translate: { scope: 'dashboard' } | async }}: {{ getLastUpdated() }}</span>\n </div>\n\n <!-- Manual refresh button -->\n <div class=\"axp-weather-refresh-action\">\n <button\n class=\"axp-weather-refresh-button\"\n (click)=\"refreshWeather()\"\n [attr.aria-label]=\"'weather.refresh' | translate: { scope: 'dashboard' } | async\"\n [title]=\"'weather.refresh' | translate: { scope: 'dashboard' } | async\"\n >\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.refresh' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n </div>\n } @else if (!isLoading() && !hasError()) {\n <!-- No data state (not loading, no error) -->\n <div class=\"axp-weather-no-data-state\">\n <i class=\"fa-solid fa-cloud-sun\"></i>\n <p>{{ 'weather.no-data' | translate: { scope: 'dashboard' } | async }}</p>\n <button class=\"axp-weather-refresh-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.load-data' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%;--primary-gradient-start: #2196f3;--primary-gradient-end: #1976d2;--shadow-color: rgba(0, 0, 0, .2);--glass-bg: rgba(255, 255, 255, .15);--glass-border: rgba(255, 255, 255, .2);--text-primary: rgba(255, 255, 255, .95);--text-secondary: rgba(255, 255, 255, .75);--transition-speed: .3s}.axp-weather-container{width:100%;height:100%;overflow:hidden;position:relative;box-shadow:0 4px 8px rgba(0,0,0,.1);min-height:300px}.axp-weather-loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(44,62,80,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-loading-spinner{text-align:center}.axp-weather-loading-spinner i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-loading-spinner span{display:block;color:#fff;font-size:1rem}.axp-weather-error-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(189,54,47,.85);display:flex;justify-content:center;align-items:center}.axp-weather-error-message{text-align:center;padding:1rem}.axp-weather-error-message i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-error-message span{display:block;color:#fff;font-size:1.1rem;margin-bottom:1rem}.axp-weather-error-message .axp-weather-retry-button{color:#bd362f;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-error-message .axp-weather-retry-button:hover{transform:translateY(-1px)}.axp-weather-no-data-state{display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%;padding:2rem;text-align:center}.axp-weather-no-data-state i{font-size:3rem;margin-bottom:1rem;color:rgba(255,255,255,.8)}.axp-weather-no-data-state p{margin-bottom:1.5rem;font-size:1.1rem}.axp-weather-no-data-state .axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-no-data-state .axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-background-decorations{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.axp-weather-decoration{position:absolute;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:center}.axp-weather-gradient-overlay{position:absolute;top:0;left:0;width:100%;height:100%}.axp-weather-inner{position:relative;z-index:2;height:100%;padding:1.5rem;display:flex;flex-direction:column;justify-content:space-between}.axp-weather-location-info{display:flex;align-items:center;margin-bottom:1.5rem}.axp-weather-location-icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;background-color:rgba(255,255,255,.2);border-radius:50%;margin-right:.75rem}.axp-weather-location-icon i{color:#fff}.axp-weather-location-name{margin:0;font-size:1.5rem;font-weight:500;text-shadow:1px 1px 3px rgba(0,0,0,.2);text-transform:capitalize}.axp-weather-current-weather{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap}.axp-weather-condition{display:flex;flex-direction:column;align-items:center}.axp-weather-icon-wrapper{position:relative;margin-bottom:.5rem}.axp-weather-icon{position:relative;z-index:2;scale:2}.axp-weather-icon i{font-size:2.75rem;filter:drop-shadow(0 0 8px rgba(0,0,0,.3))}.axp-weather-icon-glow{position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);width:45px;height:45px;border-radius:50%;filter:blur(15px);opacity:.4}.axp-weather-condition-name{font-size:1.1rem;text-align:center;text-shadow:1px 1px 2px rgba(0,0,0,.2)}.axp-weather-temperature{display:flex;align-items:flex-start;text-shadow:1px 1px 3px rgba(0,0,0,.3)}.axp-weather-temperature-value{font-size:3.5rem;font-weight:500;line-height:1}.axp-weather-temperature-unit{font-size:1.5rem;margin-top:.25rem}.axp-weather-details{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-darker-surface),var(--tw-bg-opacity, 1));display:flex;flex-wrap:wrap;gap:1.5rem;margin-bottom:1rem;padding:1rem;border-radius:8px}.axp-weather-detail-item{display:flex;align-items:center;flex:1;min-width:120px}.axp-weather-detail-icon{width:40px;height:40px;border-radius:50%;background-color:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;margin-right:.75rem}.axp-weather-detail-icon i{font-size:1.25rem}.axp-weather-detail-info{display:flex;padding-inline:.25rem;flex-direction:column}.axp-weather-detail-label{font-size:.875rem;margin-bottom:.25rem}.axp-weather-detail-value{font-size:1.125rem;font-weight:500}.axp-weather-forecast{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-darker-surface),var(--tw-bg-opacity, 1));margin-bottom:.5rem;border-radius:8px;padding:1rem}.axp-weather-forecast-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.axp-weather-forecast-title{margin:0;font-size:1.125rem;font-weight:500;display:flex;align-items:center}.axp-weather-forecast-title i{margin-right:.5rem;opacity:.8}.axp-weather-scroll-indicator{color:rgba(255,255,255,.6)}.axp-weather-forecast-items{display:flex;overflow-x:auto;gap:.75rem;padding-bottom:.5rem}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.3);border-radius:4px}.axp-weather-forecast-items::-webkit-scrollbar-track{background-color:rgba(0,0,0,.1);border-radius:4px}.axp-weather-forecast-day{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-surface),var(--tw-bg-opacity, 1));min-width:90px;display:flex;flex-direction:column;align-items:center;padding:.75rem .5rem;border-radius:6px;transition:all .3s ease}.axp-weather-forecast-day:hover{transform:translateY(-2px)}.axp-weather-forecast-day-name{font-size:.875rem;margin-bottom:.5rem;font-weight:500}.axp-weather-forecast-icon{font-size:1.5rem;margin-bottom:.5rem}.axp-weather-forecast-icon i{filter:drop-shadow(0 0 5px rgba(0,0,0,.2))}.axp-weather-forecast-temps{display:flex;flex-direction:row;gap:.75rem;align-items:center;font-size:.775rem}.axp-weather-last-updated{text-align:center;font-size:.75rem;opacity:.7;margin-bottom:.5rem}.axp-weather-refresh-action{text-align:center}.axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:.875rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-refresh-button i{font-size:.875rem}@media (max-width: 576px){.axp-weather-inner{padding:.8rem;gap:.4rem}.axp-weather-location-name{font-size:1.1rem;padding-inline:.25rem}.axp-weather-temperature{font-size:2.5rem}.axp-weather-temperature-unit{font-size:1.1rem}.axp-weather-weather-details{flex-direction:column;gap:.5rem}.axp-weather-forecast-items{flex-wrap:nowrap;overflow-x:auto;padding-bottom:.5rem;margin:0 -.4rem;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scrollbar-width:thin;mask-image:linear-gradient(to right,#000 95%,rgba(0,0,0,0));-webkit-mask-image:linear-gradient(to right,rgb(0,0,0) 95%,rgba(0,0,0,0))}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.2);border-radius:4px}.axp-weather-forecast-day{min-width:60px;flex:0 0 auto;padding:.4rem .6rem}.axp-weather-forecast-day-name{font-size:.7rem}.axp-weather-forecast-icon{padding:.3rem;height:1.6rem}.axp-weather-forecast-temps{font-size:.7rem}.axp-weather-scroll-indicator{display:block}}:host-context(.theme-dark){--glass-bg: rgba(0, 0, 0, .3);--glass-border: rgba(255, 255, 255, .1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "ngmodule", type: HttpClientModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i2$3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
3357
4537
|
}
|
3358
4538
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPWeatherWidgetViewComponent, decorators: [{
|
3359
4539
|
type: Component,
|
@@ -3362,7 +4542,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
|
|
3362
4542
|
provide: AXPWeatherApiAbstract,
|
3363
4543
|
useClass: AXPWeatherApiService,
|
3364
4544
|
},
|
3365
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Weather Widget Component Template -->\n<div class=\"axp-weather-container\" #containerElement>\n <!-- Loading indicator -->\n @if (isLoading()) {\n <div class=\"axp-weather-loading-overlay\">\n <div class=\"axp-weather-loading-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>{{ 'weather.loading' | translate: { scope: 'dashboard' } | async }}</span>\n </div>\n </div>\n }\n\n <!-- Error message -->\n @if (hasError()) {\n <div class=\"axp-weather-error-overlay\">\n <div class=\"axp-weather-error-message\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage() | translate: { scope: 'dashboard' } | async }}</span>\n <button class=\"axp-weather-retry-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.retry' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n </div>\n }\n\n <!-- Weather content - only show when we have data -->\n @if (weatherData()) {\n <!-- Background decorations based on weather condition -->\n <div class=\"axp-weather-background-decorations\">\n <div class=\"axp-weather-decoration\" [ngClass]=\"weatherData()?.current?.condition?.toLowerCase()\"></div>\n <div class=\"axp-weather-gradient-overlay\"></div>\n </div>\n\n <div class=\"axp-weather-inner\">\n <!-- Location information section -->\n <div class=\"axp-weather-location-info\">\n <div class=\"axp-weather-location-icon\">\n <i class=\"fa-solid fa-location-dot\"></i>\n </div>\n <div class=\"axp-weather-location-text\">\n <h2 class=\"axp-weather-location-name\">{{ city() }}</h2>\n </div>\n </div>\n\n <!-- Current weather conditions section -->\n <div class=\"axp-weather-current-weather\">\n <!-- Weather icon and condition name -->\n @if (showCurrentCondition()) {\n <div class=\"axp-weather-condition\">\n <div class=\"axp-weather-icon-wrapper\">\n <div class=\"axp-weather-icon\">\n <i\n [class]=\"getConditionIcon(weatherData()?.current?.condition || '')\"\n [style.color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></i>\n </div>\n <div\n class=\"axp-weather-icon-glow\"\n [style.background-color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></div>\n </div>\n <div class=\"axp-weather-condition-name\">\n {{ getCurrentCondition() | translate: { scope: 'dashboard' } | async }}\n </div>\n </div>\n }\n\n <!-- Temperature display -->\n @if (showTemperature()) {\n <div class=\"axp-weather-temperature\">\n <span class=\"axp-weather-temperature-value\">{{ getCurrentTemperature() }}</span>\n <span class=\"axp-weather-temperature-unit\">{{\n getTemperatureUnit() | translate: { scope: 'dashboard' } | async\n }}</span>\n </div>\n }\n </div>\n\n <!-- Weather details section (humidity and wind) -->\n @if (showHumidity() || showWind()) {\n <div class=\"axp-weather-details\">\n <!-- Humidity information -->\n @if (showHumidity()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-droplet\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">\n {{ 'weather.humidity' | translate: { scope: 'dashboard' } | async }}\n </div>\n <div class=\"axp-weather-detail-value\">{{ getHumidity() }}%</div>\n </div>\n </div>\n }\n\n <!-- Wind speed information -->\n @if (showWind()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-wind\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">\n {{ 'weather.wind' | translate: { scope: 'dashboard' } | async }}\n </div>\n <div class=\"axp-weather-detail-value\">\n {{ getWindSpeed() }} {{ getWindSpeedUnit() | translate: { scope: 'dashboard' } | async }}\n </div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Weather forecast section -->\n @if (showForecast() && weatherData()?.forecast) {\n <div class=\"axp-weather-forecast\">\n <div class=\"axp-weather-forecast-header\">\n <h3 class=\"axp-weather-forecast-title\">\n <i class=\"fa-solid fa-calendar-days\"></i>\n <span class=\"ax-px-1\">{{ 'weather.forecast' | translate: { scope: 'dashboard' } | async }}</span>\n </h3>\n </div>\n <!-- Loading indicator for forecast -->\n <!-- @if (isForecastLoading()) {\n <div class=\"axp-weather-forecast-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>{{ 'weather.loading-forecast' | translate: { scope: 'dashboard' } | async }}</span>\n </div>\n } -->\n <!-- Scrollable forecast days display -->\n <div class=\"axp-weather-forecast-items\">\n @for (day of displayedForecast(); track day.day) {\n <div class=\"axp-weather-forecast-day\">\n <div class=\"axp-weather-forecast-day-name\">\n {{ getDayName(parseDate(day.date)) | translate: { scope: 'dashboard' } | async }}\n </div>\n <div\n class=\"axp-weather-forecast-icon\"\n [title]=\"getConditionName(day.condition) | translate: { scope: 'dashboard' } | async\"\n >\n <i [class]=\"getConditionIcon(day.condition)\" [style.color]=\"getConditionColor(day.condition)\"></i>\n </div>\n <div class=\"axp-weather-forecast-temps\">\n <span class=\"axp-weather-forecast-low\">\n {{ temperatureUnit() === '\u00B0C' ? day.minTempC : day.minTempF\n }}{{ getTemperatureUnit() | translate: { scope: 'dashboard' } | async }}\n </span>\n <span class=\"axp-weather-forecast-high\">\n {{ temperatureUnit() === '\u00B0C' ? day.maxTempC : day.maxTempF\n }}{{ getTemperatureUnit() | translate: { scope: 'dashboard' } | async }}\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Last updated timestamp -->\n <div class=\"axp-weather-last-updated\">\n <span>{{ 'weather.last-updated' | translate: { scope: 'dashboard' } | async }}: {{ getLastUpdated() }}</span>\n </div>\n\n <!-- Manual refresh button -->\n <div class=\"axp-weather-refresh-action\">\n <button\n class=\"axp-weather-refresh-button\"\n (click)=\"refreshWeather()\"\n [attr.aria-label]=\"'weather.refresh' | translate: { scope: 'dashboard' } | async\"\n [title]=\"'weather.refresh' | translate: { scope: 'dashboard' } | async\"\n >\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.refresh' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n </div>\n } @else if (!isLoading() && !hasError()) {\n <!-- No data state (not loading, no error) -->\n <div class=\"axp-weather-no-data-state\">\n <i class=\"fa-solid fa-cloud-sun\"></i>\n <p>{{ 'weather.no-data' | translate: { scope: 'dashboard' } | async }}</p>\n <button class=\"axp-weather-refresh-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.load-data' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%;--primary-gradient-start: #2196f3;--primary-gradient-end: #1976d2;--shadow-color: rgba(0, 0, 0, .2);--glass-bg: rgba(255, 255, 255, .15);--glass-border: rgba(255, 255, 255, .2);--text-primary: rgba(255, 255, 255, .95);--text-secondary: rgba(255, 255, 255, .75);--transition-speed: .3s}.axp-weather-container{width:100%;height:100%;overflow:hidden;position:relative;box-shadow:0 4px 8px rgba(0,0,0,.1);color:#fff;min-height:300px;background-color:#2c3e50}.axp-weather-loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(44,62,80,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-loading-spinner{text-align:center}.axp-weather-loading-spinner i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-loading-spinner span{display:block;color:#fff;font-size:1rem}.axp-weather-error-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(189,54,47,.85);display:flex;justify-content:center;align-items:center}.axp-weather-error-message{text-align:center;padding:1rem}.axp-weather-error-message i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-error-message span{display:block;color:#fff;font-size:1.1rem;margin-bottom:1rem}.axp-weather-error-message .axp-weather-retry-button{color:#bd362f;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-error-message .axp-weather-retry-button:hover{transform:translateY(-1px)}.axp-weather-no-data-state{display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%;padding:2rem;text-align:center}.axp-weather-no-data-state i{font-size:3rem;margin-bottom:1rem;color:rgba(255,255,255,.8)}.axp-weather-no-data-state p{margin-bottom:1.5rem;font-size:1.1rem}.axp-weather-no-data-state .axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-no-data-state .axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-background-decorations{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.axp-weather-decoration{position:absolute;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:center}.axp-weather-decoration.sunny{background:linear-gradient(135deg,#ff7e00,#f7d358)}.axp-weather-decoration.partlyCloudy{background:linear-gradient(135deg,#7ba2e7,#b4d2f7)}.axp-weather-decoration.cloudy{background:linear-gradient(135deg,#717e8c,#919eab)}.axp-weather-decoration.rain{background:linear-gradient(135deg,#6a8caf,#567a9e)}.axp-weather-decoration.snow{background:linear-gradient(135deg,#99b3cc,#c6d4e1)}.axp-weather-decoration.thunder{background:linear-gradient(135deg,#425777,#2c3e50)}.axp-weather-decoration.mist{background:linear-gradient(135deg,#94a3b8,#cbd5e1)}.axp-weather-gradient-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(rgba(0,0,0,.2),rgba(0,0,0,.5))}.axp-weather-inner{position:relative;z-index:2;height:100%;padding:1.5rem;display:flex;flex-direction:column;justify-content:space-between}.axp-weather-location-info{display:flex;align-items:center;margin-bottom:1.5rem}.axp-weather-location-icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;background-color:rgba(255,255,255,.2);border-radius:50%;margin-right:.75rem}.axp-weather-location-icon i{color:#fff}.axp-weather-location-name{margin:0;font-size:1.5rem;font-weight:500;text-shadow:1px 1px 3px rgba(0,0,0,.2);text-transform:capitalize}.axp-weather-current-weather{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap}.axp-weather-condition{display:flex;flex-direction:column;align-items:center}.axp-weather-icon-wrapper{position:relative;margin-bottom:.5rem}.axp-weather-icon{position:relative;z-index:2}.axp-weather-icon i{font-size:2.75rem;filter:drop-shadow(0 0 8px rgba(0,0,0,.3))}.axp-weather-icon-glow{position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);width:45px;height:45px;border-radius:50%;filter:blur(15px);opacity:.75}.axp-weather-condition-name{font-size:1.1rem;text-align:center;text-shadow:1px 1px 2px rgba(0,0,0,.2)}.axp-weather-temperature{display:flex;align-items:flex-start;text-shadow:1px 1px 3px rgba(0,0,0,.3)}.axp-weather-temperature-value{font-size:3.5rem;font-weight:500;line-height:1}.axp-weather-temperature-unit{font-size:1.5rem;margin-top:.25rem}.axp-weather-details{display:flex;flex-wrap:wrap;gap:1.5rem;margin-bottom:1rem;padding:1rem;background-color:rgba(0,0,0,.15);border-radius:8px}.axp-weather-detail-item{display:flex;align-items:center;flex:1;min-width:120px}.axp-weather-detail-icon{width:40px;height:40px;border-radius:50%;background-color:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;margin-right:.75rem}.axp-weather-detail-icon i{font-size:1.25rem}.axp-weather-detail-info{display:flex;padding-inline:.25rem;flex-direction:column}.axp-weather-detail-label{font-size:.875rem;color:rgba(255,255,255,.8);margin-bottom:.25rem}.axp-weather-detail-value{font-size:1.125rem;font-weight:500}.axp-weather-forecast{margin-bottom:.5rem;background-color:rgba(0,0,0,.15);border-radius:8px;padding:1rem}.axp-weather-forecast-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.axp-weather-forecast-title{margin:0;font-size:1.125rem;font-weight:500;display:flex;align-items:center}.axp-weather-forecast-title i{margin-right:.5rem;opacity:.8}.axp-weather-scroll-indicator{color:rgba(255,255,255,.6)}.axp-weather-forecast-items{display:flex;overflow-x:auto;gap:.75rem;padding-bottom:.5rem}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.3);border-radius:4px}.axp-weather-forecast-items::-webkit-scrollbar-track{background-color:rgba(0,0,0,.1);border-radius:4px}.axp-weather-forecast-day{min-width:90px;display:flex;flex-direction:column;align-items:center;padding:.75rem .5rem;background-color:rgba(255,255,255,.1);border-radius:6px;transition:all .3s ease}.axp-weather-forecast-day:hover{background-color:rgba(255,255,255,.15);transform:translateY(-2px)}.axp-weather-forecast-day-name{font-size:.875rem;margin-bottom:.5rem;font-weight:500}.axp-weather-forecast-icon{font-size:1.5rem;margin-bottom:.5rem}.axp-weather-forecast-icon i{filter:drop-shadow(0 0 5px rgba(0,0,0,.2))}.axp-weather-forecast-temps{display:flex;flex-direction:row;gap:.75rem;align-items:center;font-size:.775rem}.axp-weather-last-updated{text-align:center;font-size:.75rem;opacity:.7;margin-bottom:.5rem}.axp-weather-refresh-action{text-align:center}.axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:.875rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-refresh-button i{font-size:.875rem}@media (max-width: 576px){.axp-weather-inner{padding:.8rem;gap:.4rem}.axp-weather-location-name{font-size:1.1rem;padding-inline:.25rem}.axp-weather-temperature{font-size:2.5rem}.axp-weather-temperature-unit{font-size:1.1rem}.axp-weather-weather-details{flex-direction:column;gap:.5rem}.axp-weather-forecast-items{flex-wrap:nowrap;overflow-x:auto;padding-bottom:.5rem;margin:0 -.4rem;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scrollbar-width:thin;mask-image:linear-gradient(to right,#000 95%,rgba(0,0,0,0));-webkit-mask-image:linear-gradient(to right,rgb(0,0,0) 95%,rgba(0,0,0,0))}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.2);border-radius:4px}.axp-weather-forecast-day{min-width:60px;flex:0 0 auto;padding:.4rem .6rem}.axp-weather-forecast-day-name{font-size:.7rem}.axp-weather-forecast-icon{padding:.3rem;height:1.6rem}.axp-weather-forecast-temps{font-size:.7rem}.axp-weather-scroll-indicator{display:block}}:host-context(.theme-dark){--glass-bg: rgba(0, 0, 0, .3);--glass-border: rgba(255, 255, 255, .1)}\n"] }]
|
4545
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Weather Widget Component Template -->\n<div class=\"axp-weather-container\" #containerElement>\n <!-- Loading indicator -->\n @if (isLoading()) {\n <div class=\"axp-weather-loading-overlay\">\n <div class=\"axp-weather-loading-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>{{ 'weather.loading' | translate: { scope: 'dashboard' } | async }}</span>\n </div>\n </div>\n }\n\n <!-- Error message -->\n @if (hasError()) {\n <div class=\"axp-weather-error-overlay\">\n <div class=\"axp-weather-error-message\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage() | translate: { scope: 'dashboard' } | async }}</span>\n <button class=\"axp-weather-retry-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.retry' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n </div>\n }\n\n <!-- Weather content - only show when we have data -->\n @if (weatherData()) {\n <!-- Background decorations based on weather condition -->\n <div class=\"axp-weather-background-decorations\">\n <div class=\"axp-weather-decoration\" [ngClass]=\"weatherData()?.current?.condition?.toLowerCase()\"></div>\n <div class=\"axp-weather-gradient-overlay\"></div>\n </div>\n\n <div class=\"axp-weather-inner\">\n <!-- Location information section -->\n <div class=\"axp-weather-location-info\">\n <div class=\"axp-weather-location-icon\">\n <i class=\"fa-solid fa-location-dot\"></i>\n </div>\n <div class=\"axp-weather-location-text\">\n <h2 class=\"axp-weather-location-name\">{{ city() }}</h2>\n </div>\n </div>\n\n <!-- Current weather conditions section -->\n <div class=\"axp-weather-current-weather\">\n <!-- Weather icon and condition name -->\n @if (showCurrentCondition()) {\n <div class=\"axp-weather-condition\">\n <div class=\"axp-weather-icon-wrapper\">\n <div class=\"axp-weather-icon\">\n <img [src]=\"getConditionIcon(weatherData()?.current?.condition || '')\" />\n </div>\n <div\n class=\"axp-weather-icon-glow\"\n [style.background-color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></div>\n </div>\n <div class=\"axp-weather-condition-name\">\n {{ getCurrentCondition() | translate: { scope: 'dashboard' } | async }}\n </div>\n </div>\n }\n\n <!-- Temperature display -->\n @if (showTemperature()) {\n <div class=\"axp-weather-temperature\">\n <span class=\"axp-weather-temperature-value\">{{ getCurrentTemperature() }}</span>\n <span class=\"axp-weather-temperature-unit\">{{\n getTemperatureUnit() | translate: { scope: 'dashboard' } | async\n }}</span>\n </div>\n }\n </div>\n\n <!-- Weather details section (humidity and wind) -->\n @if (showHumidity() || showWind()) {\n <div class=\"axp-weather-details\">\n <!-- Humidity information -->\n @if (showHumidity()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-droplet\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">\n {{ 'weather.humidity' | translate: { scope: 'dashboard' } | async }}\n </div>\n <div class=\"axp-weather-detail-value\">{{ getHumidity() }}%</div>\n </div>\n </div>\n }\n\n <!-- Wind speed information -->\n @if (showWind()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-wind\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">\n {{ 'weather.wind' | translate: { scope: 'dashboard' } | async }}\n </div>\n <div class=\"axp-weather-detail-value\">\n {{ getWindSpeed() }} {{ getWindSpeedUnit() | translate: { scope: 'dashboard' } | async }}\n </div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Weather forecast section -->\n @if (showForecast() && weatherData()?.forecast) {\n <div class=\"axp-weather-forecast\">\n <div class=\"axp-weather-forecast-header\">\n <h3 class=\"axp-weather-forecast-title\">\n <i class=\"fa-solid fa-calendar-days\"></i>\n <span class=\"ax-px-1\">{{ 'weather.forecast' | translate: { scope: 'dashboard' } | async }}</span>\n </h3>\n </div>\n <!-- Loading indicator for forecast -->\n <!-- @if (isForecastLoading()) {\n <div class=\"axp-weather-forecast-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>{{ 'weather.loading-forecast' | translate: { scope: 'dashboard' } | async }}</span>\n </div>\n } -->\n <!-- Scrollable forecast days display -->\n <div class=\"axp-weather-forecast-items\">\n @for (day of displayedForecast(); track day.day) {\n <div class=\"axp-weather-forecast-day\">\n <div class=\"axp-weather-forecast-day-name\">\n {{ getDayName(parseDate(day.date)) | translate: { scope: 'dashboard' } | async }}\n </div>\n <div\n class=\"axp-weather-forecast-icon\"\n [title]=\"getConditionName(day.condition) | translate: { scope: 'dashboard' } | async\"\n >\n <img [src]=\"getConditionIcon(day.condition || '')\" />\n </div>\n <div class=\"axp-weather-forecast-temps\">\n <span class=\"axp-weather-forecast-low\">\n {{ temperatureUnit() === '\u00B0C' ? day.minTempC : day.minTempF\n }}{{ getTemperatureUnit() | translate: { scope: 'dashboard' } | async }}\n </span>\n <span class=\"axp-weather-forecast-high\">\n {{ temperatureUnit() === '\u00B0C' ? day.maxTempC : day.maxTempF\n }}{{ getTemperatureUnit() | translate: { scope: 'dashboard' } | async }}\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Last updated timestamp -->\n <div class=\"axp-weather-last-updated\">\n <span>{{ 'weather.last-updated' | translate: { scope: 'dashboard' } | async }}: {{ getLastUpdated() }}</span>\n </div>\n\n <!-- Manual refresh button -->\n <div class=\"axp-weather-refresh-action\">\n <button\n class=\"axp-weather-refresh-button\"\n (click)=\"refreshWeather()\"\n [attr.aria-label]=\"'weather.refresh' | translate: { scope: 'dashboard' } | async\"\n [title]=\"'weather.refresh' | translate: { scope: 'dashboard' } | async\"\n >\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.refresh' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n </div>\n } @else if (!isLoading() && !hasError()) {\n <!-- No data state (not loading, no error) -->\n <div class=\"axp-weather-no-data-state\">\n <i class=\"fa-solid fa-cloud-sun\"></i>\n <p>{{ 'weather.no-data' | translate: { scope: 'dashboard' } | async }}</p>\n <button class=\"axp-weather-refresh-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.load-data' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%;--primary-gradient-start: #2196f3;--primary-gradient-end: #1976d2;--shadow-color: rgba(0, 0, 0, .2);--glass-bg: rgba(255, 255, 255, .15);--glass-border: rgba(255, 255, 255, .2);--text-primary: rgba(255, 255, 255, .95);--text-secondary: rgba(255, 255, 255, .75);--transition-speed: .3s}.axp-weather-container{width:100%;height:100%;overflow:hidden;position:relative;box-shadow:0 4px 8px rgba(0,0,0,.1);min-height:300px}.axp-weather-loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(44,62,80,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-loading-spinner{text-align:center}.axp-weather-loading-spinner i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-loading-spinner span{display:block;color:#fff;font-size:1rem}.axp-weather-error-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(189,54,47,.85);display:flex;justify-content:center;align-items:center}.axp-weather-error-message{text-align:center;padding:1rem}.axp-weather-error-message i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-error-message span{display:block;color:#fff;font-size:1.1rem;margin-bottom:1rem}.axp-weather-error-message .axp-weather-retry-button{color:#bd362f;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-error-message .axp-weather-retry-button:hover{transform:translateY(-1px)}.axp-weather-no-data-state{display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%;padding:2rem;text-align:center}.axp-weather-no-data-state i{font-size:3rem;margin-bottom:1rem;color:rgba(255,255,255,.8)}.axp-weather-no-data-state p{margin-bottom:1.5rem;font-size:1.1rem}.axp-weather-no-data-state .axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-no-data-state .axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-background-decorations{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.axp-weather-decoration{position:absolute;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:center}.axp-weather-gradient-overlay{position:absolute;top:0;left:0;width:100%;height:100%}.axp-weather-inner{position:relative;z-index:2;height:100%;padding:1.5rem;display:flex;flex-direction:column;justify-content:space-between}.axp-weather-location-info{display:flex;align-items:center;margin-bottom:1.5rem}.axp-weather-location-icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;background-color:rgba(255,255,255,.2);border-radius:50%;margin-right:.75rem}.axp-weather-location-icon i{color:#fff}.axp-weather-location-name{margin:0;font-size:1.5rem;font-weight:500;text-shadow:1px 1px 3px rgba(0,0,0,.2);text-transform:capitalize}.axp-weather-current-weather{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap}.axp-weather-condition{display:flex;flex-direction:column;align-items:center}.axp-weather-icon-wrapper{position:relative;margin-bottom:.5rem}.axp-weather-icon{position:relative;z-index:2;scale:2}.axp-weather-icon i{font-size:2.75rem;filter:drop-shadow(0 0 8px rgba(0,0,0,.3))}.axp-weather-icon-glow{position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);width:45px;height:45px;border-radius:50%;filter:blur(15px);opacity:.4}.axp-weather-condition-name{font-size:1.1rem;text-align:center;text-shadow:1px 1px 2px rgba(0,0,0,.2)}.axp-weather-temperature{display:flex;align-items:flex-start;text-shadow:1px 1px 3px rgba(0,0,0,.3)}.axp-weather-temperature-value{font-size:3.5rem;font-weight:500;line-height:1}.axp-weather-temperature-unit{font-size:1.5rem;margin-top:.25rem}.axp-weather-details{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-darker-surface),var(--tw-bg-opacity, 1));display:flex;flex-wrap:wrap;gap:1.5rem;margin-bottom:1rem;padding:1rem;border-radius:8px}.axp-weather-detail-item{display:flex;align-items:center;flex:1;min-width:120px}.axp-weather-detail-icon{width:40px;height:40px;border-radius:50%;background-color:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;margin-right:.75rem}.axp-weather-detail-icon i{font-size:1.25rem}.axp-weather-detail-info{display:flex;padding-inline:.25rem;flex-direction:column}.axp-weather-detail-label{font-size:.875rem;margin-bottom:.25rem}.axp-weather-detail-value{font-size:1.125rem;font-weight:500}.axp-weather-forecast{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-darker-surface),var(--tw-bg-opacity, 1));margin-bottom:.5rem;border-radius:8px;padding:1rem}.axp-weather-forecast-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.axp-weather-forecast-title{margin:0;font-size:1.125rem;font-weight:500;display:flex;align-items:center}.axp-weather-forecast-title i{margin-right:.5rem;opacity:.8}.axp-weather-scroll-indicator{color:rgba(255,255,255,.6)}.axp-weather-forecast-items{display:flex;overflow-x:auto;gap:.75rem;padding-bottom:.5rem}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.3);border-radius:4px}.axp-weather-forecast-items::-webkit-scrollbar-track{background-color:rgba(0,0,0,.1);border-radius:4px}.axp-weather-forecast-day{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-surface),var(--tw-bg-opacity, 1));min-width:90px;display:flex;flex-direction:column;align-items:center;padding:.75rem .5rem;border-radius:6px;transition:all .3s ease}.axp-weather-forecast-day:hover{transform:translateY(-2px)}.axp-weather-forecast-day-name{font-size:.875rem;margin-bottom:.5rem;font-weight:500}.axp-weather-forecast-icon{font-size:1.5rem;margin-bottom:.5rem}.axp-weather-forecast-icon i{filter:drop-shadow(0 0 5px rgba(0,0,0,.2))}.axp-weather-forecast-temps{display:flex;flex-direction:row;gap:.75rem;align-items:center;font-size:.775rem}.axp-weather-last-updated{text-align:center;font-size:.75rem;opacity:.7;margin-bottom:.5rem}.axp-weather-refresh-action{text-align:center}.axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:.875rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-refresh-button i{font-size:.875rem}@media (max-width: 576px){.axp-weather-inner{padding:.8rem;gap:.4rem}.axp-weather-location-name{font-size:1.1rem;padding-inline:.25rem}.axp-weather-temperature{font-size:2.5rem}.axp-weather-temperature-unit{font-size:1.1rem}.axp-weather-weather-details{flex-direction:column;gap:.5rem}.axp-weather-forecast-items{flex-wrap:nowrap;overflow-x:auto;padding-bottom:.5rem;margin:0 -.4rem;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scrollbar-width:thin;mask-image:linear-gradient(to right,#000 95%,rgba(0,0,0,0));-webkit-mask-image:linear-gradient(to right,rgb(0,0,0) 95%,rgba(0,0,0,0))}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.2);border-radius:4px}.axp-weather-forecast-day{min-width:60px;flex:0 0 auto;padding:.4rem .6rem}.axp-weather-forecast-day-name{font-size:.7rem}.axp-weather-forecast-icon{padding:.3rem;height:1.6rem}.axp-weather-forecast-temps{font-size:.7rem}.axp-weather-scroll-indicator{display:block}}:host-context(.theme-dark){--glass-bg: rgba(0, 0, 0, .3);--glass-border: rgba(255, 255, 255, .1)}\n"] }]
|
3366
4546
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
|
3367
4547
|
|
3368
4548
|
var weatherWidget_component = /*#__PURE__*/Object.freeze({
|
@@ -3901,10 +5081,14 @@ class AXMDashboardManagementModule {
|
|
3901
5081
|
AXPBarChartWidget,
|
3902
5082
|
AXPLineChartWidget,
|
3903
5083
|
AXPGaugeChartWidget,
|
5084
|
+
//utility
|
3904
5085
|
AXPStickyNoteWidget,
|
3905
5086
|
AXPClockCalendarWidget,
|
3906
5087
|
AXPWeatherWidget,
|
3907
5088
|
AXPTaskListWidget,
|
5089
|
+
AXPMinimalWeatherWidget,
|
5090
|
+
AXPAdvancedWeatherWidget,
|
5091
|
+
AXPAnalogClockWidget,
|
3908
5092
|
],
|
3909
5093
|
})] }); }
|
3910
5094
|
}
|
@@ -3920,10 +5104,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
|
|
3920
5104
|
AXPBarChartWidget,
|
3921
5105
|
AXPLineChartWidget,
|
3922
5106
|
AXPGaugeChartWidget,
|
5107
|
+
//utility
|
3923
5108
|
AXPStickyNoteWidget,
|
3924
5109
|
AXPClockCalendarWidget,
|
3925
5110
|
AXPWeatherWidget,
|
3926
5111
|
AXPTaskListWidget,
|
5112
|
+
AXPMinimalWeatherWidget,
|
5113
|
+
AXPAdvancedWeatherWidget,
|
5114
|
+
AXPAnalogClockWidget,
|
3927
5115
|
],
|
3928
5116
|
}),
|
3929
5117
|
],
|
@@ -4007,11 +5195,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
|
|
4007
5195
|
args: [{ selector: 'axm-dashboard-widget-wrapper', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AXButtonModule, AXDecoratorModule, AXDropdownModule, AXTranslationModule, CommonModule], standalone: true, template: "<section class=\"ax-relative ax-size-full ax-flex ax-flex-col ax-group ax-overflow-hidden\">\n <!-- Action button - stays absolute -->\n @if(!isLocked()) {\n <div\n class=\"ax-p-[0.6125rem] ax-absolute ax-top-0 ax-end-0 ax-z-[99] ax-invisible group-hover:ax-visible md:group-hover:ax-visible\"\n [class.!ax-visible]=\"isDropdownOpen()\"\n (touchstart)=\"isDropdownOpen.set(true)\"\n >\n <ax-button class=\"ax-sm ax-main-button\" [look]=\"'blank'\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-ellipsis-vertical\"></ax-icon>\n </ax-prefix>\n <ax-dropdown-panel (onOpened)=\"isDropdownOpen.set(true)\" (onClosed)=\"isDropdownOpen.set(false)\">\n <ng-container *translate=\"let t\">\n <ax-button-item-list (onItemClick)=\"handleOnItemClick($event)\">\n @if(hasConfiguration()){\n <ax-button-item\n [data]=\"'configuration'\"\n [text]=\"(t('configuration', { scope: 'dashboard' }) | async) || 'configuration'\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-cog\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n <ax-divider></ax-divider>\n }\n <ax-button-item [data]=\"'delete'\" [text]=\"(t('delete') | async) || 'delete'\" color=\"danger\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ng-container>\n </ax-dropdown-panel>\n </ax-button>\n </div>\n }\n\n <!-- Title section -->\n @if(title()) {\n <div class=\"ax-ps-5 ax-pe-8 ax-py-3 ax-border-b\">\n <h3 class=\"ax-text-start ax-text-lg ax-font-medium ax-truncate\">{{title()}}</h3>\n </div>\n }\n\n <!-- Content section -->\n <div class=\"ax-overflow-auto ax-h-full\">\n <ng-content></ng-content>\n </div>\n</section>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
|
4008
5196
|
}] });
|
4009
5197
|
|
4010
|
-
const path = 'home:dashboard:';
|
4011
|
-
var AXPHomeDashboardSetting;
|
5198
|
+
const path$1 = 'home:dashboard:';
|
5199
|
+
var AXPHomeDashboardSetting$1;
|
4012
5200
|
(function (AXPHomeDashboardSetting) {
|
4013
5201
|
AXPHomeDashboardSetting["CurrentDashboard"] = "home:dashboard:current-dashboard";
|
4014
|
-
})(AXPHomeDashboardSetting || (AXPHomeDashboardSetting = {}));
|
5202
|
+
})(AXPHomeDashboardSetting$1 || (AXPHomeDashboardSetting$1 = {}));
|
4015
5203
|
|
4016
5204
|
class AXMAddDashboardPopup extends AXBasePageComponent {
|
4017
5205
|
constructor() {
|
@@ -4441,7 +5629,7 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
|
|
4441
5629
|
const dashboards = dashboardModels.map(modelToDashboardLayout);
|
4442
5630
|
const currentDashboardId = await settingService
|
4443
5631
|
.scope(AXPPlatformScope.User)
|
4444
|
-
.get(AXPHomeDashboardSetting.CurrentDashboard);
|
5632
|
+
.get(AXPHomeDashboardSetting$1.CurrentDashboard);
|
4445
5633
|
let newCurrentDashboardId = null;
|
4446
5634
|
if (dashboards.length > 0) {
|
4447
5635
|
const dashboardExists = currentDashboardId && dashboards.some((d) => d.id === currentDashboardId);
|
@@ -4449,7 +5637,7 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
|
|
4449
5637
|
if (!dashboardExists) {
|
4450
5638
|
settingService
|
4451
5639
|
.scope(AXPPlatformScope.User)
|
4452
|
-
.set(AXPHomeDashboardSetting.CurrentDashboard, newCurrentDashboardId);
|
5640
|
+
.set(AXPHomeDashboardSetting$1.CurrentDashboard, newCurrentDashboardId);
|
4453
5641
|
}
|
4454
5642
|
}
|
4455
5643
|
patchState(store, {
|
@@ -4467,7 +5655,7 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
|
|
4467
5655
|
return {
|
4468
5656
|
setCurrentDashboard(dashboardId) {
|
4469
5657
|
patchState(store, { currentDashboardId: dashboardId });
|
4470
|
-
settingService.scope(AXPPlatformScope.User).set(AXPHomeDashboardSetting.CurrentDashboard, dashboardId);
|
5658
|
+
settingService.scope(AXPPlatformScope.User).set(AXPHomeDashboardSetting$1.CurrentDashboard, dashboardId);
|
4471
5659
|
},
|
4472
5660
|
async addDashboard() {
|
4473
5661
|
try {
|
@@ -4497,7 +5685,7 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
|
|
4497
5685
|
});
|
4498
5686
|
settingService
|
4499
5687
|
.scope(AXPPlatformScope.User)
|
4500
|
-
.set(AXPHomeDashboardSetting.CurrentDashboard, dashboardWithMetadata.id);
|
5688
|
+
.set(AXPHomeDashboardSetting$1.CurrentDashboard, dashboardWithMetadata.id);
|
4501
5689
|
}
|
4502
5690
|
catch (error) {
|
4503
5691
|
console.error('Error adding dashboard:', error);
|
@@ -4622,7 +5810,7 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
|
|
4622
5810
|
if (newCurrentDashboardId) {
|
4623
5811
|
settingService
|
4624
5812
|
.scope(AXPPlatformScope.User)
|
4625
|
-
.set(AXPHomeDashboardSetting.CurrentDashboard, newCurrentDashboardId);
|
5813
|
+
.set(AXPHomeDashboardSetting$1.CurrentDashboard, newCurrentDashboardId);
|
4626
5814
|
}
|
4627
5815
|
}
|
4628
5816
|
patchState(store, {
|
@@ -4657,7 +5845,7 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
|
|
4657
5845
|
dashboards: updatedDashboards,
|
4658
5846
|
currentDashboardId: dashboard.id,
|
4659
5847
|
});
|
4660
|
-
settingService.scope(AXPPlatformScope.User).set(AXPHomeDashboardSetting.CurrentDashboard, dashboard.id);
|
5848
|
+
settingService.scope(AXPPlatformScope.User).set(AXPHomeDashboardSetting$1.CurrentDashboard, dashboard.id);
|
4661
5849
|
},
|
4662
5850
|
async onGridChange(event) {
|
4663
5851
|
if (!layoutThemeService.isDesktopDevice() || !store.selectedDashboard())
|
@@ -4979,7 +6167,7 @@ class AXMDashboardHomeComponent extends AXPPageLayoutBaseComponent {
|
|
4979
6167
|
provide: AXPPageLayoutBase,
|
4980
6168
|
useExisting: AXMDashboardHomeComponent,
|
4981
6169
|
},
|
4982
|
-
], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n <!-- Content Section -->\n\n <axp-page-content class=\"ax-relative\">\n <!-- Loading State -->\n @if(store.isLoading()) {\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-w-full ax-absolute ax-z-10 ax-bg-white/80\"\n >\n <ax-loading></ax-loading>\n <p class=\"ax-mt-3 ax-text-gray-600\">{{ t('loading', { scope: 'dashboard' }) | async }}</p>\n </div>\n } @else {\n <axp-widgets-container [context]=\"context()\">\n <ax-grid-layout-container [options]=\"store.currentLayoutOptions()\" (onChange)=\"store.onGridChange($event)\">\n <!-- No Dashboards State -->\n @if(!store.dashboards() || store.dashboards().length === 0) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">{{ t('no-dashboards', { scope: 'dashboard' }) | async }}</h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('add-first-dashboard', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- No Selected Dashboard State -->\n @else if (!store.selectedDashboard()) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">\n {{ t('no-current-dashboard', { scope: 'dashboard' }) | async }}\n </h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('select-dashboard', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- No Widgets State -->\n @else if (!store.selectedDashboard()?.widgets || store.selectedDashboard()?.widgets?.length === 0) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">{{ t('no-widgets', { scope: 'dashboard' }) | async }}</h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('add-first-widget', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- Widgets Grid -->\n @else { @for(widget of store.selectedDashboard()?.widgets; track widget.config.id) {\n <ax-grid-layout-widget
|
6170
|
+
], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n <!-- Content Section -->\n\n <axp-page-content class=\"ax-relative\">\n <!-- Loading State -->\n @if(store.isLoading()) {\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-w-full ax-absolute ax-z-10 ax-bg-white/80\"\n >\n <ax-loading></ax-loading>\n <p class=\"ax-mt-3 ax-text-gray-600\">{{ t('loading', { scope: 'dashboard' }) | async }}</p>\n </div>\n } @else {\n <axp-widgets-container [context]=\"context()\">\n <ax-grid-layout-container [options]=\"store.currentLayoutOptions()\" (onChange)=\"store.onGridChange($event)\">\n <!-- No Dashboards State -->\n @if(!store.dashboards() || store.dashboards().length === 0) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">{{ t('no-dashboards', { scope: 'dashboard' }) | async }}</h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('add-first-dashboard', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- No Selected Dashboard State -->\n @else if (!store.selectedDashboard()) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">\n {{ t('no-current-dashboard', { scope: 'dashboard' }) | async }}\n </h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('select-dashboard', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- No Widgets State -->\n @else if (!store.selectedDashboard()?.widgets || store.selectedDashboard()?.widgets?.length === 0) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">{{ t('no-widgets', { scope: 'dashboard' }) | async }}</h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('add-first-widget', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- Widgets Grid -->\n @else { @for(widget of store.selectedDashboard()?.widgets; track widget.config.id) {\n <ax-grid-layout-widget\n [options]=\"widget.config\"\n class=\"dark:[--ax-comp-grid-layout-stack-item-content-bg-color:var(--ax-sys-color-lighter-surface)] [--ax-comp-grid-layout-stack-item-content-bg-color:var(--ax-sys-color-lightest-surface)]\"\n >\n <axm-dashboard-widget-wrapper\n [title]=\"widget.node?.options?.['title']\"\n [hasConfiguration]=\"store.canConfigureWidget()(widget)\"\n [isLocked]=\"store.isWidgetLocked()(widget)\"\n (onDelete)=\"confirmWidgetDelete(store.selectedDashboard()?.id!, widget.config.id!)\"\n (onConfiguration)=\"store.handlePopupConfiguration(widget.node!)\"\n (onValueChanged)=\"store.handleValueChanged(widget?.node!,$event)\"\n (onOptionsChanged)=\"store.handleOptionsChanged(widget?.node!,$event)\"\n >\n @if(widget.node) {\n <ng-container axp-widget-renderer [node]=\"widget.node\" [mode]=\"'view'\"></ng-container>\n }\n </axm-dashboard-widget-wrapper>\n </ax-grid-layout-widget>\n } }\n </ax-grid-layout-container>\n </axp-widgets-container>\n }\n </axp-page-content>\n</axp-page-layout>\n", styles: ["axm-dashboard-home{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}axm-dashboard-home .placeholder-content{border-radius:.5rem!important;border-width:1px!important;border-style:dashed!important;--tw-border-opacity: 1 !important;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))!important;background-color:rgba(var(--ax-sys-color-primary-lightest-surface),.5)!important}axm-dashboard-home ax-grid-layout-widget .grid-stack-item-content{border-radius:.375rem!important;border-width:1px!important;--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05) !important;--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color) !important;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i2$5.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXPLayoutBuilderModule }, { kind: "component", type: i3$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i3$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXButtonGroupModule }, { kind: "ngmodule", type: AXGridLayoutBuilderModule }, { kind: "component", type: i4$1.AXGridLayoutContainerComponent, selector: "ax-grid-layout-container", inputs: ["options", "isEmpty"], outputs: ["onAdded", "onRemoved", "onWidgetChange", "onChange", "onRender", "isEmptyChange"] }, { kind: "component", type: i4$1.AXGridLayoutWidgetComponent, selector: "ax-grid-layout-widget", inputs: ["options"] }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i2$3.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXBreadcrumbsModule }, { kind: "component", type: AXMDashboardWidgetWrapperComponent, selector: "axm-dashboard-widget-wrapper", inputs: ["title", "hasConfiguration", "isLocked"], outputs: ["onDelete", "onConfiguration", "onValueChanged", "onOptionsChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
4983
6171
|
}
|
4984
6172
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXMDashboardHomeComponent, decorators: [{
|
4985
6173
|
type: Component,
|
@@ -5005,7 +6193,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
|
|
5005
6193
|
provide: AXPPageLayoutBase,
|
5006
6194
|
useExisting: AXMDashboardHomeComponent,
|
5007
6195
|
},
|
5008
|
-
], template: "<axp-page-layout *translate=\"let t\">\n <!-- Content Section -->\n\n <axp-page-content class=\"ax-relative\">\n <!-- Loading State -->\n @if(store.isLoading()) {\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-w-full ax-absolute ax-z-10 ax-bg-white/80\"\n >\n <ax-loading></ax-loading>\n <p class=\"ax-mt-3 ax-text-gray-600\">{{ t('loading', { scope: 'dashboard' }) | async }}</p>\n </div>\n } @else {\n <axp-widgets-container [context]=\"context()\">\n <ax-grid-layout-container [options]=\"store.currentLayoutOptions()\" (onChange)=\"store.onGridChange($event)\">\n <!-- No Dashboards State -->\n @if(!store.dashboards() || store.dashboards().length === 0) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">{{ t('no-dashboards', { scope: 'dashboard' }) | async }}</h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('add-first-dashboard', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- No Selected Dashboard State -->\n @else if (!store.selectedDashboard()) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">\n {{ t('no-current-dashboard', { scope: 'dashboard' }) | async }}\n </h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('select-dashboard', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- No Widgets State -->\n @else if (!store.selectedDashboard()?.widgets || store.selectedDashboard()?.widgets?.length === 0) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">{{ t('no-widgets', { scope: 'dashboard' }) | async }}</h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('add-first-widget', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- Widgets Grid -->\n @else { @for(widget of store.selectedDashboard()?.widgets; track widget.config.id) {\n <ax-grid-layout-widget
|
6196
|
+
], template: "<axp-page-layout *translate=\"let t\">\n <!-- Content Section -->\n\n <axp-page-content class=\"ax-relative\">\n <!-- Loading State -->\n @if(store.isLoading()) {\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-w-full ax-absolute ax-z-10 ax-bg-white/80\"\n >\n <ax-loading></ax-loading>\n <p class=\"ax-mt-3 ax-text-gray-600\">{{ t('loading', { scope: 'dashboard' }) | async }}</p>\n </div>\n } @else {\n <axp-widgets-container [context]=\"context()\">\n <ax-grid-layout-container [options]=\"store.currentLayoutOptions()\" (onChange)=\"store.onGridChange($event)\">\n <!-- No Dashboards State -->\n @if(!store.dashboards() || store.dashboards().length === 0) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">{{ t('no-dashboards', { scope: 'dashboard' }) | async }}</h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('add-first-dashboard', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- No Selected Dashboard State -->\n @else if (!store.selectedDashboard()) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">\n {{ t('no-current-dashboard', { scope: 'dashboard' }) | async }}\n </h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('select-dashboard', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- No Widgets State -->\n @else if (!store.selectedDashboard()?.widgets || store.selectedDashboard()?.widgets?.length === 0) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">{{ t('no-widgets', { scope: 'dashboard' }) | async }}</h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('add-first-widget', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- Widgets Grid -->\n @else { @for(widget of store.selectedDashboard()?.widgets; track widget.config.id) {\n <ax-grid-layout-widget\n [options]=\"widget.config\"\n class=\"dark:[--ax-comp-grid-layout-stack-item-content-bg-color:var(--ax-sys-color-lighter-surface)] [--ax-comp-grid-layout-stack-item-content-bg-color:var(--ax-sys-color-lightest-surface)]\"\n >\n <axm-dashboard-widget-wrapper\n [title]=\"widget.node?.options?.['title']\"\n [hasConfiguration]=\"store.canConfigureWidget()(widget)\"\n [isLocked]=\"store.isWidgetLocked()(widget)\"\n (onDelete)=\"confirmWidgetDelete(store.selectedDashboard()?.id!, widget.config.id!)\"\n (onConfiguration)=\"store.handlePopupConfiguration(widget.node!)\"\n (onValueChanged)=\"store.handleValueChanged(widget?.node!,$event)\"\n (onOptionsChanged)=\"store.handleOptionsChanged(widget?.node!,$event)\"\n >\n @if(widget.node) {\n <ng-container axp-widget-renderer [node]=\"widget.node\" [mode]=\"'view'\"></ng-container>\n }\n </axm-dashboard-widget-wrapper>\n </ax-grid-layout-widget>\n } }\n </ax-grid-layout-container>\n </axp-widgets-container>\n }\n </axp-page-content>\n</axp-page-layout>\n", styles: ["axm-dashboard-home{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}axm-dashboard-home .placeholder-content{border-radius:.5rem!important;border-width:1px!important;border-style:dashed!important;--tw-border-opacity: 1 !important;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))!important;background-color:rgba(var(--ax-sys-color-primary-lightest-surface),.5)!important}axm-dashboard-home ax-grid-layout-widget .grid-stack-item-content{border-radius:.375rem!important;border-width:1px!important;--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05) !important;--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color) !important;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)!important}\n"] }]
|
5009
6197
|
}] });
|
5010
6198
|
|
5011
6199
|
var homeDashboard = /*#__PURE__*/Object.freeze({
|
@@ -5013,9 +6201,15 @@ var homeDashboard = /*#__PURE__*/Object.freeze({
|
|
5013
6201
|
AXMDashboardHomeComponent: AXMDashboardHomeComponent
|
5014
6202
|
});
|
5015
6203
|
|
6204
|
+
const path = 'home:dashboard:';
|
6205
|
+
var AXPHomeDashboardSetting;
|
6206
|
+
(function (AXPHomeDashboardSetting) {
|
6207
|
+
AXPHomeDashboardSetting["CurrentDashboard"] = "home:dashboard:current-dashboard";
|
6208
|
+
})(AXPHomeDashboardSetting || (AXPHomeDashboardSetting = {}));
|
6209
|
+
|
5016
6210
|
/**
|
5017
6211
|
* Generated bundle index. Do not edit.
|
5018
6212
|
*/
|
5019
6213
|
|
5020
|
-
export { AXMDashboardHomeComponent, AXMDashboardManagementModule, AXMDashboardService, AXMDashboardServiceImpl, AXMDashboardStore, AXPBarChartWidget, AXPBarChartWidgetViewComponent, AXPClockCalendarWidget, AXPClockCalendarWidgetViewComponent, AXPDonutChartWidget, AXPDonutChartWidgetViewComponent, AXPGaugeChartWidget, AXPGaugeChartWidgetViewComponent, AXPLineChartWidget, AXPLineChartWidgetViewComponent, AXPStickyNoteWidget, AXPStickyNoteWidgetViewComponent, AXPTaskListWidget, AXPTaskListWidgetViewComponent, AXPWeatherApiAbstract, AXPWeatherApiMockService, AXPWeatherApiService, AXPWeatherWidget, AXPWeatherWidgetViewComponent, AXP_DATE_FORMAT_OPTIONS, AXP_TIMEZONE_OPTIONS, AXP_WIDGETS_CHART_CATEGORY, AXP_WIDGETS_UTILITY_CATEGORY, RootConfig, dashboardFactory };
|
6214
|
+
export { AXMAddDashboardPopup, AXMAnalogClockComponent, AXMClockWidgetViewComponent, AXMConfigurationPopup, AXMDashboardHomeComponent, AXMDashboardManagementModule, AXMDashboardPopupService, AXMDashboardService, AXMDashboardServiceImpl, AXMDashboardStore, AXMDashboardWidgetWrapperComponent, AXPAdvancedWeatherViewComponent, AXPAdvancedWeatherWidget, AXPAnalogClockWidget, AXPBarChartWidget, AXPBarChartWidgetViewComponent, AXPClockCalendarWidget, AXPClockCalendarWidgetViewComponent, AXPDonutChartWidget, AXPDonutChartWidgetViewComponent, AXPGaugeChartWidget, AXPGaugeChartWidgetViewComponent, AXPHomeDashboardSetting, AXPLineChartWidget, AXPLineChartWidgetViewComponent, AXPMinimalWeatherViewComponent, AXPMinimalWeatherWidget, AXPStickyNoteWidget, AXPStickyNoteWidgetViewComponent, AXPTaskListWidget, AXPTaskListWidgetViewComponent, AXPWeatherApiAbstract, AXPWeatherApiMockService, AXPWeatherApiService, AXPWeatherWidget, AXPWeatherWidgetViewComponent, AXP_DATE_FORMAT_OPTIONS, AXP_TIMEZONE_OPTIONS, AXP_WIDGETS_CHART_CATEGORY, AXP_WIDGETS_UTILITY_CATEGORY, RootConfig, dashboardFactory };
|
5021
6215
|
//# sourceMappingURL=acorex-modules-dashboard-management.mjs.map
|