@kaufmann-lab/ui 0.1.8 → 0.1.9
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, inject, computed, effect, Component, booleanAttribute, model, output, numberAttribute, contentChildren, signal, DestroyRef, viewChild, forwardRef, ViewContainerRef, HostListener, TemplateRef, contentChild, ElementRef, ChangeDetectionStrategy, afterRenderEffect, afterNextRender, Injectable } from '@angular/core';
|
|
2
|
+
import { input, inject, computed, effect, Component, booleanAttribute, model, output, numberAttribute, contentChildren, signal, DestroyRef, viewChild, forwardRef, ViewContainerRef, HostListener, TemplateRef, contentChild, ElementRef, Directive, ChangeDetectionStrategy, afterRenderEffect, afterNextRender, Injectable } from '@angular/core';
|
|
3
3
|
import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
|
|
4
4
|
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
|
|
5
5
|
import { Overlay } from '@angular/cdk/overlay';
|
|
@@ -3345,6 +3345,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
3345
3345
|
`, styles: [":host{display:block}.kf-filter-chips{display:flex;flex-wrap:wrap;gap:var(--kf-space-xs)}.kf-filter-chips__chip{font:inherit;padding:var(--kf-space-xs) var(--kf-space-md);border-radius:var(--kf-radius-pill);border:1px solid var(--kf-color-border);background:var(--kf-color-surface);color:var(--kf-color-text);cursor:pointer;transition:background .14s,border-color .14s,color .14s}.kf-filter-chips__chip:hover:not(.kf-filter-chips__chip--active){border-color:var(--kf-color-border-strong)}.kf-filter-chips__chip:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-filter-chips__chip--active{background:var(--kf-color-ink);border-color:var(--kf-color-ink);color:var(--kf-color-white)}\n"] }]
|
|
3346
3346
|
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
|
|
3347
3347
|
|
|
3348
|
+
/**
|
|
3349
|
+
* Marca el contenido que `kf-folder-tabs` debe proyectar dentro de su
|
|
3350
|
+
* panel. Sin lógica propia — existe solo como token de tipo para que
|
|
3351
|
+
* `contentChild(FolderTabsPanel)` pueda detectar si el consumidor proyectó
|
|
3352
|
+
* algo (mismo mecanismo que `kf-dropdown` usa con `contentChild(DropdownPanel)`;
|
|
3353
|
+
* acá no hace falta un componente completo, alcanza con una directiva de
|
|
3354
|
+
* atributo porque el panel no necesita comportamiento propio, solo marcar
|
|
3355
|
+
* su presencia).
|
|
3356
|
+
*
|
|
3357
|
+
* <div kf-folder-tabs-panel>...</div>
|
|
3358
|
+
*/
|
|
3359
|
+
class FolderTabsPanel {
|
|
3360
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FolderTabsPanel, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3361
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.0", type: FolderTabsPanel, isStandalone: true, selector: "[kf-folder-tabs-panel]", ngImport: i0 });
|
|
3362
|
+
}
|
|
3363
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FolderTabsPanel, decorators: [{
|
|
3364
|
+
type: Directive,
|
|
3365
|
+
args: [{ selector: '[kf-folder-tabs-panel]' }]
|
|
3366
|
+
}] });
|
|
3348
3367
|
/**
|
|
3349
3368
|
* Tabs con forma de "carpeta": el borde superior queda redondeado y el borde
|
|
3350
3369
|
* inferior de la pestaña activa se funde visualmente con el panel de
|
|
@@ -3355,9 +3374,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
3355
3374
|
* `--active` se mueve de un botón a otro, y eso vuelve a disparar el keyframe
|
|
3356
3375
|
* sin tocar JS.
|
|
3357
3376
|
*
|
|
3358
|
-
* El
|
|
3359
|
-
*
|
|
3360
|
-
*
|
|
3377
|
+
* El panel de contenido es un `<ng-content>` OPCIONAL — si el consumidor no
|
|
3378
|
+
* proyecta nada, `kf-folder-tabs` renderiza solo la fila de pestañas (mismo
|
|
3379
|
+
* comportamiento que antes de que existiera este slot, detectado con
|
|
3380
|
+
* `contentChild()` sin `.required`, igual patrón que usa `kf-dropdown` para
|
|
3381
|
+
* saber si hay un `kf-dropdown-panel` proyectado). Si SÍ proyecta contenido,
|
|
3382
|
+
* se envuelve en un panel con la esquina superior-izquierda recta (nace ahí
|
|
3383
|
+
* la primera pestaña, siempre pegada al borde izquierdo de la fila — un
|
|
3384
|
+
* radio ahí competiría visualmente con el propio borde redondeado de esa
|
|
3385
|
+
* pestaña) y las otras tres redondeadas. El `border-bottom` de 2px de la
|
|
3386
|
+
* pestaña activa (ver `.kf-folder-tabs__tab--active` más abajo) es la señal
|
|
3387
|
+
* visual de conexión con el panel para CUALQUIER pestaña activa, sin
|
|
3388
|
+
* necesitar mover ni medir nada.
|
|
3389
|
+
*
|
|
3390
|
+
* El borde izquierdo de toda la fila (y por lo tanto de la esquina recta
|
|
3391
|
+
* del panel) depende de que ninguna pestaña se corra al cambiar de estado
|
|
3392
|
+
* — ver `transform-origin: bottom left` en `.kf-folder-tabs__tab`: con el
|
|
3393
|
+
* origen centrado (como estaba antes), el `scale()` de la pestaña inactiva
|
|
3394
|
+
* encogía el borde izquierdo unos px, y ese corrimiento sub-pixel es lo que
|
|
3395
|
+
* hacía que este mismo diseño (esquina fija) se viera "roto" cuando la
|
|
3396
|
+
* pestaña activa no era la primera. Con el origen anclado a la izquierda,
|
|
3397
|
+
* el corrimiento desaparece y la esquina fija vuelve a ser una solución
|
|
3398
|
+
* válida y simple — sin necesitar medir la pestaña activa por JS.
|
|
3399
|
+
*
|
|
3400
|
+
* Antes de este slot, el patrón era que el consumidor pusiera su propia
|
|
3401
|
+
* card como HERMANO de `kf-folder-tabs` y anulara a mano el radio superior
|
|
3402
|
+
* completo (`border-top-left-radius: 0`, `border-top-right-radius: 0` — ver
|
|
3403
|
+
* el caso original de `web-portal-latam-frontend`). Encapsular esto acá
|
|
3404
|
+
* evita que cada consumidor repita esas reglas a mano.
|
|
3405
|
+
*
|
|
3406
|
+
* <kf-folder-tabs [options]="tabs" [value]="active" (valueChange)="active = $event">
|
|
3407
|
+
* <div kf-folder-tabs-panel>contenido de la pestaña activa</div>
|
|
3408
|
+
* </kf-folder-tabs>
|
|
3409
|
+
*
|
|
3410
|
+
* <!-- o, sin contenido, como antes: -->
|
|
3361
3411
|
* <kf-folder-tabs [options]="tabs" [value]="active" (valueChange)="active = $event" />
|
|
3362
3412
|
*/
|
|
3363
3413
|
class FolderTabs {
|
|
@@ -3366,6 +3416,18 @@ class FolderTabs {
|
|
|
3366
3416
|
value = input.required(/* @ts-ignore */
|
|
3367
3417
|
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
3368
3418
|
valueChange = output();
|
|
3419
|
+
/**
|
|
3420
|
+
* Detecta si el consumidor proyectó contenido marcado con
|
|
3421
|
+
* `kf-folder-tabs-panel` — sin `.required`, así que es `undefined`
|
|
3422
|
+
* cuando no hay nada proyectado (mismo patrón que usa `kf-dropdown` con
|
|
3423
|
+
* `contentChild(DropdownPanel)` para saber si hay un panel que
|
|
3424
|
+
* attachear). `hasPanel()` decide si el wrapper del panel participa del
|
|
3425
|
+
* layout (`display: contents` si no).
|
|
3426
|
+
*/
|
|
3427
|
+
projectedPanel = contentChild(FolderTabsPanel, /* @ts-ignore */
|
|
3428
|
+
...(ngDevMode ? [{ debugName: "projectedPanel" }] : /* istanbul ignore next */ []));
|
|
3429
|
+
hasPanel = computed(() => this.projectedPanel() !== undefined, /* @ts-ignore */
|
|
3430
|
+
...(ngDevMode ? [{ debugName: "hasPanel" }] : /* istanbul ignore next */ []));
|
|
3369
3431
|
select(value) {
|
|
3370
3432
|
if (value === this.value()) {
|
|
3371
3433
|
return;
|
|
@@ -3402,7 +3464,7 @@ class FolderTabs {
|
|
|
3402
3464
|
nextButton?.focus();
|
|
3403
3465
|
}
|
|
3404
3466
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FolderTabs, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3405
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: FolderTabs, isStandalone: true, selector: "kf-folder-tabs", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
|
|
3467
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: FolderTabs, isStandalone: true, selector: "kf-folder-tabs", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { valueChange: "valueChange" }, queries: [{ propertyName: "projectedPanel", first: true, predicate: FolderTabsPanel, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
3406
3468
|
<div class="kf-folder-tabs" role="tablist">
|
|
3407
3469
|
@for (option of options(); track option.value) {
|
|
3408
3470
|
<button
|
|
@@ -3424,7 +3486,11 @@ class FolderTabs {
|
|
|
3424
3486
|
</button>
|
|
3425
3487
|
}
|
|
3426
3488
|
</div>
|
|
3427
|
-
|
|
3489
|
+
|
|
3490
|
+
<div class="kf-folder-tabs__panel" [class.kf-folder-tabs__panel--empty]="!hasPanel()">
|
|
3491
|
+
<ng-content select="[kf-folder-tabs-panel]" />
|
|
3492
|
+
</div>
|
|
3493
|
+
`, isInline: true, styles: [":host{display:block;font-family:var(--kf-font-body)}.kf-folder-tabs{display:flex;align-items:flex-end;gap:var(--kf-space-xs);perspective:900px}.kf-folder-tabs__tab{position:relative;display:inline-flex;align-items:center;gap:var(--kf-space-xs);font:inherit;font-size:.9rem;color:var(--kf-color-text-muted);background:var(--kf-color-surface);border:1px solid var(--kf-color-border);border-bottom-color:var(--kf-color-border-strong);border-radius:var(--kf-radius-sm) var(--kf-radius-sm) 0 0;padding:var(--kf-space-sm) var(--kf-space-md);cursor:pointer;transform-origin:bottom left;transform:translateY(5px) scale(.985);transition:background .14s,color .14s,border-color .14s,transform .22s cubic-bezier(.32,.72,0,1)}.kf-folder-tabs__tab:hover:not(.kf-folder-tabs__tab--active){color:var(--kf-color-text);background:var(--kf-color-white);transform:translateY(2px) scale(.99)}.kf-folder-tabs__tab:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus);z-index:1}.kf-folder-tabs__tab--active{z-index:1;color:var(--kf-color-primary);font-weight:700;background:var(--kf-color-white);border-color:var(--kf-color-border);border-bottom:2px solid var(--kf-color-primary);box-shadow:0 -6px 14px -10px #10182866;transform:translateY(1px);animation:kf-folder-tabs-pull .34s cubic-bezier(.22,1.2,.36,1) both}@keyframes kf-folder-tabs-pull{0%{transform:translateY(7px) rotateX(-10deg) scale(.97)}60%{transform:translateY(1px) rotateX(2deg) scale(1.01)}to{transform:translateY(1px) rotateX(0) scale(1)}}@media(prefers-reduced-motion:reduce){.kf-folder-tabs__tab,.kf-folder-tabs__tab--active{animation:none;transition:background .14s,color .14s,border-color .14s}}.kf-folder-tabs__panel--empty{display:contents}.kf-folder-tabs__panel:not(.kf-folder-tabs__panel--empty){background:var(--kf-color-white);border-right:1px solid var(--kf-color-border);border-bottom:1px solid var(--kf-color-border);border-left:1px solid var(--kf-color-border);border-top:1px solid var(--kf-color-border);border-radius:var(--kf-radius-md);border-top-left-radius:0;overflow:hidden}\n"], dependencies: [{ kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size"] }] });
|
|
3428
3494
|
}
|
|
3429
3495
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FolderTabs, decorators: [{
|
|
3430
3496
|
type: Component,
|
|
@@ -3450,8 +3516,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
3450
3516
|
</button>
|
|
3451
3517
|
}
|
|
3452
3518
|
</div>
|
|
3453
|
-
|
|
3454
|
-
|
|
3519
|
+
|
|
3520
|
+
<div class="kf-folder-tabs__panel" [class.kf-folder-tabs__panel--empty]="!hasPanel()">
|
|
3521
|
+
<ng-content select="[kf-folder-tabs-panel]" />
|
|
3522
|
+
</div>
|
|
3523
|
+
`, styles: [":host{display:block;font-family:var(--kf-font-body)}.kf-folder-tabs{display:flex;align-items:flex-end;gap:var(--kf-space-xs);perspective:900px}.kf-folder-tabs__tab{position:relative;display:inline-flex;align-items:center;gap:var(--kf-space-xs);font:inherit;font-size:.9rem;color:var(--kf-color-text-muted);background:var(--kf-color-surface);border:1px solid var(--kf-color-border);border-bottom-color:var(--kf-color-border-strong);border-radius:var(--kf-radius-sm) var(--kf-radius-sm) 0 0;padding:var(--kf-space-sm) var(--kf-space-md);cursor:pointer;transform-origin:bottom left;transform:translateY(5px) scale(.985);transition:background .14s,color .14s,border-color .14s,transform .22s cubic-bezier(.32,.72,0,1)}.kf-folder-tabs__tab:hover:not(.kf-folder-tabs__tab--active){color:var(--kf-color-text);background:var(--kf-color-white);transform:translateY(2px) scale(.99)}.kf-folder-tabs__tab:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus);z-index:1}.kf-folder-tabs__tab--active{z-index:1;color:var(--kf-color-primary);font-weight:700;background:var(--kf-color-white);border-color:var(--kf-color-border);border-bottom:2px solid var(--kf-color-primary);box-shadow:0 -6px 14px -10px #10182866;transform:translateY(1px);animation:kf-folder-tabs-pull .34s cubic-bezier(.22,1.2,.36,1) both}@keyframes kf-folder-tabs-pull{0%{transform:translateY(7px) rotateX(-10deg) scale(.97)}60%{transform:translateY(1px) rotateX(2deg) scale(1.01)}to{transform:translateY(1px) rotateX(0) scale(1)}}@media(prefers-reduced-motion:reduce){.kf-folder-tabs__tab,.kf-folder-tabs__tab--active{animation:none;transition:background .14s,color .14s,border-color .14s}}.kf-folder-tabs__panel--empty{display:contents}.kf-folder-tabs__panel:not(.kf-folder-tabs__panel--empty){background:var(--kf-color-white);border-right:1px solid var(--kf-color-border);border-bottom:1px solid var(--kf-color-border);border-left:1px solid var(--kf-color-border);border-top:1px solid var(--kf-color-border);border-radius:var(--kf-radius-md);border-top-left-radius:0;overflow:hidden}\n"] }]
|
|
3524
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], projectedPanel: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FolderTabsPanel), { isSignal: true }] }] } });
|
|
3455
3525
|
|
|
3456
3526
|
/**
|
|
3457
3527
|
* Input de formulario apilado: label arriba (en mayúsculas vía CSS), campo con
|
|
@@ -4552,12 +4622,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
4552
4622
|
* Es distinto de `kf-page-header`/`kf-page-head` (título de una vista
|
|
4553
4623
|
* interna) — este es el chrome global del portal, se monta una sola vez.
|
|
4554
4624
|
*
|
|
4625
|
+
* `:host` es `position: sticky; top: 0` — el header queda pegado arriba al
|
|
4626
|
+
* hacer scroll. No es `fixed`: como no se superpone al contenido en el
|
|
4627
|
+
* primer render, no hace falta que el consumidor compense con
|
|
4628
|
+
* `padding-top`.
|
|
4629
|
+
*
|
|
4630
|
+
* Bajo los 768px, el `<nav>` deja de mostrarse en línea junto al logo y
|
|
4631
|
+
* colapsa detrás de un botón de menú (ícono `menu`/`x`) que despliega un
|
|
4632
|
+
* drawer lateral (desde el borde derecho, `position: fixed` + overlay de
|
|
4633
|
+
* fondo) con los mismos `navItems` en columna. Ese drawer expone un slot
|
|
4634
|
+
* (`<ng-content select="[kf-portal-header-extra]">`) al final, pensado
|
|
4635
|
+
* para que el consumidor proyecte contenido propio que en escritorio vive
|
|
4636
|
+
* en otro lugar (ej. el menú de sesión) — `PortalHeader` no sabe qué es
|
|
4637
|
+
* ese contenido ni cómo se abre, solo le da un lugar dentro del drawer ya
|
|
4638
|
+
* desplegado. El overlay cierra el drawer al tocarlo, y `Escape` también.
|
|
4639
|
+
*
|
|
4555
4640
|
* <kf-portal-header
|
|
4556
4641
|
* [isAdmin]="true"
|
|
4557
4642
|
* [adminActions]="[{ label: 'Consultar deuda clientes', href: '/deuda' }, { label: 'Cambiar DNI', href: '/dni' }]"
|
|
4558
4643
|
* [navItems]="[{ label: 'Home', href: '/', active: true }, { label: 'Vehículos', href: '/vehiculos' }]"
|
|
4559
4644
|
* userInitials="TS"
|
|
4560
|
-
*
|
|
4645
|
+
* >
|
|
4646
|
+
* <div kf-portal-header-extra>contenido propio, solo visible en el panel mobile</div>
|
|
4647
|
+
* </kf-portal-header>
|
|
4561
4648
|
*/
|
|
4562
4649
|
class PortalHeader {
|
|
4563
4650
|
brand = input('DIVEMOTOR', /* @ts-ignore */
|
|
@@ -4570,8 +4657,26 @@ class PortalHeader {
|
|
|
4570
4657
|
userInitials = input.required(/* @ts-ignore */
|
|
4571
4658
|
...(ngDevMode ? [{ debugName: "userInitials" }] : /* istanbul ignore next */ []));
|
|
4572
4659
|
sessionClick = output();
|
|
4660
|
+
/** Visibilidad del drawer de navegación mobile (bajo los 768px). */
|
|
4661
|
+
mobileMenuOpen = signal(false, /* @ts-ignore */
|
|
4662
|
+
...(ngDevMode ? [{ debugName: "mobileMenuOpen" }] : /* istanbul ignore next */ []));
|
|
4663
|
+
/** Cierra el drawer con Escape — mismo patrón que cualquier drawer/modal. */
|
|
4664
|
+
onEscape() {
|
|
4665
|
+
this.mobileMenuOpen.set(false);
|
|
4666
|
+
}
|
|
4667
|
+
/**
|
|
4668
|
+
* `ElementRef` real del botón de sesión (el avatar en la esquina
|
|
4669
|
+
* derecha), no de todo el header. Pensado para anclar un `kf-dropdown`
|
|
4670
|
+
* externo — sin esto, el único `ElementRef` disponible desde afuera es el
|
|
4671
|
+
* del host de `PortalHeader`, que ocupa el ancho completo de la pantalla
|
|
4672
|
+
* (logo + nav + sesión), y el overlay del CDK termina "pegado" a la
|
|
4673
|
+
* esquina del header entero en vez de al botón que el usuario clickeó.
|
|
4674
|
+
*
|
|
4675
|
+
* <kf-dropdown [(open)]="menuOpen" [anchor]="header().sessionButtonRef()">
|
|
4676
|
+
*/
|
|
4677
|
+
sessionButtonRef = viewChild.required('sessionButton', { ...(ngDevMode ? { debugName: "sessionButtonRef" } : /* istanbul ignore next */ {}), read: ElementRef });
|
|
4573
4678
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: PortalHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4574
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: PortalHeader, isStandalone: true, selector: "kf-portal-header", inputs: { brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: false, transformFunction: null }, isAdmin: { classPropertyName: "isAdmin", publicName: "isAdmin", isSignal: true, isRequired: false, transformFunction: null }, adminActions: { classPropertyName: "adminActions", publicName: "adminActions", isSignal: true, isRequired: false, transformFunction: null }, navItems: { classPropertyName: "navItems", publicName: "navItems", isSignal: true, isRequired: false, transformFunction: null }, userInitials: { classPropertyName: "userInitials", publicName: "userInitials", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { sessionClick: "sessionClick" }, ngImport: i0, template: `
|
|
4679
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: PortalHeader, isStandalone: true, selector: "kf-portal-header", inputs: { brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: false, transformFunction: null }, isAdmin: { classPropertyName: "isAdmin", publicName: "isAdmin", isSignal: true, isRequired: false, transformFunction: null }, adminActions: { classPropertyName: "adminActions", publicName: "adminActions", isSignal: true, isRequired: false, transformFunction: null }, navItems: { classPropertyName: "navItems", publicName: "navItems", isSignal: true, isRequired: false, transformFunction: null }, userInitials: { classPropertyName: "userInitials", publicName: "userInitials", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { sessionClick: "sessionClick" }, host: { listeners: { "document:keydown.escape": "onEscape()" } }, viewQueries: [{ propertyName: "sessionButtonRef", first: true, predicate: ["sessionButton"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: `
|
|
4575
4680
|
@if (isAdmin()) {
|
|
4576
4681
|
<div class="kf-portal-header__admin-bar">
|
|
4577
4682
|
<kf-admin-badge inline />
|
|
@@ -4584,6 +4689,7 @@ class PortalHeader {
|
|
|
4584
4689
|
}
|
|
4585
4690
|
<div class="kf-portal-header__brand-bar">
|
|
4586
4691
|
<span class="kf-portal-header__logo">{{ brand() }}</span>
|
|
4692
|
+
|
|
4587
4693
|
<nav class="kf-portal-header__nav">
|
|
4588
4694
|
@for (item of navItems(); track item.label) {
|
|
4589
4695
|
<a
|
|
@@ -4595,15 +4701,54 @@ class PortalHeader {
|
|
|
4595
4701
|
</a>
|
|
4596
4702
|
}
|
|
4597
4703
|
</nav>
|
|
4598
|
-
|
|
4704
|
+
|
|
4705
|
+
<button
|
|
4706
|
+
#sessionButton
|
|
4707
|
+
type="button"
|
|
4708
|
+
class="kf-portal-header__session"
|
|
4709
|
+
(click)="sessionClick.emit()"
|
|
4710
|
+
>
|
|
4599
4711
|
<kf-avatar [initials]="userInitials()" pill />
|
|
4600
4712
|
</button>
|
|
4713
|
+
|
|
4714
|
+
<button
|
|
4715
|
+
type="button"
|
|
4716
|
+
class="kf-portal-header__menu-toggle"
|
|
4717
|
+
[attr.aria-expanded]="mobileMenuOpen()"
|
|
4718
|
+
aria-label="Abrir menú de navegación"
|
|
4719
|
+
(click)="mobileMenuOpen.set(!mobileMenuOpen())"
|
|
4720
|
+
>
|
|
4721
|
+
<kf-icon [name]="mobileMenuOpen() ? 'x' : 'menu'" size="md" />
|
|
4722
|
+
</button>
|
|
4601
4723
|
</div>
|
|
4602
|
-
|
|
4724
|
+
|
|
4725
|
+
@if (mobileMenuOpen()) {
|
|
4726
|
+
<div class="kf-portal-header__overlay" (click)="mobileMenuOpen.set(false)"></div>
|
|
4727
|
+
}
|
|
4728
|
+
|
|
4729
|
+
<nav
|
|
4730
|
+
class="kf-portal-header__drawer"
|
|
4731
|
+
[class.kf-portal-header__drawer--open]="mobileMenuOpen()"
|
|
4732
|
+
role="menu"
|
|
4733
|
+
[attr.aria-hidden]="!mobileMenuOpen()"
|
|
4734
|
+
>
|
|
4735
|
+
@for (item of navItems(); track item.label) {
|
|
4736
|
+
<a
|
|
4737
|
+
class="kf-portal-header__mobile-nav-item"
|
|
4738
|
+
[class.kf-portal-header__mobile-nav-item--active]="item.active"
|
|
4739
|
+
[href]="item.href"
|
|
4740
|
+
(click)="mobileMenuOpen.set(false)"
|
|
4741
|
+
>
|
|
4742
|
+
{{ item.label }}
|
|
4743
|
+
</a>
|
|
4744
|
+
}
|
|
4745
|
+
<ng-content select="[kf-portal-header-extra]" />
|
|
4746
|
+
</nav>
|
|
4747
|
+
`, isInline: true, styles: [":host{display:block;position:sticky;top:0;z-index:30;font-family:var(--kf-font-body)}.kf-portal-header__admin-bar{display:flex;align-items:center;justify-content:space-between;gap:var(--kf-space-md);padding:var(--kf-space-xs) var(--kf-space-lg);background:var(--kf-color-tertiary-deep)}.kf-portal-header__admin-actions{display:flex;gap:var(--kf-space-md)}.kf-portal-header__admin-action{font-size:.8125rem;font-weight:600;color:#ffffffd9;text-decoration:none}.kf-portal-header__admin-action:hover{color:var(--kf-color-white)}.kf-portal-header__brand-bar{display:flex;align-items:center;gap:var(--kf-space-lg);padding:var(--kf-space-sm) var(--kf-space-lg);background:var(--kf-color-tertiary-deep);border-top:1px solid rgba(255,255,255,.1)}.kf-portal-header__logo{font-family:var(--kf-font-title);font-size:1.25rem;font-weight:700;letter-spacing:.02em;color:var(--kf-color-white);text-transform:uppercase;flex:1 1 auto;min-width:0}.kf-portal-header__nav{display:flex;align-items:center;gap:var(--kf-space-xs);flex:1 1 auto}.kf-portal-header__nav-item{padding:var(--kf-space-xs) var(--kf-space-md);border-radius:var(--kf-radius-sm);color:#ffffffbf;font-size:.875rem;font-weight:600;text-decoration:none;white-space:nowrap;transition:background .14s,color .14s}.kf-portal-header__nav-item:hover:not(.kf-portal-header__nav-item--active){color:var(--kf-color-white)}.kf-portal-header__nav-item--active{background:var(--kf-color-white);color:var(--kf-color-ink)}.kf-portal-header__session{flex:none;border:none;background:transparent;padding:0;cursor:pointer}.kf-portal-header__menu-toggle{display:none;flex:none;align-items:center;justify-content:center;width:36px;height:36px;border:none;border-radius:var(--kf-radius-sm);background:transparent;color:var(--kf-color-white);cursor:pointer}.kf-portal-header__menu-toggle:hover{background:#ffffff1a}.kf-portal-header__overlay{position:fixed;inset:0;background:#10182866;z-index:39}.kf-portal-header__drawer{position:fixed;top:0;right:0;bottom:0;z-index:40;display:none;flex-direction:column;width:min(80vw,320px);padding:var(--kf-space-lg);background:var(--kf-color-tertiary-deep);box-shadow:-8px 0 24px -8px #1018284d;transform:translate(100%);visibility:hidden;transition:transform .24s cubic-bezier(.32,.72,0,1),visibility 0s linear .24s}.kf-portal-header__drawer--open{transform:translate(0);visibility:visible;transition:transform .24s cubic-bezier(.32,.72,0,1),visibility 0s linear 0s}.kf-portal-header__mobile-nav-item{padding:var(--kf-space-sm) var(--kf-space-xs);color:#ffffffd9;font-size:.9375rem;font-weight:600;text-decoration:none;border-radius:var(--kf-radius-sm)}.kf-portal-header__mobile-nav-item:hover{background:#ffffff14}.kf-portal-header__mobile-nav-item--active{color:var(--kf-color-white);background:#ffffff24}@media(max-width:768px){.kf-portal-header__nav,.kf-portal-header__session{display:none}.kf-portal-header__menu-toggle{display:inline-flex}.kf-portal-header__drawer{display:flex}}\n"], dependencies: [{ kind: "component", type: AdminBadge, selector: "kf-admin-badge", inputs: ["inline"] }, { kind: "component", type: Avatar, selector: "kf-avatar", inputs: ["initials", "src", "round", "pill"] }, { kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size"] }] });
|
|
4603
4748
|
}
|
|
4604
4749
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: PortalHeader, decorators: [{
|
|
4605
4750
|
type: Component,
|
|
4606
|
-
args: [{ selector: 'kf-portal-header', imports: [AdminBadge, Avatar], template: `
|
|
4751
|
+
args: [{ selector: 'kf-portal-header', imports: [AdminBadge, Avatar, Icon], template: `
|
|
4607
4752
|
@if (isAdmin()) {
|
|
4608
4753
|
<div class="kf-portal-header__admin-bar">
|
|
4609
4754
|
<kf-admin-badge inline />
|
|
@@ -4616,6 +4761,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
4616
4761
|
}
|
|
4617
4762
|
<div class="kf-portal-header__brand-bar">
|
|
4618
4763
|
<span class="kf-portal-header__logo">{{ brand() }}</span>
|
|
4764
|
+
|
|
4619
4765
|
<nav class="kf-portal-header__nav">
|
|
4620
4766
|
@for (item of navItems(); track item.label) {
|
|
4621
4767
|
<a
|
|
@@ -4627,12 +4773,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
4627
4773
|
</a>
|
|
4628
4774
|
}
|
|
4629
4775
|
</nav>
|
|
4630
|
-
|
|
4776
|
+
|
|
4777
|
+
<button
|
|
4778
|
+
#sessionButton
|
|
4779
|
+
type="button"
|
|
4780
|
+
class="kf-portal-header__session"
|
|
4781
|
+
(click)="sessionClick.emit()"
|
|
4782
|
+
>
|
|
4631
4783
|
<kf-avatar [initials]="userInitials()" pill />
|
|
4632
4784
|
</button>
|
|
4785
|
+
|
|
4786
|
+
<button
|
|
4787
|
+
type="button"
|
|
4788
|
+
class="kf-portal-header__menu-toggle"
|
|
4789
|
+
[attr.aria-expanded]="mobileMenuOpen()"
|
|
4790
|
+
aria-label="Abrir menú de navegación"
|
|
4791
|
+
(click)="mobileMenuOpen.set(!mobileMenuOpen())"
|
|
4792
|
+
>
|
|
4793
|
+
<kf-icon [name]="mobileMenuOpen() ? 'x' : 'menu'" size="md" />
|
|
4794
|
+
</button>
|
|
4633
4795
|
</div>
|
|
4634
|
-
|
|
4635
|
-
|
|
4796
|
+
|
|
4797
|
+
@if (mobileMenuOpen()) {
|
|
4798
|
+
<div class="kf-portal-header__overlay" (click)="mobileMenuOpen.set(false)"></div>
|
|
4799
|
+
}
|
|
4800
|
+
|
|
4801
|
+
<nav
|
|
4802
|
+
class="kf-portal-header__drawer"
|
|
4803
|
+
[class.kf-portal-header__drawer--open]="mobileMenuOpen()"
|
|
4804
|
+
role="menu"
|
|
4805
|
+
[attr.aria-hidden]="!mobileMenuOpen()"
|
|
4806
|
+
>
|
|
4807
|
+
@for (item of navItems(); track item.label) {
|
|
4808
|
+
<a
|
|
4809
|
+
class="kf-portal-header__mobile-nav-item"
|
|
4810
|
+
[class.kf-portal-header__mobile-nav-item--active]="item.active"
|
|
4811
|
+
[href]="item.href"
|
|
4812
|
+
(click)="mobileMenuOpen.set(false)"
|
|
4813
|
+
>
|
|
4814
|
+
{{ item.label }}
|
|
4815
|
+
</a>
|
|
4816
|
+
}
|
|
4817
|
+
<ng-content select="[kf-portal-header-extra]" />
|
|
4818
|
+
</nav>
|
|
4819
|
+
`, styles: [":host{display:block;position:sticky;top:0;z-index:30;font-family:var(--kf-font-body)}.kf-portal-header__admin-bar{display:flex;align-items:center;justify-content:space-between;gap:var(--kf-space-md);padding:var(--kf-space-xs) var(--kf-space-lg);background:var(--kf-color-tertiary-deep)}.kf-portal-header__admin-actions{display:flex;gap:var(--kf-space-md)}.kf-portal-header__admin-action{font-size:.8125rem;font-weight:600;color:#ffffffd9;text-decoration:none}.kf-portal-header__admin-action:hover{color:var(--kf-color-white)}.kf-portal-header__brand-bar{display:flex;align-items:center;gap:var(--kf-space-lg);padding:var(--kf-space-sm) var(--kf-space-lg);background:var(--kf-color-tertiary-deep);border-top:1px solid rgba(255,255,255,.1)}.kf-portal-header__logo{font-family:var(--kf-font-title);font-size:1.25rem;font-weight:700;letter-spacing:.02em;color:var(--kf-color-white);text-transform:uppercase;flex:1 1 auto;min-width:0}.kf-portal-header__nav{display:flex;align-items:center;gap:var(--kf-space-xs);flex:1 1 auto}.kf-portal-header__nav-item{padding:var(--kf-space-xs) var(--kf-space-md);border-radius:var(--kf-radius-sm);color:#ffffffbf;font-size:.875rem;font-weight:600;text-decoration:none;white-space:nowrap;transition:background .14s,color .14s}.kf-portal-header__nav-item:hover:not(.kf-portal-header__nav-item--active){color:var(--kf-color-white)}.kf-portal-header__nav-item--active{background:var(--kf-color-white);color:var(--kf-color-ink)}.kf-portal-header__session{flex:none;border:none;background:transparent;padding:0;cursor:pointer}.kf-portal-header__menu-toggle{display:none;flex:none;align-items:center;justify-content:center;width:36px;height:36px;border:none;border-radius:var(--kf-radius-sm);background:transparent;color:var(--kf-color-white);cursor:pointer}.kf-portal-header__menu-toggle:hover{background:#ffffff1a}.kf-portal-header__overlay{position:fixed;inset:0;background:#10182866;z-index:39}.kf-portal-header__drawer{position:fixed;top:0;right:0;bottom:0;z-index:40;display:none;flex-direction:column;width:min(80vw,320px);padding:var(--kf-space-lg);background:var(--kf-color-tertiary-deep);box-shadow:-8px 0 24px -8px #1018284d;transform:translate(100%);visibility:hidden;transition:transform .24s cubic-bezier(.32,.72,0,1),visibility 0s linear .24s}.kf-portal-header__drawer--open{transform:translate(0);visibility:visible;transition:transform .24s cubic-bezier(.32,.72,0,1),visibility 0s linear 0s}.kf-portal-header__mobile-nav-item{padding:var(--kf-space-sm) var(--kf-space-xs);color:#ffffffd9;font-size:.9375rem;font-weight:600;text-decoration:none;border-radius:var(--kf-radius-sm)}.kf-portal-header__mobile-nav-item:hover{background:#ffffff14}.kf-portal-header__mobile-nav-item--active{color:var(--kf-color-white);background:#ffffff24}@media(max-width:768px){.kf-portal-header__nav,.kf-portal-header__session{display:none}.kf-portal-header__menu-toggle{display:inline-flex}.kf-portal-header__drawer{display:flex}}\n"] }]
|
|
4820
|
+
}], propDecorators: { brand: [{ type: i0.Input, args: [{ isSignal: true, alias: "brand", required: false }] }], isAdmin: [{ type: i0.Input, args: [{ isSignal: true, alias: "isAdmin", required: false }] }], adminActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "adminActions", required: false }] }], navItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "navItems", required: false }] }], userInitials: [{ type: i0.Input, args: [{ isSignal: true, alias: "userInitials", required: true }] }], sessionClick: [{ type: i0.Output, args: ["sessionClick"] }], onEscape: [{
|
|
4821
|
+
type: HostListener,
|
|
4822
|
+
args: ['document:keydown.escape']
|
|
4823
|
+
}], sessionButtonRef: [{ type: i0.ViewChild, args: ['sessionButton', { ...{ read: ElementRef }, isSignal: true }] }] } });
|
|
4636
4824
|
|
|
4637
4825
|
/**
|
|
4638
4826
|
* Estado vacío de reservas en taller con llamada a agendar (página 36):
|
|
@@ -5604,5 +5792,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
5604
5792
|
* Generated bundle index. Do not edit.
|
|
5605
5793
|
*/
|
|
5606
5794
|
|
|
5607
|
-
export { ActionTile, AdminBadge, Alert, Avatar, Badge, Breadcrumb, Button, Card, Carousel, CarouselSlide, Checkbox, Chip, CompanySelector, ContentSlot, ContentState, DataTable, Divider, Dropdown, DropdownItem, DropdownPanel, EmptyState, FeatureCard, Field, FieldLabel, FilterChips, FolderTabs, Icon, Input, Link, MetricCard, Modal, MultiSelect, PageHeader, Pagination, Panel, PortalHeader, ReserveBlock, SectionHeader, Segmented, Select, Skeleton, Spinner, StatTile, StatusPill, Tabs, Text, ToastHost, ToastService, VehicleHeader, ViewToggle };
|
|
5795
|
+
export { ActionTile, AdminBadge, Alert, Avatar, Badge, Breadcrumb, Button, Card, Carousel, CarouselSlide, Checkbox, Chip, CompanySelector, ContentSlot, ContentState, DataTable, Divider, Dropdown, DropdownItem, DropdownPanel, EmptyState, FeatureCard, Field, FieldLabel, FilterChips, FolderTabs, FolderTabsPanel, Icon, Input, Link, MetricCard, Modal, MultiSelect, PageHeader, Pagination, Panel, PortalHeader, ReserveBlock, SectionHeader, Segmented, Select, Skeleton, Spinner, StatTile, StatusPill, Tabs, Text, ToastHost, ToastService, VehicleHeader, ViewToggle };
|
|
5608
5796
|
//# sourceMappingURL=kaufmann-lab-ui.mjs.map
|