@ogidor/dashboard 1.0.11 → 1.0.13
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 +77 -41
- package/app/dashboard.component.d.ts +18 -4
- package/app/models.d.ts +20 -0
- package/esm2020/app/dashboard.component.mjs +272 -70
- package/esm2020/app/models.mjs +1 -1
- package/fesm2015/ogidor-dashboard.mjs +272 -70
- package/fesm2015/ogidor-dashboard.mjs.map +1 -1
- package/fesm2020/ogidor-dashboard.mjs +271 -69
- 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, Pipe, 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';
|
|
@@ -880,16 +880,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
880
880
|
const DEFAULT_THEME = {
|
|
881
881
|
backgroundColor: '#000000',
|
|
882
882
|
panelColor: '#1c1c1e',
|
|
883
|
+
panelBorderColor: 'rgba(255,255,255,0.05)',
|
|
883
884
|
widgetCardColor: '#2c2c2e',
|
|
884
885
|
foreColor: '#8e8e93',
|
|
885
886
|
accentColor: '#0a84ff',
|
|
887
|
+
accentTintColor: 'rgba(10,132,255,0.15)',
|
|
888
|
+
accentTintStrongColor: 'rgba(10,132,255,0.25)',
|
|
886
889
|
dangerColor: '#ff453a',
|
|
890
|
+
dangerTintColor: 'rgba(255,69,58,0.22)',
|
|
887
891
|
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
|
|
888
892
|
tabsContainerColor: 'rgba(44,44,46,0.6)',
|
|
889
893
|
tabActiveColor: '#3a3a3c',
|
|
890
894
|
tabActiveTextColor: '#ffffff',
|
|
891
895
|
tabHoverTextColor: '#e5e5ea',
|
|
896
|
+
tabHoverBgColor: 'rgba(255,255,255,0.05)',
|
|
892
897
|
addWidgetButtonTextColor: '#ffffff',
|
|
898
|
+
overflowBtnBgColor: 'rgba(255,255,255,0.08)',
|
|
899
|
+
overflowBtnBorderColor: 'rgba(255,255,255,0.12)',
|
|
900
|
+
overlayBgColor: 'rgba(0,0,0,0.55)',
|
|
901
|
+
sheetBorderColor: 'rgba(255,255,255,0.08)',
|
|
902
|
+
scrollbarColor: 'rgba(255,255,255,0.15)',
|
|
893
903
|
popoutTitleColor: '#ffffff',
|
|
894
904
|
widgetTitleColor: '#ffffff',
|
|
895
905
|
dragHandleColor: 'rgba(255,255,255,0.2)',
|
|
@@ -920,10 +930,19 @@ class DashboardComponent {
|
|
|
920
930
|
this.resolvedTheme = { ...DEFAULT_THEME };
|
|
921
931
|
this.wrapperStyles = {};
|
|
922
932
|
this.pages = [];
|
|
933
|
+
this.visiblePages = [];
|
|
934
|
+
this.hiddenCount = 0;
|
|
923
935
|
this.activePageId = '';
|
|
924
936
|
this.isPoppedOut = false;
|
|
925
|
-
this.
|
|
937
|
+
this.tabSwitcherOpen = false;
|
|
926
938
|
this.subs = new Subscription();
|
|
939
|
+
// Reserved space for the overflow "+N" button and the add "+" button (px)
|
|
940
|
+
this.OVERFLOW_BTN_W = 80;
|
|
941
|
+
this.ADD_BTN_W = 52;
|
|
942
|
+
this.GAP = 6;
|
|
943
|
+
this.PADDING = 12; // 6px each side
|
|
944
|
+
// Cache of measured tab widths (including gap) indexed by page position
|
|
945
|
+
this._tabWidthCache = [];
|
|
927
946
|
}
|
|
928
947
|
ngOnChanges(changes) {
|
|
929
948
|
if (changes['theme'] || changes['initialLayout'])
|
|
@@ -944,11 +963,15 @@ class DashboardComponent {
|
|
|
944
963
|
this.isPoppedOut = true;
|
|
945
964
|
this.subs.add(this.stateService.pages$.subscribe(pages => {
|
|
946
965
|
this.pages = pages;
|
|
966
|
+
this._tabWidthCache = []; // invalidate cache — page list changed
|
|
947
967
|
if (this.isPoppedOut && hash) {
|
|
948
968
|
if (pages.find(p => p.id === hash))
|
|
949
969
|
this.stateService.setActivePage(hash);
|
|
950
970
|
}
|
|
951
971
|
this.updateActivePage();
|
|
972
|
+
this.recalcVisibleTabs();
|
|
973
|
+
// Second pass after Angular has rendered the updated tab elements
|
|
974
|
+
setTimeout(() => this.recalcVisibleTabs());
|
|
952
975
|
}));
|
|
953
976
|
this.subs.add(this.stateService.activePageId$.subscribe(id => {
|
|
954
977
|
this.activePageId = id;
|
|
@@ -956,18 +979,16 @@ class DashboardComponent {
|
|
|
956
979
|
}));
|
|
957
980
|
}
|
|
958
981
|
ngAfterViewInit() {
|
|
959
|
-
if (!this.
|
|
982
|
+
if (!this.tabsTrackRef)
|
|
960
983
|
return;
|
|
961
984
|
this.zone.runOutsideAngular(() => {
|
|
962
985
|
this.resizeObserver = new ResizeObserver(() => {
|
|
963
|
-
this.zone.run(() => this.
|
|
986
|
+
this.zone.run(() => this.recalcVisibleTabs());
|
|
964
987
|
});
|
|
965
|
-
this.resizeObserver.observe(this.
|
|
966
|
-
});
|
|
967
|
-
// Also detect scroll so fade hides when scrolled to end
|
|
968
|
-
this.tabsContainerRef.nativeElement.addEventListener('scroll', () => {
|
|
969
|
-
this.zone.run(() => this.checkOverflow());
|
|
988
|
+
this.resizeObserver.observe(this.tabsTrackRef.nativeElement);
|
|
970
989
|
});
|
|
990
|
+
// Initial measurement pass now that the DOM is ready
|
|
991
|
+
setTimeout(() => this.recalcVisibleTabs());
|
|
971
992
|
}
|
|
972
993
|
ngOnDestroy() {
|
|
973
994
|
this.subs.unsubscribe();
|
|
@@ -993,12 +1014,82 @@ class DashboardComponent {
|
|
|
993
1014
|
this.stateService.popOutPage(pageId);
|
|
994
1015
|
}
|
|
995
1016
|
serializeLayout() { return this.stateService.serializeLayout(); }
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1017
|
+
openTabSwitcher() { this.tabSwitcherOpen = true; }
|
|
1018
|
+
closeTabSwitcher() { this.tabSwitcherOpen = false; }
|
|
1019
|
+
onEscapeKey() { this.closeTabSwitcher(); }
|
|
1020
|
+
onSwitcherSelect(pageId) {
|
|
1021
|
+
this.stateService.setActivePage(pageId);
|
|
1022
|
+
this.closeTabSwitcher();
|
|
1023
|
+
}
|
|
1024
|
+
onSwitcherPopOut(event, pageId) {
|
|
1025
|
+
event.stopPropagation();
|
|
1026
|
+
this.stateService.popOutPage(pageId);
|
|
1027
|
+
this.closeTabSwitcher();
|
|
1028
|
+
}
|
|
1029
|
+
onSwitcherRemove(event, pageId) {
|
|
1030
|
+
event.stopPropagation();
|
|
1031
|
+
if (confirm('Remove this workspace?')) {
|
|
1032
|
+
this.stateService.removePage(pageId);
|
|
1033
|
+
if (this.pages.length <= 1)
|
|
1034
|
+
this.closeTabSwitcher();
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
onSwitcherAdd() {
|
|
1038
|
+
const name = prompt('Workspace name:', `Workspace ${this.pages.length + 1}`);
|
|
1039
|
+
if (name)
|
|
1040
|
+
this.stateService.addPage(name);
|
|
1041
|
+
}
|
|
1042
|
+
recalcVisibleTabs() {
|
|
1043
|
+
if (!this.tabsTrackRef || !this.pages.length) {
|
|
1044
|
+
this.visiblePages = this.pages;
|
|
1045
|
+
this.hiddenCount = 0;
|
|
1046
|
+
this.cdr.markForCheck();
|
|
999
1047
|
return;
|
|
1000
|
-
|
|
1001
|
-
|
|
1048
|
+
}
|
|
1049
|
+
const track = this.tabsTrackRef.nativeElement;
|
|
1050
|
+
const trackW = track.clientWidth;
|
|
1051
|
+
// Space always consumed by the add "+" button + padding
|
|
1052
|
+
const baseReserved = this.ADD_BTN_W + this.GAP + this.PADDING;
|
|
1053
|
+
// Space needed for the overflow "+N" button when shown
|
|
1054
|
+
const overflowSlot = this.OVERFLOW_BTN_W + this.GAP;
|
|
1055
|
+
// Measure each real tab element currently in the DOM.
|
|
1056
|
+
// The DOM always renders all visiblePages tabs, so we may not have all tabs
|
|
1057
|
+
// measured yet — fall back to the previous measured cache or a generous estimate.
|
|
1058
|
+
const tabEls = Array.from(track.querySelectorAll('.tab'));
|
|
1059
|
+
// Build a width map by index (only covers currently visible tabs)
|
|
1060
|
+
const measuredWidths = this.pages.map((_, i) => {
|
|
1061
|
+
const el = tabEls[i];
|
|
1062
|
+
return el ? el.getBoundingClientRect().width + this.GAP : this._tabWidthCache[i] ?? 150 + this.GAP;
|
|
1063
|
+
});
|
|
1064
|
+
// Update cache for next call
|
|
1065
|
+
tabEls.forEach((el, i) => {
|
|
1066
|
+
this._tabWidthCache[i] = el.getBoundingClientRect().width + this.GAP;
|
|
1067
|
+
});
|
|
1068
|
+
// How much space the tabs need in total (no overflow button)
|
|
1069
|
+
const totalNeeded = measuredWidths.reduce((s, w) => s + w, 0) - this.GAP; // remove trailing gap
|
|
1070
|
+
if (totalNeeded <= trackW - baseReserved) {
|
|
1071
|
+
// Everything fits — show all
|
|
1072
|
+
this.visiblePages = this.pages;
|
|
1073
|
+
this.hiddenCount = 0;
|
|
1074
|
+
}
|
|
1075
|
+
else {
|
|
1076
|
+
// Not everything fits — fill as many as possible while always leaving room for overflow btn
|
|
1077
|
+
const budget = trackW - baseReserved - overflowSlot;
|
|
1078
|
+
let used = 0;
|
|
1079
|
+
let count = 0;
|
|
1080
|
+
for (let i = 0; i < this.pages.length; i++) {
|
|
1081
|
+
used += measuredWidths[i];
|
|
1082
|
+
if (used - this.GAP <= budget) { // -GAP: last item has no trailing gap
|
|
1083
|
+
count++;
|
|
1084
|
+
}
|
|
1085
|
+
else {
|
|
1086
|
+
break;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
count = Math.max(1, count);
|
|
1090
|
+
this.visiblePages = this.pages.slice(0, count);
|
|
1091
|
+
this.hiddenCount = this.pages.length - count;
|
|
1092
|
+
}
|
|
1002
1093
|
this.cdr.markForCheck();
|
|
1003
1094
|
}
|
|
1004
1095
|
applyTheme() {
|
|
@@ -1007,16 +1098,26 @@ class DashboardComponent {
|
|
|
1007
1098
|
this.wrapperStyles = {
|
|
1008
1099
|
'--dash-bg': t.backgroundColor,
|
|
1009
1100
|
'--dash-panel-bg': t.panelColor,
|
|
1101
|
+
'--dash-panel-border': t.panelBorderColor,
|
|
1010
1102
|
'--dash-card-bg': t.widgetCardColor,
|
|
1011
1103
|
'--dash-fore-color': t.foreColor,
|
|
1012
1104
|
'--dash-accent-color': t.accentColor,
|
|
1105
|
+
'--dash-accent-tint': t.accentTintColor,
|
|
1106
|
+
'--dash-accent-tint-strong': t.accentTintStrongColor,
|
|
1013
1107
|
'--dash-danger-color': t.dangerColor,
|
|
1108
|
+
'--dash-danger-tint': t.dangerTintColor,
|
|
1014
1109
|
'--dash-font-family': t.fontFamily,
|
|
1015
1110
|
'--dash-tabs-container-color': t.tabsContainerColor,
|
|
1016
1111
|
'--dash-tab-active-color': t.tabActiveColor,
|
|
1017
1112
|
'--dash-tab-active-text': t.tabActiveTextColor,
|
|
1018
1113
|
'--dash-tab-hover-text': t.tabHoverTextColor,
|
|
1114
|
+
'--dash-tab-hover-bg': t.tabHoverBgColor,
|
|
1019
1115
|
'--dash-add-widget-text': t.addWidgetButtonTextColor,
|
|
1116
|
+
'--dash-overflow-btn-bg': t.overflowBtnBgColor,
|
|
1117
|
+
'--dash-overflow-btn-border': t.overflowBtnBorderColor,
|
|
1118
|
+
'--dash-overlay-bg': t.overlayBgColor,
|
|
1119
|
+
'--dash-sheet-border': t.sheetBorderColor,
|
|
1120
|
+
'--dash-scrollbar-color': t.scrollbarColor,
|
|
1020
1121
|
'--dash-popout-title-color': t.popoutTitleColor,
|
|
1021
1122
|
'--dash-widget-title-color': t.widgetTitleColor,
|
|
1022
1123
|
'--dash-drag-handle-color': t.dragHandleColor,
|
|
@@ -1029,18 +1130,10 @@ class DashboardComponent {
|
|
|
1029
1130
|
}
|
|
1030
1131
|
updateActivePage() {
|
|
1031
1132
|
this.activePage = this.pages.find(p => p.id === this.activePageId);
|
|
1032
|
-
// scroll active tab into view
|
|
1033
|
-
setTimeout(() => {
|
|
1034
|
-
if (!this.tabsContainerRef)
|
|
1035
|
-
return;
|
|
1036
|
-
const active = this.tabsContainerRef.nativeElement.querySelector('.tab.active');
|
|
1037
|
-
active?.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });
|
|
1038
|
-
this.checkOverflow();
|
|
1039
|
-
});
|
|
1040
1133
|
}
|
|
1041
1134
|
}
|
|
1042
1135
|
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 });
|
|
1043
|
-
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: "
|
|
1136
|
+
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: `
|
|
1044
1137
|
<!-- POPPED-OUT MODE -->
|
|
1045
1138
|
<ng-container *ngIf="isPoppedOut; else normalMode">
|
|
1046
1139
|
<div class="popout-wrapper" [ngStyle]="wrapperStyles">
|
|
@@ -1069,29 +1162,39 @@ DashboardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", ver
|
|
|
1069
1162
|
|
|
1070
1163
|
<header class="dashboard-header">
|
|
1071
1164
|
|
|
1072
|
-
<!--
|
|
1073
|
-
<div class="tabs-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
</button>
|
|
1088
|
-
</div>
|
|
1089
|
-
<button class="btn-add-page" (click)="onAddPage()" title="New workspace">
|
|
1090
|
-
<i class="la la-plus"></i>
|
|
1165
|
+
<!-- Tab bar -->
|
|
1166
|
+
<div class="tabs-track" #tabsTrack>
|
|
1167
|
+
<!-- Visible tabs -->
|
|
1168
|
+
<div
|
|
1169
|
+
*ngFor="let page of visiblePages"
|
|
1170
|
+
class="tab"
|
|
1171
|
+
[class.active]="page.id === activePageId"
|
|
1172
|
+
(click)="onSelectPage(page.id)"
|
|
1173
|
+
>
|
|
1174
|
+
<span class="tab-name">{{ page.name }}</span>
|
|
1175
|
+
<button class="tab-action tab-popout" (click)="onPopOut($event, page.id)" title="Open in new window">
|
|
1176
|
+
<i class="la la-external-link-alt"></i>
|
|
1177
|
+
</button>
|
|
1178
|
+
<button class="tab-action tab-close" *ngIf="pages.length > 1" (click)="onRemovePage($event, page.id)" title="Close">
|
|
1179
|
+
<i class="la la-times"></i>
|
|
1091
1180
|
</button>
|
|
1092
1181
|
</div>
|
|
1093
|
-
|
|
1094
|
-
|
|
1182
|
+
|
|
1183
|
+
<!-- Overflow button — shown only when there are hidden tabs -->
|
|
1184
|
+
<button
|
|
1185
|
+
*ngIf="hiddenCount > 0"
|
|
1186
|
+
class="btn-overflow"
|
|
1187
|
+
(click)="openTabSwitcher()"
|
|
1188
|
+
title="Show all workspaces"
|
|
1189
|
+
>
|
|
1190
|
+
<span>+{{ hiddenCount }}</span>
|
|
1191
|
+
<i class="la la-th-large"></i>
|
|
1192
|
+
</button>
|
|
1193
|
+
|
|
1194
|
+
<!-- Add page button -->
|
|
1195
|
+
<button class="btn-add-page" (click)="onAddPage()" title="New workspace">
|
|
1196
|
+
<i class="la la-plus"></i>
|
|
1197
|
+
</button>
|
|
1095
1198
|
</div>
|
|
1096
1199
|
|
|
1097
1200
|
<button class="btn-add-widget" (click)="addWidgetRequested.emit()" title="Add widget">
|
|
@@ -1101,6 +1204,49 @@ DashboardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", ver
|
|
|
1101
1204
|
|
|
1102
1205
|
</header>
|
|
1103
1206
|
|
|
1207
|
+
<!-- ── Tab-switcher overlay (Chrome mobile style) ── -->
|
|
1208
|
+
<div class="tab-switcher-overlay" *ngIf="tabSwitcherOpen" (click)="closeTabSwitcher()">
|
|
1209
|
+
<div class="tab-switcher-sheet" (click)="$event.stopPropagation()">
|
|
1210
|
+
|
|
1211
|
+
<div class="tab-switcher-header">
|
|
1212
|
+
<span class="tab-switcher-title">{{ pages.length }} Workspace{{ pages.length !== 1 ? 's' : '' }}</span>
|
|
1213
|
+
<button class="tab-switcher-close-btn" (click)="closeTabSwitcher()" title="Close">
|
|
1214
|
+
<i class="la la-times"></i>
|
|
1215
|
+
</button>
|
|
1216
|
+
</div>
|
|
1217
|
+
|
|
1218
|
+
<div class="tab-switcher-grid">
|
|
1219
|
+
<div
|
|
1220
|
+
*ngFor="let page of pages"
|
|
1221
|
+
class="tab-card"
|
|
1222
|
+
[class.active]="page.id === activePageId"
|
|
1223
|
+
(click)="onSwitcherSelect(page.id)"
|
|
1224
|
+
>
|
|
1225
|
+
<div class="tab-card-icon">
|
|
1226
|
+
<i class="la la-th-large"></i>
|
|
1227
|
+
</div>
|
|
1228
|
+
<span class="tab-card-name">{{ page.name }}</span>
|
|
1229
|
+
<div class="tab-card-actions">
|
|
1230
|
+
<button class="tab-card-btn tab-card-popout" (click)="onSwitcherPopOut($event, page.id)" title="Open in new window">
|
|
1231
|
+
<i class="la la-external-link-alt"></i>
|
|
1232
|
+
</button>
|
|
1233
|
+
<button class="tab-card-btn tab-card-remove" *ngIf="pages.length > 1" (click)="onSwitcherRemove($event, page.id)" title="Close">
|
|
1234
|
+
<i class="la la-times"></i>
|
|
1235
|
+
</button>
|
|
1236
|
+
</div>
|
|
1237
|
+
</div>
|
|
1238
|
+
</div>
|
|
1239
|
+
|
|
1240
|
+
<div class="tab-switcher-footer">
|
|
1241
|
+
<button class="tab-switcher-add-btn" (click)="onSwitcherAdd()">
|
|
1242
|
+
<i class="la la-plus"></i>
|
|
1243
|
+
<span>New Workspace</span>
|
|
1244
|
+
</button>
|
|
1245
|
+
</div>
|
|
1246
|
+
|
|
1247
|
+
</div>
|
|
1248
|
+
</div>
|
|
1249
|
+
|
|
1104
1250
|
<div class="grid-container">
|
|
1105
1251
|
<app-grid [widgets]="activePage?.widgets || []" (itemChanged)="onItemChanged($event)">
|
|
1106
1252
|
<ng-template gridCell let-widget="widget">
|
|
@@ -1119,7 +1265,7 @@ DashboardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", ver
|
|
|
1119
1265
|
</main>
|
|
1120
1266
|
</div>
|
|
1121
1267
|
</ng-template>
|
|
1122
|
-
`, 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
|
|
1268
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;width:100%;height:100%;min-height:0;--dash-bg: #000000;--dash-panel-bg: #1c1c1e;--dash-panel-border: rgba(255,255,255,.05);--dash-card-bg: #2c2c2e;--dash-fore-color: #8e8e93;--dash-accent-color: #0a84ff;--dash-accent-tint: rgba(10,132,255,.15);--dash-accent-tint-strong: rgba(10,132,255,.25);--dash-danger-color: #ff453a;--dash-danger-tint: rgba(255,69,58,.22);--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-tab-hover-bg: rgba(255,255,255,.05);--dash-add-widget-text: #ffffff;--dash-overflow-btn-bg: rgba(255,255,255,.08);--dash-overflow-btn-border: rgba(255,255,255,.12);--dash-overlay-bg: rgba(0,0,0,.55);--dash-sheet-border: rgba(255,255,255,.08);--dash-scrollbar-color: rgba(255,255,255,.15);--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 var(--dash-panel-border);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 var(--dash-panel-border);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:var(--dash-tab-hover-bg)}.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:var(--dash-accent-tint)}.tab-close:hover{color:var(--dash-danger-color);background:var(--dash-danger-tint)}.btn-overflow{display:inline-flex;align-items:center;gap:5px;background:var(--dash-overflow-btn-bg);border:1px solid var(--dash-overflow-btn-border);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,color .2s}.btn-overflow:hover{background:var(--dash-accent-tint);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:var(--dash-accent-tint)}.tab-switcher-overlay{position:absolute;inset:0;z-index:1000;background:var(--dash-overlay-bg);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 var(--dash-sheet-border);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 var(--dash-sheet-border);flex-shrink:0}.tab-switcher-title{font-size:15px;font-weight:700;color:var(--dash-tab-active-text)}.tab-switcher-close-btn{background:var(--dash-widget-btn-bg);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:var(--dash-danger-tint);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:var(--dash-scrollbar-color) 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:var(--dash-tab-hover-bg);transform:translateY(-2px)}.tab-card.active{border-color:var(--dash-accent-color);background:var(--dash-accent-tint)}.tab-card-icon{width:44px;height:44px;border-radius:12px;background:var(--dash-widget-btn-bg);display:flex;align-items:center;justify-content:center;font-size:20px;color:var(--dash-fore-color)}.tab-card.active .tab-card-icon{background:var(--dash-accent-tint-strong);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:var(--dash-widget-btn-bg);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:var(--dash-accent-tint-strong);color:var(--dash-accent-color)}.tab-card-remove:hover{background:var(--dash-danger-tint);color:var(--dash-danger-color)}.tab-switcher-footer{padding:12px 16px 16px;border-top:1px solid var(--dash-sheet-border);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:var(--dash-accent-tint);border:1.5px dashed var(--dash-accent-tint-strong);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:var(--dash-accent-tint-strong);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]" }] });
|
|
1123
1269
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DashboardComponent, decorators: [{
|
|
1124
1270
|
type: Component,
|
|
1125
1271
|
args: [{ selector: 'app-dashboard', template: `
|
|
@@ -1151,29 +1297,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1151
1297
|
|
|
1152
1298
|
<header class="dashboard-header">
|
|
1153
1299
|
|
|
1154
|
-
<!--
|
|
1155
|
-
<div class="tabs-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
</button>
|
|
1170
|
-
</div>
|
|
1171
|
-
<button class="btn-add-page" (click)="onAddPage()" title="New workspace">
|
|
1172
|
-
<i class="la la-plus"></i>
|
|
1300
|
+
<!-- Tab bar -->
|
|
1301
|
+
<div class="tabs-track" #tabsTrack>
|
|
1302
|
+
<!-- Visible tabs -->
|
|
1303
|
+
<div
|
|
1304
|
+
*ngFor="let page of visiblePages"
|
|
1305
|
+
class="tab"
|
|
1306
|
+
[class.active]="page.id === activePageId"
|
|
1307
|
+
(click)="onSelectPage(page.id)"
|
|
1308
|
+
>
|
|
1309
|
+
<span class="tab-name">{{ page.name }}</span>
|
|
1310
|
+
<button class="tab-action tab-popout" (click)="onPopOut($event, page.id)" title="Open in new window">
|
|
1311
|
+
<i class="la la-external-link-alt"></i>
|
|
1312
|
+
</button>
|
|
1313
|
+
<button class="tab-action tab-close" *ngIf="pages.length > 1" (click)="onRemovePage($event, page.id)" title="Close">
|
|
1314
|
+
<i class="la la-times"></i>
|
|
1173
1315
|
</button>
|
|
1174
1316
|
</div>
|
|
1175
|
-
|
|
1176
|
-
|
|
1317
|
+
|
|
1318
|
+
<!-- Overflow button — shown only when there are hidden tabs -->
|
|
1319
|
+
<button
|
|
1320
|
+
*ngIf="hiddenCount > 0"
|
|
1321
|
+
class="btn-overflow"
|
|
1322
|
+
(click)="openTabSwitcher()"
|
|
1323
|
+
title="Show all workspaces"
|
|
1324
|
+
>
|
|
1325
|
+
<span>+{{ hiddenCount }}</span>
|
|
1326
|
+
<i class="la la-th-large"></i>
|
|
1327
|
+
</button>
|
|
1328
|
+
|
|
1329
|
+
<!-- Add page button -->
|
|
1330
|
+
<button class="btn-add-page" (click)="onAddPage()" title="New workspace">
|
|
1331
|
+
<i class="la la-plus"></i>
|
|
1332
|
+
</button>
|
|
1177
1333
|
</div>
|
|
1178
1334
|
|
|
1179
1335
|
<button class="btn-add-widget" (click)="addWidgetRequested.emit()" title="Add widget">
|
|
@@ -1183,6 +1339,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1183
1339
|
|
|
1184
1340
|
</header>
|
|
1185
1341
|
|
|
1342
|
+
<!-- ── Tab-switcher overlay (Chrome mobile style) ── -->
|
|
1343
|
+
<div class="tab-switcher-overlay" *ngIf="tabSwitcherOpen" (click)="closeTabSwitcher()">
|
|
1344
|
+
<div class="tab-switcher-sheet" (click)="$event.stopPropagation()">
|
|
1345
|
+
|
|
1346
|
+
<div class="tab-switcher-header">
|
|
1347
|
+
<span class="tab-switcher-title">{{ pages.length }} Workspace{{ pages.length !== 1 ? 's' : '' }}</span>
|
|
1348
|
+
<button class="tab-switcher-close-btn" (click)="closeTabSwitcher()" title="Close">
|
|
1349
|
+
<i class="la la-times"></i>
|
|
1350
|
+
</button>
|
|
1351
|
+
</div>
|
|
1352
|
+
|
|
1353
|
+
<div class="tab-switcher-grid">
|
|
1354
|
+
<div
|
|
1355
|
+
*ngFor="let page of pages"
|
|
1356
|
+
class="tab-card"
|
|
1357
|
+
[class.active]="page.id === activePageId"
|
|
1358
|
+
(click)="onSwitcherSelect(page.id)"
|
|
1359
|
+
>
|
|
1360
|
+
<div class="tab-card-icon">
|
|
1361
|
+
<i class="la la-th-large"></i>
|
|
1362
|
+
</div>
|
|
1363
|
+
<span class="tab-card-name">{{ page.name }}</span>
|
|
1364
|
+
<div class="tab-card-actions">
|
|
1365
|
+
<button class="tab-card-btn tab-card-popout" (click)="onSwitcherPopOut($event, page.id)" title="Open in new window">
|
|
1366
|
+
<i class="la la-external-link-alt"></i>
|
|
1367
|
+
</button>
|
|
1368
|
+
<button class="tab-card-btn tab-card-remove" *ngIf="pages.length > 1" (click)="onSwitcherRemove($event, page.id)" title="Close">
|
|
1369
|
+
<i class="la la-times"></i>
|
|
1370
|
+
</button>
|
|
1371
|
+
</div>
|
|
1372
|
+
</div>
|
|
1373
|
+
</div>
|
|
1374
|
+
|
|
1375
|
+
<div class="tab-switcher-footer">
|
|
1376
|
+
<button class="tab-switcher-add-btn" (click)="onSwitcherAdd()">
|
|
1377
|
+
<i class="la la-plus"></i>
|
|
1378
|
+
<span>New Workspace</span>
|
|
1379
|
+
</button>
|
|
1380
|
+
</div>
|
|
1381
|
+
|
|
1382
|
+
</div>
|
|
1383
|
+
</div>
|
|
1384
|
+
|
|
1186
1385
|
<div class="grid-container">
|
|
1187
1386
|
<app-grid [widgets]="activePage?.widgets || []" (itemChanged)="onItemChanged($event)">
|
|
1188
1387
|
<ng-template gridCell let-widget="widget">
|
|
@@ -1201,7 +1400,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1201
1400
|
</main>
|
|
1202
1401
|
</div>
|
|
1203
1402
|
</ng-template>
|
|
1204
|
-
`, 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
|
|
1403
|
+
`, styles: [":host{display:flex;flex-direction:column;width:100%;height:100%;min-height:0;--dash-bg: #000000;--dash-panel-bg: #1c1c1e;--dash-panel-border: rgba(255,255,255,.05);--dash-card-bg: #2c2c2e;--dash-fore-color: #8e8e93;--dash-accent-color: #0a84ff;--dash-accent-tint: rgba(10,132,255,.15);--dash-accent-tint-strong: rgba(10,132,255,.25);--dash-danger-color: #ff453a;--dash-danger-tint: rgba(255,69,58,.22);--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-tab-hover-bg: rgba(255,255,255,.05);--dash-add-widget-text: #ffffff;--dash-overflow-btn-bg: rgba(255,255,255,.08);--dash-overflow-btn-border: rgba(255,255,255,.12);--dash-overlay-bg: rgba(0,0,0,.55);--dash-sheet-border: rgba(255,255,255,.08);--dash-scrollbar-color: rgba(255,255,255,.15);--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 var(--dash-panel-border);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 var(--dash-panel-border);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:var(--dash-tab-hover-bg)}.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:var(--dash-accent-tint)}.tab-close:hover{color:var(--dash-danger-color);background:var(--dash-danger-tint)}.btn-overflow{display:inline-flex;align-items:center;gap:5px;background:var(--dash-overflow-btn-bg);border:1px solid var(--dash-overflow-btn-border);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,color .2s}.btn-overflow:hover{background:var(--dash-accent-tint);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:var(--dash-accent-tint)}.tab-switcher-overlay{position:absolute;inset:0;z-index:1000;background:var(--dash-overlay-bg);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 var(--dash-sheet-border);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 var(--dash-sheet-border);flex-shrink:0}.tab-switcher-title{font-size:15px;font-weight:700;color:var(--dash-tab-active-text)}.tab-switcher-close-btn{background:var(--dash-widget-btn-bg);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:var(--dash-danger-tint);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:var(--dash-scrollbar-color) 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:var(--dash-tab-hover-bg);transform:translateY(-2px)}.tab-card.active{border-color:var(--dash-accent-color);background:var(--dash-accent-tint)}.tab-card-icon{width:44px;height:44px;border-radius:12px;background:var(--dash-widget-btn-bg);display:flex;align-items:center;justify-content:center;font-size:20px;color:var(--dash-fore-color)}.tab-card.active .tab-card-icon{background:var(--dash-accent-tint-strong);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:var(--dash-widget-btn-bg);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:var(--dash-accent-tint-strong);color:var(--dash-accent-color)}.tab-card-remove:hover{background:var(--dash-danger-tint);color:var(--dash-danger-color)}.tab-switcher-footer{padding:12px 16px 16px;border-top:1px solid var(--dash-sheet-border);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:var(--dash-accent-tint);border:1.5px dashed var(--dash-accent-tint-strong);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:var(--dash-accent-tint-strong);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"] }]
|
|
1205
1404
|
}], ctorParameters: function () { return [{ type: DashboardStateService }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }]; }, propDecorators: { initialLayout: [{
|
|
1206
1405
|
type: Input
|
|
1207
1406
|
}], theme: [{
|
|
@@ -1213,9 +1412,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
1213
1412
|
}], cellTemplate: [{
|
|
1214
1413
|
type: ContentChild,
|
|
1215
1414
|
args: [GridCellDirective, { read: TemplateRef }]
|
|
1216
|
-
}],
|
|
1415
|
+
}], tabsTrackRef: [{
|
|
1217
1416
|
type: ViewChild,
|
|
1218
|
-
args: ['
|
|
1417
|
+
args: ['tabsTrack']
|
|
1418
|
+
}], onEscapeKey: [{
|
|
1419
|
+
type: HostListener,
|
|
1420
|
+
args: ['document:keydown.escape']
|
|
1219
1421
|
}] } });
|
|
1220
1422
|
|
|
1221
1423
|
class DashboardModule {
|