@ogidor/dashboard 1.0.10 → 1.0.12
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/app/app.module.d.ts +1 -1
- package/app/dashboard.component.d.ts +29 -15
- package/esm2020/app/app.module.mjs +6 -2
- package/esm2020/app/dashboard.component.mjs +294 -93
- package/fesm2015/ogidor-dashboard.mjs +300 -93
- package/fesm2015/ogidor-dashboard.mjs.map +1 -1
- package/fesm2020/ogidor-dashboard.mjs +298 -93
- 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, HostListener, 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';
|
|
@@ -885,43 +885,54 @@ const DEFAULT_THEME = {
|
|
|
885
885
|
accentColor: '#0a84ff',
|
|
886
886
|
dangerColor: '#ff453a',
|
|
887
887
|
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
|
|
888
|
-
// Header / Tabs
|
|
889
888
|
tabsContainerColor: 'rgba(44,44,46,0.6)',
|
|
890
889
|
tabActiveColor: '#3a3a3c',
|
|
891
890
|
tabActiveTextColor: '#ffffff',
|
|
892
891
|
tabHoverTextColor: '#e5e5ea',
|
|
893
892
|
addWidgetButtonTextColor: '#ffffff',
|
|
894
|
-
// Pop-out
|
|
895
893
|
popoutTitleColor: '#ffffff',
|
|
896
|
-
// Widget card
|
|
897
894
|
widgetTitleColor: '#ffffff',
|
|
898
895
|
dragHandleColor: 'rgba(255,255,255,0.2)',
|
|
899
896
|
widgetBorderColor: 'rgba(255,255,255,0.07)',
|
|
900
897
|
widgetButtonBgColor: 'rgba(255,255,255,0.07)',
|
|
901
898
|
widgetButtonColor: 'rgba(255,255,255,0.5)',
|
|
902
|
-
// Grid
|
|
903
899
|
placeholderColor: '#0a84ff',
|
|
904
900
|
resizeHandleColor: 'rgba(255,255,255,0.25)',
|
|
905
901
|
};
|
|
902
|
+
class OverflowActivePipe {
|
|
903
|
+
transform(pages, activePageId) {
|
|
904
|
+
return pages.some(p => p.id === activePageId);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
OverflowActivePipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: OverflowActivePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
908
|
+
OverflowActivePipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: OverflowActivePipe, name: "overflowActive" });
|
|
909
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: OverflowActivePipe, decorators: [{
|
|
910
|
+
type: Pipe,
|
|
911
|
+
args: [{ name: 'overflowActive' }]
|
|
912
|
+
}] });
|
|
906
913
|
class DashboardComponent {
|
|
907
|
-
constructor(stateService) {
|
|
914
|
+
constructor(stateService, cdr, zone) {
|
|
908
915
|
this.stateService = stateService;
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
* The consumer should open their own dialog and call `stateService.addWidget(...)`.
|
|
912
|
-
*/
|
|
916
|
+
this.cdr = cdr;
|
|
917
|
+
this.zone = zone;
|
|
913
918
|
this.addWidgetRequested = new EventEmitter();
|
|
914
|
-
/**
|
|
915
|
-
* Emits the Widget when the user clicks the edit (pen) icon on a card.
|
|
916
|
-
* The consumer should open their own edit UI and call `stateService.updateWidget(...)`.
|
|
917
|
-
*/
|
|
918
919
|
this.editWidgetRequested = new EventEmitter();
|
|
919
920
|
this.resolvedTheme = { ...DEFAULT_THEME };
|
|
920
921
|
this.wrapperStyles = {};
|
|
921
922
|
this.pages = [];
|
|
923
|
+
this.visiblePages = [];
|
|
924
|
+
this.hiddenCount = 0;
|
|
922
925
|
this.activePageId = '';
|
|
923
926
|
this.isPoppedOut = false;
|
|
927
|
+
this.tabSwitcherOpen = false;
|
|
924
928
|
this.subs = new Subscription();
|
|
929
|
+
// Reserved space for the overflow "+N" button and the add "+" button (px)
|
|
930
|
+
this.OVERFLOW_BTN_W = 80;
|
|
931
|
+
this.ADD_BTN_W = 52;
|
|
932
|
+
this.GAP = 6;
|
|
933
|
+
this.PADDING = 12; // 6px each side
|
|
934
|
+
// Cache of measured tab widths (including gap) indexed by page position
|
|
935
|
+
this._tabWidthCache = [];
|
|
925
936
|
}
|
|
926
937
|
ngOnChanges(changes) {
|
|
927
938
|
if (changes['theme'] || changes['initialLayout'])
|
|
@@ -942,19 +953,37 @@ class DashboardComponent {
|
|
|
942
953
|
this.isPoppedOut = true;
|
|
943
954
|
this.subs.add(this.stateService.pages$.subscribe(pages => {
|
|
944
955
|
this.pages = pages;
|
|
956
|
+
this._tabWidthCache = []; // invalidate cache — page list changed
|
|
945
957
|
if (this.isPoppedOut && hash) {
|
|
946
|
-
|
|
947
|
-
if (target)
|
|
958
|
+
if (pages.find(p => p.id === hash))
|
|
948
959
|
this.stateService.setActivePage(hash);
|
|
949
960
|
}
|
|
950
961
|
this.updateActivePage();
|
|
962
|
+
this.recalcVisibleTabs();
|
|
963
|
+
// Second pass after Angular has rendered the updated tab elements
|
|
964
|
+
setTimeout(() => this.recalcVisibleTabs());
|
|
951
965
|
}));
|
|
952
966
|
this.subs.add(this.stateService.activePageId$.subscribe(id => {
|
|
953
967
|
this.activePageId = id;
|
|
954
968
|
this.updateActivePage();
|
|
955
969
|
}));
|
|
956
970
|
}
|
|
957
|
-
|
|
971
|
+
ngAfterViewInit() {
|
|
972
|
+
if (!this.tabsTrackRef)
|
|
973
|
+
return;
|
|
974
|
+
this.zone.runOutsideAngular(() => {
|
|
975
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
976
|
+
this.zone.run(() => this.recalcVisibleTabs());
|
|
977
|
+
});
|
|
978
|
+
this.resizeObserver.observe(this.tabsTrackRef.nativeElement);
|
|
979
|
+
});
|
|
980
|
+
// Initial measurement pass now that the DOM is ready
|
|
981
|
+
setTimeout(() => this.recalcVisibleTabs());
|
|
982
|
+
}
|
|
983
|
+
ngOnDestroy() {
|
|
984
|
+
this.subs.unsubscribe();
|
|
985
|
+
this.resizeObserver?.disconnect();
|
|
986
|
+
}
|
|
958
987
|
onItemChanged(widget) {
|
|
959
988
|
this.stateService.updateWidgetPosition(this.activePageId, widget.id, widget.x, widget.y, widget.cols, widget.rows);
|
|
960
989
|
}
|
|
@@ -975,6 +1004,84 @@ class DashboardComponent {
|
|
|
975
1004
|
this.stateService.popOutPage(pageId);
|
|
976
1005
|
}
|
|
977
1006
|
serializeLayout() { return this.stateService.serializeLayout(); }
|
|
1007
|
+
openTabSwitcher() { this.tabSwitcherOpen = true; }
|
|
1008
|
+
closeTabSwitcher() { this.tabSwitcherOpen = false; }
|
|
1009
|
+
onEscapeKey() { this.closeTabSwitcher(); }
|
|
1010
|
+
onSwitcherSelect(pageId) {
|
|
1011
|
+
this.stateService.setActivePage(pageId);
|
|
1012
|
+
this.closeTabSwitcher();
|
|
1013
|
+
}
|
|
1014
|
+
onSwitcherPopOut(event, pageId) {
|
|
1015
|
+
event.stopPropagation();
|
|
1016
|
+
this.stateService.popOutPage(pageId);
|
|
1017
|
+
this.closeTabSwitcher();
|
|
1018
|
+
}
|
|
1019
|
+
onSwitcherRemove(event, pageId) {
|
|
1020
|
+
event.stopPropagation();
|
|
1021
|
+
if (confirm('Remove this workspace?')) {
|
|
1022
|
+
this.stateService.removePage(pageId);
|
|
1023
|
+
if (this.pages.length <= 1)
|
|
1024
|
+
this.closeTabSwitcher();
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
onSwitcherAdd() {
|
|
1028
|
+
const name = prompt('Workspace name:', `Workspace ${this.pages.length + 1}`);
|
|
1029
|
+
if (name)
|
|
1030
|
+
this.stateService.addPage(name);
|
|
1031
|
+
}
|
|
1032
|
+
recalcVisibleTabs() {
|
|
1033
|
+
if (!this.tabsTrackRef || !this.pages.length) {
|
|
1034
|
+
this.visiblePages = this.pages;
|
|
1035
|
+
this.hiddenCount = 0;
|
|
1036
|
+
this.cdr.markForCheck();
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
1039
|
+
const track = this.tabsTrackRef.nativeElement;
|
|
1040
|
+
const trackW = track.clientWidth;
|
|
1041
|
+
// Space always consumed by the add "+" button + padding
|
|
1042
|
+
const baseReserved = this.ADD_BTN_W + this.GAP + this.PADDING;
|
|
1043
|
+
// Space needed for the overflow "+N" button when shown
|
|
1044
|
+
const overflowSlot = this.OVERFLOW_BTN_W + this.GAP;
|
|
1045
|
+
// Measure each real tab element currently in the DOM.
|
|
1046
|
+
// The DOM always renders all visiblePages tabs, so we may not have all tabs
|
|
1047
|
+
// measured yet — fall back to the previous measured cache or a generous estimate.
|
|
1048
|
+
const tabEls = Array.from(track.querySelectorAll('.tab'));
|
|
1049
|
+
// Build a width map by index (only covers currently visible tabs)
|
|
1050
|
+
const measuredWidths = this.pages.map((_, i) => {
|
|
1051
|
+
const el = tabEls[i];
|
|
1052
|
+
return el ? el.getBoundingClientRect().width + this.GAP : this._tabWidthCache[i] ?? 150 + this.GAP;
|
|
1053
|
+
});
|
|
1054
|
+
// Update cache for next call
|
|
1055
|
+
tabEls.forEach((el, i) => {
|
|
1056
|
+
this._tabWidthCache[i] = el.getBoundingClientRect().width + this.GAP;
|
|
1057
|
+
});
|
|
1058
|
+
// How much space the tabs need in total (no overflow button)
|
|
1059
|
+
const totalNeeded = measuredWidths.reduce((s, w) => s + w, 0) - this.GAP; // remove trailing gap
|
|
1060
|
+
if (totalNeeded <= trackW - baseReserved) {
|
|
1061
|
+
// Everything fits — show all
|
|
1062
|
+
this.visiblePages = this.pages;
|
|
1063
|
+
this.hiddenCount = 0;
|
|
1064
|
+
}
|
|
1065
|
+
else {
|
|
1066
|
+
// Not everything fits — fill as many as possible while always leaving room for overflow btn
|
|
1067
|
+
const budget = trackW - baseReserved - overflowSlot;
|
|
1068
|
+
let used = 0;
|
|
1069
|
+
let count = 0;
|
|
1070
|
+
for (let i = 0; i < this.pages.length; i++) {
|
|
1071
|
+
used += measuredWidths[i];
|
|
1072
|
+
if (used - this.GAP <= budget) { // -GAP: last item has no trailing gap
|
|
1073
|
+
count++;
|
|
1074
|
+
}
|
|
1075
|
+
else {
|
|
1076
|
+
break;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
count = Math.max(1, count);
|
|
1080
|
+
this.visiblePages = this.pages.slice(0, count);
|
|
1081
|
+
this.hiddenCount = this.pages.length - count;
|
|
1082
|
+
}
|
|
1083
|
+
this.cdr.markForCheck();
|
|
1084
|
+
}
|
|
978
1085
|
applyTheme() {
|
|
979
1086
|
this.resolvedTheme = { ...DEFAULT_THEME, ...(this.theme ?? {}) };
|
|
980
1087
|
const t = this.resolvedTheme;
|
|
@@ -1005,48 +1112,41 @@ class DashboardComponent {
|
|
|
1005
1112
|
this.activePage = this.pages.find(p => p.id === this.activePageId);
|
|
1006
1113
|
}
|
|
1007
1114
|
}
|
|
1008
|
-
DashboardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DashboardComponent, deps: [{ token: DashboardStateService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1009
|
-
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: `
|
|
1010
|
-
<!--
|
|
1011
|
-
POPPED-OUT MODE
|
|
1012
|
-
══════════════════════════════════════════════════════════ -->
|
|
1115
|
+
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 });
|
|
1116
|
+
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" }, host: { listeners: { "document:keydown.escape": "onEscapeKey()" } }, queries: [{ propertyName: "cellTemplate", first: true, predicate: GridCellDirective, descendants: true, read: TemplateRef }], viewQueries: [{ propertyName: "tabsTrackRef", first: true, predicate: ["tabsTrack"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
1117
|
+
<!-- POPPED-OUT MODE -->
|
|
1013
1118
|
<ng-container *ngIf="isPoppedOut; else normalMode">
|
|
1014
1119
|
<div class="popout-wrapper" [ngStyle]="wrapperStyles">
|
|
1015
1120
|
<header class="popout-header">
|
|
1016
1121
|
<span class="popout-title">{{ activePage?.name }}</span>
|
|
1017
1122
|
</header>
|
|
1018
|
-
<
|
|
1019
|
-
<
|
|
1020
|
-
<
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
>
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
[ngTemplateOutletContext]="{ widget: widget }">
|
|
1031
|
-
</ng-container>
|
|
1032
|
-
</app-widget-renderer>
|
|
1033
|
-
</ng-template>
|
|
1034
|
-
</app-grid>
|
|
1035
|
-
</div>
|
|
1123
|
+
<app-grid [widgets]="activePage?.widgets || []" (itemChanged)="onItemChanged($event)">
|
|
1124
|
+
<ng-template gridCell let-widget="widget">
|
|
1125
|
+
<app-widget-renderer [widget]="widget" [theme]="resolvedTheme"
|
|
1126
|
+
(editRequested)="editWidgetRequested.emit($event)"
|
|
1127
|
+
(removeRequested)="onRemoveWidget($event)">
|
|
1128
|
+
<ng-container *ngIf="cellTemplate"
|
|
1129
|
+
[ngTemplateOutlet]="cellTemplate"
|
|
1130
|
+
[ngTemplateOutletContext]="{ widget: widget }">
|
|
1131
|
+
</ng-container>
|
|
1132
|
+
</app-widget-renderer>
|
|
1133
|
+
</ng-template>
|
|
1134
|
+
</app-grid>
|
|
1036
1135
|
</div>
|
|
1037
1136
|
</ng-container>
|
|
1038
1137
|
|
|
1039
|
-
<!--
|
|
1040
|
-
NORMAL MODE
|
|
1041
|
-
══════════════════════════════════════════════════════════ -->
|
|
1138
|
+
<!-- NORMAL MODE -->
|
|
1042
1139
|
<ng-template #normalMode>
|
|
1043
1140
|
<div class="dashboard-wrapper" [ngStyle]="wrapperStyles">
|
|
1044
1141
|
<main class="main-content">
|
|
1045
1142
|
|
|
1046
1143
|
<header class="dashboard-header">
|
|
1047
|
-
|
|
1144
|
+
|
|
1145
|
+
<!-- Tab bar -->
|
|
1146
|
+
<div class="tabs-track" #tabsTrack>
|
|
1147
|
+
<!-- Visible tabs -->
|
|
1048
1148
|
<div
|
|
1049
|
-
*ngFor="let page of
|
|
1149
|
+
*ngFor="let page of visiblePages"
|
|
1050
1150
|
class="tab"
|
|
1051
1151
|
[class.active]="page.id === activePageId"
|
|
1052
1152
|
(click)="onSelectPage(page.id)"
|
|
@@ -1059,30 +1159,81 @@ DashboardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", ver
|
|
|
1059
1159
|
<i class="la la-times"></i>
|
|
1060
1160
|
</button>
|
|
1061
1161
|
</div>
|
|
1162
|
+
|
|
1163
|
+
<!-- Overflow button — shown only when there are hidden tabs -->
|
|
1164
|
+
<button
|
|
1165
|
+
*ngIf="hiddenCount > 0"
|
|
1166
|
+
class="btn-overflow"
|
|
1167
|
+
(click)="openTabSwitcher()"
|
|
1168
|
+
title="Show all workspaces"
|
|
1169
|
+
>
|
|
1170
|
+
<span>+{{ hiddenCount }}</span>
|
|
1171
|
+
<i class="la la-th-large"></i>
|
|
1172
|
+
</button>
|
|
1173
|
+
|
|
1174
|
+
<!-- Add page button -->
|
|
1062
1175
|
<button class="btn-add-page" (click)="onAddPage()" title="New workspace">
|
|
1063
1176
|
<i class="la la-plus"></i>
|
|
1064
1177
|
</button>
|
|
1065
1178
|
</div>
|
|
1066
1179
|
|
|
1067
|
-
<!-- Add Widget button — consumer decides what happens -->
|
|
1068
1180
|
<button class="btn-add-widget" (click)="addWidgetRequested.emit()" title="Add widget">
|
|
1069
1181
|
<i class="la la-plus"></i>
|
|
1070
1182
|
<span>Add Widget</span>
|
|
1071
1183
|
</button>
|
|
1184
|
+
|
|
1072
1185
|
</header>
|
|
1073
1186
|
|
|
1187
|
+
<!-- ── Tab-switcher overlay (Chrome mobile style) ── -->
|
|
1188
|
+
<div class="tab-switcher-overlay" *ngIf="tabSwitcherOpen" (click)="closeTabSwitcher()">
|
|
1189
|
+
<div class="tab-switcher-sheet" (click)="$event.stopPropagation()">
|
|
1190
|
+
|
|
1191
|
+
<div class="tab-switcher-header">
|
|
1192
|
+
<span class="tab-switcher-title">{{ pages.length }} Workspace{{ pages.length !== 1 ? 's' : '' }}</span>
|
|
1193
|
+
<button class="tab-switcher-close-btn" (click)="closeTabSwitcher()" title="Close">
|
|
1194
|
+
<i class="la la-times"></i>
|
|
1195
|
+
</button>
|
|
1196
|
+
</div>
|
|
1197
|
+
|
|
1198
|
+
<div class="tab-switcher-grid">
|
|
1199
|
+
<div
|
|
1200
|
+
*ngFor="let page of pages"
|
|
1201
|
+
class="tab-card"
|
|
1202
|
+
[class.active]="page.id === activePageId"
|
|
1203
|
+
(click)="onSwitcherSelect(page.id)"
|
|
1204
|
+
>
|
|
1205
|
+
<div class="tab-card-icon">
|
|
1206
|
+
<i class="la la-th-large"></i>
|
|
1207
|
+
</div>
|
|
1208
|
+
<span class="tab-card-name">{{ page.name }}</span>
|
|
1209
|
+
<div class="tab-card-actions">
|
|
1210
|
+
<button class="tab-card-btn tab-card-popout" (click)="onSwitcherPopOut($event, page.id)" title="Open in new window">
|
|
1211
|
+
<i class="la la-external-link-alt"></i>
|
|
1212
|
+
</button>
|
|
1213
|
+
<button class="tab-card-btn tab-card-remove" *ngIf="pages.length > 1" (click)="onSwitcherRemove($event, page.id)" title="Close">
|
|
1214
|
+
<i class="la la-times"></i>
|
|
1215
|
+
</button>
|
|
1216
|
+
</div>
|
|
1217
|
+
</div>
|
|
1218
|
+
</div>
|
|
1219
|
+
|
|
1220
|
+
<div class="tab-switcher-footer">
|
|
1221
|
+
<button class="tab-switcher-add-btn" (click)="onSwitcherAdd()">
|
|
1222
|
+
<i class="la la-plus"></i>
|
|
1223
|
+
<span>New Workspace</span>
|
|
1224
|
+
</button>
|
|
1225
|
+
</div>
|
|
1226
|
+
|
|
1227
|
+
</div>
|
|
1228
|
+
</div>
|
|
1229
|
+
|
|
1074
1230
|
<div class="grid-container">
|
|
1075
1231
|
<app-grid [widgets]="activePage?.widgets || []" (itemChanged)="onItemChanged($event)">
|
|
1076
1232
|
<ng-template gridCell let-widget="widget">
|
|
1077
|
-
<app-widget-renderer
|
|
1078
|
-
[widget]="widget"
|
|
1079
|
-
[theme]="resolvedTheme"
|
|
1233
|
+
<app-widget-renderer [widget]="widget" [theme]="resolvedTheme"
|
|
1080
1234
|
(editRequested)="editWidgetRequested.emit($event)"
|
|
1081
|
-
(removeRequested)="onRemoveWidget($event)"
|
|
1082
|
-
|
|
1083
|
-
<!-- Stamp consumer's cell template (if provided) inside the card body -->
|
|
1084
|
-
<ng-container
|
|
1085
|
-
*ngIf="cellTemplate"
|
|
1235
|
+
(removeRequested)="onRemoveWidget($event)">
|
|
1236
|
+
<ng-container *ngIf="cellTemplate"
|
|
1086
1237
|
[ngTemplateOutlet]="cellTemplate"
|
|
1087
1238
|
[ngTemplateOutletContext]="{ widget: widget }">
|
|
1088
1239
|
</ng-container>
|
|
@@ -1094,50 +1245,43 @@ DashboardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", ver
|
|
|
1094
1245
|
</main>
|
|
1095
1246
|
</div>
|
|
1096
1247
|
</ng-template>
|
|
1097
|
-
`, 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;
|
|
1248
|
+
`, 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);position:relative}.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-track{display:flex;align-items:center;gap:6px;flex:1;min-width:0;background:var(--dash-tabs-container-color);backdrop-filter:blur(10px);border-radius:25px;padding:6px;overflow:hidden}.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:background .2s,color .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{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-overflow{display:inline-flex;align-items:center;gap:5px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12);border-radius:20px;padding:7px 13px;cursor:pointer;font-size:13px;font-weight:600;color:var(--dash-tab-active-text);white-space:nowrap;flex-shrink:0;transition:background .2s,border-color .2s}.btn-overflow:hover{background:rgba(10,132,255,.18);border-color:var(--dash-accent-color);color:var(--dash-accent-color)}.btn-add-page{background:transparent;border:none;color:var(--dash-fore-color);padding:8px 14px;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)}.tab-switcher-overlay{position:absolute;inset:0;z-index:1000;background:rgba(0,0,0,.55);backdrop-filter:blur(4px);display:flex;align-items:flex-start;justify-content:center;padding-top:60px;animation:overlay-in .18s ease}@keyframes overlay-in{0%{opacity:0}to{opacity:1}}.tab-switcher-sheet{background:var(--dash-panel-bg);border:1px solid rgba(255,255,255,.08);border-radius:24px;width:min(520px,calc(100% - 32px));max-height:calc(100% - 80px);display:flex;flex-direction:column;overflow:hidden;animation:sheet-in .22s cubic-bezier(.32,1.2,.5,1)}@keyframes sheet-in{0%{transform:translateY(-16px) scale(.97);opacity:0}to{transform:translateY(0) scale(1);opacity:1}}.tab-switcher-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px 12px;border-bottom:1px solid rgba(255,255,255,.06);flex-shrink:0}.tab-switcher-title{font-size:15px;font-weight:700;color:var(--dash-tab-active-text)}.tab-switcher-close-btn{background:rgba(255,255,255,.07);border:none;color:var(--dash-fore-color);width:28px;height:28px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:14px;transition:background .15s,color .15s}.tab-switcher-close-btn:hover{background:rgba(255,69,58,.25);color:var(--dash-danger-color)}.tab-switcher-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:10px;padding:16px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}.tab-card{display:flex;flex-direction:column;align-items:center;gap:8px;padding:16px 12px 12px;border-radius:16px;background:var(--dash-card-bg);border:1.5px solid transparent;cursor:pointer;transition:border-color .15s,background .15s,transform .12s;position:relative}.tab-card:hover{background:rgba(255,255,255,.06);transform:translateY(-2px)}.tab-card.active{border-color:var(--dash-accent-color);background:rgba(10,132,255,.12)}.tab-card-icon{width:44px;height:44px;border-radius:12px;background:rgba(255,255,255,.07);display:flex;align-items:center;justify-content:center;font-size:20px;color:var(--dash-fore-color)}.tab-card.active .tab-card-icon{background:rgba(10,132,255,.25);color:var(--dash-accent-color)}.tab-card-name{font-size:13px;font-weight:500;color:var(--dash-tab-active-text);text-align:center;word-break:break-word;line-height:1.3}.tab-card-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}.tab-card:hover .tab-card-actions{opacity:1}.tab-card-btn{background:rgba(255,255,255,.07);border:none;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:12px;color:var(--dash-fore-color);transition:background .15s,color .15s}.tab-card-popout:hover{background:rgba(10,132,255,.25);color:var(--dash-accent-color)}.tab-card-remove:hover{background:rgba(255,69,58,.25);color:var(--dash-danger-color)}.tab-switcher-footer{padding:12px 16px 16px;border-top:1px solid rgba(255,255,255,.06);flex-shrink:0}.tab-switcher-add-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:11px 20px;border-radius:16px;background:rgba(10,132,255,.15);border:1.5px dashed rgba(10,132,255,.4);color:var(--dash-accent-color);font-size:14px;font-weight:600;cursor:pointer;transition:background .15s,border-color .15s}.tab-switcher-add-btn:hover{background:rgba(10,132,255,.25);border-color:var(--dash-accent-color)}.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]" }] });
|
|
1098
1249
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DashboardComponent, decorators: [{
|
|
1099
1250
|
type: Component,
|
|
1100
1251
|
args: [{ selector: 'app-dashboard', template: `
|
|
1101
|
-
<!--
|
|
1102
|
-
POPPED-OUT MODE
|
|
1103
|
-
══════════════════════════════════════════════════════════ -->
|
|
1252
|
+
<!-- POPPED-OUT MODE -->
|
|
1104
1253
|
<ng-container *ngIf="isPoppedOut; else normalMode">
|
|
1105
1254
|
<div class="popout-wrapper" [ngStyle]="wrapperStyles">
|
|
1106
1255
|
<header class="popout-header">
|
|
1107
1256
|
<span class="popout-title">{{ activePage?.name }}</span>
|
|
1108
1257
|
</header>
|
|
1109
|
-
<
|
|
1110
|
-
<
|
|
1111
|
-
<
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
>
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
[ngTemplateOutletContext]="{ widget: widget }">
|
|
1122
|
-
</ng-container>
|
|
1123
|
-
</app-widget-renderer>
|
|
1124
|
-
</ng-template>
|
|
1125
|
-
</app-grid>
|
|
1126
|
-
</div>
|
|
1258
|
+
<app-grid [widgets]="activePage?.widgets || []" (itemChanged)="onItemChanged($event)">
|
|
1259
|
+
<ng-template gridCell let-widget="widget">
|
|
1260
|
+
<app-widget-renderer [widget]="widget" [theme]="resolvedTheme"
|
|
1261
|
+
(editRequested)="editWidgetRequested.emit($event)"
|
|
1262
|
+
(removeRequested)="onRemoveWidget($event)">
|
|
1263
|
+
<ng-container *ngIf="cellTemplate"
|
|
1264
|
+
[ngTemplateOutlet]="cellTemplate"
|
|
1265
|
+
[ngTemplateOutletContext]="{ widget: widget }">
|
|
1266
|
+
</ng-container>
|
|
1267
|
+
</app-widget-renderer>
|
|
1268
|
+
</ng-template>
|
|
1269
|
+
</app-grid>
|
|
1127
1270
|
</div>
|
|
1128
1271
|
</ng-container>
|
|
1129
1272
|
|
|
1130
|
-
<!--
|
|
1131
|
-
NORMAL MODE
|
|
1132
|
-
══════════════════════════════════════════════════════════ -->
|
|
1273
|
+
<!-- NORMAL MODE -->
|
|
1133
1274
|
<ng-template #normalMode>
|
|
1134
1275
|
<div class="dashboard-wrapper" [ngStyle]="wrapperStyles">
|
|
1135
1276
|
<main class="main-content">
|
|
1136
1277
|
|
|
1137
1278
|
<header class="dashboard-header">
|
|
1138
|
-
|
|
1279
|
+
|
|
1280
|
+
<!-- Tab bar -->
|
|
1281
|
+
<div class="tabs-track" #tabsTrack>
|
|
1282
|
+
<!-- Visible tabs -->
|
|
1139
1283
|
<div
|
|
1140
|
-
*ngFor="let page of
|
|
1284
|
+
*ngFor="let page of visiblePages"
|
|
1141
1285
|
class="tab"
|
|
1142
1286
|
[class.active]="page.id === activePageId"
|
|
1143
1287
|
(click)="onSelectPage(page.id)"
|
|
@@ -1150,30 +1294,81 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1150
1294
|
<i class="la la-times"></i>
|
|
1151
1295
|
</button>
|
|
1152
1296
|
</div>
|
|
1297
|
+
|
|
1298
|
+
<!-- Overflow button — shown only when there are hidden tabs -->
|
|
1299
|
+
<button
|
|
1300
|
+
*ngIf="hiddenCount > 0"
|
|
1301
|
+
class="btn-overflow"
|
|
1302
|
+
(click)="openTabSwitcher()"
|
|
1303
|
+
title="Show all workspaces"
|
|
1304
|
+
>
|
|
1305
|
+
<span>+{{ hiddenCount }}</span>
|
|
1306
|
+
<i class="la la-th-large"></i>
|
|
1307
|
+
</button>
|
|
1308
|
+
|
|
1309
|
+
<!-- Add page button -->
|
|
1153
1310
|
<button class="btn-add-page" (click)="onAddPage()" title="New workspace">
|
|
1154
1311
|
<i class="la la-plus"></i>
|
|
1155
1312
|
</button>
|
|
1156
1313
|
</div>
|
|
1157
1314
|
|
|
1158
|
-
<!-- Add Widget button — consumer decides what happens -->
|
|
1159
1315
|
<button class="btn-add-widget" (click)="addWidgetRequested.emit()" title="Add widget">
|
|
1160
1316
|
<i class="la la-plus"></i>
|
|
1161
1317
|
<span>Add Widget</span>
|
|
1162
1318
|
</button>
|
|
1319
|
+
|
|
1163
1320
|
</header>
|
|
1164
1321
|
|
|
1322
|
+
<!-- ── Tab-switcher overlay (Chrome mobile style) ── -->
|
|
1323
|
+
<div class="tab-switcher-overlay" *ngIf="tabSwitcherOpen" (click)="closeTabSwitcher()">
|
|
1324
|
+
<div class="tab-switcher-sheet" (click)="$event.stopPropagation()">
|
|
1325
|
+
|
|
1326
|
+
<div class="tab-switcher-header">
|
|
1327
|
+
<span class="tab-switcher-title">{{ pages.length }} Workspace{{ pages.length !== 1 ? 's' : '' }}</span>
|
|
1328
|
+
<button class="tab-switcher-close-btn" (click)="closeTabSwitcher()" title="Close">
|
|
1329
|
+
<i class="la la-times"></i>
|
|
1330
|
+
</button>
|
|
1331
|
+
</div>
|
|
1332
|
+
|
|
1333
|
+
<div class="tab-switcher-grid">
|
|
1334
|
+
<div
|
|
1335
|
+
*ngFor="let page of pages"
|
|
1336
|
+
class="tab-card"
|
|
1337
|
+
[class.active]="page.id === activePageId"
|
|
1338
|
+
(click)="onSwitcherSelect(page.id)"
|
|
1339
|
+
>
|
|
1340
|
+
<div class="tab-card-icon">
|
|
1341
|
+
<i class="la la-th-large"></i>
|
|
1342
|
+
</div>
|
|
1343
|
+
<span class="tab-card-name">{{ page.name }}</span>
|
|
1344
|
+
<div class="tab-card-actions">
|
|
1345
|
+
<button class="tab-card-btn tab-card-popout" (click)="onSwitcherPopOut($event, page.id)" title="Open in new window">
|
|
1346
|
+
<i class="la la-external-link-alt"></i>
|
|
1347
|
+
</button>
|
|
1348
|
+
<button class="tab-card-btn tab-card-remove" *ngIf="pages.length > 1" (click)="onSwitcherRemove($event, page.id)" title="Close">
|
|
1349
|
+
<i class="la la-times"></i>
|
|
1350
|
+
</button>
|
|
1351
|
+
</div>
|
|
1352
|
+
</div>
|
|
1353
|
+
</div>
|
|
1354
|
+
|
|
1355
|
+
<div class="tab-switcher-footer">
|
|
1356
|
+
<button class="tab-switcher-add-btn" (click)="onSwitcherAdd()">
|
|
1357
|
+
<i class="la la-plus"></i>
|
|
1358
|
+
<span>New Workspace</span>
|
|
1359
|
+
</button>
|
|
1360
|
+
</div>
|
|
1361
|
+
|
|
1362
|
+
</div>
|
|
1363
|
+
</div>
|
|
1364
|
+
|
|
1165
1365
|
<div class="grid-container">
|
|
1166
1366
|
<app-grid [widgets]="activePage?.widgets || []" (itemChanged)="onItemChanged($event)">
|
|
1167
1367
|
<ng-template gridCell let-widget="widget">
|
|
1168
|
-
<app-widget-renderer
|
|
1169
|
-
[widget]="widget"
|
|
1170
|
-
[theme]="resolvedTheme"
|
|
1368
|
+
<app-widget-renderer [widget]="widget" [theme]="resolvedTheme"
|
|
1171
1369
|
(editRequested)="editWidgetRequested.emit($event)"
|
|
1172
|
-
(removeRequested)="onRemoveWidget($event)"
|
|
1173
|
-
|
|
1174
|
-
<!-- Stamp consumer's cell template (if provided) inside the card body -->
|
|
1175
|
-
<ng-container
|
|
1176
|
-
*ngIf="cellTemplate"
|
|
1370
|
+
(removeRequested)="onRemoveWidget($event)">
|
|
1371
|
+
<ng-container *ngIf="cellTemplate"
|
|
1177
1372
|
[ngTemplateOutlet]="cellTemplate"
|
|
1178
1373
|
[ngTemplateOutletContext]="{ widget: widget }">
|
|
1179
1374
|
</ng-container>
|
|
@@ -1185,8 +1380,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1185
1380
|
</main>
|
|
1186
1381
|
</div>
|
|
1187
1382
|
</ng-template>
|
|
1188
|
-
`, 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;
|
|
1189
|
-
}], ctorParameters: function () { return [{ type: DashboardStateService }]; }, propDecorators: { initialLayout: [{
|
|
1383
|
+
`, 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);position:relative}.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-track{display:flex;align-items:center;gap:6px;flex:1;min-width:0;background:var(--dash-tabs-container-color);backdrop-filter:blur(10px);border-radius:25px;padding:6px;overflow:hidden}.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:background .2s,color .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{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-overflow{display:inline-flex;align-items:center;gap:5px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12);border-radius:20px;padding:7px 13px;cursor:pointer;font-size:13px;font-weight:600;color:var(--dash-tab-active-text);white-space:nowrap;flex-shrink:0;transition:background .2s,border-color .2s}.btn-overflow:hover{background:rgba(10,132,255,.18);border-color:var(--dash-accent-color);color:var(--dash-accent-color)}.btn-add-page{background:transparent;border:none;color:var(--dash-fore-color);padding:8px 14px;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)}.tab-switcher-overlay{position:absolute;inset:0;z-index:1000;background:rgba(0,0,0,.55);backdrop-filter:blur(4px);display:flex;align-items:flex-start;justify-content:center;padding-top:60px;animation:overlay-in .18s ease}@keyframes overlay-in{0%{opacity:0}to{opacity:1}}.tab-switcher-sheet{background:var(--dash-panel-bg);border:1px solid rgba(255,255,255,.08);border-radius:24px;width:min(520px,calc(100% - 32px));max-height:calc(100% - 80px);display:flex;flex-direction:column;overflow:hidden;animation:sheet-in .22s cubic-bezier(.32,1.2,.5,1)}@keyframes sheet-in{0%{transform:translateY(-16px) scale(.97);opacity:0}to{transform:translateY(0) scale(1);opacity:1}}.tab-switcher-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px 12px;border-bottom:1px solid rgba(255,255,255,.06);flex-shrink:0}.tab-switcher-title{font-size:15px;font-weight:700;color:var(--dash-tab-active-text)}.tab-switcher-close-btn{background:rgba(255,255,255,.07);border:none;color:var(--dash-fore-color);width:28px;height:28px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:14px;transition:background .15s,color .15s}.tab-switcher-close-btn:hover{background:rgba(255,69,58,.25);color:var(--dash-danger-color)}.tab-switcher-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:10px;padding:16px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}.tab-card{display:flex;flex-direction:column;align-items:center;gap:8px;padding:16px 12px 12px;border-radius:16px;background:var(--dash-card-bg);border:1.5px solid transparent;cursor:pointer;transition:border-color .15s,background .15s,transform .12s;position:relative}.tab-card:hover{background:rgba(255,255,255,.06);transform:translateY(-2px)}.tab-card.active{border-color:var(--dash-accent-color);background:rgba(10,132,255,.12)}.tab-card-icon{width:44px;height:44px;border-radius:12px;background:rgba(255,255,255,.07);display:flex;align-items:center;justify-content:center;font-size:20px;color:var(--dash-fore-color)}.tab-card.active .tab-card-icon{background:rgba(10,132,255,.25);color:var(--dash-accent-color)}.tab-card-name{font-size:13px;font-weight:500;color:var(--dash-tab-active-text);text-align:center;word-break:break-word;line-height:1.3}.tab-card-actions{display:flex;gap:4px;opacity:0;transition:opacity .15s}.tab-card:hover .tab-card-actions{opacity:1}.tab-card-btn{background:rgba(255,255,255,.07);border:none;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:12px;color:var(--dash-fore-color);transition:background .15s,color .15s}.tab-card-popout:hover{background:rgba(10,132,255,.25);color:var(--dash-accent-color)}.tab-card-remove:hover{background:rgba(255,69,58,.25);color:var(--dash-danger-color)}.tab-switcher-footer{padding:12px 16px 16px;border-top:1px solid rgba(255,255,255,.06);flex-shrink:0}.tab-switcher-add-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:11px 20px;border-radius:16px;background:rgba(10,132,255,.15);border:1.5px dashed rgba(10,132,255,.4);color:var(--dash-accent-color);font-size:14px;font-weight:600;cursor:pointer;transition:background .15s,border-color .15s}.tab-switcher-add-btn:hover{background:rgba(10,132,255,.25);border-color:var(--dash-accent-color)}.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"] }]
|
|
1384
|
+
}], ctorParameters: function () { return [{ type: DashboardStateService }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }]; }, propDecorators: { initialLayout: [{
|
|
1190
1385
|
type: Input
|
|
1191
1386
|
}], theme: [{
|
|
1192
1387
|
type: Input
|
|
@@ -1197,15 +1392,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1197
1392
|
}], cellTemplate: [{
|
|
1198
1393
|
type: ContentChild,
|
|
1199
1394
|
args: [GridCellDirective, { read: TemplateRef }]
|
|
1395
|
+
}], tabsTrackRef: [{
|
|
1396
|
+
type: ViewChild,
|
|
1397
|
+
args: ['tabsTrack']
|
|
1398
|
+
}], onEscapeKey: [{
|
|
1399
|
+
type: HostListener,
|
|
1400
|
+
args: ['document:keydown.escape']
|
|
1200
1401
|
}] } });
|
|
1201
1402
|
|
|
1202
1403
|
class DashboardModule {
|
|
1203
1404
|
}
|
|
1204
1405
|
DashboardModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DashboardModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1205
1406
|
DashboardModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: DashboardModule, declarations: [DashboardComponent,
|
|
1407
|
+
OverflowActivePipe,
|
|
1206
1408
|
WidgetRendererComponent,
|
|
1207
1409
|
CustomGridComponent,
|
|
1208
1410
|
GridCellDirective], imports: [CommonModule], exports: [DashboardComponent,
|
|
1411
|
+
OverflowActivePipe,
|
|
1209
1412
|
WidgetRendererComponent,
|
|
1210
1413
|
CustomGridComponent,
|
|
1211
1414
|
GridCellDirective] });
|
|
@@ -1215,6 +1418,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1215
1418
|
args: [{
|
|
1216
1419
|
declarations: [
|
|
1217
1420
|
DashboardComponent,
|
|
1421
|
+
OverflowActivePipe,
|
|
1218
1422
|
WidgetRendererComponent,
|
|
1219
1423
|
CustomGridComponent,
|
|
1220
1424
|
GridCellDirective,
|
|
@@ -1225,6 +1429,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1225
1429
|
providers: [DashboardStateService],
|
|
1226
1430
|
exports: [
|
|
1227
1431
|
DashboardComponent,
|
|
1432
|
+
OverflowActivePipe,
|
|
1228
1433
|
WidgetRendererComponent,
|
|
1229
1434
|
CustomGridComponent,
|
|
1230
1435
|
GridCellDirective,
|
|
@@ -1256,5 +1461,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1256
1461
|
* Generated bundle index. Do not edit.
|
|
1257
1462
|
*/
|
|
1258
1463
|
|
|
1259
|
-
export { AppModule, CustomGridComponent, DashboardComponent, DashboardModule, DashboardStateService, GridCellDirective, WidgetRendererComponent };
|
|
1464
|
+
export { AppModule, CustomGridComponent, DashboardComponent, DashboardModule, DashboardStateService, GridCellDirective, OverflowActivePipe, WidgetRendererComponent };
|
|
1260
1465
|
//# sourceMappingURL=ogidor-dashboard.mjs.map
|