@ogidor/dashboard 1.0.9 → 1.0.11
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/README.md +22 -0
- package/app/app.module.d.ts +1 -1
- package/app/dashboard.component.d.ts +15 -15
- package/esm2020/app/app.module.mjs +6 -2
- package/esm2020/app/dashboard.component.mjs +140 -121
- package/fesm2015/ogidor-dashboard.mjs +146 -121
- package/fesm2015/ogidor-dashboard.mjs.map +1 -1
- package/fesm2020/ogidor-dashboard.mjs +144 -121
- package/fesm2020/ogidor-dashboard.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Directive, EventEmitter, TemplateRef, Component, ChangeDetectionStrategy, Input, Output, ViewChild, ContentChild, Injectable, NgModule } from '@angular/core';
|
|
2
|
+
import { Directive, EventEmitter, TemplateRef, Component, ChangeDetectionStrategy, Input, Output, ViewChild, ContentChild, Injectable, Pipe, NgModule } from '@angular/core';
|
|
3
3
|
import { BrowserModule } from '@angular/platform-browser';
|
|
4
4
|
import * as i2 from '@angular/common';
|
|
5
5
|
import { CommonModule } from '@angular/common';
|
|
@@ -887,42 +887,44 @@ const DEFAULT_THEME = {
|
|
|
887
887
|
accentColor: '#0a84ff',
|
|
888
888
|
dangerColor: '#ff453a',
|
|
889
889
|
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
|
|
890
|
-
// Header / Tabs
|
|
891
890
|
tabsContainerColor: 'rgba(44,44,46,0.6)',
|
|
892
891
|
tabActiveColor: '#3a3a3c',
|
|
893
892
|
tabActiveTextColor: '#ffffff',
|
|
894
893
|
tabHoverTextColor: '#e5e5ea',
|
|
895
894
|
addWidgetButtonTextColor: '#ffffff',
|
|
896
|
-
// Pop-out
|
|
897
895
|
popoutTitleColor: '#ffffff',
|
|
898
|
-
// Widget card
|
|
899
896
|
widgetTitleColor: '#ffffff',
|
|
900
897
|
dragHandleColor: 'rgba(255,255,255,0.2)',
|
|
901
898
|
widgetBorderColor: 'rgba(255,255,255,0.07)',
|
|
902
899
|
widgetButtonBgColor: 'rgba(255,255,255,0.07)',
|
|
903
900
|
widgetButtonColor: 'rgba(255,255,255,0.5)',
|
|
904
|
-
// Grid
|
|
905
901
|
placeholderColor: '#0a84ff',
|
|
906
902
|
resizeHandleColor: 'rgba(255,255,255,0.25)',
|
|
907
903
|
};
|
|
904
|
+
class OverflowActivePipe {
|
|
905
|
+
transform(pages, activePageId) {
|
|
906
|
+
return pages.some(p => p.id === activePageId);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
OverflowActivePipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: OverflowActivePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
910
|
+
OverflowActivePipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: OverflowActivePipe, name: "overflowActive" });
|
|
911
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: OverflowActivePipe, decorators: [{
|
|
912
|
+
type: Pipe,
|
|
913
|
+
args: [{ name: 'overflowActive' }]
|
|
914
|
+
}] });
|
|
908
915
|
class DashboardComponent {
|
|
909
|
-
constructor(stateService) {
|
|
916
|
+
constructor(stateService, cdr, zone) {
|
|
910
917
|
this.stateService = stateService;
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
* The consumer should open their own dialog and call `stateService.addWidget(...)`.
|
|
914
|
-
*/
|
|
918
|
+
this.cdr = cdr;
|
|
919
|
+
this.zone = zone;
|
|
915
920
|
this.addWidgetRequested = new EventEmitter();
|
|
916
|
-
/**
|
|
917
|
-
* Emits the Widget when the user clicks the edit (pen) icon on a card.
|
|
918
|
-
* The consumer should open their own edit UI and call `stateService.updateWidget(...)`.
|
|
919
|
-
*/
|
|
920
921
|
this.editWidgetRequested = new EventEmitter();
|
|
921
922
|
this.resolvedTheme = Object.assign({}, DEFAULT_THEME);
|
|
922
923
|
this.wrapperStyles = {};
|
|
923
924
|
this.pages = [];
|
|
924
925
|
this.activePageId = '';
|
|
925
926
|
this.isPoppedOut = false;
|
|
927
|
+
this.tabsOverflow = false;
|
|
926
928
|
this.subs = new Subscription();
|
|
927
929
|
}
|
|
928
930
|
ngOnChanges(changes) {
|
|
@@ -946,8 +948,7 @@ class DashboardComponent {
|
|
|
946
948
|
this.subs.add(this.stateService.pages$.subscribe(pages => {
|
|
947
949
|
this.pages = pages;
|
|
948
950
|
if (this.isPoppedOut && hash) {
|
|
949
|
-
|
|
950
|
-
if (target)
|
|
951
|
+
if (pages.find(p => p.id === hash))
|
|
951
952
|
this.stateService.setActivePage(hash);
|
|
952
953
|
}
|
|
953
954
|
this.updateActivePage();
|
|
@@ -957,7 +958,25 @@ class DashboardComponent {
|
|
|
957
958
|
this.updateActivePage();
|
|
958
959
|
}));
|
|
959
960
|
}
|
|
960
|
-
|
|
961
|
+
ngAfterViewInit() {
|
|
962
|
+
if (!this.tabsContainerRef)
|
|
963
|
+
return;
|
|
964
|
+
this.zone.runOutsideAngular(() => {
|
|
965
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
966
|
+
this.zone.run(() => this.checkOverflow());
|
|
967
|
+
});
|
|
968
|
+
this.resizeObserver.observe(this.tabsContainerRef.nativeElement);
|
|
969
|
+
});
|
|
970
|
+
// Also detect scroll so fade hides when scrolled to end
|
|
971
|
+
this.tabsContainerRef.nativeElement.addEventListener('scroll', () => {
|
|
972
|
+
this.zone.run(() => this.checkOverflow());
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
ngOnDestroy() {
|
|
976
|
+
var _a;
|
|
977
|
+
this.subs.unsubscribe();
|
|
978
|
+
(_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
979
|
+
}
|
|
961
980
|
onItemChanged(widget) {
|
|
962
981
|
this.stateService.updateWidgetPosition(this.activePageId, widget.id, widget.x, widget.y, widget.cols, widget.rows);
|
|
963
982
|
}
|
|
@@ -978,6 +997,15 @@ class DashboardComponent {
|
|
|
978
997
|
this.stateService.popOutPage(pageId);
|
|
979
998
|
}
|
|
980
999
|
serializeLayout() { return this.stateService.serializeLayout(); }
|
|
1000
|
+
checkOverflow() {
|
|
1001
|
+
var _a;
|
|
1002
|
+
const el = (_a = this.tabsContainerRef) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
1003
|
+
if (!el)
|
|
1004
|
+
return;
|
|
1005
|
+
const atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 4;
|
|
1006
|
+
this.tabsOverflow = !atEnd && el.scrollWidth > el.clientWidth;
|
|
1007
|
+
this.cdr.markForCheck();
|
|
1008
|
+
}
|
|
981
1009
|
applyTheme() {
|
|
982
1010
|
var _a;
|
|
983
1011
|
this.resolvedTheme = Object.assign(Object.assign({}, DEFAULT_THEME), ((_a = this.theme) !== null && _a !== void 0 ? _a : {}));
|
|
@@ -1007,86 +1035,85 @@ class DashboardComponent {
|
|
|
1007
1035
|
}
|
|
1008
1036
|
updateActivePage() {
|
|
1009
1037
|
this.activePage = this.pages.find(p => p.id === this.activePageId);
|
|
1038
|
+
// scroll active tab into view
|
|
1039
|
+
setTimeout(() => {
|
|
1040
|
+
if (!this.tabsContainerRef)
|
|
1041
|
+
return;
|
|
1042
|
+
const active = this.tabsContainerRef.nativeElement.querySelector('.tab.active');
|
|
1043
|
+
active === null || active === void 0 ? void 0 : active.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });
|
|
1044
|
+
this.checkOverflow();
|
|
1045
|
+
});
|
|
1010
1046
|
}
|
|
1011
1047
|
}
|
|
1012
|
-
DashboardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DashboardComponent, deps: [{ token: DashboardStateService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1013
|
-
DashboardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DashboardComponent, selector: "app-dashboard", inputs: { initialLayout: "initialLayout", theme: "theme" }, outputs: { addWidgetRequested: "addWidgetRequested", editWidgetRequested: "editWidgetRequested" }, queries: [{ propertyName: "cellTemplate", first: true, predicate: GridCellDirective, descendants: true, read: TemplateRef }], usesOnChanges: true, ngImport: i0, template: `
|
|
1014
|
-
<!--
|
|
1015
|
-
POPPED-OUT MODE
|
|
1016
|
-
══════════════════════════════════════════════════════════ -->
|
|
1048
|
+
DashboardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DashboardComponent, deps: [{ token: DashboardStateService }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
|
|
1049
|
+
DashboardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DashboardComponent, selector: "app-dashboard", inputs: { initialLayout: "initialLayout", theme: "theme" }, outputs: { addWidgetRequested: "addWidgetRequested", editWidgetRequested: "editWidgetRequested" }, queries: [{ propertyName: "cellTemplate", first: true, predicate: GridCellDirective, descendants: true, read: TemplateRef }], viewQueries: [{ propertyName: "tabsContainerRef", first: true, predicate: ["tabsContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
1050
|
+
<!-- POPPED-OUT MODE -->
|
|
1017
1051
|
<ng-container *ngIf="isPoppedOut; else normalMode">
|
|
1018
1052
|
<div class="popout-wrapper" [ngStyle]="wrapperStyles">
|
|
1019
1053
|
<header class="popout-header">
|
|
1020
1054
|
<span class="popout-title">{{ activePage?.name }}</span>
|
|
1021
1055
|
</header>
|
|
1022
|
-
<
|
|
1023
|
-
<
|
|
1024
|
-
<
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
>
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
[ngTemplateOutletContext]="{ widget: widget }">
|
|
1035
|
-
</ng-container>
|
|
1036
|
-
</app-widget-renderer>
|
|
1037
|
-
</ng-template>
|
|
1038
|
-
</app-grid>
|
|
1039
|
-
</div>
|
|
1056
|
+
<app-grid [widgets]="activePage?.widgets || []" (itemChanged)="onItemChanged($event)">
|
|
1057
|
+
<ng-template gridCell let-widget="widget">
|
|
1058
|
+
<app-widget-renderer [widget]="widget" [theme]="resolvedTheme"
|
|
1059
|
+
(editRequested)="editWidgetRequested.emit($event)"
|
|
1060
|
+
(removeRequested)="onRemoveWidget($event)">
|
|
1061
|
+
<ng-container *ngIf="cellTemplate"
|
|
1062
|
+
[ngTemplateOutlet]="cellTemplate"
|
|
1063
|
+
[ngTemplateOutletContext]="{ widget: widget }">
|
|
1064
|
+
</ng-container>
|
|
1065
|
+
</app-widget-renderer>
|
|
1066
|
+
</ng-template>
|
|
1067
|
+
</app-grid>
|
|
1040
1068
|
</div>
|
|
1041
1069
|
</ng-container>
|
|
1042
1070
|
|
|
1043
|
-
<!--
|
|
1044
|
-
NORMAL MODE
|
|
1045
|
-
══════════════════════════════════════════════════════════ -->
|
|
1071
|
+
<!-- NORMAL MODE -->
|
|
1046
1072
|
<ng-template #normalMode>
|
|
1047
1073
|
<div class="dashboard-wrapper" [ngStyle]="wrapperStyles">
|
|
1048
1074
|
<main class="main-content">
|
|
1049
1075
|
|
|
1050
1076
|
<header class="dashboard-header">
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1077
|
+
|
|
1078
|
+
<!-- Tabs pill — scrollable, fades when overflowing -->
|
|
1079
|
+
<div class="tabs-scroll-track">
|
|
1080
|
+
<div class="tabs-container" #tabsContainer>
|
|
1081
|
+
<div
|
|
1082
|
+
*ngFor="let page of pages"
|
|
1083
|
+
class="tab"
|
|
1084
|
+
[class.active]="page.id === activePageId"
|
|
1085
|
+
(click)="onSelectPage(page.id)"
|
|
1086
|
+
>
|
|
1087
|
+
<span class="tab-name">{{ page.name }}</span>
|
|
1088
|
+
<button class="tab-action tab-popout" (click)="onPopOut($event, page.id)" title="Open in new window">
|
|
1089
|
+
<i class="la la-external-link-alt"></i>
|
|
1090
|
+
</button>
|
|
1091
|
+
<button class="tab-action tab-close" *ngIf="pages.length > 1" (click)="onRemovePage($event, page.id)" title="Close">
|
|
1092
|
+
<i class="la la-times"></i>
|
|
1093
|
+
</button>
|
|
1094
|
+
</div>
|
|
1095
|
+
<button class="btn-add-page" (click)="onAddPage()" title="New workspace">
|
|
1096
|
+
<i class="la la-plus"></i>
|
|
1064
1097
|
</button>
|
|
1065
1098
|
</div>
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
</button>
|
|
1099
|
+
<!-- fade hint shown when scrollable -->
|
|
1100
|
+
<div class="tabs-fade-right" *ngIf="tabsOverflow"></div>
|
|
1069
1101
|
</div>
|
|
1070
1102
|
|
|
1071
|
-
<!-- Add Widget button — consumer decides what happens -->
|
|
1072
1103
|
<button class="btn-add-widget" (click)="addWidgetRequested.emit()" title="Add widget">
|
|
1073
1104
|
<i class="la la-plus"></i>
|
|
1074
1105
|
<span>Add Widget</span>
|
|
1075
1106
|
</button>
|
|
1107
|
+
|
|
1076
1108
|
</header>
|
|
1077
1109
|
|
|
1078
1110
|
<div class="grid-container">
|
|
1079
1111
|
<app-grid [widgets]="activePage?.widgets || []" (itemChanged)="onItemChanged($event)">
|
|
1080
1112
|
<ng-template gridCell let-widget="widget">
|
|
1081
|
-
<app-widget-renderer
|
|
1082
|
-
[widget]="widget"
|
|
1083
|
-
[theme]="resolvedTheme"
|
|
1113
|
+
<app-widget-renderer [widget]="widget" [theme]="resolvedTheme"
|
|
1084
1114
|
(editRequested)="editWidgetRequested.emit($event)"
|
|
1085
|
-
(removeRequested)="onRemoveWidget($event)"
|
|
1086
|
-
|
|
1087
|
-
<!-- Stamp consumer's cell template (if provided) inside the card body -->
|
|
1088
|
-
<ng-container
|
|
1089
|
-
*ngIf="cellTemplate"
|
|
1115
|
+
(removeRequested)="onRemoveWidget($event)">
|
|
1116
|
+
<ng-container *ngIf="cellTemplate"
|
|
1090
1117
|
[ngTemplateOutlet]="cellTemplate"
|
|
1091
1118
|
[ngTemplateOutletContext]="{ widget: widget }">
|
|
1092
1119
|
</ng-container>
|
|
@@ -1098,86 +1125,77 @@ DashboardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", ver
|
|
|
1098
1125
|
</main>
|
|
1099
1126
|
</div>
|
|
1100
1127
|
</ng-template>
|
|
1101
|
-
`, isInline: true, styles: [":host{display:
|
|
1128
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;width:100%;height:100%;min-height:0;--dash-bg: #000000;--dash-panel-bg: #1c1c1e;--dash-card-bg: #2c2c2e;--dash-fore-color: #8e8e93;--dash-accent-color: #0a84ff;--dash-danger-color: #ff453a;--dash-font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;--dash-tabs-container-color: rgba(44,44,46,.6);--dash-tab-active-color: #3a3a3c;--dash-tab-active-text: #ffffff;--dash-tab-hover-text: #e5e5ea;--dash-add-widget-text: #ffffff;--dash-popout-title-color: #ffffff;--dash-widget-title-color: #ffffff;--dash-drag-handle-color: rgba(255,255,255,.2);--dash-widget-border-color: rgba(255,255,255,.07);--dash-widget-btn-bg: rgba(255,255,255,.07);--dash-widget-btn-color: rgba(255,255,255,.5);--dash-placeholder-color: #0a84ff;--dash-resize-handle-color: rgba(255,255,255,.25)}.dashboard-wrapper{display:flex;flex:1;min-height:0;overflow:hidden;padding:16px;box-sizing:border-box;background:var(--dash-bg);color:var(--dash-fore-color);font-family:var(--dash-font-family)}.main-content{flex:1;display:flex;flex-direction:column;overflow:hidden;border-radius:40px;padding:20px;background:var(--dash-panel-bg);border:1px solid rgba(255,255,255,.05)}.popout-wrapper{display:flex;flex:1;flex-direction:column;min-height:0;overflow:hidden;padding:16px;box-sizing:border-box;background:var(--dash-bg);color:var(--dash-fore-color);font-family:var(--dash-font-family)}.popout-header{display:flex;align-items:center;margin-bottom:16px;padding:10px 18px;background:var(--dash-panel-bg);border-radius:20px;border:1px solid rgba(255,255,255,.06);flex-shrink:0}.popout-title{font-size:16px;font-weight:700;color:var(--dash-popout-title-color)}.popout-wrapper app-grid{flex:1;min-height:0;overflow:auto}.dashboard-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:20px;gap:12px;flex-shrink:0}.tabs-scroll-track{position:relative;flex:1;min-width:0}.tabs-container{display:flex;align-items:center;gap:8px;background:var(--dash-tabs-container-color);backdrop-filter:blur(10px);border-radius:25px;padding:6px;overflow-x:auto;overflow-y:hidden;scrollbar-width:none}.tabs-container::-webkit-scrollbar{display:none}.tabs-fade-right{position:absolute;top:0;right:0;width:60px;height:100%;border-radius:0 25px 25px 0;pointer-events:none;background:linear-gradient(to right,transparent,var(--dash-panel-bg))}.tab{display:flex;align-items:center;gap:4px;padding:8px 14px 8px 18px;border-radius:20px;cursor:pointer;font-size:14px;font-weight:500;color:var(--dash-fore-color);white-space:nowrap;flex-shrink:0;transition:all .2s}.tab.active{background:var(--dash-tab-active-color);color:var(--dash-tab-active-text)}.tab:hover:not(.active){color:var(--dash-tab-hover-text);background:rgba(255,255,255,.05)}.tab-name{flex:1;white-space:nowrap}.tab-action{background:transparent;border:none;color:var(--dash-fore-color);padding:2px;font-size:11px;cursor:pointer;opacity:0;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;transition:all .2s;flex-shrink:0}.tab:hover .tab-action{opacity:1}.tab-popout:hover{color:var(--dash-accent-color);background:rgba(10,132,255,.18)}.tab-close:hover{color:var(--dash-danger-color);background:rgba(255,69,58,.2)}.btn-add-page{background:transparent;border:none;color:var(--dash-fore-color);padding:8px 16px;cursor:pointer;border-radius:20px;flex-shrink:0;transition:all .2s}.btn-add-page:hover{color:var(--dash-accent-color);background:rgba(10,132,255,.1)}.btn-add-widget{display:flex;align-items:center;gap:6px;background:var(--dash-accent-color);border:none;color:var(--dash-add-widget-text);font-size:14px;font-weight:600;padding:10px 20px;border-radius:22px;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:opacity .2s,transform .15s}.btn-add-widget:hover{opacity:.9;transform:translateY(-1px)}.btn-add-widget:active{transform:translateY(0)}.main-content .grid-container{flex:1;overflow:auto;border-radius:24px;min-height:0}app-grid{background:transparent;display:block;height:100%;width:100%}\n"], dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: WidgetRendererComponent, selector: "app-widget-renderer", inputs: ["widget", "theme"], outputs: ["editRequested", "removeRequested"] }, { kind: "component", type: CustomGridComponent, selector: "app-grid", inputs: ["widgets", "columns", "gap", "rowHeight", "minItemCols", "minItemRows"], outputs: ["itemChanged", "layoutChanged"] }, { kind: "directive", type: GridCellDirective, selector: "[gridCell]" }] });
|
|
1102
1129
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DashboardComponent, decorators: [{
|
|
1103
1130
|
type: Component,
|
|
1104
1131
|
args: [{ selector: 'app-dashboard', template: `
|
|
1105
|
-
<!--
|
|
1106
|
-
POPPED-OUT MODE
|
|
1107
|
-
══════════════════════════════════════════════════════════ -->
|
|
1132
|
+
<!-- POPPED-OUT MODE -->
|
|
1108
1133
|
<ng-container *ngIf="isPoppedOut; else normalMode">
|
|
1109
1134
|
<div class="popout-wrapper" [ngStyle]="wrapperStyles">
|
|
1110
1135
|
<header class="popout-header">
|
|
1111
1136
|
<span class="popout-title">{{ activePage?.name }}</span>
|
|
1112
1137
|
</header>
|
|
1113
|
-
<
|
|
1114
|
-
<
|
|
1115
|
-
<
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
>
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
[ngTemplateOutletContext]="{ widget: widget }">
|
|
1126
|
-
</ng-container>
|
|
1127
|
-
</app-widget-renderer>
|
|
1128
|
-
</ng-template>
|
|
1129
|
-
</app-grid>
|
|
1130
|
-
</div>
|
|
1138
|
+
<app-grid [widgets]="activePage?.widgets || []" (itemChanged)="onItemChanged($event)">
|
|
1139
|
+
<ng-template gridCell let-widget="widget">
|
|
1140
|
+
<app-widget-renderer [widget]="widget" [theme]="resolvedTheme"
|
|
1141
|
+
(editRequested)="editWidgetRequested.emit($event)"
|
|
1142
|
+
(removeRequested)="onRemoveWidget($event)">
|
|
1143
|
+
<ng-container *ngIf="cellTemplate"
|
|
1144
|
+
[ngTemplateOutlet]="cellTemplate"
|
|
1145
|
+
[ngTemplateOutletContext]="{ widget: widget }">
|
|
1146
|
+
</ng-container>
|
|
1147
|
+
</app-widget-renderer>
|
|
1148
|
+
</ng-template>
|
|
1149
|
+
</app-grid>
|
|
1131
1150
|
</div>
|
|
1132
1151
|
</ng-container>
|
|
1133
1152
|
|
|
1134
|
-
<!--
|
|
1135
|
-
NORMAL MODE
|
|
1136
|
-
══════════════════════════════════════════════════════════ -->
|
|
1153
|
+
<!-- NORMAL MODE -->
|
|
1137
1154
|
<ng-template #normalMode>
|
|
1138
1155
|
<div class="dashboard-wrapper" [ngStyle]="wrapperStyles">
|
|
1139
1156
|
<main class="main-content">
|
|
1140
1157
|
|
|
1141
1158
|
<header class="dashboard-header">
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1159
|
+
|
|
1160
|
+
<!-- Tabs pill — scrollable, fades when overflowing -->
|
|
1161
|
+
<div class="tabs-scroll-track">
|
|
1162
|
+
<div class="tabs-container" #tabsContainer>
|
|
1163
|
+
<div
|
|
1164
|
+
*ngFor="let page of pages"
|
|
1165
|
+
class="tab"
|
|
1166
|
+
[class.active]="page.id === activePageId"
|
|
1167
|
+
(click)="onSelectPage(page.id)"
|
|
1168
|
+
>
|
|
1169
|
+
<span class="tab-name">{{ page.name }}</span>
|
|
1170
|
+
<button class="tab-action tab-popout" (click)="onPopOut($event, page.id)" title="Open in new window">
|
|
1171
|
+
<i class="la la-external-link-alt"></i>
|
|
1172
|
+
</button>
|
|
1173
|
+
<button class="tab-action tab-close" *ngIf="pages.length > 1" (click)="onRemovePage($event, page.id)" title="Close">
|
|
1174
|
+
<i class="la la-times"></i>
|
|
1175
|
+
</button>
|
|
1176
|
+
</div>
|
|
1177
|
+
<button class="btn-add-page" (click)="onAddPage()" title="New workspace">
|
|
1178
|
+
<i class="la la-plus"></i>
|
|
1155
1179
|
</button>
|
|
1156
1180
|
</div>
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
</button>
|
|
1181
|
+
<!-- fade hint shown when scrollable -->
|
|
1182
|
+
<div class="tabs-fade-right" *ngIf="tabsOverflow"></div>
|
|
1160
1183
|
</div>
|
|
1161
1184
|
|
|
1162
|
-
<!-- Add Widget button — consumer decides what happens -->
|
|
1163
1185
|
<button class="btn-add-widget" (click)="addWidgetRequested.emit()" title="Add widget">
|
|
1164
1186
|
<i class="la la-plus"></i>
|
|
1165
1187
|
<span>Add Widget</span>
|
|
1166
1188
|
</button>
|
|
1189
|
+
|
|
1167
1190
|
</header>
|
|
1168
1191
|
|
|
1169
1192
|
<div class="grid-container">
|
|
1170
1193
|
<app-grid [widgets]="activePage?.widgets || []" (itemChanged)="onItemChanged($event)">
|
|
1171
1194
|
<ng-template gridCell let-widget="widget">
|
|
1172
|
-
<app-widget-renderer
|
|
1173
|
-
[widget]="widget"
|
|
1174
|
-
[theme]="resolvedTheme"
|
|
1195
|
+
<app-widget-renderer [widget]="widget" [theme]="resolvedTheme"
|
|
1175
1196
|
(editRequested)="editWidgetRequested.emit($event)"
|
|
1176
|
-
(removeRequested)="onRemoveWidget($event)"
|
|
1177
|
-
|
|
1178
|
-
<!-- Stamp consumer's cell template (if provided) inside the card body -->
|
|
1179
|
-
<ng-container
|
|
1180
|
-
*ngIf="cellTemplate"
|
|
1197
|
+
(removeRequested)="onRemoveWidget($event)">
|
|
1198
|
+
<ng-container *ngIf="cellTemplate"
|
|
1181
1199
|
[ngTemplateOutlet]="cellTemplate"
|
|
1182
1200
|
[ngTemplateOutletContext]="{ widget: widget }">
|
|
1183
1201
|
</ng-container>
|
|
@@ -1189,8 +1207,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1189
1207
|
</main>
|
|
1190
1208
|
</div>
|
|
1191
1209
|
</ng-template>
|
|
1192
|
-
`, styles: [":host{display:
|
|
1193
|
-
}], ctorParameters: function () { return [{ type: DashboardStateService }]; }, propDecorators: { initialLayout: [{
|
|
1210
|
+
`, styles: [":host{display:flex;flex-direction:column;width:100%;height:100%;min-height:0;--dash-bg: #000000;--dash-panel-bg: #1c1c1e;--dash-card-bg: #2c2c2e;--dash-fore-color: #8e8e93;--dash-accent-color: #0a84ff;--dash-danger-color: #ff453a;--dash-font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;--dash-tabs-container-color: rgba(44,44,46,.6);--dash-tab-active-color: #3a3a3c;--dash-tab-active-text: #ffffff;--dash-tab-hover-text: #e5e5ea;--dash-add-widget-text: #ffffff;--dash-popout-title-color: #ffffff;--dash-widget-title-color: #ffffff;--dash-drag-handle-color: rgba(255,255,255,.2);--dash-widget-border-color: rgba(255,255,255,.07);--dash-widget-btn-bg: rgba(255,255,255,.07);--dash-widget-btn-color: rgba(255,255,255,.5);--dash-placeholder-color: #0a84ff;--dash-resize-handle-color: rgba(255,255,255,.25)}.dashboard-wrapper{display:flex;flex:1;min-height:0;overflow:hidden;padding:16px;box-sizing:border-box;background:var(--dash-bg);color:var(--dash-fore-color);font-family:var(--dash-font-family)}.main-content{flex:1;display:flex;flex-direction:column;overflow:hidden;border-radius:40px;padding:20px;background:var(--dash-panel-bg);border:1px solid rgba(255,255,255,.05)}.popout-wrapper{display:flex;flex:1;flex-direction:column;min-height:0;overflow:hidden;padding:16px;box-sizing:border-box;background:var(--dash-bg);color:var(--dash-fore-color);font-family:var(--dash-font-family)}.popout-header{display:flex;align-items:center;margin-bottom:16px;padding:10px 18px;background:var(--dash-panel-bg);border-radius:20px;border:1px solid rgba(255,255,255,.06);flex-shrink:0}.popout-title{font-size:16px;font-weight:700;color:var(--dash-popout-title-color)}.popout-wrapper app-grid{flex:1;min-height:0;overflow:auto}.dashboard-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:20px;gap:12px;flex-shrink:0}.tabs-scroll-track{position:relative;flex:1;min-width:0}.tabs-container{display:flex;align-items:center;gap:8px;background:var(--dash-tabs-container-color);backdrop-filter:blur(10px);border-radius:25px;padding:6px;overflow-x:auto;overflow-y:hidden;scrollbar-width:none}.tabs-container::-webkit-scrollbar{display:none}.tabs-fade-right{position:absolute;top:0;right:0;width:60px;height:100%;border-radius:0 25px 25px 0;pointer-events:none;background:linear-gradient(to right,transparent,var(--dash-panel-bg))}.tab{display:flex;align-items:center;gap:4px;padding:8px 14px 8px 18px;border-radius:20px;cursor:pointer;font-size:14px;font-weight:500;color:var(--dash-fore-color);white-space:nowrap;flex-shrink:0;transition:all .2s}.tab.active{background:var(--dash-tab-active-color);color:var(--dash-tab-active-text)}.tab:hover:not(.active){color:var(--dash-tab-hover-text);background:rgba(255,255,255,.05)}.tab-name{flex:1;white-space:nowrap}.tab-action{background:transparent;border:none;color:var(--dash-fore-color);padding:2px;font-size:11px;cursor:pointer;opacity:0;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;transition:all .2s;flex-shrink:0}.tab:hover .tab-action{opacity:1}.tab-popout:hover{color:var(--dash-accent-color);background:rgba(10,132,255,.18)}.tab-close:hover{color:var(--dash-danger-color);background:rgba(255,69,58,.2)}.btn-add-page{background:transparent;border:none;color:var(--dash-fore-color);padding:8px 16px;cursor:pointer;border-radius:20px;flex-shrink:0;transition:all .2s}.btn-add-page:hover{color:var(--dash-accent-color);background:rgba(10,132,255,.1)}.btn-add-widget{display:flex;align-items:center;gap:6px;background:var(--dash-accent-color);border:none;color:var(--dash-add-widget-text);font-size:14px;font-weight:600;padding:10px 20px;border-radius:22px;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:opacity .2s,transform .15s}.btn-add-widget:hover{opacity:.9;transform:translateY(-1px)}.btn-add-widget:active{transform:translateY(0)}.main-content .grid-container{flex:1;overflow:auto;border-radius:24px;min-height:0}app-grid{background:transparent;display:block;height:100%;width:100%}\n"] }]
|
|
1211
|
+
}], ctorParameters: function () { return [{ type: DashboardStateService }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }]; }, propDecorators: { initialLayout: [{
|
|
1194
1212
|
type: Input
|
|
1195
1213
|
}], theme: [{
|
|
1196
1214
|
type: Input
|
|
@@ -1201,15 +1219,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1201
1219
|
}], cellTemplate: [{
|
|
1202
1220
|
type: ContentChild,
|
|
1203
1221
|
args: [GridCellDirective, { read: TemplateRef }]
|
|
1222
|
+
}], tabsContainerRef: [{
|
|
1223
|
+
type: ViewChild,
|
|
1224
|
+
args: ['tabsContainer']
|
|
1204
1225
|
}] } });
|
|
1205
1226
|
|
|
1206
1227
|
class DashboardModule {
|
|
1207
1228
|
}
|
|
1208
1229
|
DashboardModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DashboardModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1209
1230
|
DashboardModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: DashboardModule, declarations: [DashboardComponent,
|
|
1231
|
+
OverflowActivePipe,
|
|
1210
1232
|
WidgetRendererComponent,
|
|
1211
1233
|
CustomGridComponent,
|
|
1212
1234
|
GridCellDirective], imports: [CommonModule], exports: [DashboardComponent,
|
|
1235
|
+
OverflowActivePipe,
|
|
1213
1236
|
WidgetRendererComponent,
|
|
1214
1237
|
CustomGridComponent,
|
|
1215
1238
|
GridCellDirective] });
|
|
@@ -1219,6 +1242,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1219
1242
|
args: [{
|
|
1220
1243
|
declarations: [
|
|
1221
1244
|
DashboardComponent,
|
|
1245
|
+
OverflowActivePipe,
|
|
1222
1246
|
WidgetRendererComponent,
|
|
1223
1247
|
CustomGridComponent,
|
|
1224
1248
|
GridCellDirective,
|
|
@@ -1229,6 +1253,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1229
1253
|
providers: [DashboardStateService],
|
|
1230
1254
|
exports: [
|
|
1231
1255
|
DashboardComponent,
|
|
1256
|
+
OverflowActivePipe,
|
|
1232
1257
|
WidgetRendererComponent,
|
|
1233
1258
|
CustomGridComponent,
|
|
1234
1259
|
GridCellDirective,
|
|
@@ -1260,5 +1285,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1260
1285
|
* Generated bundle index. Do not edit.
|
|
1261
1286
|
*/
|
|
1262
1287
|
|
|
1263
|
-
export { AppModule, CustomGridComponent, DashboardComponent, DashboardModule, DashboardStateService, GridCellDirective, WidgetRendererComponent };
|
|
1288
|
+
export { AppModule, CustomGridComponent, DashboardComponent, DashboardModule, DashboardStateService, GridCellDirective, OverflowActivePipe, WidgetRendererComponent };
|
|
1264
1289
|
//# sourceMappingURL=ogidor-dashboard.mjs.map
|