@flyos/design-system 3.10.0 → 3.12.0
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/fesm2022/flyos-design-system.mjs +669 -149
- package/fesm2022/flyos-design-system.mjs.map +1 -1
- package/package.json +1 -1
- package/scss/_app-surface-tokens.scss +58 -48
- package/scss/_nova-glass.scss +14 -5
- package/types/flyos-design-system.d.ts +421 -7
- package/types/flyos-design-system.d.ts.map +1 -1
|
@@ -47,7 +47,7 @@ import { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
|
|
|
47
47
|
// tools/publish-library.ps1 at bump time, and asserted by the spec beside this file.
|
|
48
48
|
// Used only for the diagnostic message; the duplicate-instance detection itself is
|
|
49
49
|
// version-agnostic, so a stale literal misnames a fork rather than hiding one.
|
|
50
|
-
const FLY_DS_VERSION = '3.
|
|
50
|
+
const FLY_DS_VERSION = '3.12.0';
|
|
51
51
|
const FLY_DS_REGISTRY_KEY = '__FLY_DS_INSTANCES__';
|
|
52
52
|
/**
|
|
53
53
|
* Records this design-system instance on the shared `scope` and returns the
|
|
@@ -3339,6 +3339,46 @@ function provideFlyStandaloneAuth(config) {
|
|
|
3339
3339
|
]);
|
|
3340
3340
|
}
|
|
3341
3341
|
|
|
3342
|
+
const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
3343
|
+
/**
|
|
3344
|
+
* Auth wiring for a UI-developer build: sign in as a representative tenant user so the app runs
|
|
3345
|
+
* with **no STS**, and present a fixed bearer to whatever backend (real or mocked) it talks to.
|
|
3346
|
+
*
|
|
3347
|
+
* <p>The offline counterpart of `provideFlyStandaloneAuth`, and it deliberately provides the SAME
|
|
3348
|
+
* {@link FLY_STANDALONE_AUTH_CONFIG}. Two reasons, both learned the hard way:</p>
|
|
3349
|
+
* <ul>
|
|
3350
|
+
* <li>`flyStandaloneAuthInterceptor` injects that token unconditionally. Omitting it here does
|
|
3351
|
+
* not degrade gracefully — every HTTP call in the offline build throws a DI error at runtime,
|
|
3352
|
+
* which no typecheck or unit test catches.</li>
|
|
3353
|
+
* <li>The interceptor's path rules then hold identically in all build modes instead of being
|
|
3354
|
+
* re-stated per mode.</li>
|
|
3355
|
+
* </ul>
|
|
3356
|
+
*
|
|
3357
|
+
* <p>Seeding the shared {@link AuthService} store is the whole implementation, because that store
|
|
3358
|
+
* is the single source of truth for identity: `FlyStandaloneAuthService.isAuthenticated()` delegates
|
|
3359
|
+
* to it, so `flyStandaloneAuthGuard` passes and never reaches `startLogin()`, and the interceptor
|
|
3360
|
+
* reads the same token. No PKCE code path is entered offline.</p>
|
|
3361
|
+
*
|
|
3362
|
+
* <p><b>`STEP_UP_REAUTH_HANDLER` is intentionally NOT provided.</b> A step-up challenge cannot
|
|
3363
|
+
* arise offline, and a handler that redirected to a real STS would be actively wrong in a build
|
|
3364
|
+
* that has none.</p>
|
|
3365
|
+
*
|
|
3366
|
+
* @example
|
|
3367
|
+
* providers: [
|
|
3368
|
+
* offlineDataEnabled
|
|
3369
|
+
* ? provideFlyOfflineAuth({ auth: PPM_AUTH_CONFIG, user: OFFLINE_USER, accessToken: DEV_BEARER })
|
|
3370
|
+
* : provideFlyStandaloneAuth(PPM_AUTH_CONFIG),
|
|
3371
|
+
* ]
|
|
3372
|
+
*/
|
|
3373
|
+
function provideFlyOfflineAuth(config) {
|
|
3374
|
+
return makeEnvironmentProviders([
|
|
3375
|
+
{ provide: FLY_STANDALONE_AUTH_CONFIG, useValue: config.auth },
|
|
3376
|
+
provideAppInitializer(() => {
|
|
3377
|
+
inject(AuthService).setSession(config.user, config.accessToken, Date.now() + (config.sessionTtlMs ?? DEFAULT_TTL_MS));
|
|
3378
|
+
}),
|
|
3379
|
+
]);
|
|
3380
|
+
}
|
|
3381
|
+
|
|
3342
3382
|
/** Single source of truth for persisted / API theme strings. */
|
|
3343
3383
|
const FLY_THEME_MODE_IDS = ['light', 'dark'];
|
|
3344
3384
|
/** Factory default: `dark` (opaque dark / `html.dark-theme`); shell i18n `settings.theme.dark`. Keep in sync with `UserSettings` defaults. */
|
|
@@ -3569,8 +3609,23 @@ const FLY_REMOTE_BASE_PATH = new InjectionToken('FLY_REMOTE_BASE_PATH');
|
|
|
3569
3609
|
* `FlyRemoteRouter.matchedRoute()`.
|
|
3570
3610
|
*/
|
|
3571
3611
|
function matchFlyRoutePattern(pattern, segments) {
|
|
3612
|
+
const matched = matchFlyRoutePrefix(pattern, segments);
|
|
3613
|
+
return matched && matched.rest.length === 0 ? matched.params : null;
|
|
3614
|
+
}
|
|
3615
|
+
/**
|
|
3616
|
+
* Match a pattern against the FRONT of `segments`, returning what it captured
|
|
3617
|
+
* plus the segments it did not consume. `null` when the pattern cannot match.
|
|
3618
|
+
*
|
|
3619
|
+
* This is the prefix half of {@link matchFlyRoutePattern}, which is now simply
|
|
3620
|
+
* "prefix-match, and insist nothing is left over". A parent route stops at the
|
|
3621
|
+
* prefix and hands `rest` to its `children`.
|
|
3622
|
+
*
|
|
3623
|
+
* Exported for unit testing — consumers should rely on
|
|
3624
|
+
* `FlyRemoteRouter.matchedRoute()`.
|
|
3625
|
+
*/
|
|
3626
|
+
function matchFlyRoutePrefix(pattern, segments) {
|
|
3572
3627
|
const patternSegments = pattern.split('/').filter(Boolean);
|
|
3573
|
-
if (patternSegments.length
|
|
3628
|
+
if (patternSegments.length > segments.length)
|
|
3574
3629
|
return null;
|
|
3575
3630
|
const params = {};
|
|
3576
3631
|
for (let i = 0; i < patternSegments.length; i++) {
|
|
@@ -3583,8 +3638,59 @@ function matchFlyRoutePattern(pattern, segments) {
|
|
|
3583
3638
|
return null;
|
|
3584
3639
|
}
|
|
3585
3640
|
}
|
|
3586
|
-
return params;
|
|
3641
|
+
return { params, rest: segments.slice(patternSegments.length) };
|
|
3642
|
+
}
|
|
3643
|
+
/**
|
|
3644
|
+
* Resolve `segments` against a route table, descending into `children`.
|
|
3645
|
+
*
|
|
3646
|
+
* First-match-wins in declaration order, at every level. A row WITHOUT children
|
|
3647
|
+
* must consume the URL exactly — the flat-table rule, unchanged. A row WITH
|
|
3648
|
+
* children consumes its own prefix and must then find a matching descendant;
|
|
3649
|
+
* if none matches, the row is skipped and its later siblings still get a turn,
|
|
3650
|
+
* so a routing miss never renders a layout wrapped around an empty outlet.
|
|
3651
|
+
*
|
|
3652
|
+
* `inherited` carries ancestor params down, which is what lets a child read a
|
|
3653
|
+
* `:id` captured by its layout.
|
|
3654
|
+
*
|
|
3655
|
+
* Exported for unit testing — consumers should rely on
|
|
3656
|
+
* `FlyRemoteRouter.matchedRoute()`.
|
|
3657
|
+
*/
|
|
3658
|
+
function matchFlyRouteTable(routes, segments, inherited = {}) {
|
|
3659
|
+
for (const route of routes) {
|
|
3660
|
+
const prefix = matchFlyRoutePrefix(route.path, segments);
|
|
3661
|
+
if (!prefix)
|
|
3662
|
+
continue;
|
|
3663
|
+
const params = { ...inherited, ...prefix.params };
|
|
3664
|
+
if (!route.children?.length) {
|
|
3665
|
+
if (prefix.rest.length > 0)
|
|
3666
|
+
continue;
|
|
3667
|
+
return { route, params, child: null };
|
|
3668
|
+
}
|
|
3669
|
+
const child = matchFlyRouteTable(route.children, prefix.rest, params);
|
|
3670
|
+
if (child)
|
|
3671
|
+
return { route, params, child };
|
|
3672
|
+
}
|
|
3673
|
+
return null;
|
|
3587
3674
|
}
|
|
3675
|
+
/** Walk a match chain to its leaf — the row that actually consumed the URL. */
|
|
3676
|
+
function deepestFlyMatch(match) {
|
|
3677
|
+
let current = match;
|
|
3678
|
+
while (current.child)
|
|
3679
|
+
current = current.child;
|
|
3680
|
+
return current;
|
|
3681
|
+
}
|
|
3682
|
+
/**
|
|
3683
|
+
* Nesting depth of a `<fly-remote-router-outlet>`, so an outlet knows which link
|
|
3684
|
+
* of the match chain it is responsible for. Each outlet provides its own depth
|
|
3685
|
+
* for its subtree, so the outlet a layout renders resolves to depth + 1 with no
|
|
3686
|
+
* wiring on the consumer's part — the same way Angular's own `RouterOutlet`
|
|
3687
|
+
* derives its level from the injector rather than an input.
|
|
3688
|
+
*
|
|
3689
|
+
* Consumers never provide this themselves.
|
|
3690
|
+
*
|
|
3691
|
+
* Available since design-system **3.12.0**.
|
|
3692
|
+
*/
|
|
3693
|
+
const FLY_REMOTE_OUTLET_DEPTH = new InjectionToken('FLY_REMOTE_OUTLET_DEPTH');
|
|
3588
3694
|
|
|
3589
3695
|
/**
|
|
3590
3696
|
* FlyOS standard navigation surface for Business / Supporting App remotes.
|
|
@@ -3713,16 +3819,12 @@ class FlyRemoteRouter {
|
|
|
3713
3819
|
*
|
|
3714
3820
|
* Match order: routes are tried in declaration order. Put more specific
|
|
3715
3821
|
* patterns (e.g. `'signals/:id'`) before catch-alls.
|
|
3822
|
+
*
|
|
3823
|
+
* On a table using `children` this is the ROOT of the match chain — follow
|
|
3824
|
+
* `.child` for the nested links, which is what the nested outlets do. A flat
|
|
3825
|
+
* table always yields `child: null`, so this reads exactly as it always did.
|
|
3716
3826
|
*/
|
|
3717
|
-
matchedRoute = computed(() => {
|
|
3718
|
-
const segs = this.segments();
|
|
3719
|
-
for (const route of this.routes) {
|
|
3720
|
-
const params = matchFlyRoutePattern(route.path, segs);
|
|
3721
|
-
if (params != null)
|
|
3722
|
-
return { route, params };
|
|
3723
|
-
}
|
|
3724
|
-
return null;
|
|
3725
|
-
}, ...(ngDevMode ? [{ debugName: "matchedRoute" }] : /* istanbul ignore next */ []));
|
|
3827
|
+
matchedRoute = computed(() => matchFlyRouteTable(this.routes, this.segments()), ...(ngDevMode ? [{ debugName: "matchedRoute" }] : /* istanbul ignore next */ []));
|
|
3726
3828
|
/**
|
|
3727
3829
|
* Captured route params from the active route, e.g. `{ id: 'abc' }` for a
|
|
3728
3830
|
* `'signals/:id'` match on `/signals/abc`. Empty object if no route matched
|
|
@@ -3734,7 +3836,13 @@ class FlyRemoteRouter {
|
|
|
3734
3836
|
* readonly signalId = computed(() => this.flyRouter.params()['id'] ?? '');
|
|
3735
3837
|
* ```
|
|
3736
3838
|
*/
|
|
3737
|
-
params = computed(() =>
|
|
3839
|
+
params = computed(() => {
|
|
3840
|
+
const match = this.matchedRoute();
|
|
3841
|
+
// The DEEPEST link, not the root: on a nested table the leaf is the row that
|
|
3842
|
+
// actually consumed the URL, and its params already carry everything its
|
|
3843
|
+
// ancestors captured. Identical to the root on a flat table.
|
|
3844
|
+
return match ? deepestFlyMatch(match).params : {};
|
|
3845
|
+
}, ...(ngDevMode ? [{ debugName: "params" }] : /* istanbul ignore next */ []));
|
|
3738
3846
|
destroyRef = inject(DestroyRef);
|
|
3739
3847
|
constructor() {
|
|
3740
3848
|
if (!this.isEmbedded && this.router) {
|
|
@@ -5271,6 +5379,27 @@ function unwrapLoaded(loaded) {
|
|
|
5271
5379
|
* - No query-param / hash handling — only path segments.
|
|
5272
5380
|
* - No `RouterLink` directive — use `(click)="router.navigate(...)"`.
|
|
5273
5381
|
*
|
|
5382
|
+
* ## Layout routes (3.12.0)
|
|
5383
|
+
*
|
|
5384
|
+
* A route with `children` renders its own component as a LAYOUT and resolves the
|
|
5385
|
+
* rest of the URL into a nested outlet placed in that layout's template:
|
|
5386
|
+
*
|
|
5387
|
+
* ```html
|
|
5388
|
+
* <!-- workspace-layout.component.html -->
|
|
5389
|
+
* <fly-entity-header [entity]="project()" />
|
|
5390
|
+
* <fly-tab-strip [projectId]="id()" />
|
|
5391
|
+
* <fly-remote-router-outlet /> <!-- the tab body, and only the tab body -->
|
|
5392
|
+
* ```
|
|
5393
|
+
*
|
|
5394
|
+
* The layout instance survives navigation between its children, because only the
|
|
5395
|
+
* nested outlet's component changes. That is what stops shared chrome from
|
|
5396
|
+
* re-fetching, re-animating and flashing empty on every tab switch — the failure
|
|
5397
|
+
* this feature exists to remove.
|
|
5398
|
+
*
|
|
5399
|
+
* Nesting is derived from the injector, not declared: each outlet publishes its
|
|
5400
|
+
* own depth to its subtree, so a nested outlet needs no input and no consumer
|
|
5401
|
+
* wiring. Depth beyond the end of the match chain renders nothing.
|
|
5402
|
+
*
|
|
5274
5403
|
* Components rendered by this outlet read route params via `FlyRemoteRouter.params`:
|
|
5275
5404
|
* ```ts
|
|
5276
5405
|
* private readonly router = inject(FlyRemoteRouter);
|
|
@@ -5305,11 +5434,23 @@ function unwrapLoaded(loaded) {
|
|
|
5305
5434
|
class FlyRemoteRouterOutletComponent {
|
|
5306
5435
|
router = inject(FlyRemoteRouter);
|
|
5307
5436
|
errorHandler = inject(ErrorHandler);
|
|
5437
|
+
/** This outlet's link in the match chain — 0 at the root, +1 per nesting. */
|
|
5438
|
+
depth = inject(FLY_REMOTE_OUTLET_DEPTH);
|
|
5308
5439
|
/**
|
|
5309
|
-
*
|
|
5310
|
-
*
|
|
5440
|
+
* The match this outlet is responsible for: `matchedRoute()` walked down
|
|
5441
|
+
* `depth` links. Read directly from FlyRemoteRouter so the outlet re-renders
|
|
5442
|
+
* whenever the URL changes (signal-based, OnPush-friendly).
|
|
5443
|
+
*
|
|
5444
|
+
* `null` past the end of the chain — a nested outlet in a layout whose match
|
|
5445
|
+
* has no child renders nothing rather than repeating its parent.
|
|
5311
5446
|
*/
|
|
5312
|
-
matched =
|
|
5447
|
+
matched = computed(() => {
|
|
5448
|
+
let match = this.router.matchedRoute();
|
|
5449
|
+
for (let level = 0; level < this.depth && match; level++) {
|
|
5450
|
+
match = match.child ?? null;
|
|
5451
|
+
}
|
|
5452
|
+
return match;
|
|
5453
|
+
}, ...(ngDevMode ? [{ debugName: "matched" }] : /* istanbul ignore next */ []));
|
|
5313
5454
|
/** Loaders that have resolved — consulted synchronously, so a revisit never flashes. */
|
|
5314
5455
|
loaded = new Map();
|
|
5315
5456
|
/** Loaders currently in flight, so a param change mid-load doesn't start a second fetch. */
|
|
@@ -5363,10 +5504,19 @@ class FlyRemoteRouterOutletComponent {
|
|
|
5363
5504
|
});
|
|
5364
5505
|
}
|
|
5365
5506
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyRemoteRouterOutletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5366
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyRemoteRouterOutletComponent, isStandalone: true, selector: "fly-remote-router-outlet",
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5507
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyRemoteRouterOutletComponent, isStandalone: true, selector: "fly-remote-router-outlet", providers: [
|
|
5508
|
+
{
|
|
5509
|
+
// Each outlet publishes its own depth to its subtree, so an outlet a
|
|
5510
|
+
// layout renders resolves one level deeper with nothing declared by the
|
|
5511
|
+
// consumer. `skipSelf` reads the ANCESTOR outlet's value; absent (the
|
|
5512
|
+
// top-level outlet) it starts the chain at 0.
|
|
5513
|
+
provide: FLY_REMOTE_OUTLET_DEPTH,
|
|
5514
|
+
useFactory: () => (inject(FLY_REMOTE_OUTLET_DEPTH, { optional: true, skipSelf: true }) ?? -1) + 1,
|
|
5515
|
+
},
|
|
5516
|
+
], ngImport: i0, template: `
|
|
5517
|
+
@if (rendered(); as cmp) {
|
|
5518
|
+
<ng-container *ngComponentOutlet="cmp" />
|
|
5519
|
+
}
|
|
5370
5520
|
`, isInline: true, dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5371
5521
|
}
|
|
5372
5522
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyRemoteRouterOutletComponent, decorators: [{
|
|
@@ -5376,10 +5526,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
5376
5526
|
standalone: true,
|
|
5377
5527
|
imports: [NgComponentOutlet],
|
|
5378
5528
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5529
|
+
providers: [
|
|
5530
|
+
{
|
|
5531
|
+
// Each outlet publishes its own depth to its subtree, so an outlet a
|
|
5532
|
+
// layout renders resolves one level deeper with nothing declared by the
|
|
5533
|
+
// consumer. `skipSelf` reads the ANCESTOR outlet's value; absent (the
|
|
5534
|
+
// top-level outlet) it starts the chain at 0.
|
|
5535
|
+
provide: FLY_REMOTE_OUTLET_DEPTH,
|
|
5536
|
+
useFactory: () => (inject(FLY_REMOTE_OUTLET_DEPTH, { optional: true, skipSelf: true }) ?? -1) + 1,
|
|
5537
|
+
},
|
|
5538
|
+
],
|
|
5539
|
+
template: `
|
|
5540
|
+
@if (rendered(); as cmp) {
|
|
5541
|
+
<ng-container *ngComponentOutlet="cmp" />
|
|
5542
|
+
}
|
|
5383
5543
|
`,
|
|
5384
5544
|
}]
|
|
5385
5545
|
}], ctorParameters: () => [] });
|
|
@@ -9829,11 +9989,11 @@ class FlyBlockUiComponent {
|
|
|
9829
9989
|
return k && k.length > 0 ? k : 'common.loading';
|
|
9830
9990
|
}, ...(ngDevMode ? [{ debugName: "resolvedMessageKey" }] : /* istanbul ignore next */ []));
|
|
9831
9991
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyBlockUiComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9832
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyBlockUiComponent, isStandalone: true, selector: "fly-block-ui", inputs: { active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: true, transformFunction: null }, messageKey: { classPropertyName: "messageKey", publicName: "messageKey", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (active()) {\
|
|
9992
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyBlockUiComponent, isStandalone: true, selector: "fly-block-ui", inputs: { active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: true, transformFunction: null }, messageKey: { classPropertyName: "messageKey", publicName: "messageKey", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (active()) {\n <div\n class=\"fly-block-ui\"\n role=\"status\"\n aria-live=\"polite\"\n aria-busy=\"true\"\n [attr.aria-label]=\"resolvedMessageKey() | translate\">\n <div class=\"fly-block-ui__card\">\n <i class=\"pi pi-spin pi-spinner fly-block-ui__spinner\" aria-hidden=\"true\"></i>\n <span class=\"fly-block-ui__text\">{{ resolvedMessageKey() | translate }}</span>\n </div>\n </div>\n}\n", styles: [":host{display:contents}.fly-block-ui{position:absolute;inset:0;z-index:50;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,var(--surface-ground, #0c0c12) 58%,transparent);-webkit-backdrop-filter:blur(6px) saturate(120%);backdrop-filter:blur(6px) saturate(120%)}.fly-block-ui__card{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 36px;border-radius:12px;background:var(--glass-bg, rgba(255, 255, 255, .14));border:1px solid var(--glass-border, rgba(255, 255, 255, .22));box-shadow:0 8px 32px #0000002e}.fly-block-ui__spinner{font-size:2rem;color:var(--primary-color)}.fly-block-ui__text{font-size:.875rem;color:var(--text-color-secondary)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9833
9993
|
}
|
|
9834
9994
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyBlockUiComponent, decorators: [{
|
|
9835
9995
|
type: Component,
|
|
9836
|
-
args: [{ selector: 'fly-block-ui', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (active()) {\
|
|
9996
|
+
args: [{ selector: 'fly-block-ui', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (active()) {\n <div\n class=\"fly-block-ui\"\n role=\"status\"\n aria-live=\"polite\"\n aria-busy=\"true\"\n [attr.aria-label]=\"resolvedMessageKey() | translate\">\n <div class=\"fly-block-ui__card\">\n <i class=\"pi pi-spin pi-spinner fly-block-ui__spinner\" aria-hidden=\"true\"></i>\n <span class=\"fly-block-ui__text\">{{ resolvedMessageKey() | translate }}</span>\n </div>\n </div>\n}\n", styles: [":host{display:contents}.fly-block-ui{position:absolute;inset:0;z-index:50;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,var(--surface-ground, #0c0c12) 58%,transparent);-webkit-backdrop-filter:blur(6px) saturate(120%);backdrop-filter:blur(6px) saturate(120%)}.fly-block-ui__card{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 36px;border-radius:12px;background:var(--glass-bg, rgba(255, 255, 255, .14));border:1px solid var(--glass-border, rgba(255, 255, 255, .22));box-shadow:0 8px 32px #0000002e}.fly-block-ui__spinner{font-size:2rem;color:var(--primary-color)}.fly-block-ui__text{font-size:.875rem;color:var(--text-color-secondary)}\n"] }]
|
|
9837
9997
|
}], propDecorators: { active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: true }] }], messageKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "messageKey", required: false }] }] } });
|
|
9838
9998
|
|
|
9839
9999
|
const STATE_KEY = {
|
|
@@ -20134,11 +20294,11 @@ class FlyPeoplePickerComponent {
|
|
|
20134
20294
|
this.selectionChange.emit(this._selected().map((o) => o.id));
|
|
20135
20295
|
}
|
|
20136
20296
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyPeoplePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
20137
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyPeoplePickerComponent, isStandalone: true, selector: "fly-people-picker", inputs: { searchFn: { classPropertyName: "searchFn", publicName: "searchFn", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, excludeIds: { classPropertyName: "excludeIds", publicName: "excludeIds", isSignal: true, isRequired: false, transformFunction: null }, initialSelection: { classPropertyName: "initialSelection", publicName: "initialSelection", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { classAttribute: "fly-people-picker" }, viewQueries: [{ propertyName: "typeahead", first: true, predicate: FlyTypeaheadComponent, descendants: true }], ngImport: i0, template: "@if (selected().length > 0) {\
|
|
20297
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyPeoplePickerComponent, isStandalone: true, selector: "fly-people-picker", inputs: { searchFn: { classPropertyName: "searchFn", publicName: "searchFn", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, excludeIds: { classPropertyName: "excludeIds", publicName: "excludeIds", isSignal: true, isRequired: false, transformFunction: null }, initialSelection: { classPropertyName: "initialSelection", publicName: "initialSelection", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { classAttribute: "fly-people-picker" }, viewQueries: [{ propertyName: "typeahead", first: true, predicate: FlyTypeaheadComponent, descendants: true }], ngImport: i0, template: "@if (selected().length > 0) {\n <ul class=\"fly-people-picker__chips\" role=\"list\">\n @for (o of selected(); track o.id) {\n <li class=\"fly-people-picker__chip\" role=\"listitem\">\n <span class=\"fly-people-picker__chip-avatar\" aria-hidden=\"true\">\n @if (o.avatarUrl) {\n <img [src]=\"o.avatarUrl\" alt=\"\" />\n } @else {\n <span class=\"fly-people-picker__chip-initials\">{{ initialsFor(o.displayName) }}</span>\n }\n </span>\n <span class=\"fly-people-picker__chip-name\" [title]=\"o.email || o.displayName\">{{ o.displayName }}</span>\n <button\n type=\"button\"\n class=\"fly-people-picker__chip-remove\"\n [attr.aria-label]=\"'people_picker.remove' | translate: { name: o.displayName }\"\n (click)=\"remove(o.id)\">\n \u2715\n </button>\n </li>\n }\n </ul>\n}\n\n@if (showSearch()) {\n <fly-typeahead\n [searchFn]=\"typeaheadSearchFn\"\n [placeholder]=\"placeholder() || ('people_picker.search_placeholder' | translate)\"\n [allowFreeText]=\"false\"\n (selected)=\"onPicked($event)\" />\n} @else {\n <button type=\"button\" class=\"fly-people-picker__change-btn\" (click)=\"change()\">\n {{ 'people_picker.change' | translate }}\n </button>\n}\n", styles: [":host,:host *,:host *:before,:host *:after{box-sizing:border-box}:host{--_surface: var(--surface-card, #fff);--_surface-hover: var(--surface-hover, #f1f5f9);--_border: var(--separator, var(--surface-border, #e2e8f0));--_text: var(--label-primary, var(--text-color, #0f172a));--_text-subtle: var(--label-secondary, var(--text-color-secondary, #64748b));--_fill: var(--fill-tertiary, #f3f4f6);--_accent: var(--accent);--_danger: var(--system-red, #ef4444);--_radius: 999px;display:flex;flex-direction:column;gap:8px;inline-size:100%;color:var(--_text);font-size:13px}.fly-people-picker__chips{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}.fly-people-picker__chip{display:inline-flex;align-items:center;gap:6px;padding-block:3px;padding-inline:3px 6px;border-radius:var(--_radius);background:var(--_fill);max-inline-size:220px}.fly-people-picker__chip-avatar{inline-size:22px;block-size:22px;border-radius:50%;overflow:hidden;flex:none;background:var(--_surface);display:flex;align-items:center;justify-content:center}.fly-people-picker__chip-avatar img{inline-size:100%;block-size:100%;object-fit:cover}.fly-people-picker__chip-initials{font-size:9px;font-weight:700;color:var(--_text-subtle);text-transform:uppercase}.fly-people-picker__chip-name{font-size:12px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fly-people-picker__chip-remove{border:none;background:transparent;padding:2px;margin-inline-start:2px;border-radius:50%;color:var(--_text-subtle);font-size:10px;line-height:1;cursor:pointer;flex:none}.fly-people-picker__chip-remove:hover{background:color-mix(in srgb,var(--_danger) 18%,transparent);color:var(--_danger)}.fly-people-picker__change-btn{align-self:flex-start;border:1px solid var(--_border);border-radius:8px;background:var(--_surface);padding:5px 12px;color:var(--_text);font:inherit;font-weight:600;cursor:pointer}.fly-people-picker__change-btn:hover{background:var(--_surface-hover)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: FlyTypeaheadComponent, selector: "fly-typeahead", inputs: ["searchFn", "debounceMs", "placeholder", "ariaLabel", "value", "allowFreeText", "openOnFocus"], outputs: ["valueChange", "selected", "cleared"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
20138
20298
|
}
|
|
20139
20299
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyPeoplePickerComponent, decorators: [{
|
|
20140
20300
|
type: Component,
|
|
20141
|
-
args: [{ selector: 'fly-people-picker', standalone: true, imports: [CommonModule, TranslatePipe, FlyTypeaheadComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'fly-people-picker' }, template: "@if (selected().length > 0) {\
|
|
20301
|
+
args: [{ selector: 'fly-people-picker', standalone: true, imports: [CommonModule, TranslatePipe, FlyTypeaheadComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'fly-people-picker' }, template: "@if (selected().length > 0) {\n <ul class=\"fly-people-picker__chips\" role=\"list\">\n @for (o of selected(); track o.id) {\n <li class=\"fly-people-picker__chip\" role=\"listitem\">\n <span class=\"fly-people-picker__chip-avatar\" aria-hidden=\"true\">\n @if (o.avatarUrl) {\n <img [src]=\"o.avatarUrl\" alt=\"\" />\n } @else {\n <span class=\"fly-people-picker__chip-initials\">{{ initialsFor(o.displayName) }}</span>\n }\n </span>\n <span class=\"fly-people-picker__chip-name\" [title]=\"o.email || o.displayName\">{{ o.displayName }}</span>\n <button\n type=\"button\"\n class=\"fly-people-picker__chip-remove\"\n [attr.aria-label]=\"'people_picker.remove' | translate: { name: o.displayName }\"\n (click)=\"remove(o.id)\">\n \u2715\n </button>\n </li>\n }\n </ul>\n}\n\n@if (showSearch()) {\n <fly-typeahead\n [searchFn]=\"typeaheadSearchFn\"\n [placeholder]=\"placeholder() || ('people_picker.search_placeholder' | translate)\"\n [allowFreeText]=\"false\"\n (selected)=\"onPicked($event)\" />\n} @else {\n <button type=\"button\" class=\"fly-people-picker__change-btn\" (click)=\"change()\">\n {{ 'people_picker.change' | translate }}\n </button>\n}\n", styles: [":host,:host *,:host *:before,:host *:after{box-sizing:border-box}:host{--_surface: var(--surface-card, #fff);--_surface-hover: var(--surface-hover, #f1f5f9);--_border: var(--separator, var(--surface-border, #e2e8f0));--_text: var(--label-primary, var(--text-color, #0f172a));--_text-subtle: var(--label-secondary, var(--text-color-secondary, #64748b));--_fill: var(--fill-tertiary, #f3f4f6);--_accent: var(--accent);--_danger: var(--system-red, #ef4444);--_radius: 999px;display:flex;flex-direction:column;gap:8px;inline-size:100%;color:var(--_text);font-size:13px}.fly-people-picker__chips{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}.fly-people-picker__chip{display:inline-flex;align-items:center;gap:6px;padding-block:3px;padding-inline:3px 6px;border-radius:var(--_radius);background:var(--_fill);max-inline-size:220px}.fly-people-picker__chip-avatar{inline-size:22px;block-size:22px;border-radius:50%;overflow:hidden;flex:none;background:var(--_surface);display:flex;align-items:center;justify-content:center}.fly-people-picker__chip-avatar img{inline-size:100%;block-size:100%;object-fit:cover}.fly-people-picker__chip-initials{font-size:9px;font-weight:700;color:var(--_text-subtle);text-transform:uppercase}.fly-people-picker__chip-name{font-size:12px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fly-people-picker__chip-remove{border:none;background:transparent;padding:2px;margin-inline-start:2px;border-radius:50%;color:var(--_text-subtle);font-size:10px;line-height:1;cursor:pointer;flex:none}.fly-people-picker__chip-remove:hover{background:color-mix(in srgb,var(--_danger) 18%,transparent);color:var(--_danger)}.fly-people-picker__change-btn{align-self:flex-start;border:1px solid var(--_border);border-radius:8px;background:var(--_surface);padding:5px 12px;color:var(--_text);font:inherit;font-weight:600;cursor:pointer}.fly-people-picker__change-btn:hover{background:var(--_surface-hover)}\n"] }]
|
|
20142
20302
|
}], ctorParameters: () => [], propDecorators: { searchFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchFn", required: true }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], excludeIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "excludeIds", required: false }] }], initialSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialSelection", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], typeahead: [{
|
|
20143
20303
|
type: ViewChild,
|
|
20144
20304
|
args: [FlyTypeaheadComponent]
|
|
@@ -23103,6 +23263,298 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
23103
23263
|
args: [{ selector: 'fly-meta', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<dl>\r\n @for (item of items(); track $index) {\r\n <div>\r\n <dt>{{ item.labelKey | translate }}</dt>\r\n <dd [class.mono]=\"item.mono ?? false\">{{ item.value }}</dd>\r\n </div>\r\n }\r\n <ng-content />\r\n</dl>\r\n", styles: [":host{display:block}dl{margin:0;display:flex;flex-direction:column;gap:10px}dl ::ng-deep>div{display:grid;grid-template-columns:96px 1fr;gap:var(--sp-3);align-items:baseline;font-size:var(--text-sm)}dl ::ng-deep dt{margin:0;font-size:10.5px;font-weight:var(--fw-medium);letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--ink-4)}dl ::ng-deep dd{margin:0;min-width:0;color:var(--ink);word-break:break-word;line-height:1.45}dl ::ng-deep dd.mono,dl ::ng-deep dd .mono{font-size:var(--text-2xs)}\n"] }]
|
|
23104
23264
|
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }] } });
|
|
23105
23265
|
|
|
23266
|
+
/**
|
|
23267
|
+
* Generic Overview-section content surface — the `--w03`/`--w06` tinted
|
|
23268
|
+
* plate a non-card section body (Description text, a chips tray, a members
|
|
23269
|
+
* tray, an activity tray) sits on inside a {@link FlyOverviewSectionComponent}.
|
|
23270
|
+
* Deliberately presentation-only: no shadow, gradient, hover, or cursor —
|
|
23271
|
+
* this is quiet inner paper, not a clickable surface.
|
|
23272
|
+
*
|
|
23273
|
+
* Content is left to projection so each Overview variant keeps its own real
|
|
23274
|
+
* markup (and, for Members/Chips/Activity, its own live Angular bindings and
|
|
23275
|
+
* interactions) — this component only paints the box.
|
|
23276
|
+
*
|
|
23277
|
+
* `[proseText]` additionally applies the Description-section body-copy
|
|
23278
|
+
* typography directly on the host, for the common case of one bound string
|
|
23279
|
+
* with nothing else inside. Leave it off for any other content (chips,
|
|
23280
|
+
* member rows, a nested `fly-overview-rows`) — those bring their own type.
|
|
23281
|
+
*
|
|
23282
|
+
* ```html
|
|
23283
|
+
* <fly-overview-surface [proseText]="true">{{ project().description }}</fly-overview-surface>
|
|
23284
|
+
*
|
|
23285
|
+
* <fly-overview-surface>
|
|
23286
|
+
* @for (m of project().members; track m.id) { <fly-chip>{{ m.name }}</fly-chip> }
|
|
23287
|
+
* </fly-overview-surface>
|
|
23288
|
+
* ```
|
|
23289
|
+
*/
|
|
23290
|
+
class FlyOverviewSurfaceComponent {
|
|
23291
|
+
/** Apply the Description-section body-copy typography on the host. */
|
|
23292
|
+
proseText = input(false, ...(ngDevMode ? [{ debugName: "proseText" }] : /* istanbul ignore next */ []));
|
|
23293
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewSurfaceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
23294
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.19", type: FlyOverviewSurfaceComponent, isStandalone: true, selector: "fly-overview-surface", inputs: { proseText: { classPropertyName: "proseText", publicName: "proseText", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.ovsf--prose": "proseText()" }, classAttribute: "ovsf" }, ngImport: i0, template: '<ng-content />', isInline: true, styles: [":host{display:block;padding:12px 14px;border-radius:11px;background:var(--w03);border:1px solid var(--w06)}:host(.ovsf--prose){font-family:var(--font-family);font-weight:400;font-size:13px;line-height:1.55;color:var(--w72);text-wrap:pretty}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
23295
|
+
}
|
|
23296
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewSurfaceComponent, decorators: [{
|
|
23297
|
+
type: Component,
|
|
23298
|
+
args: [{ selector: 'fly-overview-surface', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
23299
|
+
class: 'ovsf',
|
|
23300
|
+
'[class.ovsf--prose]': 'proseText()',
|
|
23301
|
+
}, template: '<ng-content />', styles: [":host{display:block;padding:12px 14px;border-radius:11px;background:var(--w03);border:1px solid var(--w06)}:host(.ovsf--prose){font-family:var(--font-family);font-weight:400;font-size:13px;line-height:1.55;color:var(--w72);text-wrap:pretty}\n"] }]
|
|
23302
|
+
}], propDecorators: { proseText: [{ type: i0.Input, args: [{ isSignal: true, alias: "proseText", required: false }] }] } });
|
|
23303
|
+
|
|
23304
|
+
/**
|
|
23305
|
+
* Overview "Summary" KPI row — a wrapping row of flat stat cards, each with
|
|
23306
|
+
* the value/label stack at inline-start and the icon on a solid tone tile at
|
|
23307
|
+
* inline-end (the KPI-tile treatment, 2026-08-20 fidelity pass).
|
|
23308
|
+
* `order: 1`/`order: 2` (not `flex-direction: row-reverse`) drive that split
|
|
23309
|
+
* so the layout auto-mirrors under `dir="rtl"`: inline-start/-end follow
|
|
23310
|
+
* direction, a fixed left/right would not.
|
|
23311
|
+
*
|
|
23312
|
+
* Default layout is a wrapping flex row (any item count degrades gracefully);
|
|
23313
|
+
* a design that pins an exact no-reflow column count (the Project-Details
|
|
23314
|
+
* Overview pins five) passes `columns` instead.
|
|
23315
|
+
*
|
|
23316
|
+
* ```html
|
|
23317
|
+
* <fly-overview-kpi-row [columns]="5" [items]="[
|
|
23318
|
+
* { icon: 'pi-chart-line', value: '64%', labelKey: 'ppm.projects.overview.progress', tone: 'blue' },
|
|
23319
|
+
* { icon: 'pi-flag', value: '3/8', labelKey: 'ppm.projects.overview.milestones', tone: 'purple' },
|
|
23320
|
+
* ]" />
|
|
23321
|
+
* ```
|
|
23322
|
+
*/
|
|
23323
|
+
class FlyOverviewKpiRowComponent {
|
|
23324
|
+
items = input.required(...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
23325
|
+
/** Exact equal-width column count (no reflow). Omit for the default wrapping flex row. */
|
|
23326
|
+
columns = input(...(ngDevMode ? [undefined, { debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
23327
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewKpiRowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
23328
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyOverviewKpiRowComponent, isStandalone: true, selector: "fly-overview-kpi-row", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
23329
|
+
<div class="okr" [class.okr--grid]="columns() != null" [style.--okr-columns]="columns()">
|
|
23330
|
+
@for (item of items(); track item.labelKey) {
|
|
23331
|
+
<div class="okr__card" [attr.data-tone]="item.tone">
|
|
23332
|
+
<div class="okr__text">
|
|
23333
|
+
<span class="okr__value">{{ item.value }}</span>
|
|
23334
|
+
<span class="okr__label">{{ item.labelKey | translate }}</span>
|
|
23335
|
+
</div>
|
|
23336
|
+
<i class="pi {{ item.icon }} okr__icon" aria-hidden="true"></i>
|
|
23337
|
+
</div>
|
|
23338
|
+
}
|
|
23339
|
+
</div>
|
|
23340
|
+
`, isInline: true, styles: [":host{display:block}.okr{display:flex;align-items:stretch;gap:10px;flex-wrap:wrap}.okr--grid{--okr-columns: 1;display:grid;grid-template-columns:repeat(var(--okr-columns),minmax(0,1fr))}.okr__card{flex:1;min-width:150px;display:flex;align-items:center;gap:11px;padding:13px 14px;border-radius:var(--r-lg);background:var(--w03);border:1px solid var(--w06)}.okr__card[data-tone=blue]{--okr-tone: var(--sys-blue)}.okr__card[data-tone=purple]{--okr-tone: var(--sys-purple)}.okr__card[data-tone=orange]{--okr-tone: var(--sys-orange)}.okr__card[data-tone=red]{--okr-tone: var(--sys-red)}.okr__card[data-tone=teal]{--okr-tone: var(--sys-teal)}.okr__text{order:1;flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.okr__icon{order:2;flex:none;inline-size:32px;block-size:32px;border-radius:9px;display:grid;place-items:center;background:var(--okr-tone, var(--w6));color:var(--ink-inverse);font-size:15px}.okr__value{font-family:var(--font-family-display);font-weight:var(--fw-bold);font-size:20px;line-height:1;letter-spacing:var(--tracking-tight);font-variant-numeric:tabular-nums;color:var(--ink)}.okr__label{font-family:var(--font-family);font-weight:var(--fw-medium);font-size:var(--text-2xs);line-height:1.2;color:var(--w45)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
23341
|
+
}
|
|
23342
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewKpiRowComponent, decorators: [{
|
|
23343
|
+
type: Component,
|
|
23344
|
+
args: [{ selector: 'fly-overview-kpi-row', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
23345
|
+
<div class="okr" [class.okr--grid]="columns() != null" [style.--okr-columns]="columns()">
|
|
23346
|
+
@for (item of items(); track item.labelKey) {
|
|
23347
|
+
<div class="okr__card" [attr.data-tone]="item.tone">
|
|
23348
|
+
<div class="okr__text">
|
|
23349
|
+
<span class="okr__value">{{ item.value }}</span>
|
|
23350
|
+
<span class="okr__label">{{ item.labelKey | translate }}</span>
|
|
23351
|
+
</div>
|
|
23352
|
+
<i class="pi {{ item.icon }} okr__icon" aria-hidden="true"></i>
|
|
23353
|
+
</div>
|
|
23354
|
+
}
|
|
23355
|
+
</div>
|
|
23356
|
+
`, styles: [":host{display:block}.okr{display:flex;align-items:stretch;gap:10px;flex-wrap:wrap}.okr--grid{--okr-columns: 1;display:grid;grid-template-columns:repeat(var(--okr-columns),minmax(0,1fr))}.okr__card{flex:1;min-width:150px;display:flex;align-items:center;gap:11px;padding:13px 14px;border-radius:var(--r-lg);background:var(--w03);border:1px solid var(--w06)}.okr__card[data-tone=blue]{--okr-tone: var(--sys-blue)}.okr__card[data-tone=purple]{--okr-tone: var(--sys-purple)}.okr__card[data-tone=orange]{--okr-tone: var(--sys-orange)}.okr__card[data-tone=red]{--okr-tone: var(--sys-red)}.okr__card[data-tone=teal]{--okr-tone: var(--sys-teal)}.okr__text{order:1;flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.okr__icon{order:2;flex:none;inline-size:32px;block-size:32px;border-radius:9px;display:grid;place-items:center;background:var(--okr-tone, var(--w6));color:var(--ink-inverse);font-size:15px}.okr__value{font-family:var(--font-family-display);font-weight:var(--fw-bold);font-size:20px;line-height:1;letter-spacing:var(--tracking-tight);font-variant-numeric:tabular-nums;color:var(--ink)}.okr__label{font-family:var(--font-family);font-weight:var(--fw-medium);font-size:var(--text-2xs);line-height:1.2;color:var(--w45)}\n"] }]
|
|
23357
|
+
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }] } });
|
|
23358
|
+
|
|
23359
|
+
/**
|
|
23360
|
+
* Overview "Details" body — a self-contained `--w03`/`--w06` surface holding
|
|
23361
|
+
* label/value rows. Distinct from {@link FlyMetaListComponent} (`fly-meta`):
|
|
23362
|
+
* that component is the compact sidecard metalist (96px label column,
|
|
23363
|
+
* uppercase eyebrow labels, no surrounding surface — it expects to sit
|
|
23364
|
+
* inside a `fly-detail-card`), while this one is the wider Overview-page
|
|
23365
|
+
* "Details" block (132px label column, sentence-case labels, and the surface
|
|
23366
|
+
* built in) — the two visual specs don't share numbers, so this stays its
|
|
23367
|
+
* own component rather than a variant of the sidecard one.
|
|
23368
|
+
*
|
|
23369
|
+
* Simple rows come from `rows`; a richer value (a link, a chip, a user
|
|
23370
|
+
* label) projects through the default slot — reuse the `ovr__row` /
|
|
23371
|
+
* `ovr__label` / `ovr__value` classes on the projected markup to pick up the
|
|
23372
|
+
* same layout.
|
|
23373
|
+
*
|
|
23374
|
+
* ```html
|
|
23375
|
+
* <fly-overview-rows [rows]="[
|
|
23376
|
+
* { labelKey: 'ppm.projects.overview.owner', value: project().ownerName },
|
|
23377
|
+
* { labelKey: 'ppm.projects.overview.dueDate', value: project().dueDateLabel },
|
|
23378
|
+
* ]">
|
|
23379
|
+
* <div class="ovr__row">
|
|
23380
|
+
* <span class="ovr__label">{{ 'ppm.projects.overview.strategy' | translate }}</span>
|
|
23381
|
+
* <a class="ovr__value" [routerLink]="['/strategies', project().strategyId]">{{ project().strategyName }}</a>
|
|
23382
|
+
* </div>
|
|
23383
|
+
* </fly-overview-rows>
|
|
23384
|
+
* ```
|
|
23385
|
+
*/
|
|
23386
|
+
class FlyOverviewRowsComponent {
|
|
23387
|
+
rows = input([], ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
23388
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewRowsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
23389
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyOverviewRowsComponent, isStandalone: true, selector: "fly-overview-rows", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
23390
|
+
<div class="ovr">
|
|
23391
|
+
@for (row of rows(); track row.labelKey) {
|
|
23392
|
+
<div class="ovr__row">
|
|
23393
|
+
<span class="ovr__label">{{ row.labelKey | translate }}</span>
|
|
23394
|
+
<span class="ovr__value">{{ row.value }}</span>
|
|
23395
|
+
</div>
|
|
23396
|
+
}
|
|
23397
|
+
<ng-content />
|
|
23398
|
+
</div>
|
|
23399
|
+
`, isInline: true, styles: [":host{display:block}.ovr{display:flex;flex-direction:column;gap:9px;padding:12px 14px;border-radius:11px;background:var(--w03);border:1px solid var(--w06)}.ovr ::ng-deep .ovr__row{display:flex;align-items:baseline;gap:14px}.ovr ::ng-deep .ovr__label{flex:0 0 auto;width:132px;font-family:var(--font-family);font-weight:var(--fw-medium);font-size:12px;line-height:1.4;color:var(--w45)}.ovr ::ng-deep .ovr__value{flex:1;min-width:0;font-family:var(--font-family);font-weight:var(--fw-medium);font-size:var(--text-sm);line-height:1.4;color:var(--w85)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
23400
|
+
}
|
|
23401
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewRowsComponent, decorators: [{
|
|
23402
|
+
type: Component,
|
|
23403
|
+
args: [{ selector: 'fly-overview-rows', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
23404
|
+
<div class="ovr">
|
|
23405
|
+
@for (row of rows(); track row.labelKey) {
|
|
23406
|
+
<div class="ovr__row">
|
|
23407
|
+
<span class="ovr__label">{{ row.labelKey | translate }}</span>
|
|
23408
|
+
<span class="ovr__value">{{ row.value }}</span>
|
|
23409
|
+
</div>
|
|
23410
|
+
}
|
|
23411
|
+
<ng-content />
|
|
23412
|
+
</div>
|
|
23413
|
+
`, styles: [":host{display:block}.ovr{display:flex;flex-direction:column;gap:9px;padding:12px 14px;border-radius:11px;background:var(--w03);border:1px solid var(--w06)}.ovr ::ng-deep .ovr__row{display:flex;align-items:baseline;gap:14px}.ovr ::ng-deep .ovr__label{flex:0 0 auto;width:132px;font-family:var(--font-family);font-weight:var(--fw-medium);font-size:12px;line-height:1.4;color:var(--w45)}.ovr ::ng-deep .ovr__value{flex:1;min-width:0;font-family:var(--font-family);font-weight:var(--fw-medium);font-size:var(--text-sm);line-height:1.4;color:var(--w85)}\n"] }]
|
|
23414
|
+
}], propDecorators: { rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }] } });
|
|
23415
|
+
|
|
23416
|
+
/**
|
|
23417
|
+
* Project-lifecycle phase-gate stepper — the Overview-section kit's fourth
|
|
23418
|
+
* body variant. Summary/Description/Details are `fly-overview-kpi-row` /
|
|
23419
|
+
* `-surface` / `-rows`; this is the "Lifecycle" section's own body, per
|
|
23420
|
+
* `fly-overview-section`'s own doc comment ("Lifecycle's 'Move to' actions").
|
|
23421
|
+
* A caller resolves the gate vocabulary (approved/in-progress/not-started, …)
|
|
23422
|
+
* into an already-formatted `tone` per step — this component stays
|
|
23423
|
+
* domain-agnostic, same discipline as `OverviewKpiItem`/`OverviewRow`. Step
|
|
23424
|
+
* names accept either an i18n `labelKey` or a verbatim `label`, because real
|
|
23425
|
+
* lifecycles carry server-provided gate names that are data, not locale keys.
|
|
23426
|
+
*
|
|
23427
|
+
* The index badge and the trailing `fly-chip` always share one color, driven
|
|
23428
|
+
* by the SAME `tone` field, so the two never drift out of sync. A
|
|
23429
|
+
* `success`-toned step swaps its numeral for a check mark. The optional
|
|
23430
|
+
* rollup strip is a flat tally legend, not another `fly-overview-rows` (that
|
|
23431
|
+
* component's 132px label column is built for a vertical "Details" block,
|
|
23432
|
+
* not an inline summary strip).
|
|
23433
|
+
*
|
|
23434
|
+
* ```html
|
|
23435
|
+
* <fly-lifecycle-pipeline ariaLabelKey="ppm.projects.lifecycle.stagesLabel" [steps]="[
|
|
23436
|
+
* { labelKey: 'ppm.projects.lifecycle.phase1Gate', statusLabelKey: 'common.status.approved', tone: 'success', progress: '1 / 1' },
|
|
23437
|
+
* { labelKey: 'ppm.projects.lifecycle.phase2Gate', statusLabelKey: 'ppm.projects.lifecycle.status.inProgress', tone: 'accent', current: true },
|
|
23438
|
+
* { labelKey: 'ppm.projects.lifecycle.closureGate', statusLabelKey: 'ppm.projects.lifecycle.status.notStarted', tone: 'neutral' },
|
|
23439
|
+
* ]" [rollup]="[
|
|
23440
|
+
* { labelKey: 'ppm.projects.lifecycle.rollup.planned', value: 2 },
|
|
23441
|
+
* { labelKey: 'ppm.projects.lifecycle.rollup.inProgress', value: 2 },
|
|
23442
|
+
* ]" />
|
|
23443
|
+
* ```
|
|
23444
|
+
*/
|
|
23445
|
+
class FlyLifecyclePipelineComponent {
|
|
23446
|
+
steps = input.required(...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
|
|
23447
|
+
rollup = input([], ...(ngDevMode ? [{ debugName: "rollup" }] : /* istanbul ignore next */ []));
|
|
23448
|
+
/** i18n key for the `role="list"` accessible name. */
|
|
23449
|
+
ariaLabelKey = input.required(...(ngDevMode ? [{ debugName: "ariaLabelKey" }] : /* istanbul ignore next */ []));
|
|
23450
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyLifecyclePipelineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
23451
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyLifecyclePipelineComponent, isStandalone: true, selector: "fly-lifecycle-pipeline", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: true, transformFunction: null }, rollup: { classPropertyName: "rollup", publicName: "rollup", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelKey: { classPropertyName: "ariaLabelKey", publicName: "ariaLabelKey", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
23452
|
+
<div class="lp">
|
|
23453
|
+
<div class="lp__row" role="list" [attr.aria-label]="ariaLabelKey() | translate">
|
|
23454
|
+
@for (
|
|
23455
|
+
step of steps();
|
|
23456
|
+
track step.label ?? step.labelKey;
|
|
23457
|
+
let i = $index;
|
|
23458
|
+
let last = $last
|
|
23459
|
+
) {
|
|
23460
|
+
<div
|
|
23461
|
+
class="lp__step"
|
|
23462
|
+
[class.lp__step--current]="step.current"
|
|
23463
|
+
role="listitem"
|
|
23464
|
+
[attr.aria-current]="step.current ? 'step' : null"
|
|
23465
|
+
>
|
|
23466
|
+
<span class="lp__index" [attr.data-tone]="step.tone">
|
|
23467
|
+
@if (step.tone === 'success') {
|
|
23468
|
+
<i class="pi pi-check" aria-hidden="true"></i>
|
|
23469
|
+
} @else {
|
|
23470
|
+
{{ i + 1 }}
|
|
23471
|
+
}
|
|
23472
|
+
</span>
|
|
23473
|
+
<span class="lp__name">
|
|
23474
|
+
@if (step.label) {
|
|
23475
|
+
{{ step.label }}
|
|
23476
|
+
} @else if (step.labelKey) {
|
|
23477
|
+
{{ step.labelKey | translate }}
|
|
23478
|
+
}
|
|
23479
|
+
</span>
|
|
23480
|
+
<fly-chip [tone]="step.tone">{{ step.statusLabelKey | translate }}</fly-chip>
|
|
23481
|
+
@if (step.progress) {
|
|
23482
|
+
<span class="lp__progress">{{ step.progress }}</span>
|
|
23483
|
+
}
|
|
23484
|
+
</div>
|
|
23485
|
+
@if (!last) {
|
|
23486
|
+
<span class="lp__connector" aria-hidden="true"></span>
|
|
23487
|
+
}
|
|
23488
|
+
}
|
|
23489
|
+
</div>
|
|
23490
|
+
@if (rollup().length) {
|
|
23491
|
+
<div class="lp__rollup">
|
|
23492
|
+
@for (item of rollup(); track item.labelKey) {
|
|
23493
|
+
<span class="lp__rollup-item">
|
|
23494
|
+
<span class="lp__rollup-label">{{ item.labelKey | translate }}</span>
|
|
23495
|
+
<span class="lp__rollup-value">{{ item.value }}</span>
|
|
23496
|
+
</span>
|
|
23497
|
+
}
|
|
23498
|
+
</div>
|
|
23499
|
+
}
|
|
23500
|
+
</div>
|
|
23501
|
+
`, isInline: true, styles: [":host{display:block}.lp{display:flex;flex-direction:column;gap:var(--sp-3)}.lp__row{display:flex;align-items:center;flex-wrap:wrap;row-gap:var(--sp-3)}.lp__step{display:flex;align-items:center;gap:var(--sp-2);padding:6px 10px;border-radius:var(--r-lg);border:1px solid transparent}.lp__step--current{border-color:var(--accent-fill);background:var(--tint-sel)}.lp__index{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:22px;height:22px;border-radius:999px;font-family:var(--font-family);font-size:11px;font-weight:var(--fw-bold);line-height:1}.lp__index .pi{font-size:10px}.lp__index[data-tone=neutral]{background:var(--w06);color:var(--w85)}.lp__index[data-tone=accent]{background:var(--accent-fill);color:var(--on-accent-fill)}.lp__index[data-tone=success]{background:var(--success-bg);color:var(--success)}.lp__index[data-tone=warning]{background:var(--warning-bg);color:var(--warning-fg)}.lp__index[data-tone=danger]{background:var(--danger-bg);color:var(--danger)}.lp__name{font-family:var(--font-family);font-weight:var(--fw-medium);font-size:var(--text-sm);color:var(--ink);white-space:nowrap}.lp__step--current .lp__name{font-weight:var(--fw-bold)}.lp__progress{font-family:var(--font-family);font-size:var(--text-xs);color:var(--w45);font-variant-numeric:tabular-nums}.lp__connector{flex:1 1 32px;min-width:20px;height:1px;background:var(--w16);margin-inline:2px}.lp__rollup{display:flex;flex-wrap:wrap;gap:var(--sp-1) var(--sp-4);padding-block-start:var(--sp-2);border-block-start:1px solid var(--w06)}.lp__rollup-item{display:inline-flex;align-items:baseline;gap:5px;font-family:var(--font-family);font-size:var(--text-xs)}.lp__rollup-label{color:var(--w45)}.lp__rollup-value{color:var(--w85);font-weight:var(--fw-bold);font-variant-numeric:tabular-nums}\n"], dependencies: [{ kind: "component", type: FlyChipComponent, selector: "fly-chip", inputs: ["tone"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
23502
|
+
}
|
|
23503
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyLifecyclePipelineComponent, decorators: [{
|
|
23504
|
+
type: Component,
|
|
23505
|
+
args: [{ selector: 'fly-lifecycle-pipeline', standalone: true, imports: [TranslatePipe, FlyChipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
23506
|
+
<div class="lp">
|
|
23507
|
+
<div class="lp__row" role="list" [attr.aria-label]="ariaLabelKey() | translate">
|
|
23508
|
+
@for (
|
|
23509
|
+
step of steps();
|
|
23510
|
+
track step.label ?? step.labelKey;
|
|
23511
|
+
let i = $index;
|
|
23512
|
+
let last = $last
|
|
23513
|
+
) {
|
|
23514
|
+
<div
|
|
23515
|
+
class="lp__step"
|
|
23516
|
+
[class.lp__step--current]="step.current"
|
|
23517
|
+
role="listitem"
|
|
23518
|
+
[attr.aria-current]="step.current ? 'step' : null"
|
|
23519
|
+
>
|
|
23520
|
+
<span class="lp__index" [attr.data-tone]="step.tone">
|
|
23521
|
+
@if (step.tone === 'success') {
|
|
23522
|
+
<i class="pi pi-check" aria-hidden="true"></i>
|
|
23523
|
+
} @else {
|
|
23524
|
+
{{ i + 1 }}
|
|
23525
|
+
}
|
|
23526
|
+
</span>
|
|
23527
|
+
<span class="lp__name">
|
|
23528
|
+
@if (step.label) {
|
|
23529
|
+
{{ step.label }}
|
|
23530
|
+
} @else if (step.labelKey) {
|
|
23531
|
+
{{ step.labelKey | translate }}
|
|
23532
|
+
}
|
|
23533
|
+
</span>
|
|
23534
|
+
<fly-chip [tone]="step.tone">{{ step.statusLabelKey | translate }}</fly-chip>
|
|
23535
|
+
@if (step.progress) {
|
|
23536
|
+
<span class="lp__progress">{{ step.progress }}</span>
|
|
23537
|
+
}
|
|
23538
|
+
</div>
|
|
23539
|
+
@if (!last) {
|
|
23540
|
+
<span class="lp__connector" aria-hidden="true"></span>
|
|
23541
|
+
}
|
|
23542
|
+
}
|
|
23543
|
+
</div>
|
|
23544
|
+
@if (rollup().length) {
|
|
23545
|
+
<div class="lp__rollup">
|
|
23546
|
+
@for (item of rollup(); track item.labelKey) {
|
|
23547
|
+
<span class="lp__rollup-item">
|
|
23548
|
+
<span class="lp__rollup-label">{{ item.labelKey | translate }}</span>
|
|
23549
|
+
<span class="lp__rollup-value">{{ item.value }}</span>
|
|
23550
|
+
</span>
|
|
23551
|
+
}
|
|
23552
|
+
</div>
|
|
23553
|
+
}
|
|
23554
|
+
</div>
|
|
23555
|
+
`, styles: [":host{display:block}.lp{display:flex;flex-direction:column;gap:var(--sp-3)}.lp__row{display:flex;align-items:center;flex-wrap:wrap;row-gap:var(--sp-3)}.lp__step{display:flex;align-items:center;gap:var(--sp-2);padding:6px 10px;border-radius:var(--r-lg);border:1px solid transparent}.lp__step--current{border-color:var(--accent-fill);background:var(--tint-sel)}.lp__index{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:22px;height:22px;border-radius:999px;font-family:var(--font-family);font-size:11px;font-weight:var(--fw-bold);line-height:1}.lp__index .pi{font-size:10px}.lp__index[data-tone=neutral]{background:var(--w06);color:var(--w85)}.lp__index[data-tone=accent]{background:var(--accent-fill);color:var(--on-accent-fill)}.lp__index[data-tone=success]{background:var(--success-bg);color:var(--success)}.lp__index[data-tone=warning]{background:var(--warning-bg);color:var(--warning-fg)}.lp__index[data-tone=danger]{background:var(--danger-bg);color:var(--danger)}.lp__name{font-family:var(--font-family);font-weight:var(--fw-medium);font-size:var(--text-sm);color:var(--ink);white-space:nowrap}.lp__step--current .lp__name{font-weight:var(--fw-bold)}.lp__progress{font-family:var(--font-family);font-size:var(--text-xs);color:var(--w45);font-variant-numeric:tabular-nums}.lp__connector{flex:1 1 32px;min-width:20px;height:1px;background:var(--w16);margin-inline:2px}.lp__rollup{display:flex;flex-wrap:wrap;gap:var(--sp-1) var(--sp-4);padding-block-start:var(--sp-2);border-block-start:1px solid var(--w06)}.lp__rollup-item{display:inline-flex;align-items:baseline;gap:5px;font-family:var(--font-family);font-size:var(--text-xs)}.lp__rollup-label{color:var(--w45)}.lp__rollup-value{color:var(--w85);font-weight:var(--fw-bold);font-variant-numeric:tabular-nums}\n"] }]
|
|
23556
|
+
}], propDecorators: { steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: true }] }], rollup: [{ type: i0.Input, args: [{ isSignal: true, alias: "rollup", required: false }] }], ariaLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelKey", required: true }] }] } });
|
|
23557
|
+
|
|
23106
23558
|
function canGoPrev$1(page) {
|
|
23107
23559
|
return page > 1;
|
|
23108
23560
|
}
|
|
@@ -24251,6 +24703,65 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
24251
24703
|
`, styles: [":host{display:block}.sh{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:13px 16px;border-block-end:1px solid var(--line-3)}.sh__t{margin:0;font-size:13px;font-weight:var(--fw-semibold);color:var(--ink);letter-spacing:-.005em;min-width:0}.sh__a{display:inline-flex;align-items:center;gap:var(--sp-1);flex-shrink:0}.sh__a ::ng-deep a:not([fly-button]),.sh__a ::ng-deep button:not([fly-button],[fly-icon-button]){display:inline-flex;align-items:center;gap:5px;background:transparent;border:0;color:var(--accent);font-size:12px;font-weight:var(--fw-medium);cursor:pointer;padding:4px 6px;border-radius:var(--r-sm);font-family:inherit;text-decoration:none;transition:background var(--t-state)}.sh__a ::ng-deep a:not([fly-button]):hover,.sh__a ::ng-deep button:not([fly-button],[fly-icon-button]):hover{background:color-mix(in srgb,var(--accent-soft) 50%,transparent)}.sh__a ::ng-deep a:not([fly-button]):focus-visible,.sh__a ::ng-deep button:not([fly-button],[fly-icon-button]):focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}\n"] }]
|
|
24252
24704
|
}], propDecorators: { titleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleKey", required: false }] }] } });
|
|
24253
24705
|
|
|
24706
|
+
/**
|
|
24707
|
+
* Shared shell for a Project-Details-style "Overview" page: a flat stack of
|
|
24708
|
+
* sections separated by hairlines — deliberately NOT a stack of cards. Every
|
|
24709
|
+
* section gets the same quiet eyebrow label; the body (stats / text / rows /
|
|
24710
|
+
* chips / members / …) is left to content projection, so a section that
|
|
24711
|
+
* carries real interaction (Members' add/remove, Lifecycle's "Move to"
|
|
24712
|
+
* actions) keeps its own live markup untouched. This component owns only the
|
|
24713
|
+
* shell + eyebrow + divider rhythm, never the variant bodies.
|
|
24714
|
+
*
|
|
24715
|
+
* First/last spacing resolves from DOM position (`:first-of-type` /
|
|
24716
|
+
* `:last-of-type` on the host tag), not an input — sections render from a
|
|
24717
|
+
* list, and a caller reordering or filtering that list should never also
|
|
24718
|
+
* have to recompute an explicit "am I first" flag.
|
|
24719
|
+
*
|
|
24720
|
+
* ```html
|
|
24721
|
+
* <fly-overview-section titleKey="ppm.projects.overview.summary">
|
|
24722
|
+
* <fly-overview-kpi-row [items]="kpis()" />
|
|
24723
|
+
* </fly-overview-section>
|
|
24724
|
+
*
|
|
24725
|
+
* <fly-overview-section titleKey="ppm.projects.overview.description">
|
|
24726
|
+
* <fly-overview-surface [proseText]="true">{{ project().description }}</fly-overview-surface>
|
|
24727
|
+
* </fly-overview-section>
|
|
24728
|
+
*
|
|
24729
|
+
* <!-- Sections with their own live interaction just project their existing
|
|
24730
|
+
* markup — the shell never dictates what a Members/Lifecycle body renders. -->
|
|
24731
|
+
* <fly-overview-section titleKey="ppm.projects.overview.members">
|
|
24732
|
+
* <fly-overview-surface>
|
|
24733
|
+
* <app-project-members-list [members]="members()" (removed)="onRemove($event)" />
|
|
24734
|
+
* </fly-overview-surface>
|
|
24735
|
+
* </fly-overview-section>
|
|
24736
|
+
* ```
|
|
24737
|
+
*/
|
|
24738
|
+
class FlyOverviewSectionComponent {
|
|
24739
|
+
/** i18n key for the eyebrow label; alternatively project `[section-title]`. */
|
|
24740
|
+
titleKey = input(...(ngDevMode ? [undefined, { debugName: "titleKey" }] : /* istanbul ignore next */ []));
|
|
24741
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
24742
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyOverviewSectionComponent, isStandalone: true, selector: "fly-overview-section", inputs: { titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
24743
|
+
<h2 class="ovs__eyebrow">
|
|
24744
|
+
@if (titleKey(); as key) {
|
|
24745
|
+
{{ key | translate }}
|
|
24746
|
+
}
|
|
24747
|
+
<ng-content select="[section-title]" />
|
|
24748
|
+
</h2>
|
|
24749
|
+
<ng-content />
|
|
24750
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;gap:var(--sp-2);padding:var(--sp-4) 0;border-block-end:1px solid var(--w06)}:host:first-of-type{padding-block-start:0}:host:last-of-type{border-block-end:0}.ovs__eyebrow{margin:0;font-family:var(--font-family);font-weight:var(--fw-bold);font-size:10.5px;line-height:1;letter-spacing:.03em;color:var(--w42)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
24751
|
+
}
|
|
24752
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewSectionComponent, decorators: [{
|
|
24753
|
+
type: Component,
|
|
24754
|
+
args: [{ selector: 'fly-overview-section', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
24755
|
+
<h2 class="ovs__eyebrow">
|
|
24756
|
+
@if (titleKey(); as key) {
|
|
24757
|
+
{{ key | translate }}
|
|
24758
|
+
}
|
|
24759
|
+
<ng-content select="[section-title]" />
|
|
24760
|
+
</h2>
|
|
24761
|
+
<ng-content />
|
|
24762
|
+
`, styles: [":host{display:flex;flex-direction:column;gap:var(--sp-2);padding:var(--sp-4) 0;border-block-end:1px solid var(--w06)}:host:first-of-type{padding-block-start:0}:host:last-of-type{border-block-end:0}.ovs__eyebrow{margin:0;font-family:var(--font-family);font-weight:var(--fw-bold);font-size:10.5px;line-height:1;letter-spacing:.03em;color:var(--w42)}\n"] }]
|
|
24763
|
+
}], propDecorators: { titleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleKey", required: false }] }] } });
|
|
24764
|
+
|
|
24254
24765
|
/**
|
|
24255
24766
|
* Detail-page content card — the surface every panel and sidebar block on a detail
|
|
24256
24767
|
* screen sits on: `card-surface` fill/hairline/radius/shadow, an optional
|
|
@@ -24291,30 +24802,30 @@ class FlyDetailCardComponent {
|
|
|
24291
24802
|
/** Drop the body padding — for a child that brings its own list/table chrome. */
|
|
24292
24803
|
flush = input(false, ...(ngDevMode ? [{ debugName: "flush" }] : /* istanbul ignore next */ []));
|
|
24293
24804
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyDetailCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
24294
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyDetailCardComponent, isStandalone: true, selector: "fly-detail-card", inputs: { titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null }, hasProjectedTitle: { classPropertyName: "hasProjectedTitle", publicName: "hasProjectedTitle", isSignal: true, isRequired: false, transformFunction: null }, flush: { classPropertyName: "flush", publicName: "flush", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
24295
|
-
@if (titleKey() || hasProjectedTitle()) {
|
|
24296
|
-
<fly-section-header [titleKey]="titleKey()">
|
|
24297
|
-
<ng-content select="[card-title]" ngProjectAs="[section-title]" />
|
|
24298
|
-
<ng-content select="[card-actions]" ngProjectAs="[section-actions]" />
|
|
24299
|
-
</fly-section-header>
|
|
24300
|
-
}
|
|
24301
|
-
<div class="dc__body" [class.dc__body--flush]="flush()">
|
|
24302
|
-
<ng-content />
|
|
24303
|
-
</div>
|
|
24805
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyDetailCardComponent, isStandalone: true, selector: "fly-detail-card", inputs: { titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null }, hasProjectedTitle: { classPropertyName: "hasProjectedTitle", publicName: "hasProjectedTitle", isSignal: true, isRequired: false, transformFunction: null }, flush: { classPropertyName: "flush", publicName: "flush", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
24806
|
+
@if (titleKey() || hasProjectedTitle()) {
|
|
24807
|
+
<fly-section-header [titleKey]="titleKey()">
|
|
24808
|
+
<ng-content select="[card-title]" ngProjectAs="[section-title]" />
|
|
24809
|
+
<ng-content select="[card-actions]" ngProjectAs="[section-actions]" />
|
|
24810
|
+
</fly-section-header>
|
|
24811
|
+
}
|
|
24812
|
+
<div class="dc__body" [class.dc__body--flush]="flush()">
|
|
24813
|
+
<ng-content />
|
|
24814
|
+
</div>
|
|
24304
24815
|
`, isInline: true, styles: [":host{display:block;background:var(--bg-2);border:1px solid var(--w08);border-radius:var(--r-lg);box-shadow:var(--shadow-card);overflow:hidden;animation:itemIn .3s var(--nova-ease-micro) both}.dc__body{padding:var(--sp-3) var(--sp-4) var(--sp-4)}.dc__body--flush{padding:0}\n"], dependencies: [{ kind: "component", type: FlySectionHeaderComponent, selector: "fly-section-header", inputs: ["titleKey"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
24305
24816
|
}
|
|
24306
24817
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyDetailCardComponent, decorators: [{
|
|
24307
24818
|
type: Component,
|
|
24308
|
-
args: [{ selector: 'fly-detail-card', standalone: true, imports: [FlySectionHeaderComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
24309
|
-
@if (titleKey() || hasProjectedTitle()) {
|
|
24310
|
-
<fly-section-header [titleKey]="titleKey()">
|
|
24311
|
-
<ng-content select="[card-title]" ngProjectAs="[section-title]" />
|
|
24312
|
-
<ng-content select="[card-actions]" ngProjectAs="[section-actions]" />
|
|
24313
|
-
</fly-section-header>
|
|
24314
|
-
}
|
|
24315
|
-
<div class="dc__body" [class.dc__body--flush]="flush()">
|
|
24316
|
-
<ng-content />
|
|
24317
|
-
</div>
|
|
24819
|
+
args: [{ selector: 'fly-detail-card', standalone: true, imports: [FlySectionHeaderComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
24820
|
+
@if (titleKey() || hasProjectedTitle()) {
|
|
24821
|
+
<fly-section-header [titleKey]="titleKey()">
|
|
24822
|
+
<ng-content select="[card-title]" ngProjectAs="[section-title]" />
|
|
24823
|
+
<ng-content select="[card-actions]" ngProjectAs="[section-actions]" />
|
|
24824
|
+
</fly-section-header>
|
|
24825
|
+
}
|
|
24826
|
+
<div class="dc__body" [class.dc__body--flush]="flush()">
|
|
24827
|
+
<ng-content />
|
|
24828
|
+
</div>
|
|
24318
24829
|
`, styles: [":host{display:block;background:var(--bg-2);border:1px solid var(--w08);border-radius:var(--r-lg);box-shadow:var(--shadow-card);overflow:hidden;animation:itemIn .3s var(--nova-ease-micro) both}.dc__body{padding:var(--sp-3) var(--sp-4) var(--sp-4)}.dc__body--flush{padding:0}\n"] }]
|
|
24319
24830
|
}], propDecorators: { titleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleKey", required: false }] }], hasProjectedTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasProjectedTitle", required: false }] }], flush: [{ type: i0.Input, args: [{ isSignal: true, alias: "flush", required: false }] }] } });
|
|
24320
24831
|
|
|
@@ -24442,108 +24953,108 @@ class FlyDetailShellComponent {
|
|
|
24442
24953
|
buttons?.[next]?.focus();
|
|
24443
24954
|
}
|
|
24444
24955
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyDetailShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
24445
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyDetailShellComponent, isStandalone: true, selector: "fly-detail-shell", inputs: { sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, sectionsLabelKey: { classPropertyName: "sectionsLabelKey", publicName: "sectionsLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selectedChange" }, viewQueries: [{ propertyName: "rail", first: true, predicate: ["rail"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
24446
|
-
<div class="ds__layout">
|
|
24447
|
-
<aside class="ds__aside">
|
|
24448
|
-
<div class="ds__pinned">
|
|
24449
|
-
<ng-content select="[detail-aside]" />
|
|
24450
|
-
</div>
|
|
24451
|
-
|
|
24452
|
-
@if (sections().length > 0) {
|
|
24453
|
-
<div
|
|
24454
|
-
#rail
|
|
24455
|
-
class="ds__rail"
|
|
24456
|
-
role="tablist"
|
|
24457
|
-
tabindex="-1"
|
|
24458
|
-
[attr.aria-orientation]="'vertical'"
|
|
24459
|
-
[attr.aria-label]="sectionsLabelKey() | translate"
|
|
24460
|
-
(keydown)="onKey($event)"
|
|
24461
|
-
>
|
|
24462
|
-
@for (s of sections(); track s.id) {
|
|
24463
|
-
<button
|
|
24464
|
-
type="button"
|
|
24465
|
-
class="ds__tab"
|
|
24466
|
-
role="tab"
|
|
24467
|
-
[id]="tabId(s.id)"
|
|
24468
|
-
[class.ds__tab--active]="activeId() === s.id"
|
|
24469
|
-
[attr.aria-selected]="activeId() === s.id"
|
|
24470
|
-
[attr.aria-controls]="panelId()"
|
|
24471
|
-
[attr.tabindex]="activeId() === s.id ? 0 : -1"
|
|
24472
|
-
[attr.title]="s.labelKey | translate"
|
|
24473
|
-
(click)="select(s.id)"
|
|
24474
|
-
>
|
|
24475
|
-
@if (s.icon) {
|
|
24476
|
-
<span class="pi {{ s.icon }} ds__tab-ico" aria-hidden="true"></span>
|
|
24477
|
-
}
|
|
24478
|
-
<span class="ds__tab-label">{{ s.labelKey | translate }}</span>
|
|
24479
|
-
</button>
|
|
24480
|
-
}
|
|
24481
|
-
</div>
|
|
24482
|
-
}
|
|
24483
|
-
</aside>
|
|
24484
|
-
|
|
24485
|
-
<div
|
|
24486
|
-
class="ds__panel"
|
|
24487
|
-
[id]="panelId()"
|
|
24488
|
-
[attr.role]="sections().length ? 'tabpanel' : null"
|
|
24489
|
-
[attr.aria-labelledby]="activeId() ? tabId(activeId()!) : null"
|
|
24490
|
-
>
|
|
24491
|
-
<ng-content />
|
|
24492
|
-
</div>
|
|
24493
|
-
</div>
|
|
24956
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyDetailShellComponent, isStandalone: true, selector: "fly-detail-shell", inputs: { sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, sectionsLabelKey: { classPropertyName: "sectionsLabelKey", publicName: "sectionsLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selectedChange" }, viewQueries: [{ propertyName: "rail", first: true, predicate: ["rail"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
24957
|
+
<div class="ds__layout">
|
|
24958
|
+
<aside class="ds__aside">
|
|
24959
|
+
<div class="ds__pinned">
|
|
24960
|
+
<ng-content select="[detail-aside]" />
|
|
24961
|
+
</div>
|
|
24962
|
+
|
|
24963
|
+
@if (sections().length > 0) {
|
|
24964
|
+
<div
|
|
24965
|
+
#rail
|
|
24966
|
+
class="ds__rail"
|
|
24967
|
+
role="tablist"
|
|
24968
|
+
tabindex="-1"
|
|
24969
|
+
[attr.aria-orientation]="'vertical'"
|
|
24970
|
+
[attr.aria-label]="sectionsLabelKey() | translate"
|
|
24971
|
+
(keydown)="onKey($event)"
|
|
24972
|
+
>
|
|
24973
|
+
@for (s of sections(); track s.id) {
|
|
24974
|
+
<button
|
|
24975
|
+
type="button"
|
|
24976
|
+
class="ds__tab"
|
|
24977
|
+
role="tab"
|
|
24978
|
+
[id]="tabId(s.id)"
|
|
24979
|
+
[class.ds__tab--active]="activeId() === s.id"
|
|
24980
|
+
[attr.aria-selected]="activeId() === s.id"
|
|
24981
|
+
[attr.aria-controls]="panelId()"
|
|
24982
|
+
[attr.tabindex]="activeId() === s.id ? 0 : -1"
|
|
24983
|
+
[attr.title]="s.labelKey | translate"
|
|
24984
|
+
(click)="select(s.id)"
|
|
24985
|
+
>
|
|
24986
|
+
@if (s.icon) {
|
|
24987
|
+
<span class="pi {{ s.icon }} ds__tab-ico" aria-hidden="true"></span>
|
|
24988
|
+
}
|
|
24989
|
+
<span class="ds__tab-label">{{ s.labelKey | translate }}</span>
|
|
24990
|
+
</button>
|
|
24991
|
+
}
|
|
24992
|
+
</div>
|
|
24993
|
+
}
|
|
24994
|
+
</aside>
|
|
24995
|
+
|
|
24996
|
+
<div
|
|
24997
|
+
class="ds__panel"
|
|
24998
|
+
[id]="panelId()"
|
|
24999
|
+
[attr.role]="sections().length ? 'tabpanel' : null"
|
|
25000
|
+
[attr.aria-labelledby]="activeId() ? tabId(activeId()!) : null"
|
|
25001
|
+
>
|
|
25002
|
+
<ng-content />
|
|
25003
|
+
</div>
|
|
25004
|
+
</div>
|
|
24494
25005
|
`, isInline: true, styles: [":host{display:block;container-type:inline-size}.ds__layout{display:grid;grid-template-columns:var(--fly-detail-aside, 300px) minmax(0,1fr);gap:var(--sp-4);align-items:start}.ds__aside{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0}.ds__aside .ds__rail{order:-1}.ds__pinned{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0}.ds__panel{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0;align-self:stretch}.ds__panel>:only-child{flex:1}.ds__rail{display:flex;flex-direction:column;gap:var(--sp-1);padding:var(--sp-2);background:var(--bg-2);border:1px solid var(--w08);border-radius:var(--r-lg);box-shadow:var(--shadow-card)}.ds__tab{display:flex;align-items:center;gap:var(--sp-3);width:100%;padding:var(--sp-2);border:0;background:transparent;border-radius:var(--r-md);color:var(--ink-2);cursor:pointer;font-family:inherit;font-size:var(--text-sm);text-align:start;white-space:nowrap;overflow:hidden;transition:background var(--t-state),color var(--t-state)}.ds__tab:hover{background:var(--w06);color:var(--ink)}.ds__tab:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ds__tab--active{background:var(--accent-fill);color:var(--on-accent-fill);font-weight:var(--fw-semibold)}.ds__tab-ico{font-size:var(--text-md);flex-shrink:0;width:20px;text-align:center}.ds__tab-label{min-width:0;overflow:hidden;text-overflow:ellipsis}@container (width <= 980px){.ds__layout{grid-template-columns:minmax(0,1fr)}.ds__rail{flex-flow:row wrap}.ds__tab{width:auto}}@media(width<=980px){.ds__layout{grid-template-columns:minmax(0,1fr)}.ds__rail{flex-flow:row wrap}.ds__tab{width:auto}}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
24495
25006
|
}
|
|
24496
25007
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyDetailShellComponent, decorators: [{
|
|
24497
25008
|
type: Component,
|
|
24498
|
-
args: [{ selector: 'fly-detail-shell', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
24499
|
-
<div class="ds__layout">
|
|
24500
|
-
<aside class="ds__aside">
|
|
24501
|
-
<div class="ds__pinned">
|
|
24502
|
-
<ng-content select="[detail-aside]" />
|
|
24503
|
-
</div>
|
|
24504
|
-
|
|
24505
|
-
@if (sections().length > 0) {
|
|
24506
|
-
<div
|
|
24507
|
-
#rail
|
|
24508
|
-
class="ds__rail"
|
|
24509
|
-
role="tablist"
|
|
24510
|
-
tabindex="-1"
|
|
24511
|
-
[attr.aria-orientation]="'vertical'"
|
|
24512
|
-
[attr.aria-label]="sectionsLabelKey() | translate"
|
|
24513
|
-
(keydown)="onKey($event)"
|
|
24514
|
-
>
|
|
24515
|
-
@for (s of sections(); track s.id) {
|
|
24516
|
-
<button
|
|
24517
|
-
type="button"
|
|
24518
|
-
class="ds__tab"
|
|
24519
|
-
role="tab"
|
|
24520
|
-
[id]="tabId(s.id)"
|
|
24521
|
-
[class.ds__tab--active]="activeId() === s.id"
|
|
24522
|
-
[attr.aria-selected]="activeId() === s.id"
|
|
24523
|
-
[attr.aria-controls]="panelId()"
|
|
24524
|
-
[attr.tabindex]="activeId() === s.id ? 0 : -1"
|
|
24525
|
-
[attr.title]="s.labelKey | translate"
|
|
24526
|
-
(click)="select(s.id)"
|
|
24527
|
-
>
|
|
24528
|
-
@if (s.icon) {
|
|
24529
|
-
<span class="pi {{ s.icon }} ds__tab-ico" aria-hidden="true"></span>
|
|
24530
|
-
}
|
|
24531
|
-
<span class="ds__tab-label">{{ s.labelKey | translate }}</span>
|
|
24532
|
-
</button>
|
|
24533
|
-
}
|
|
24534
|
-
</div>
|
|
24535
|
-
}
|
|
24536
|
-
</aside>
|
|
24537
|
-
|
|
24538
|
-
<div
|
|
24539
|
-
class="ds__panel"
|
|
24540
|
-
[id]="panelId()"
|
|
24541
|
-
[attr.role]="sections().length ? 'tabpanel' : null"
|
|
24542
|
-
[attr.aria-labelledby]="activeId() ? tabId(activeId()!) : null"
|
|
24543
|
-
>
|
|
24544
|
-
<ng-content />
|
|
24545
|
-
</div>
|
|
24546
|
-
</div>
|
|
25009
|
+
args: [{ selector: 'fly-detail-shell', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
25010
|
+
<div class="ds__layout">
|
|
25011
|
+
<aside class="ds__aside">
|
|
25012
|
+
<div class="ds__pinned">
|
|
25013
|
+
<ng-content select="[detail-aside]" />
|
|
25014
|
+
</div>
|
|
25015
|
+
|
|
25016
|
+
@if (sections().length > 0) {
|
|
25017
|
+
<div
|
|
25018
|
+
#rail
|
|
25019
|
+
class="ds__rail"
|
|
25020
|
+
role="tablist"
|
|
25021
|
+
tabindex="-1"
|
|
25022
|
+
[attr.aria-orientation]="'vertical'"
|
|
25023
|
+
[attr.aria-label]="sectionsLabelKey() | translate"
|
|
25024
|
+
(keydown)="onKey($event)"
|
|
25025
|
+
>
|
|
25026
|
+
@for (s of sections(); track s.id) {
|
|
25027
|
+
<button
|
|
25028
|
+
type="button"
|
|
25029
|
+
class="ds__tab"
|
|
25030
|
+
role="tab"
|
|
25031
|
+
[id]="tabId(s.id)"
|
|
25032
|
+
[class.ds__tab--active]="activeId() === s.id"
|
|
25033
|
+
[attr.aria-selected]="activeId() === s.id"
|
|
25034
|
+
[attr.aria-controls]="panelId()"
|
|
25035
|
+
[attr.tabindex]="activeId() === s.id ? 0 : -1"
|
|
25036
|
+
[attr.title]="s.labelKey | translate"
|
|
25037
|
+
(click)="select(s.id)"
|
|
25038
|
+
>
|
|
25039
|
+
@if (s.icon) {
|
|
25040
|
+
<span class="pi {{ s.icon }} ds__tab-ico" aria-hidden="true"></span>
|
|
25041
|
+
}
|
|
25042
|
+
<span class="ds__tab-label">{{ s.labelKey | translate }}</span>
|
|
25043
|
+
</button>
|
|
25044
|
+
}
|
|
25045
|
+
</div>
|
|
25046
|
+
}
|
|
25047
|
+
</aside>
|
|
25048
|
+
|
|
25049
|
+
<div
|
|
25050
|
+
class="ds__panel"
|
|
25051
|
+
[id]="panelId()"
|
|
25052
|
+
[attr.role]="sections().length ? 'tabpanel' : null"
|
|
25053
|
+
[attr.aria-labelledby]="activeId() ? tabId(activeId()!) : null"
|
|
25054
|
+
>
|
|
25055
|
+
<ng-content />
|
|
25056
|
+
</div>
|
|
25057
|
+
</div>
|
|
24547
25058
|
`, styles: [":host{display:block;container-type:inline-size}.ds__layout{display:grid;grid-template-columns:var(--fly-detail-aside, 300px) minmax(0,1fr);gap:var(--sp-4);align-items:start}.ds__aside{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0}.ds__aside .ds__rail{order:-1}.ds__pinned{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0}.ds__panel{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0;align-self:stretch}.ds__panel>:only-child{flex:1}.ds__rail{display:flex;flex-direction:column;gap:var(--sp-1);padding:var(--sp-2);background:var(--bg-2);border:1px solid var(--w08);border-radius:var(--r-lg);box-shadow:var(--shadow-card)}.ds__tab{display:flex;align-items:center;gap:var(--sp-3);width:100%;padding:var(--sp-2);border:0;background:transparent;border-radius:var(--r-md);color:var(--ink-2);cursor:pointer;font-family:inherit;font-size:var(--text-sm);text-align:start;white-space:nowrap;overflow:hidden;transition:background var(--t-state),color var(--t-state)}.ds__tab:hover{background:var(--w06);color:var(--ink)}.ds__tab:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ds__tab--active{background:var(--accent-fill);color:var(--on-accent-fill);font-weight:var(--fw-semibold)}.ds__tab-ico{font-size:var(--text-md);flex-shrink:0;width:20px;text-align:center}.ds__tab-label{min-width:0;overflow:hidden;text-overflow:ellipsis}@container (width <= 980px){.ds__layout{grid-template-columns:minmax(0,1fr)}.ds__rail{flex-flow:row wrap}.ds__tab{width:auto}}@media(width<=980px){.ds__layout{grid-template-columns:minmax(0,1fr)}.ds__rail{flex-flow:row wrap}.ds__tab{width:auto}}\n"] }]
|
|
24548
25059
|
}], propDecorators: { rail: [{ type: i0.ViewChild, args: ['rail', { isSignal: true }] }], sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }, { type: i0.Output, args: ["selectedChange"] }], sectionsLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionsLabelKey", required: false }] }] } });
|
|
24549
25060
|
|
|
@@ -24960,6 +25471,15 @@ function sectionHintKey(section, expanded) {
|
|
|
24960
25471
|
* Icons reuse `flyModuleIcon` — the SAME directive the topbar takes — so an app that
|
|
24961
25472
|
* renders both declares its icon templates once per surface, in the same syntax.
|
|
24962
25473
|
*
|
|
25474
|
+
* ## App colour (3.12.0)
|
|
25475
|
+
*
|
|
25476
|
+
* The launch-card family (feature tile, hover wash, hover ring) follows the app's
|
|
25477
|
+
* authored brand colour, received by CSS CASCADE rather than input: the shell window
|
|
25478
|
+
* publishes the app's derived palette (`--app-color`, `--app-color-deep`, `--app-ink`)
|
|
25479
|
+
* on `.window`, so a federated landing is branded with zero wiring; a standalone host
|
|
25480
|
+
* brands itself by setting the same custom properties on any ancestor element. Where
|
|
25481
|
+
* nothing cascades, the fixed `--module-teal` family renders exactly as before.
|
|
25482
|
+
*
|
|
24963
25483
|
* a11y: cards are real `<button>`s in a labelled group; a collapsible section is a
|
|
24964
25484
|
* disclosure (`aria-expanded` + `aria-controls`), and the region carries the section
|
|
24965
25485
|
* heading. Layout is logical-property only, so it mirrors under `dir="rtl"` on its own —
|
|
@@ -25015,11 +25535,11 @@ class FlyAppHomeComponent {
|
|
|
25015
25535
|
return `fly-app-home-sec-${index}`;
|
|
25016
25536
|
}
|
|
25017
25537
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyAppHomeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
25018
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyAppHomeComponent, isStandalone: true, selector: "fly-app-home", inputs: { brandLabelKey: { classPropertyName: "brandLabelKey", publicName: "brandLabelKey", isSignal: true, isRequired: false, transformFunction: null }, titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null }, subtitleKey: { classPropertyName: "subtitleKey", publicName: "subtitleKey", isSignal: true, isRequired: false, transformFunction: null }, sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, modulesLabelKey: { classPropertyName: "modulesLabelKey", publicName: "modulesLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { moduleSelected: "moduleSelected", brandSelected: "brandSelected" }, queries: [{ propertyName: "icons", predicate: FlyModuleIconDirective, isSignal: true }], ngImport: i0, template: "<div class=\"ah\">\r\n <header class=\"ah__util\">\r\n <button type=\"button\" class=\"ah__brand\" (click)=\"brandSelected.emit()\">\r\n <span class=\"ah__brand-mark\"><ng-content select=\"[app-home-brand]\" /></span>\r\n @if (brandLabelKey(); as key) {\r\n <span class=\"ah__brand-name\">{{ key | translate }}</span>\r\n }\r\n </button>\r\n <ng-content select=\"[app-home-actions]\" />\r\n </header>\r\n\r\n <main class=\"ah__main\">\r\n @if (titleKey() || subtitleKey()) {\r\n <section class=\"ah__hero\">\r\n @if (titleKey(); as key) {\r\n <h1 class=\"ah__title\">{{ key | translate }}</h1>\r\n }\r\n @if (subtitleKey(); as key) {\r\n <p class=\"ah__sub\">{{ key | translate }}</p>\r\n }\r\n </section>\r\n }\r\n\r\n @for (row of rows(); track row.index) {\r\n <section\r\n class=\"ah__sec\"\r\n [class.ah__sec--secondary]=\"row.index > 0\"\r\n [attr.aria-label]=\"row.section.titleKey ? null : (modulesLabelKey() | translate)\"\r\n >\r\n @if (row.section.titleKey; as titleKey) {\r\n @if (row.section.collapsible) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__sec-hd\"\r\n (click)=\"toggle(row.index)\"\r\n [attr.aria-expanded]=\"row.expanded\"\r\n [attr.aria-controls]=\"sectionId(row.index)\"\r\n >\r\n <!-- Points end-ward when shut, down when open. `--open` wins over the RTL\r\n flip below because a downward chevron has no direction to mirror. -->\r\n <svg\r\n class=\"ah__sec-chev\"\r\n [class.ah__sec-chev--open]=\"row.expanded\"\r\n width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n <span class=\"ah__sec-title\">{{ titleKey | translate }}</span>\r\n <span class=\"ah__sec-count\">{{ row.section.modules.length }}</span>\r\n @if (row.hintKey; as hint) {\r\n <span class=\"ah__sec-hint\">{{ hint | translate }}</span>\r\n }\r\n </button>\r\n } @else {\r\n <h2 class=\"ah__sec-title ah__sec-title--static\">{{ titleKey | translate }}</h2>\r\n }\r\n }\r\n\r\n @if (row.expanded) {\r\n <div class=\"ah__grid\" [class.ah__grid--compact]=\"row.layout === 'compact'\" [id]=\"sectionId(row.index)\">\r\n @for (mod of row.section.modules; track mod.key) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__card\"\r\n [class.ah__card--compact]=\"row.layout === 'compact'\"\r\n [disabled]=\"mod.disabled\"\r\n (click)=\"select(mod)\"\r\n >\r\n <span class=\"ah__card-ico\">\r\n @if (iconFor(mod.key); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\" />\r\n } @else if (mod.iconClass) {\r\n <i [class]=\"mod.iconClass\" aria-hidden=\"true\"></i>\r\n }\r\n </span>\r\n\r\n @if (row.layout === 'compact') {\r\n <span class=\"ah__card-main\">\r\n <span class=\"ah__card-title\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc\">{{ descKey | translate }}</span>\r\n }\r\n </span>\r\n <svg\r\n class=\"ah__card-arrow\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n } @else {\r\n <!-- No \"Open \u203A\" affordance row \u2014 the design's module card (MainContent.dc.html)\r\n ends at the description; the whole card is the click target and hover carries\r\n the affordance. Removed at the 2026-08-17 fidelity pass. -->\r\n <span class=\"ah__card-title ah__card-title--feature\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc ah__card-desc--feature\">{{ descKey | translate }}</span>\r\n }\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n </section>\r\n }\r\n </main>\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:100%;container-type:inline-size}.ah{display:flex;flex-direction:column;flex:1;min-height:100%}.ah__util{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-4) var(--sp-6)}:host-context(.window-content) .ah__brand{display:none}:host-context(.window-content) .ah__util{justify-content:flex-end}:host-context(.window-content) .ah__util:not(:has(>:not(.ah__brand))){display:none}.ah__brand{display:inline-flex;align-items:center;gap:var(--sp-2);padding:0;border:0;background:none;color:var(--ink);font-family:inherit;cursor:pointer}.ah__brand:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__brand-name{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__main{flex:1;inline-size:100%;max-inline-size:1120px;margin-inline:auto;padding:56px 40px;display:flex;flex-direction:column;justify-content:center;gap:44px}.ah__hero{max-inline-size:640px}.ah__title{margin:0 0 var(--sp-3);font-size:44px;font-weight:var(--fw-semibold);letter-spacing:-.03em;text-wrap:balance;background:linear-gradient(180deg,var(--ink),var(--ink-2));-webkit-background-clip:text;background-clip:text;color:transparent}.ah__sub{margin:0;max-inline-size:560px;font-size:var(--text-lg);line-height:1.55;color:var(--ink-3);text-wrap:pretty}.ah__sec{display:flex;flex-direction:column;gap:var(--sp-4)}.ah__sec--secondary{padding-block-start:28px;border-block-start:1px solid var(--w08)}.ah__sec-hd{display:flex;align-items:center;gap:var(--sp-3);inline-size:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;color:var(--ink);text-align:start}.ah__sec-hd:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__sec-chev{flex-shrink:0;color:var(--ink-3);transition:transform var(--t-overlay)}.ah__sec-title{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__sec-title--static{margin:0;color:var(--ink-3);font-size:var(--text-xs);letter-spacing:var(--tracking-wide);text-transform:uppercase}.ah__sec-count{display:inline-grid;place-items:center;min-inline-size:22px;block-size:20px;padding-inline:6px;border-radius:999px;background:var(--bg-3);border:1px solid var(--line);font-size:var(--text-2xs);font-weight:var(--fw-medium);font-variant-numeric:tabular-nums;color:var(--ink-3)}.ah__sec-hint{margin-inline-start:auto;font-size:var(--text-xs);color:var(--ink-3)}.ah__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px}.ah__card{display:flex;flex-direction:column;align-items:stretch;position:relative;overflow:hidden;text-align:start;padding:20px;background-image:linear-gradient(160deg,var(--w055),var(--w02));border:1px solid var(--w09);border-radius:20px;color:inherit;font-family:inherit;cursor:pointer;animation:appTileIn .3s var(--nova-ease-micro) both}.ah__card:nth-child(1){animation-delay:0ms}.ah__card:nth-child(2){animation-delay:20ms}.ah__card:nth-child(3){animation-delay:40ms}.ah__card:nth-child(4){animation-delay:60ms}.ah__card:nth-child(5){animation-delay:80ms}.ah__card:nth-child(6){animation-delay:.1s}.ah__card:nth-child(7){animation-delay:.12s}.ah__card:nth-child(8){animation-delay:.14s}.ah__card:nth-child(9){animation-delay:.16s}.ah__card:nth-child(10){animation-delay:.18s}.ah__card:nth-child(11){animation-delay:.2s}.ah__card:nth-child(12){animation-delay:.22s}.ah__card:nth-child(n+13){animation-delay:.22s}.ah__card{transition:transform var(--t-overlay),box-shadow var(--t-overlay),border-color var(--t-state),background-image var(--t-state)}.ah__card:hover:not(:disabled){transform:translateY(-3px);border-color:color-mix(in oklab,var(--accent) 50%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card:focus-visible{outline:0;border-color:color-mix(in oklab,var(--accent) 50%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 0 0 3px var(--accent-soft),0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card:disabled{cursor:default;opacity:.5}.ah__card-ico{display:grid;place-items:center;inline-size:42px;block-size:42px;margin-block-end:16px;border-radius:13px;background:linear-gradient(140deg,color-mix(in srgb,var(--accent) 50%,transparent),color-mix(in srgb,var(--sys-teal) 22%,transparent));box-shadow:0 6px 16px color-mix(in srgb,var(--accent) 30%,transparent),inset 0 1px 0 var(--edge-highlight);border:0;color:var(--on-accent);font-size:var(--icon-lg)}.ah__card--compact:hover:not(:disabled) .ah__card-ico,.ah__card--compact:focus-visible .ah__card-ico{background:linear-gradient(135deg,var(--accent),var(--sys-teal));box-shadow:inset 0 1px 0 var(--edge-highlight);color:var(--on-accent)}.ah__card-title{font-size:var(--text-sm);font-weight:var(--fw-semibold);letter-spacing:-.01em;color:var(--ink)}.ah__card-title--feature{margin-block-end:5px;font-size:16.5px;line-height:1.25;letter-spacing:-.005em}.ah__card-desc{font-size:var(--text-xs);line-height:1.45;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ah__card-desc--feature{margin-block-end:0;font-size:13px;line-height:1.45;text-wrap:pretty;overflow:visible;white-space:normal}.ah__card-arrow{flex-shrink:0;transition:color var(--t-overlay),transform var(--t-overlay)}.ah__card--compact{flex-direction:row;align-items:center;gap:var(--sp-3);padding:14px 16px;background-color:var(--bg);background-image:linear-gradient(160deg,var(--w035),var(--w035));border-radius:16px;border-color:var(--w08)}.ah__card--compact:hover:not(:disabled),.ah__card--compact:focus-visible{border-color:color-mix(in oklab,var(--accent) 40%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent)}.ah__card--compact .ah__card-ico{inline-size:32px;block-size:32px;margin-block-end:0;flex-shrink:0;border-radius:10px;font-size:var(--icon-md);background:var(--bg-3);box-shadow:none;color:var(--ink)}.ah__card-main{display:flex;flex-direction:column;gap:2px;flex:1;min-inline-size:0}.ah__card--compact .ah__card-arrow{color:var(--ink-4)}.ah__card--compact:hover:not(:disabled) .ah__card-arrow{color:var(--accent);transform:translate(2px)}:host-context([dir=rtl]) .ah__card-arrow{transform:scaleX(-1)}:host-context([dir=rtl]) .ah__sec-chev:not(.ah__sec-chev--open){transform:scaleX(-1)}:host-context([dir=rtl]) .ah__card--compact:hover:not(:disabled) .ah__card-arrow{transform:scaleX(-1) translate(2px)}.ah__sec-chev--open{transform:rotate(90deg)}@container (width <= 900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@media(width<=900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@container (width <= 560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}@media(width<=560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
25538
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyAppHomeComponent, isStandalone: true, selector: "fly-app-home", inputs: { brandLabelKey: { classPropertyName: "brandLabelKey", publicName: "brandLabelKey", isSignal: true, isRequired: false, transformFunction: null }, titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null }, subtitleKey: { classPropertyName: "subtitleKey", publicName: "subtitleKey", isSignal: true, isRequired: false, transformFunction: null }, sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, modulesLabelKey: { classPropertyName: "modulesLabelKey", publicName: "modulesLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { moduleSelected: "moduleSelected", brandSelected: "brandSelected" }, queries: [{ propertyName: "icons", predicate: FlyModuleIconDirective, isSignal: true }], ngImport: i0, template: "<div class=\"ah\">\r\n <header class=\"ah__util\">\r\n <button type=\"button\" class=\"ah__brand\" (click)=\"brandSelected.emit()\">\r\n <span class=\"ah__brand-mark\"><ng-content select=\"[app-home-brand]\" /></span>\r\n @if (brandLabelKey(); as key) {\r\n <span class=\"ah__brand-name\">{{ key | translate }}</span>\r\n }\r\n </button>\r\n <ng-content select=\"[app-home-actions]\" />\r\n </header>\r\n\r\n <main class=\"ah__main\">\r\n @if (titleKey() || subtitleKey()) {\r\n <section class=\"ah__hero\">\r\n @if (titleKey(); as key) {\r\n <h1 class=\"ah__title\">{{ key | translate }}</h1>\r\n }\r\n @if (subtitleKey(); as key) {\r\n <p class=\"ah__sub\">{{ key | translate }}</p>\r\n }\r\n </section>\r\n }\r\n\r\n @for (row of rows(); track row.index) {\r\n <section\r\n class=\"ah__sec\"\r\n [class.ah__sec--secondary]=\"row.index > 0\"\r\n [attr.aria-label]=\"row.section.titleKey ? null : (modulesLabelKey() | translate)\"\r\n >\r\n @if (row.section.titleKey; as titleKey) {\r\n @if (row.section.collapsible) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__sec-hd\"\r\n (click)=\"toggle(row.index)\"\r\n [attr.aria-expanded]=\"row.expanded\"\r\n [attr.aria-controls]=\"sectionId(row.index)\"\r\n >\r\n <!-- Points end-ward when shut, down when open. `--open` wins over the RTL\r\n flip below because a downward chevron has no direction to mirror. -->\r\n <svg\r\n class=\"ah__sec-chev\"\r\n [class.ah__sec-chev--open]=\"row.expanded\"\r\n width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n <span class=\"ah__sec-title\">{{ titleKey | translate }}</span>\r\n <span class=\"ah__sec-count\">{{ row.section.modules.length }}</span>\r\n @if (row.hintKey; as hint) {\r\n <span class=\"ah__sec-hint\">{{ hint | translate }}</span>\r\n }\r\n </button>\r\n } @else {\r\n <h2 class=\"ah__sec-title ah__sec-title--static\">{{ titleKey | translate }}</h2>\r\n }\r\n }\r\n\r\n @if (row.expanded) {\r\n <div class=\"ah__grid\" [class.ah__grid--compact]=\"row.layout === 'compact'\" [id]=\"sectionId(row.index)\">\r\n @for (mod of row.section.modules; track mod.key) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__card\"\r\n [class.ah__card--compact]=\"row.layout === 'compact'\"\r\n [disabled]=\"mod.disabled\"\r\n (click)=\"select(mod)\"\r\n >\r\n <span class=\"ah__card-ico\">\r\n @if (iconFor(mod.key); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\" />\r\n } @else if (mod.iconClass) {\r\n <i [class]=\"mod.iconClass\" aria-hidden=\"true\"></i>\r\n }\r\n </span>\r\n\r\n @if (row.layout === 'compact') {\r\n <span class=\"ah__card-main\">\r\n <span class=\"ah__card-title\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc\">{{ descKey | translate }}</span>\r\n }\r\n </span>\r\n <svg\r\n class=\"ah__card-arrow\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n } @else {\r\n <!-- No \"Open \u203A\" affordance row \u2014 the design's module card (MainContent.dc.html)\r\n ends at the description; the whole card is the click target and hover carries\r\n the affordance. Removed at the 2026-08-17 fidelity pass. -->\r\n <!-- Text stack: icon-to-text spacing is `.ah__card`'s own gap; this wrapper's\r\n gap is title-to-description only (module-card fidelity pass, 2026-08-20). -->\r\n <span class=\"ah__card-text\">\r\n <span class=\"ah__card-title ah__card-title--feature\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc ah__card-desc--feature\">{{ descKey | translate }}</span>\r\n }\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n </section>\r\n }\r\n </main>\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:100%;container-type:inline-size;--ah-brand: var(--app-color, var(--module-teal));--ah-brand-deep: var(--app-color-deep, var(--module-teal-deep));--ah-brand-soft: var(--app-color, var(--sys-teal));--ah-brand-ink: var(--app-ink, var(--ink-inverse))}.ah{display:flex;flex-direction:column;flex:1;min-height:100%}.ah__util{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-4) var(--sp-6)}:host-context(.window-content) .ah__brand{display:none}:host-context(.window-content) .ah__util{justify-content:flex-end}:host-context(.window-content) .ah__util:not(:has(>:not(.ah__brand))){display:none}.ah__brand{display:inline-flex;align-items:center;gap:var(--sp-2);padding:0;border:0;background:none;color:var(--ink);font-family:inherit;cursor:pointer}.ah__brand:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__brand-name{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__main{flex:1;inline-size:100%;max-inline-size:1120px;margin-inline:auto;padding:56px 40px;display:flex;flex-direction:column;justify-content:center;gap:44px}.ah__hero{max-inline-size:640px}.ah__title{margin:0 0 var(--sp-3);font-size:44px;font-weight:var(--fw-semibold);letter-spacing:-.03em;text-wrap:balance;background:linear-gradient(180deg,var(--ink),var(--ink-2));-webkit-background-clip:text;background-clip:text;color:transparent}.ah__sub{margin:0;max-inline-size:560px;font-size:var(--text-lg);line-height:1.55;color:var(--ink-3);text-wrap:pretty}.ah__sec{display:flex;flex-direction:column;gap:var(--sp-4)}.ah__sec--secondary{padding-block-start:28px;border-block-start:1px solid var(--w08)}.ah__sec-hd{display:flex;align-items:center;gap:var(--sp-3);inline-size:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;color:var(--ink);text-align:start}.ah__sec-hd:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__sec-chev{flex-shrink:0;color:var(--ink-3);transition:transform var(--t-overlay)}.ah__sec-title{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__sec-title--static{margin:0;color:var(--ink-3);font-size:var(--text-xs);letter-spacing:var(--tracking-wide);text-transform:uppercase}.ah__sec-count{display:inline-grid;place-items:center;min-inline-size:22px;block-size:20px;padding-inline:6px;border-radius:999px;background:var(--bg-3);border:1px solid var(--line);font-size:var(--text-2xs);font-weight:var(--fw-medium);font-variant-numeric:tabular-nums;color:var(--ink-3)}.ah__sec-hint{margin-inline-start:auto;font-size:var(--text-xs);color:var(--ink-3)}.ah__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;margin-top:4px;justify-content:flex-start}.ah__card{display:flex;flex-direction:column;align-items:stretch;position:relative;overflow:hidden;text-align:start;padding:20px;gap:16px;background:linear-gradient(160deg,var(--w055),var(--w02));border:1px solid var(--w09);border-radius:20px;color:inherit;font-family:inherit;cursor:pointer;animation:appTileIn .3s var(--nova-ease-micro) both}.ah__card:nth-child(1){animation-delay:0ms}.ah__card:nth-child(2){animation-delay:20ms}.ah__card:nth-child(3){animation-delay:40ms}.ah__card:nth-child(4){animation-delay:60ms}.ah__card:nth-child(5){animation-delay:80ms}.ah__card:nth-child(6){animation-delay:.1s}.ah__card:nth-child(7){animation-delay:.12s}.ah__card:nth-child(8){animation-delay:.14s}.ah__card:nth-child(9){animation-delay:.16s}.ah__card:nth-child(10){animation-delay:.18s}.ah__card:nth-child(11){animation-delay:.2s}.ah__card:nth-child(12){animation-delay:.22s}.ah__card:nth-child(n+13){animation-delay:.22s}.ah__card{transition:transform var(--t-overlay),box-shadow var(--t-overlay),border-color var(--t-state),background var(--t-state)}.ah__card:hover:not(:disabled){transform:translateY(-3px);background:linear-gradient(160deg,color-mix(in srgb,var(--ah-brand) 22%,transparent),color-mix(in srgb,var(--ah-brand-soft) 5%,transparent));border-color:color-mix(in srgb,var(--ah-brand) 50%,transparent);box-shadow:inset 0 1px color-mix(in srgb,var(--edge-highlight) 20%,transparent),0 20px 46px color-mix(in srgb,var(--ah-brand) 16%,transparent),var(--shadow-filter)}.ah__card:focus-visible{outline:0;border-color:color-mix(in oklab,var(--accent) 50%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 0 0 3px var(--accent-soft),0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card:disabled{cursor:default;opacity:.5}.ah__card-ico{display:grid;place-items:center;inline-size:42px;block-size:42px;flex:none;border-radius:13px;background:linear-gradient(140deg,color-mix(in srgb,var(--ah-brand-deep) 62%,transparent),color-mix(in srgb,var(--ah-brand) 30%,transparent));box-shadow:0 6px 16px color-mix(in srgb,var(--ah-brand-deep) 30%,transparent),inset 0 1px color-mix(in srgb,var(--edge-highlight) 50%,transparent);border:0;color:var(--ah-brand-ink);font-size:18px;transition:transform var(--t-overlay)}.ah__card--compact:hover:not(:disabled) .ah__card-ico,.ah__card--compact:focus-visible .ah__card-ico{background:linear-gradient(135deg,var(--accent),var(--sys-teal));box-shadow:inset 0 1px 0 var(--edge-highlight);color:var(--on-accent)}.ah__card-title{font-size:var(--text-sm);font-weight:var(--fw-semibold);letter-spacing:-.01em;color:var(--ink)}.ah__card-text{display:flex;flex-direction:column;gap:5px}.ah__card-title--feature{font-family:var(--font-family);font-weight:var(--fw-semibold);font-size:16.5px;line-height:1.25;letter-spacing:-.005em;color:var(--ink)}.ah__card-desc{font-size:var(--text-xs);line-height:1.45;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ah__card-desc--feature{font-family:var(--font-family);font-weight:400;font-size:13px;line-height:1.45;color:var(--w55);text-wrap:pretty;overflow:visible;white-space:normal}.ah__card-arrow{flex-shrink:0;transition:color var(--t-overlay),transform var(--t-overlay)}.ah__card--compact{flex-direction:row;align-items:center;gap:var(--sp-3);padding:14px 16px;background-color:var(--bg);background-image:linear-gradient(160deg,var(--w035),var(--w035));border-radius:16px;border-color:var(--w08)}.ah__card--compact:hover:not(:disabled),.ah__card--compact:focus-visible{border-color:color-mix(in oklab,var(--accent) 40%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card--compact .ah__card-ico{inline-size:32px;block-size:32px;margin-block-end:0;flex-shrink:0;border-radius:10px;font-size:var(--icon-md);background:var(--bg-3);box-shadow:none;color:var(--ink)}.ah__card-main{display:flex;flex-direction:column;gap:2px;flex:1;min-inline-size:0}.ah__card--compact .ah__card-arrow{color:var(--ink-4)}.ah__card--compact:hover:not(:disabled) .ah__card-arrow{color:var(--accent);transform:translate(2px)}:host-context([dir=rtl]) .ah__card-arrow{transform:scaleX(-1)}:host-context([dir=rtl]) .ah__sec-chev:not(.ah__sec-chev--open){transform:scaleX(-1)}:host-context([dir=rtl]) .ah__card--compact:hover:not(:disabled) .ah__card-arrow{transform:scaleX(-1) translate(2px)}.ah__sec-chev--open{transform:rotate(90deg)}@container (width <= 900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@media(width<=900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@container (width <= 560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}@media(width<=560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
25019
25539
|
}
|
|
25020
25540
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyAppHomeComponent, decorators: [{
|
|
25021
25541
|
type: Component,
|
|
25022
|
-
args: [{ selector: 'fly-app-home', standalone: true, imports: [NgTemplateOutlet, TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ah\">\r\n <header class=\"ah__util\">\r\n <button type=\"button\" class=\"ah__brand\" (click)=\"brandSelected.emit()\">\r\n <span class=\"ah__brand-mark\"><ng-content select=\"[app-home-brand]\" /></span>\r\n @if (brandLabelKey(); as key) {\r\n <span class=\"ah__brand-name\">{{ key | translate }}</span>\r\n }\r\n </button>\r\n <ng-content select=\"[app-home-actions]\" />\r\n </header>\r\n\r\n <main class=\"ah__main\">\r\n @if (titleKey() || subtitleKey()) {\r\n <section class=\"ah__hero\">\r\n @if (titleKey(); as key) {\r\n <h1 class=\"ah__title\">{{ key | translate }}</h1>\r\n }\r\n @if (subtitleKey(); as key) {\r\n <p class=\"ah__sub\">{{ key | translate }}</p>\r\n }\r\n </section>\r\n }\r\n\r\n @for (row of rows(); track row.index) {\r\n <section\r\n class=\"ah__sec\"\r\n [class.ah__sec--secondary]=\"row.index > 0\"\r\n [attr.aria-label]=\"row.section.titleKey ? null : (modulesLabelKey() | translate)\"\r\n >\r\n @if (row.section.titleKey; as titleKey) {\r\n @if (row.section.collapsible) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__sec-hd\"\r\n (click)=\"toggle(row.index)\"\r\n [attr.aria-expanded]=\"row.expanded\"\r\n [attr.aria-controls]=\"sectionId(row.index)\"\r\n >\r\n <!-- Points end-ward when shut, down when open. `--open` wins over the RTL\r\n flip below because a downward chevron has no direction to mirror. -->\r\n <svg\r\n class=\"ah__sec-chev\"\r\n [class.ah__sec-chev--open]=\"row.expanded\"\r\n width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n <span class=\"ah__sec-title\">{{ titleKey | translate }}</span>\r\n <span class=\"ah__sec-count\">{{ row.section.modules.length }}</span>\r\n @if (row.hintKey; as hint) {\r\n <span class=\"ah__sec-hint\">{{ hint | translate }}</span>\r\n }\r\n </button>\r\n } @else {\r\n <h2 class=\"ah__sec-title ah__sec-title--static\">{{ titleKey | translate }}</h2>\r\n }\r\n }\r\n\r\n @if (row.expanded) {\r\n <div class=\"ah__grid\" [class.ah__grid--compact]=\"row.layout === 'compact'\" [id]=\"sectionId(row.index)\">\r\n @for (mod of row.section.modules; track mod.key) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__card\"\r\n [class.ah__card--compact]=\"row.layout === 'compact'\"\r\n [disabled]=\"mod.disabled\"\r\n (click)=\"select(mod)\"\r\n >\r\n <span class=\"ah__card-ico\">\r\n @if (iconFor(mod.key); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\" />\r\n } @else if (mod.iconClass) {\r\n <i [class]=\"mod.iconClass\" aria-hidden=\"true\"></i>\r\n }\r\n </span>\r\n\r\n @if (row.layout === 'compact') {\r\n <span class=\"ah__card-main\">\r\n <span class=\"ah__card-title\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc\">{{ descKey | translate }}</span>\r\n }\r\n </span>\r\n <svg\r\n class=\"ah__card-arrow\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n } @else {\r\n <!-- No \"Open \u203A\" affordance row \u2014 the design's module card (MainContent.dc.html)\r\n ends at the description; the whole card is the click target and hover carries\r\n the affordance. Removed at the 2026-08-17 fidelity pass. -->\r\n <span class=\"ah__card-title ah__card-title--feature\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc ah__card-desc--feature\">{{ descKey | translate }}</span>\r\n }\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n </section>\r\n }\r\n </main>\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:100%;container-type:inline-size}.ah{display:flex;flex-direction:column;flex:1;min-height:100%}.ah__util{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-4) var(--sp-6)}:host-context(.window-content) .ah__brand{display:none}:host-context(.window-content) .ah__util{justify-content:flex-end}:host-context(.window-content) .ah__util:not(:has(>:not(.ah__brand))){display:none}.ah__brand{display:inline-flex;align-items:center;gap:var(--sp-2);padding:0;border:0;background:none;color:var(--ink);font-family:inherit;cursor:pointer}.ah__brand:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__brand-name{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__main{flex:1;inline-size:100%;max-inline-size:1120px;margin-inline:auto;padding:56px 40px;display:flex;flex-direction:column;justify-content:center;gap:44px}.ah__hero{max-inline-size:640px}.ah__title{margin:0 0 var(--sp-3);font-size:44px;font-weight:var(--fw-semibold);letter-spacing:-.03em;text-wrap:balance;background:linear-gradient(180deg,var(--ink),var(--ink-2));-webkit-background-clip:text;background-clip:text;color:transparent}.ah__sub{margin:0;max-inline-size:560px;font-size:var(--text-lg);line-height:1.55;color:var(--ink-3);text-wrap:pretty}.ah__sec{display:flex;flex-direction:column;gap:var(--sp-4)}.ah__sec--secondary{padding-block-start:28px;border-block-start:1px solid var(--w08)}.ah__sec-hd{display:flex;align-items:center;gap:var(--sp-3);inline-size:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;color:var(--ink);text-align:start}.ah__sec-hd:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__sec-chev{flex-shrink:0;color:var(--ink-3);transition:transform var(--t-overlay)}.ah__sec-title{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__sec-title--static{margin:0;color:var(--ink-3);font-size:var(--text-xs);letter-spacing:var(--tracking-wide);text-transform:uppercase}.ah__sec-count{display:inline-grid;place-items:center;min-inline-size:22px;block-size:20px;padding-inline:6px;border-radius:999px;background:var(--bg-3);border:1px solid var(--line);font-size:var(--text-2xs);font-weight:var(--fw-medium);font-variant-numeric:tabular-nums;color:var(--ink-3)}.ah__sec-hint{margin-inline-start:auto;font-size:var(--text-xs);color:var(--ink-3)}.ah__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px}.ah__card{display:flex;flex-direction:column;align-items:stretch;position:relative;overflow:hidden;text-align:start;padding:20px;background-image:linear-gradient(160deg,var(--w055),var(--w02));border:1px solid var(--w09);border-radius:20px;color:inherit;font-family:inherit;cursor:pointer;animation:appTileIn .3s var(--nova-ease-micro) both}.ah__card:nth-child(1){animation-delay:0ms}.ah__card:nth-child(2){animation-delay:20ms}.ah__card:nth-child(3){animation-delay:40ms}.ah__card:nth-child(4){animation-delay:60ms}.ah__card:nth-child(5){animation-delay:80ms}.ah__card:nth-child(6){animation-delay:.1s}.ah__card:nth-child(7){animation-delay:.12s}.ah__card:nth-child(8){animation-delay:.14s}.ah__card:nth-child(9){animation-delay:.16s}.ah__card:nth-child(10){animation-delay:.18s}.ah__card:nth-child(11){animation-delay:.2s}.ah__card:nth-child(12){animation-delay:.22s}.ah__card:nth-child(n+13){animation-delay:.22s}.ah__card{transition:transform var(--t-overlay),box-shadow var(--t-overlay),border-color var(--t-state),background-image var(--t-state)}.ah__card:hover:not(:disabled){transform:translateY(-3px);border-color:color-mix(in oklab,var(--accent) 50%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card:focus-visible{outline:0;border-color:color-mix(in oklab,var(--accent) 50%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 0 0 3px var(--accent-soft),0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card:disabled{cursor:default;opacity:.5}.ah__card-ico{display:grid;place-items:center;inline-size:42px;block-size:42px;margin-block-end:16px;border-radius:13px;background:linear-gradient(140deg,color-mix(in srgb,var(--accent) 50%,transparent),color-mix(in srgb,var(--sys-teal) 22%,transparent));box-shadow:0 6px 16px color-mix(in srgb,var(--accent) 30%,transparent),inset 0 1px 0 var(--edge-highlight);border:0;color:var(--on-accent);font-size:var(--icon-lg)}.ah__card--compact:hover:not(:disabled) .ah__card-ico,.ah__card--compact:focus-visible .ah__card-ico{background:linear-gradient(135deg,var(--accent),var(--sys-teal));box-shadow:inset 0 1px 0 var(--edge-highlight);color:var(--on-accent)}.ah__card-title{font-size:var(--text-sm);font-weight:var(--fw-semibold);letter-spacing:-.01em;color:var(--ink)}.ah__card-title--feature{margin-block-end:5px;font-size:16.5px;line-height:1.25;letter-spacing:-.005em}.ah__card-desc{font-size:var(--text-xs);line-height:1.45;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ah__card-desc--feature{margin-block-end:0;font-size:13px;line-height:1.45;text-wrap:pretty;overflow:visible;white-space:normal}.ah__card-arrow{flex-shrink:0;transition:color var(--t-overlay),transform var(--t-overlay)}.ah__card--compact{flex-direction:row;align-items:center;gap:var(--sp-3);padding:14px 16px;background-color:var(--bg);background-image:linear-gradient(160deg,var(--w035),var(--w035));border-radius:16px;border-color:var(--w08)}.ah__card--compact:hover:not(:disabled),.ah__card--compact:focus-visible{border-color:color-mix(in oklab,var(--accent) 40%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent)}.ah__card--compact .ah__card-ico{inline-size:32px;block-size:32px;margin-block-end:0;flex-shrink:0;border-radius:10px;font-size:var(--icon-md);background:var(--bg-3);box-shadow:none;color:var(--ink)}.ah__card-main{display:flex;flex-direction:column;gap:2px;flex:1;min-inline-size:0}.ah__card--compact .ah__card-arrow{color:var(--ink-4)}.ah__card--compact:hover:not(:disabled) .ah__card-arrow{color:var(--accent);transform:translate(2px)}:host-context([dir=rtl]) .ah__card-arrow{transform:scaleX(-1)}:host-context([dir=rtl]) .ah__sec-chev:not(.ah__sec-chev--open){transform:scaleX(-1)}:host-context([dir=rtl]) .ah__card--compact:hover:not(:disabled) .ah__card-arrow{transform:scaleX(-1) translate(2px)}.ah__sec-chev--open{transform:rotate(90deg)}@container (width <= 900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@media(width<=900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@container (width <= 560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}@media(width<=560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}\n"] }]
|
|
25542
|
+
args: [{ selector: 'fly-app-home', standalone: true, imports: [NgTemplateOutlet, TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ah\">\r\n <header class=\"ah__util\">\r\n <button type=\"button\" class=\"ah__brand\" (click)=\"brandSelected.emit()\">\r\n <span class=\"ah__brand-mark\"><ng-content select=\"[app-home-brand]\" /></span>\r\n @if (brandLabelKey(); as key) {\r\n <span class=\"ah__brand-name\">{{ key | translate }}</span>\r\n }\r\n </button>\r\n <ng-content select=\"[app-home-actions]\" />\r\n </header>\r\n\r\n <main class=\"ah__main\">\r\n @if (titleKey() || subtitleKey()) {\r\n <section class=\"ah__hero\">\r\n @if (titleKey(); as key) {\r\n <h1 class=\"ah__title\">{{ key | translate }}</h1>\r\n }\r\n @if (subtitleKey(); as key) {\r\n <p class=\"ah__sub\">{{ key | translate }}</p>\r\n }\r\n </section>\r\n }\r\n\r\n @for (row of rows(); track row.index) {\r\n <section\r\n class=\"ah__sec\"\r\n [class.ah__sec--secondary]=\"row.index > 0\"\r\n [attr.aria-label]=\"row.section.titleKey ? null : (modulesLabelKey() | translate)\"\r\n >\r\n @if (row.section.titleKey; as titleKey) {\r\n @if (row.section.collapsible) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__sec-hd\"\r\n (click)=\"toggle(row.index)\"\r\n [attr.aria-expanded]=\"row.expanded\"\r\n [attr.aria-controls]=\"sectionId(row.index)\"\r\n >\r\n <!-- Points end-ward when shut, down when open. `--open` wins over the RTL\r\n flip below because a downward chevron has no direction to mirror. -->\r\n <svg\r\n class=\"ah__sec-chev\"\r\n [class.ah__sec-chev--open]=\"row.expanded\"\r\n width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n <span class=\"ah__sec-title\">{{ titleKey | translate }}</span>\r\n <span class=\"ah__sec-count\">{{ row.section.modules.length }}</span>\r\n @if (row.hintKey; as hint) {\r\n <span class=\"ah__sec-hint\">{{ hint | translate }}</span>\r\n }\r\n </button>\r\n } @else {\r\n <h2 class=\"ah__sec-title ah__sec-title--static\">{{ titleKey | translate }}</h2>\r\n }\r\n }\r\n\r\n @if (row.expanded) {\r\n <div class=\"ah__grid\" [class.ah__grid--compact]=\"row.layout === 'compact'\" [id]=\"sectionId(row.index)\">\r\n @for (mod of row.section.modules; track mod.key) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__card\"\r\n [class.ah__card--compact]=\"row.layout === 'compact'\"\r\n [disabled]=\"mod.disabled\"\r\n (click)=\"select(mod)\"\r\n >\r\n <span class=\"ah__card-ico\">\r\n @if (iconFor(mod.key); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\" />\r\n } @else if (mod.iconClass) {\r\n <i [class]=\"mod.iconClass\" aria-hidden=\"true\"></i>\r\n }\r\n </span>\r\n\r\n @if (row.layout === 'compact') {\r\n <span class=\"ah__card-main\">\r\n <span class=\"ah__card-title\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc\">{{ descKey | translate }}</span>\r\n }\r\n </span>\r\n <svg\r\n class=\"ah__card-arrow\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n } @else {\r\n <!-- No \"Open \u203A\" affordance row \u2014 the design's module card (MainContent.dc.html)\r\n ends at the description; the whole card is the click target and hover carries\r\n the affordance. Removed at the 2026-08-17 fidelity pass. -->\r\n <!-- Text stack: icon-to-text spacing is `.ah__card`'s own gap; this wrapper's\r\n gap is title-to-description only (module-card fidelity pass, 2026-08-20). -->\r\n <span class=\"ah__card-text\">\r\n <span class=\"ah__card-title ah__card-title--feature\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc ah__card-desc--feature\">{{ descKey | translate }}</span>\r\n }\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n </section>\r\n }\r\n </main>\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:100%;container-type:inline-size;--ah-brand: var(--app-color, var(--module-teal));--ah-brand-deep: var(--app-color-deep, var(--module-teal-deep));--ah-brand-soft: var(--app-color, var(--sys-teal));--ah-brand-ink: var(--app-ink, var(--ink-inverse))}.ah{display:flex;flex-direction:column;flex:1;min-height:100%}.ah__util{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-4) var(--sp-6)}:host-context(.window-content) .ah__brand{display:none}:host-context(.window-content) .ah__util{justify-content:flex-end}:host-context(.window-content) .ah__util:not(:has(>:not(.ah__brand))){display:none}.ah__brand{display:inline-flex;align-items:center;gap:var(--sp-2);padding:0;border:0;background:none;color:var(--ink);font-family:inherit;cursor:pointer}.ah__brand:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__brand-name{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__main{flex:1;inline-size:100%;max-inline-size:1120px;margin-inline:auto;padding:56px 40px;display:flex;flex-direction:column;justify-content:center;gap:44px}.ah__hero{max-inline-size:640px}.ah__title{margin:0 0 var(--sp-3);font-size:44px;font-weight:var(--fw-semibold);letter-spacing:-.03em;text-wrap:balance;background:linear-gradient(180deg,var(--ink),var(--ink-2));-webkit-background-clip:text;background-clip:text;color:transparent}.ah__sub{margin:0;max-inline-size:560px;font-size:var(--text-lg);line-height:1.55;color:var(--ink-3);text-wrap:pretty}.ah__sec{display:flex;flex-direction:column;gap:var(--sp-4)}.ah__sec--secondary{padding-block-start:28px;border-block-start:1px solid var(--w08)}.ah__sec-hd{display:flex;align-items:center;gap:var(--sp-3);inline-size:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;color:var(--ink);text-align:start}.ah__sec-hd:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__sec-chev{flex-shrink:0;color:var(--ink-3);transition:transform var(--t-overlay)}.ah__sec-title{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__sec-title--static{margin:0;color:var(--ink-3);font-size:var(--text-xs);letter-spacing:var(--tracking-wide);text-transform:uppercase}.ah__sec-count{display:inline-grid;place-items:center;min-inline-size:22px;block-size:20px;padding-inline:6px;border-radius:999px;background:var(--bg-3);border:1px solid var(--line);font-size:var(--text-2xs);font-weight:var(--fw-medium);font-variant-numeric:tabular-nums;color:var(--ink-3)}.ah__sec-hint{margin-inline-start:auto;font-size:var(--text-xs);color:var(--ink-3)}.ah__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;margin-top:4px;justify-content:flex-start}.ah__card{display:flex;flex-direction:column;align-items:stretch;position:relative;overflow:hidden;text-align:start;padding:20px;gap:16px;background:linear-gradient(160deg,var(--w055),var(--w02));border:1px solid var(--w09);border-radius:20px;color:inherit;font-family:inherit;cursor:pointer;animation:appTileIn .3s var(--nova-ease-micro) both}.ah__card:nth-child(1){animation-delay:0ms}.ah__card:nth-child(2){animation-delay:20ms}.ah__card:nth-child(3){animation-delay:40ms}.ah__card:nth-child(4){animation-delay:60ms}.ah__card:nth-child(5){animation-delay:80ms}.ah__card:nth-child(6){animation-delay:.1s}.ah__card:nth-child(7){animation-delay:.12s}.ah__card:nth-child(8){animation-delay:.14s}.ah__card:nth-child(9){animation-delay:.16s}.ah__card:nth-child(10){animation-delay:.18s}.ah__card:nth-child(11){animation-delay:.2s}.ah__card:nth-child(12){animation-delay:.22s}.ah__card:nth-child(n+13){animation-delay:.22s}.ah__card{transition:transform var(--t-overlay),box-shadow var(--t-overlay),border-color var(--t-state),background var(--t-state)}.ah__card:hover:not(:disabled){transform:translateY(-3px);background:linear-gradient(160deg,color-mix(in srgb,var(--ah-brand) 22%,transparent),color-mix(in srgb,var(--ah-brand-soft) 5%,transparent));border-color:color-mix(in srgb,var(--ah-brand) 50%,transparent);box-shadow:inset 0 1px color-mix(in srgb,var(--edge-highlight) 20%,transparent),0 20px 46px color-mix(in srgb,var(--ah-brand) 16%,transparent),var(--shadow-filter)}.ah__card:focus-visible{outline:0;border-color:color-mix(in oklab,var(--accent) 50%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 0 0 3px var(--accent-soft),0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card:disabled{cursor:default;opacity:.5}.ah__card-ico{display:grid;place-items:center;inline-size:42px;block-size:42px;flex:none;border-radius:13px;background:linear-gradient(140deg,color-mix(in srgb,var(--ah-brand-deep) 62%,transparent),color-mix(in srgb,var(--ah-brand) 30%,transparent));box-shadow:0 6px 16px color-mix(in srgb,var(--ah-brand-deep) 30%,transparent),inset 0 1px color-mix(in srgb,var(--edge-highlight) 50%,transparent);border:0;color:var(--ah-brand-ink);font-size:18px;transition:transform var(--t-overlay)}.ah__card--compact:hover:not(:disabled) .ah__card-ico,.ah__card--compact:focus-visible .ah__card-ico{background:linear-gradient(135deg,var(--accent),var(--sys-teal));box-shadow:inset 0 1px 0 var(--edge-highlight);color:var(--on-accent)}.ah__card-title{font-size:var(--text-sm);font-weight:var(--fw-semibold);letter-spacing:-.01em;color:var(--ink)}.ah__card-text{display:flex;flex-direction:column;gap:5px}.ah__card-title--feature{font-family:var(--font-family);font-weight:var(--fw-semibold);font-size:16.5px;line-height:1.25;letter-spacing:-.005em;color:var(--ink)}.ah__card-desc{font-size:var(--text-xs);line-height:1.45;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ah__card-desc--feature{font-family:var(--font-family);font-weight:400;font-size:13px;line-height:1.45;color:var(--w55);text-wrap:pretty;overflow:visible;white-space:normal}.ah__card-arrow{flex-shrink:0;transition:color var(--t-overlay),transform var(--t-overlay)}.ah__card--compact{flex-direction:row;align-items:center;gap:var(--sp-3);padding:14px 16px;background-color:var(--bg);background-image:linear-gradient(160deg,var(--w035),var(--w035));border-radius:16px;border-color:var(--w08)}.ah__card--compact:hover:not(:disabled),.ah__card--compact:focus-visible{border-color:color-mix(in oklab,var(--accent) 40%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card--compact .ah__card-ico{inline-size:32px;block-size:32px;margin-block-end:0;flex-shrink:0;border-radius:10px;font-size:var(--icon-md);background:var(--bg-3);box-shadow:none;color:var(--ink)}.ah__card-main{display:flex;flex-direction:column;gap:2px;flex:1;min-inline-size:0}.ah__card--compact .ah__card-arrow{color:var(--ink-4)}.ah__card--compact:hover:not(:disabled) .ah__card-arrow{color:var(--accent);transform:translate(2px)}:host-context([dir=rtl]) .ah__card-arrow{transform:scaleX(-1)}:host-context([dir=rtl]) .ah__sec-chev:not(.ah__sec-chev--open){transform:scaleX(-1)}:host-context([dir=rtl]) .ah__card--compact:hover:not(:disabled) .ah__card-arrow{transform:scaleX(-1) translate(2px)}.ah__sec-chev--open{transform:rotate(90deg)}@container (width <= 900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@media(width<=900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@container (width <= 560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}@media(width<=560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}\n"] }]
|
|
25023
25543
|
}], propDecorators: { brandLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandLabelKey", required: false }] }], titleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleKey", required: false }] }], subtitleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitleKey", required: false }] }], sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], modulesLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "modulesLabelKey", required: false }] }], moduleSelected: [{ type: i0.Output, args: ["moduleSelected"] }], brandSelected: [{ type: i0.Output, args: ["brandSelected"] }], icons: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FlyModuleIconDirective), { isSignal: true }] }] } });
|
|
25024
25544
|
|
|
25025
25545
|
/**
|
|
@@ -27447,5 +27967,5 @@ const AUDIENCE_ERROR_CODES = {
|
|
|
27447
27967
|
* Generated bundle index. Do not edit.
|
|
27448
27968
|
*/
|
|
27449
27969
|
|
|
27450
|
-
export { AGENT_DRAG_MIME, AGENT_PAYLOAD_VERSION, APP_LOOKUP, AUDIENCE_ERROR_CODES, AUDIENCE_LIMITS, AUDIENCE_PRESETS, AUDIENCE_TERM_KINDS, AgentActionBus, AgentActionUnsupportedDispatchError, AgentCommandRegistry, AgentDropRegistry, AgentFlightAnimator, AgentLookupRegistry, AgentPayloadOversizeError, AudienceBuilderComponent, AuthService, BilingualFieldComponent, CRON_MODES, CRON_WEEKDAYS, ContextMenuComponent, DEFAULT_AGENT_PAYLOAD_LIMITS, DEFAULT_FLY_THEME_MODE, DS_BASELINE_LOCALES, DashboardKpiComponent, DialogResult, ENTITY_LINK_LAUNCHER, EntityLookupComponent, FLYOS_LAUNCH_EVENT, FLYOS_LAUNCH_REQUEST_EVENT, FLYOS_REMOTE_ROUTE_EVENT, FLY_ACCENT_PROPERTY, FLY_ADMIN_ROLES, FLY_CHUNK_RELOAD_FLAG, FLY_COMPACT_THRESHOLD, FLY_COUNTRIES, FLY_CURRENCIES_BRIEF_ENDPOINT, FLY_CURRENCY_DEFAULT_ENDPOINT, FLY_EMOJI_BY_ID, FLY_EMOJI_CATEGORIES, FLY_EMOJI_CATEGORY_BY_ID, FLY_EMOJI_DEFAULT_CATEGORIES, FLY_EMOJI_PACK, FLY_EMOJI_PACK_MISSING_MESSAGE, FLY_EMOJI_PREVIEW_COUNT, FLY_EMPTY_VALUE, FLY_LOCALE_CATALOG, FLY_MAGIC_BAR_EVENT, FLY_MAGIC_BAR_ICONS, FLY_MAGIC_BAR_STORE_KEY, FLY_NF_CACHE_HEAL_FLAG, FLY_RELOAD_DEBOUNCE_MS, FLY_RELOAD_REARM_MS, FLY_REMOTE_BASE_PATH, FLY_REMOTE_CONTEXT_EVENT, FLY_REMOTE_CONTEXT_STORE_KEY, FLY_REMOTE_ROUTES, FLY_SCAN_PENDING_DEFAULT_DELAY_MS, FLY_SCAN_PENDING_MAX_RETRIES, FLY_SCAN_PENDING_STATUS, FLY_SEARCH_DEBOUNCE_MS, FLY_SKIN_TONES, FLY_STANDALONE_AUTH_CONFIG, FLY_STRATEGY_OBJECTIVES_LOOKUP_ENDPOINT, FLY_THEME_MODE_IDS, FLY_VIEWPORT_IS_MOBILE, FLY_WINDOW_BREADCRUMBS_EVENT, FLY_WINDOW_BREADCRUMBS_STORE_KEY, FLY_WINDOW_HELP_HINT_EVENT, FLY_WINDOW_PAGE_TITLE_EVENT, FlyAchievementProgressComponent, FlyActionMenuComponent, FlyActionStackComponent, FlyAgentDraggableDirective, FlyAnimatedEmojiComponent, FlyAppHomeComponent, FlyAppTopbarComponent, FlyAppUnavailableComponent, FlyAuthLiveRefresh, FlyBadgeWallComponent, FlyBlockUiComponent, FlyBreadcrumbComponent, FlyButtonComponent, FlyBytesPipe, FlyCaptchaComponent, FlyCardActionsComponent, FlyCardBodyComponent, FlyCardComponent, FlyCardFooterComponent, FlyCardGridComponent, FlyCardMediaComponent, FlyCardMetaComponent, FlyCardStatusComponent, FlyCardTitleComponent, FlyCellDirective, FlyCheckboxComponent, FlyChipComponent, FlyChunkReloadErrorHandler, FlyClickOutsideDirective, FlyCollapsibleComponent, FlyCommentThreadComponent, FlyCompactNumberPipe, FlyConfirmDialogComponent, FlyControlDirective, FlyCronBuilderComponent, FlyCurrencyCatalogService, FlyCurrencySelectorComponent, FlyDataTableComponent, FlyDatePipe, FlyDateTimePipe, FlyDebouncer, FlyDecimalNumberPipe, FlyDeepLinkPrefetchService, FlyDetailCardComponent, FlyDetailShellComponent, FlyDrawerComponent, FlyDurationPipe, FlyDynamicFormComponent, FlyEmojiPickerComponent, FlyFieldComponent, FlyFileDownloadService, FlyFileUploadComponent, FlyFilterPanelComponent, FlyFormBannerComponent, FlyFormFooterComponent, FlyFormGridComponent, FlyFormSectionComponent, FlyFullNumberPipe, FlyGanttComponent, FlyHubClient, FlyIconButtonComponent, FlyIfAdminDirective, FlyIfRoleDirective, FlyImageUploadComponent, FlyLeaderboardComponent, FlyMagicActionsComponent, FlyMetaListComponent, FlyModalComponent, FlyModerationQueueComponent, FlyModuleIconDirective, FlyMoneyPipe, FlyPagerComponent, FlyPaginationComponent, FlyPeoplePickerComponent, FlyPointsTierComponent, FlyProgressComponent, FlyRelativeTimePipe, FlyRemoteContextService, FlyRemoteRouter, FlyRemoteRouterOutletComponent, FlySearchInputComponent, FlySectionHeaderComponent, FlySecureSrcDirective, FlySegmentedComponent, FlySelectComponent, FlySkeletonComponent, FlySliderComponent, FlySparklineComponent, FlySpinnerComponent, FlyStandaloneAuthCallbackComponent, FlyStandaloneAuthService, FlyStandaloneMagicActionsComponent, FlyStateMessageComponent, FlyStrategySelectorComponent, FlyDynamicFormComponent as FlySurveyFormComponent, FlyTabComponent, FlyTabsComponent, FlyTagsInputComponent, FlyThemeService, FlyTimePipe, FlyToastService, FlyToggleComponent, FlyTooltipDirective, FlyTreeNavComponent, FlyTypeaheadComponent, FlyUserDirectoryService, FlyWindowHelpService, FlyWindowTitleService, FlyosPendingLaunchesGlobalKey, FlyosShellHandlesLaunchRequestsGlobalKey, FlyosShellOwnsHistoryGlobalKey, GANTT_DEPENDENCY_TYPES, GANTT_ROW_TINT_ALPHA, GANTT_ZOOMS, I18nService, LAUNCH_CONTEXT, MAGIC_BAR_SEARCH_WIDTH_DEFAULT, MAGIC_BAR_SEARCH_WIDTH_MAX, MAGIC_BAR_SEARCH_WIDTH_MIN, MagicBarRegistry, MessageBoxButtons, MessageBoxComponent, MessageBoxIcon, MessageBoxService, MockAuthService, NOVA_PRIORITY_TONE, NOVA_STATUS_TONE, NOVA_TONE_FALLBACK, OverlayStack, PRESENCE_COLORS, PageHeaderComponent, RTL_LOCALE_SET, SHARE_ORG_CHART_SYSTEM_KEY_APPS, SHARE_ORG_CHART_SYSTEM_KEY_DEFAULT, SHARE_PANEL_DEFAULT_FILE_LEVELS, STATE_DEFAULT_ICONS, STATE_DEFAULT_MESSAGE_KEYS, STEP_UP_CODE, STEP_UP_REAUTH_HANDLER, STEP_UP_RETURN_KEY, SUPPORTED_AGENT_PAYLOAD_VERSIONS, SharePanelComponent, SourceAppResolver, StandaloneWindowManagerService, StatusBadgeComponent, StepUpService, ToastHostComponent, TranslatePipe, WINDOW_DATA, WINDOW_HELP_HINT, WindowBreadcrumbsRegistry, WindowManagerService, applySkinTone, applySuggestion, ariaSort, buildCron, canConfirm, canGoNext$1 as canGoNext, canGoPrev$1 as canGoPrev, captureFocus, clampMagicBarSearchWidth, clampPage$1 as clampPage, clampSliderValue, connectRemoteLaunch, enterActivatesNatively, filterGroup, filterSuggestions, findLocaleByDialect, findLocaleByPrefix, firstEnabledIndex, firstModuleIndex, flattenModules, flyAdminGuard, flyApiErrorMessage, flyCaptchaBase64Utf8, flyCaptchaBuildToken, flyCaptchaSha256Hex, flyCompactNumber, flyDebounced, flyDecimalNumber, flyDownloadBlob, flyDuration, flyEmojiFor, flyEmojiIsTonable, flyEmojiPackUrl, flyExportFileName, flyFirstEnabledIndex, flyFormatBytes, flyFormatDate, flyFormatDateTime, flyFormatMoney, flyFormatTime, flyFullNumber, flyNextEnabledIndex, flyNextSegmentIndex, flyRelativeTime, flyResolveActiveTab, flyRoleGuard, flyScanPendingDelayMs, flyScanRetry, flySignedCompact, flySkinToneLabelKey, flyStandaloneAuthGuard, flyStandaloneAuthInterceptor, flyToDateOnly, flyToPage, flyUnwrap, flyUnwrapCurrencies, flyUnwrapCurrency, flyUnwrapLenient, flyUnwrapObjectiveLookup, hasAnyRoleIn, healNativeFederationCacheOnce, initialExpanded, isAccentColor, isChunkLoadError, isFlyAuthStorePopulated, isNativeFederationCacheError, isRtlLocale, isRtlLocaleEntry, isValidCron, isValidSingleField, loadRemoteStyles, magicBarOwnerKey, magicBarSearchText, matchFlyRoutePattern, nextEnabledIndex, nextModuleIndex, nextSegmentIndex, nextSort, normalizeFlyTheme, normalizeRoles, novaPriorityToneVar, novaStatusToneVar, overlayStack, canGoNext as pagerCanGoNext, canGoPrev as pagerCanGoPrev, clampPage as pagerClampPage, parseCron, parseStepUpChallenge, parseTags, prefetchRemoteStyles, presenceColorFor, printConsoleSecurityWarning, provideFlyChunkReloadRecovery, provideFlyEmojiPack, provideFlyStandaloneAuth, reloadOnceForChunkError, requestAppLaunch, resolveActiveModule, resolveActiveSection, resolveActiveTab, resolveCellValue, resolveStateIcon, resolveStateMessageKey, restoreFocus, sameTags, sectionHintKey, sectionLayout, sliderTrackGradient, sparklinePath, sparklinePoints, stepUpInterceptor, stepUpReturnKey, trimAgentPayload, trimAgentString, unloadRemoteStyles, utf8ByteLength, validateAgentPayload, warnIfEmbeddedSessionMissing };
|
|
27970
|
+
export { AGENT_DRAG_MIME, AGENT_PAYLOAD_VERSION, APP_LOOKUP, AUDIENCE_ERROR_CODES, AUDIENCE_LIMITS, AUDIENCE_PRESETS, AUDIENCE_TERM_KINDS, AgentActionBus, AgentActionUnsupportedDispatchError, AgentCommandRegistry, AgentDropRegistry, AgentFlightAnimator, AgentLookupRegistry, AgentPayloadOversizeError, AudienceBuilderComponent, AuthService, BilingualFieldComponent, CRON_MODES, CRON_WEEKDAYS, ContextMenuComponent, DEFAULT_AGENT_PAYLOAD_LIMITS, DEFAULT_FLY_THEME_MODE, DS_BASELINE_LOCALES, DashboardKpiComponent, DialogResult, ENTITY_LINK_LAUNCHER, EntityLookupComponent, FLYOS_LAUNCH_EVENT, FLYOS_LAUNCH_REQUEST_EVENT, FLYOS_REMOTE_ROUTE_EVENT, FLY_ACCENT_PROPERTY, FLY_ADMIN_ROLES, FLY_CHUNK_RELOAD_FLAG, FLY_COMPACT_THRESHOLD, FLY_COUNTRIES, FLY_CURRENCIES_BRIEF_ENDPOINT, FLY_CURRENCY_DEFAULT_ENDPOINT, FLY_EMOJI_BY_ID, FLY_EMOJI_CATEGORIES, FLY_EMOJI_CATEGORY_BY_ID, FLY_EMOJI_DEFAULT_CATEGORIES, FLY_EMOJI_PACK, FLY_EMOJI_PACK_MISSING_MESSAGE, FLY_EMOJI_PREVIEW_COUNT, FLY_EMPTY_VALUE, FLY_LOCALE_CATALOG, FLY_MAGIC_BAR_EVENT, FLY_MAGIC_BAR_ICONS, FLY_MAGIC_BAR_STORE_KEY, FLY_NF_CACHE_HEAL_FLAG, FLY_RELOAD_DEBOUNCE_MS, FLY_RELOAD_REARM_MS, FLY_REMOTE_BASE_PATH, FLY_REMOTE_CONTEXT_EVENT, FLY_REMOTE_CONTEXT_STORE_KEY, FLY_REMOTE_OUTLET_DEPTH, FLY_REMOTE_ROUTES, FLY_SCAN_PENDING_DEFAULT_DELAY_MS, FLY_SCAN_PENDING_MAX_RETRIES, FLY_SCAN_PENDING_STATUS, FLY_SEARCH_DEBOUNCE_MS, FLY_SKIN_TONES, FLY_STANDALONE_AUTH_CONFIG, FLY_STRATEGY_OBJECTIVES_LOOKUP_ENDPOINT, FLY_THEME_MODE_IDS, FLY_VIEWPORT_IS_MOBILE, FLY_WINDOW_BREADCRUMBS_EVENT, FLY_WINDOW_BREADCRUMBS_STORE_KEY, FLY_WINDOW_HELP_HINT_EVENT, FLY_WINDOW_PAGE_TITLE_EVENT, FlyAchievementProgressComponent, FlyActionMenuComponent, FlyActionStackComponent, FlyAgentDraggableDirective, FlyAnimatedEmojiComponent, FlyAppHomeComponent, FlyAppTopbarComponent, FlyAppUnavailableComponent, FlyAuthLiveRefresh, FlyBadgeWallComponent, FlyBlockUiComponent, FlyBreadcrumbComponent, FlyButtonComponent, FlyBytesPipe, FlyCaptchaComponent, FlyCardActionsComponent, FlyCardBodyComponent, FlyCardComponent, FlyCardFooterComponent, FlyCardGridComponent, FlyCardMediaComponent, FlyCardMetaComponent, FlyCardStatusComponent, FlyCardTitleComponent, FlyCellDirective, FlyCheckboxComponent, FlyChipComponent, FlyChunkReloadErrorHandler, FlyClickOutsideDirective, FlyCollapsibleComponent, FlyCommentThreadComponent, FlyCompactNumberPipe, FlyConfirmDialogComponent, FlyControlDirective, FlyCronBuilderComponent, FlyCurrencyCatalogService, FlyCurrencySelectorComponent, FlyDataTableComponent, FlyDatePipe, FlyDateTimePipe, FlyDebouncer, FlyDecimalNumberPipe, FlyDeepLinkPrefetchService, FlyDetailCardComponent, FlyDetailShellComponent, FlyDrawerComponent, FlyDurationPipe, FlyDynamicFormComponent, FlyEmojiPickerComponent, FlyFieldComponent, FlyFileDownloadService, FlyFileUploadComponent, FlyFilterPanelComponent, FlyFormBannerComponent, FlyFormFooterComponent, FlyFormGridComponent, FlyFormSectionComponent, FlyFullNumberPipe, FlyGanttComponent, FlyHubClient, FlyIconButtonComponent, FlyIfAdminDirective, FlyIfRoleDirective, FlyImageUploadComponent, FlyLeaderboardComponent, FlyLifecyclePipelineComponent, FlyMagicActionsComponent, FlyMetaListComponent, FlyModalComponent, FlyModerationQueueComponent, FlyModuleIconDirective, FlyMoneyPipe, FlyOverviewKpiRowComponent, FlyOverviewRowsComponent, FlyOverviewSectionComponent, FlyOverviewSurfaceComponent, FlyPagerComponent, FlyPaginationComponent, FlyPeoplePickerComponent, FlyPointsTierComponent, FlyProgressComponent, FlyRelativeTimePipe, FlyRemoteContextService, FlyRemoteRouter, FlyRemoteRouterOutletComponent, FlySearchInputComponent, FlySectionHeaderComponent, FlySecureSrcDirective, FlySegmentedComponent, FlySelectComponent, FlySkeletonComponent, FlySliderComponent, FlySparklineComponent, FlySpinnerComponent, FlyStandaloneAuthCallbackComponent, FlyStandaloneAuthService, FlyStandaloneMagicActionsComponent, FlyStateMessageComponent, FlyStrategySelectorComponent, FlyDynamicFormComponent as FlySurveyFormComponent, FlyTabComponent, FlyTabsComponent, FlyTagsInputComponent, FlyThemeService, FlyTimePipe, FlyToastService, FlyToggleComponent, FlyTooltipDirective, FlyTreeNavComponent, FlyTypeaheadComponent, FlyUserDirectoryService, FlyWindowHelpService, FlyWindowTitleService, FlyosPendingLaunchesGlobalKey, FlyosShellHandlesLaunchRequestsGlobalKey, FlyosShellOwnsHistoryGlobalKey, GANTT_DEPENDENCY_TYPES, GANTT_ROW_TINT_ALPHA, GANTT_ZOOMS, I18nService, LAUNCH_CONTEXT, MAGIC_BAR_SEARCH_WIDTH_DEFAULT, MAGIC_BAR_SEARCH_WIDTH_MAX, MAGIC_BAR_SEARCH_WIDTH_MIN, MagicBarRegistry, MessageBoxButtons, MessageBoxComponent, MessageBoxIcon, MessageBoxService, MockAuthService, NOVA_PRIORITY_TONE, NOVA_STATUS_TONE, NOVA_TONE_FALLBACK, OverlayStack, PRESENCE_COLORS, PageHeaderComponent, RTL_LOCALE_SET, SHARE_ORG_CHART_SYSTEM_KEY_APPS, SHARE_ORG_CHART_SYSTEM_KEY_DEFAULT, SHARE_PANEL_DEFAULT_FILE_LEVELS, STATE_DEFAULT_ICONS, STATE_DEFAULT_MESSAGE_KEYS, STEP_UP_CODE, STEP_UP_REAUTH_HANDLER, STEP_UP_RETURN_KEY, SUPPORTED_AGENT_PAYLOAD_VERSIONS, SharePanelComponent, SourceAppResolver, StandaloneWindowManagerService, StatusBadgeComponent, StepUpService, ToastHostComponent, TranslatePipe, WINDOW_DATA, WINDOW_HELP_HINT, WindowBreadcrumbsRegistry, WindowManagerService, applySkinTone, applySuggestion, ariaSort, buildCron, canConfirm, canGoNext$1 as canGoNext, canGoPrev$1 as canGoPrev, captureFocus, clampMagicBarSearchWidth, clampPage$1 as clampPage, clampSliderValue, connectRemoteLaunch, deepestFlyMatch, enterActivatesNatively, filterGroup, filterSuggestions, findLocaleByDialect, findLocaleByPrefix, firstEnabledIndex, firstModuleIndex, flattenModules, flyAdminGuard, flyApiErrorMessage, flyCaptchaBase64Utf8, flyCaptchaBuildToken, flyCaptchaSha256Hex, flyCompactNumber, flyDebounced, flyDecimalNumber, flyDownloadBlob, flyDuration, flyEmojiFor, flyEmojiIsTonable, flyEmojiPackUrl, flyExportFileName, flyFirstEnabledIndex, flyFormatBytes, flyFormatDate, flyFormatDateTime, flyFormatMoney, flyFormatTime, flyFullNumber, flyNextEnabledIndex, flyNextSegmentIndex, flyRelativeTime, flyResolveActiveTab, flyRoleGuard, flyScanPendingDelayMs, flyScanRetry, flySignedCompact, flySkinToneLabelKey, flyStandaloneAuthGuard, flyStandaloneAuthInterceptor, flyToDateOnly, flyToPage, flyUnwrap, flyUnwrapCurrencies, flyUnwrapCurrency, flyUnwrapLenient, flyUnwrapObjectiveLookup, hasAnyRoleIn, healNativeFederationCacheOnce, initialExpanded, isAccentColor, isChunkLoadError, isFlyAuthStorePopulated, isNativeFederationCacheError, isRtlLocale, isRtlLocaleEntry, isValidCron, isValidSingleField, loadRemoteStyles, magicBarOwnerKey, magicBarSearchText, matchFlyRoutePattern, matchFlyRoutePrefix, matchFlyRouteTable, nextEnabledIndex, nextModuleIndex, nextSegmentIndex, nextSort, normalizeFlyTheme, normalizeRoles, novaPriorityToneVar, novaStatusToneVar, overlayStack, canGoNext as pagerCanGoNext, canGoPrev as pagerCanGoPrev, clampPage as pagerClampPage, parseCron, parseStepUpChallenge, parseTags, prefetchRemoteStyles, presenceColorFor, printConsoleSecurityWarning, provideFlyChunkReloadRecovery, provideFlyEmojiPack, provideFlyOfflineAuth, provideFlyStandaloneAuth, reloadOnceForChunkError, requestAppLaunch, resolveActiveModule, resolveActiveSection, resolveActiveTab, resolveCellValue, resolveStateIcon, resolveStateMessageKey, restoreFocus, sameTags, sectionHintKey, sectionLayout, sliderTrackGradient, sparklinePath, sparklinePoints, stepUpInterceptor, stepUpReturnKey, trimAgentPayload, trimAgentString, unloadRemoteStyles, utf8ByteLength, validateAgentPayload, warnIfEmbeddedSessionMissing };
|
|
27451
27971
|
//# sourceMappingURL=flyos-design-system.mjs.map
|