@cerca/design-system 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -357
- package/fesm2022/cerca-design-system.mjs +2604 -570
- package/fesm2022/cerca-design-system.mjs.map +1 -1
- package/package.json +4 -5
- package/types/cerca-design-system.d.ts +1252 -235
|
@@ -1,82 +1,239 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
import * as i1$2 from '@angular/common';
|
|
4
|
-
import { CommonModule } from '@angular/common';
|
|
5
|
-
import * as i1 from 'ng-zorro-antd/button';
|
|
6
|
-
import { NzButtonModule } from 'ng-zorro-antd/button';
|
|
7
|
-
import * as i3$1 from 'ng-zorro-antd/icon';
|
|
8
|
-
import { NzIconModule } from 'ng-zorro-antd/icon';
|
|
9
|
-
import * as i2 from 'ng-zorro-antd/core/transition-patch';
|
|
10
|
-
import * as i3 from 'ng-zorro-antd/core/wave';
|
|
2
|
+
import { Component, Injectable, Input, input, computed, output, HostListener, inject, signal, forwardRef, ViewEncapsulation, effect, createComponent, ChangeDetectionStrategy, ContentChild, ViewContainerRef, ViewChild, HostBinding } from '@angular/core';
|
|
11
3
|
import * as i1$1 from '@angular/forms';
|
|
12
|
-
import { FormsModule, NG_VALUE_ACCESSOR,
|
|
13
|
-
import * as
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import
|
|
17
|
-
import {
|
|
18
|
-
import { Subject, Subscription } from 'rxjs';
|
|
4
|
+
import { Validators, FormBuilder, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule, FormGroup, FormControl } from '@angular/forms';
|
|
5
|
+
import * as i1 from '@angular/common';
|
|
6
|
+
import { CommonModule, NgClass, DatePipe, CurrencyPipe, DecimalPipe, PercentPipe } from '@angular/common';
|
|
7
|
+
import { Subject, Subscription, debounceTime as debounceTime$1, distinctUntilChanged as distinctUntilChanged$1, takeUntil } from 'rxjs';
|
|
8
|
+
import { __decorate } from 'tslib';
|
|
9
|
+
import { z } from 'zod';
|
|
19
10
|
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
|
|
20
|
-
import
|
|
21
|
-
import
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
11
|
+
import * as i1$2 from '@angular/router';
|
|
12
|
+
import { RouterLink, RouterLinkActive } from '@angular/router';
|
|
13
|
+
|
|
14
|
+
class DesignSystem {
|
|
15
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: DesignSystem, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
16
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.4", type: DesignSystem, isStandalone: true, selector: "ad-design-system", ngImport: i0, template: `
|
|
17
|
+
<p>
|
|
18
|
+
design-system works!
|
|
19
|
+
</p>
|
|
20
|
+
`, isInline: true, styles: [""] });
|
|
21
|
+
}
|
|
22
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: DesignSystem, decorators: [{
|
|
23
|
+
type: Component,
|
|
24
|
+
args: [{ selector: 'ad-design-system', imports: [], template: `
|
|
25
|
+
<p>
|
|
26
|
+
design-system works!
|
|
27
|
+
</p>
|
|
28
|
+
` }]
|
|
29
|
+
}] });
|
|
30
|
+
|
|
31
|
+
class FieldRendererRegistry {
|
|
32
|
+
renderers = new Map();
|
|
33
|
+
register(key, component) {
|
|
34
|
+
if (this.renderers.has(key)) {
|
|
35
|
+
console.warn(`Renderer for key '${key}' is already registered. Overwriting.`);
|
|
36
|
+
}
|
|
37
|
+
this.renderers.set(key, component);
|
|
38
|
+
}
|
|
39
|
+
get(key) {
|
|
40
|
+
return this.renderers.get(key);
|
|
41
|
+
}
|
|
42
|
+
has(key) {
|
|
43
|
+
return this.renderers.has(key);
|
|
44
|
+
}
|
|
45
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: FieldRendererRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
46
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: FieldRendererRegistry, providedIn: 'root' });
|
|
47
|
+
}
|
|
48
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: FieldRendererRegistry, decorators: [{
|
|
49
|
+
type: Injectable,
|
|
50
|
+
args: [{
|
|
51
|
+
providedIn: 'root'
|
|
52
|
+
}]
|
|
53
|
+
}] });
|
|
54
|
+
|
|
55
|
+
class ValidatorRegistry {
|
|
56
|
+
validators = new Map();
|
|
28
57
|
constructor() {
|
|
29
|
-
this.
|
|
30
|
-
this.type = input('button', ...(ngDevMode ? [{ debugName: "type" }] : []));
|
|
31
|
-
this._disabled = signal(false, ...(ngDevMode ? [{ debugName: "_disabled" }] : []));
|
|
32
|
-
this.loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
33
|
-
this.icon = input(undefined, ...(ngDevMode ? [{ debugName: "icon" }] : []));
|
|
34
|
-
this.size = input('default', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
35
|
-
this.nzType = computed(() => {
|
|
36
|
-
const variantMap = {
|
|
37
|
-
'primary': 'primary',
|
|
38
|
-
'secondary': 'default',
|
|
39
|
-
'ghost': 'text',
|
|
40
|
-
'outline': 'dashed'
|
|
41
|
-
};
|
|
42
|
-
return variantMap[this.variant()] || 'default';
|
|
43
|
-
}, ...(ngDevMode ? [{ debugName: "nzType" }] : []));
|
|
58
|
+
this.registerDefaults();
|
|
44
59
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
60
|
+
registerDefaults() {
|
|
61
|
+
this.register('required', () => Validators.required);
|
|
62
|
+
this.register('email', () => Validators.email);
|
|
63
|
+
this.register('min', (min) => Validators.min(min));
|
|
64
|
+
this.register('max', (max) => Validators.max(max));
|
|
65
|
+
this.register('minLength', (len) => Validators.minLength(len));
|
|
66
|
+
this.register('maxLength', (len) => Validators.maxLength(len));
|
|
67
|
+
this.register('pattern', (pattern) => Validators.pattern(pattern));
|
|
68
|
+
}
|
|
69
|
+
register(key, factory) {
|
|
70
|
+
this.validators.set(key, factory);
|
|
71
|
+
}
|
|
72
|
+
get(key, args) {
|
|
73
|
+
const factory = this.validators.get(key);
|
|
74
|
+
if (!factory) {
|
|
75
|
+
console.warn(`Validator '${key}' not found.`);
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return factory(args);
|
|
79
|
+
}
|
|
80
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: ValidatorRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
81
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: ValidatorRegistry, providedIn: 'root' });
|
|
49
82
|
}
|
|
50
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
83
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: ValidatorRegistry, decorators: [{
|
|
84
|
+
type: Injectable,
|
|
85
|
+
args: [{
|
|
86
|
+
providedIn: 'root'
|
|
87
|
+
}]
|
|
88
|
+
}], ctorParameters: () => [] });
|
|
89
|
+
|
|
90
|
+
class AdIconComponent {
|
|
91
|
+
name = '';
|
|
92
|
+
size = 'md';
|
|
93
|
+
color = 'currentColor';
|
|
94
|
+
get sizeClass() {
|
|
95
|
+
switch (this.size) {
|
|
96
|
+
case 'xs': return 'w-3 h-3 text-xs';
|
|
97
|
+
case 'sm': return 'w-4 h-4 text-base';
|
|
98
|
+
case 'md': return 'w-5 h-5 text-xl';
|
|
99
|
+
case 'lg': return 'w-6 h-6 text-2xl';
|
|
100
|
+
case 'xl': return 'w-8 h-8 text-3xl';
|
|
101
|
+
default: return 'w-5 h-5 text-xl';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
105
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdIconComponent, isStandalone: true, selector: "ad-icon", inputs: { name: "name", size: "size", color: "color" }, ngImport: i0, template: "@if (name === 'user') {\r\n<svg [class]=\"sizeClass\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n d=\"M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z\" />\r\n</svg>\r\n} @else if (name === 'lock') {\r\n<svg [class]=\"sizeClass\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n d=\"M16.5 10.5V6.75a4.5 4.5 0 1 0-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 0 0 2.25-2.25v-6.75a2.25 2.25 0 0 0-2.25-2.25H6.75a2.25 2.25 0 0 0-2.25 2.25v6.75a2.25 2.25 0 0 0 2.25 2.25Z\" />\r\n</svg>\r\n} @else if (name === 'eye') {\r\n<svg [class]=\"sizeClass\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n d=\"M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z\" />\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z\" />\r\n</svg>\r\n} @else if (name === 'plus') {\r\n<svg [class]=\"sizeClass\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 4.5v15m7.5-7.5h-15\" />\r\n</svg>\r\n} @else if (name === 'download') {\r\n<svg [class]=\"sizeClass\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n d=\"M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3\" />\r\n</svg>\r\n} @else if (name === 'eye-invisible') {\r\n<svg [class]=\"sizeClass\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n d=\"M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88\" />\r\n</svg>\r\n} @else {\r\n<!-- Fallback -->\r\n<span class=\"material-icons-outlined ad-icon\" [ngClass]=\"sizeClass\">{{ name }}</span>\r\n}", styles: [".ad-icon{display:inline-flex;align-items:center;justify-content:center;font-family:Material Icons Outlined;font-weight:400;font-style:normal;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-smoothing:antialiased}.ad-icon.icon-xs{font-size:16px;width:16px;height:16px}.ad-icon.icon-sm{font-size:20px;width:20px;height:20px}.ad-icon.icon-md{font-size:24px;width:24px;height:24px}.ad-icon.icon-lg{font-size:32px;width:32px;height:32px}.ad-icon.icon-xl{font-size:40px;width:40px;height:40px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
|
|
106
|
+
}
|
|
107
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdIconComponent, decorators: [{
|
|
51
108
|
type: Component,
|
|
52
|
-
args: [{ selector: '
|
|
53
|
-
}], propDecorators: {
|
|
109
|
+
args: [{ selector: 'ad-icon', standalone: true, imports: [CommonModule], template: "@if (name === 'user') {\r\n<svg [class]=\"sizeClass\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n d=\"M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z\" />\r\n</svg>\r\n} @else if (name === 'lock') {\r\n<svg [class]=\"sizeClass\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n d=\"M16.5 10.5V6.75a4.5 4.5 0 1 0-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 0 0 2.25-2.25v-6.75a2.25 2.25 0 0 0-2.25-2.25H6.75a2.25 2.25 0 0 0-2.25 2.25v6.75a2.25 2.25 0 0 0 2.25 2.25Z\" />\r\n</svg>\r\n} @else if (name === 'eye') {\r\n<svg [class]=\"sizeClass\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n d=\"M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z\" />\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z\" />\r\n</svg>\r\n} @else if (name === 'plus') {\r\n<svg [class]=\"sizeClass\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 4.5v15m7.5-7.5h-15\" />\r\n</svg>\r\n} @else if (name === 'download') {\r\n<svg [class]=\"sizeClass\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n d=\"M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3\" />\r\n</svg>\r\n} @else if (name === 'eye-invisible') {\r\n<svg [class]=\"sizeClass\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n d=\"M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88\" />\r\n</svg>\r\n} @else {\r\n<!-- Fallback -->\r\n<span class=\"material-icons-outlined ad-icon\" [ngClass]=\"sizeClass\">{{ name }}</span>\r\n}", styles: [".ad-icon{display:inline-flex;align-items:center;justify-content:center;font-family:Material Icons Outlined;font-weight:400;font-style:normal;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-smoothing:antialiased}.ad-icon.icon-xs{font-size:16px;width:16px;height:16px}.ad-icon.icon-sm{font-size:20px;width:20px;height:20px}.ad-icon.icon-md{font-size:24px;width:24px;height:24px}.ad-icon.icon-lg{font-size:32px;width:32px;height:32px}.ad-icon.icon-xl{font-size:40px;width:40px;height:40px}\n"] }]
|
|
110
|
+
}], propDecorators: { name: [{
|
|
111
|
+
type: Input
|
|
112
|
+
}], size: [{
|
|
54
113
|
type: Input
|
|
55
|
-
}],
|
|
114
|
+
}], color: [{
|
|
115
|
+
type: Input
|
|
116
|
+
}] } });
|
|
56
117
|
|
|
57
|
-
class
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
this.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
118
|
+
class AdModalComponent {
|
|
119
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
120
|
+
isOpen = computed(() => this.resource().isOpen ?? false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
121
|
+
title = computed(() => this.resource().title ?? '', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
122
|
+
accentedTitle = computed(() => this.resource().accentedTitle, ...(ngDevMode ? [{ debugName: "accentedTitle" }] : []));
|
|
123
|
+
size = computed(() => this.resource().size ?? 'md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
124
|
+
closeOnOverlay = computed(() => this.resource().closeOnOverlay ?? true, ...(ngDevMode ? [{ debugName: "closeOnOverlay" }] : []));
|
|
125
|
+
showFooter = computed(() => this.resource().showFooter ?? true, ...(ngDevMode ? [{ debugName: "showFooter" }] : []));
|
|
126
|
+
close = output();
|
|
127
|
+
onOverlayClick(event) {
|
|
128
|
+
if (this.closeOnOverlay() && event.target.classList.contains('ad-modal-overlay')) {
|
|
129
|
+
this.close.emit();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
onEscape() {
|
|
133
|
+
if (this.isOpen()) {
|
|
134
|
+
this.close.emit();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
138
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdModalComponent, isStandalone: true, selector: "ad-modal", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { close: "close" }, host: { listeners: { "document:keydown.escape": "onEscape()" } }, ngImport: i0, template: "@if (isOpen()){\r\n<div class=\"ad-modal-overlay\" (click)=\"onOverlayClick($event)\">\r\n\r\n <div class=\"ad-modal\" [ngClass]=\"'size-' + size()\" role=\"dialog\" aria-modal=\"true\">\r\n\r\n <header class=\"ad-modal-header\">\r\n <h3 class=\"ad-modal-title\">\r\n {{ title() }}\r\n @if (accentedTitle()) {\r\n <span class=\"accent-text\">{{ accentedTitle() }}</span>\r\n }\r\n </h3>\r\n <button class=\"ad-modal-close\" (click)=\"close.emit()\" type=\"button\">\r\n <ad-icon name=\"close\" size=\"md\"></ad-icon>\r\n </button>\r\n </header>\r\n\r\n <div class=\"ad-modal-body\">\r\n <ng-content></ng-content>\r\n </div>\r\n @if (showFooter()){\r\n <footer class=\"ad-modal-footer\">\r\n <ng-content select=\"[footer]\"></ng-content>\r\n </footer>\r\n }\r\n </div>\r\n</div>\r\n}", styles: [".ad-modal-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:var(--modal-overlay-bg);display:flex;align-items:center;justify-content:center;z-index:var(--modal-z-index);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);padding:var(--space-4)}.ad-modal{background-color:var(--modal-bg);border-radius:var(--modal-radius);box-shadow:var(--modal-shadow);display:flex;flex-direction:column;max-height:90vh;width:100%;animation:modalScaleUp .2s ease-out;overflow:hidden;position:relative}.ad-modal.size-sm{max-width:var(--modal-sm-width)}.ad-modal.size-md{max-width:var(--modal-md-width)}.ad-modal.size-lg{max-width:var(--modal-lg-width)}.ad-modal-header{padding:var(--modal-header-padding);display:flex;align-items:center;justify-content:space-between;position:relative;border-bottom:none}.ad-modal-header:after{content:\"\";position:absolute;bottom:0;left:0;width:100%;height:4px;background:linear-gradient(to right,var(--color-primary),var(--color-primary-accent, #00d2ff))}.ad-modal-title{font-size:var(--font-size-lg);font-weight:var(--font-weight-bold);color:var(--color-text-primary);margin:0}.ad-modal-title .accent-text{background:linear-gradient(135deg,var(--color-primary) 0%,var(--color-primary-accent, #00d2ff) 100%);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;margin-left:.3rem}.ad-modal-close{background:transparent;border:none;color:var(--color-text-muted);cursor:pointer;padding:var(--space-1);border-radius:var(--radius-md);display:flex;transition:all .15s ease}.ad-modal-close:hover{background-color:var(--color-bg-secondary);color:var(--color-text-primary)}.ad-modal-body{padding:var(--modal-body-padding);overflow-y:auto;flex:1}.ad-modal-footer{padding:var(--modal-footer-padding);border-top:1px solid var(--color-border-subtle);display:flex;justify-content:flex-end;gap:var(--space-3);background-color:var(--color-bg-secondary)}@keyframes modalScaleUp{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: AdIconComponent, selector: "ad-icon", inputs: ["name", "size", "color"] }] });
|
|
139
|
+
}
|
|
140
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdModalComponent, decorators: [{
|
|
141
|
+
type: Component,
|
|
142
|
+
args: [{ selector: 'ad-modal', standalone: true, imports: [CommonModule, AdIconComponent], template: "@if (isOpen()){\r\n<div class=\"ad-modal-overlay\" (click)=\"onOverlayClick($event)\">\r\n\r\n <div class=\"ad-modal\" [ngClass]=\"'size-' + size()\" role=\"dialog\" aria-modal=\"true\">\r\n\r\n <header class=\"ad-modal-header\">\r\n <h3 class=\"ad-modal-title\">\r\n {{ title() }}\r\n @if (accentedTitle()) {\r\n <span class=\"accent-text\">{{ accentedTitle() }}</span>\r\n }\r\n </h3>\r\n <button class=\"ad-modal-close\" (click)=\"close.emit()\" type=\"button\">\r\n <ad-icon name=\"close\" size=\"md\"></ad-icon>\r\n </button>\r\n </header>\r\n\r\n <div class=\"ad-modal-body\">\r\n <ng-content></ng-content>\r\n </div>\r\n @if (showFooter()){\r\n <footer class=\"ad-modal-footer\">\r\n <ng-content select=\"[footer]\"></ng-content>\r\n </footer>\r\n }\r\n </div>\r\n</div>\r\n}", styles: [".ad-modal-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:var(--modal-overlay-bg);display:flex;align-items:center;justify-content:center;z-index:var(--modal-z-index);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);padding:var(--space-4)}.ad-modal{background-color:var(--modal-bg);border-radius:var(--modal-radius);box-shadow:var(--modal-shadow);display:flex;flex-direction:column;max-height:90vh;width:100%;animation:modalScaleUp .2s ease-out;overflow:hidden;position:relative}.ad-modal.size-sm{max-width:var(--modal-sm-width)}.ad-modal.size-md{max-width:var(--modal-md-width)}.ad-modal.size-lg{max-width:var(--modal-lg-width)}.ad-modal-header{padding:var(--modal-header-padding);display:flex;align-items:center;justify-content:space-between;position:relative;border-bottom:none}.ad-modal-header:after{content:\"\";position:absolute;bottom:0;left:0;width:100%;height:4px;background:linear-gradient(to right,var(--color-primary),var(--color-primary-accent, #00d2ff))}.ad-modal-title{font-size:var(--font-size-lg);font-weight:var(--font-weight-bold);color:var(--color-text-primary);margin:0}.ad-modal-title .accent-text{background:linear-gradient(135deg,var(--color-primary) 0%,var(--color-primary-accent, #00d2ff) 100%);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;margin-left:.3rem}.ad-modal-close{background:transparent;border:none;color:var(--color-text-muted);cursor:pointer;padding:var(--space-1);border-radius:var(--radius-md);display:flex;transition:all .15s ease}.ad-modal-close:hover{background-color:var(--color-bg-secondary);color:var(--color-text-primary)}.ad-modal-body{padding:var(--modal-body-padding);overflow-y:auto;flex:1}.ad-modal-footer{padding:var(--modal-footer-padding);border-top:1px solid var(--color-border-subtle);display:flex;justify-content:flex-end;gap:var(--space-3);background-color:var(--color-bg-secondary)}@keyframes modalScaleUp{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}\n"] }]
|
|
143
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], close: [{ type: i0.Output, args: ["close"] }], onEscape: [{
|
|
144
|
+
type: HostListener,
|
|
145
|
+
args: ['document:keydown.escape']
|
|
146
|
+
}] } });
|
|
147
|
+
|
|
148
|
+
let FormEngineService = class FormEngineService {
|
|
149
|
+
fb = inject(FormBuilder);
|
|
150
|
+
validatorRegistry = inject(ValidatorRegistry); // Assuming this exists or mocking behavior
|
|
151
|
+
createFormGroup(schema, model = {}) {
|
|
152
|
+
const group = {};
|
|
153
|
+
// Support Legacy Sections
|
|
154
|
+
if (schema.sections) {
|
|
155
|
+
schema.sections.forEach(section => {
|
|
156
|
+
this.processFields(section.fields, group, model);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
// Support New Recursive Fields
|
|
160
|
+
if (schema.fields) {
|
|
161
|
+
this.processRecursiveFields(schema.fields, group, model);
|
|
162
|
+
}
|
|
163
|
+
return this.fb.group(group);
|
|
164
|
+
}
|
|
165
|
+
processFields(fields, group, model) {
|
|
166
|
+
fields.forEach(field => {
|
|
167
|
+
this.addFieldToGroup(field, group, model);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
processRecursiveFields(nodes, group, model) {
|
|
171
|
+
nodes.forEach(node => {
|
|
172
|
+
if ('children' in node && node.children) {
|
|
173
|
+
this.processRecursiveFields(node.children, group, model);
|
|
74
174
|
}
|
|
75
|
-
|
|
76
|
-
|
|
175
|
+
else {
|
|
176
|
+
// It's a field
|
|
177
|
+
this.addFieldToGroup(node, group, model);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
addFieldToGroup(field, group, model) {
|
|
182
|
+
// Handle name/key alias
|
|
183
|
+
const fieldName = field.name || field.key;
|
|
184
|
+
if (!fieldName)
|
|
185
|
+
return; // Skip if no name
|
|
186
|
+
const validators = field.validators || [];
|
|
187
|
+
// Handle required shortcut
|
|
188
|
+
if (field.required || field.props?.['required']) {
|
|
189
|
+
validators.push(Validators.required);
|
|
190
|
+
}
|
|
191
|
+
const initialValue = model[fieldName] !== undefined ? model[fieldName] : (field.defaultValue !== undefined ? field.defaultValue : null);
|
|
192
|
+
const state = { value: initialValue, disabled: field.disabled };
|
|
193
|
+
group[fieldName] = [state, validators];
|
|
77
194
|
}
|
|
195
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: FormEngineService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
196
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: FormEngineService, providedIn: 'root' });
|
|
197
|
+
};
|
|
198
|
+
FormEngineService = __decorate([
|
|
199
|
+
Injectable({
|
|
200
|
+
providedIn: 'root'
|
|
201
|
+
})
|
|
202
|
+
], FormEngineService);
|
|
203
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: FormEngineService, decorators: [{
|
|
204
|
+
type: Injectable,
|
|
205
|
+
args: [{
|
|
206
|
+
providedIn: 'root'
|
|
207
|
+
}]
|
|
208
|
+
}, {
|
|
209
|
+
type: Injectable,
|
|
210
|
+
args: [{
|
|
211
|
+
providedIn: 'root'
|
|
212
|
+
}]
|
|
213
|
+
}] });
|
|
214
|
+
|
|
215
|
+
class AdInputComponent {
|
|
216
|
+
type = input('text', ...(ngDevMode ? [{ debugName: "type" }] : []));
|
|
217
|
+
placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
218
|
+
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
219
|
+
error = input(false, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
220
|
+
rows = input(3, ...(ngDevMode ? [{ debugName: "rows" }] : []));
|
|
221
|
+
_disabled = signal(false, ...(ngDevMode ? [{ debugName: "_disabled" }] : []));
|
|
78
222
|
set disabled(value) { this._disabled.set(value); }
|
|
79
223
|
get disabled() { return this._disabled(); }
|
|
224
|
+
size = input('small', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
225
|
+
prefix = input(undefined, ...(ngDevMode ? [{ debugName: "prefix" }] : []));
|
|
226
|
+
suffix = input(undefined, ...(ngDevMode ? [{ debugName: "suffix" }] : []));
|
|
227
|
+
value = '';
|
|
228
|
+
passwordVisible = signal(false, ...(ngDevMode ? [{ debugName: "passwordVisible" }] : []));
|
|
229
|
+
onChange = () => { };
|
|
230
|
+
onTouched = () => { };
|
|
231
|
+
inputType = computed(() => {
|
|
232
|
+
if (this.type() === 'password') {
|
|
233
|
+
return this.passwordVisible() ? 'text' : 'password';
|
|
234
|
+
}
|
|
235
|
+
return this.type();
|
|
236
|
+
}, ...(ngDevMode ? [{ debugName: "inputType" }] : []));
|
|
80
237
|
onInputChange(event) {
|
|
81
238
|
const target = event.target;
|
|
82
239
|
this.value = target.value;
|
|
@@ -100,47 +257,45 @@ class CcInputComponent {
|
|
|
100
257
|
setDisabledState(isDisabled) {
|
|
101
258
|
this._disabled.set(isDisabled);
|
|
102
259
|
}
|
|
103
|
-
static
|
|
104
|
-
static
|
|
260
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
261
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdInputComponent, isStandalone: true, selector: "ad-input", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, prefix: { classPropertyName: "prefix", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
105
262
|
{
|
|
106
263
|
provide: NG_VALUE_ACCESSOR,
|
|
107
|
-
useExisting: forwardRef(() =>
|
|
264
|
+
useExisting: forwardRef(() => AdInputComponent),
|
|
108
265
|
multi: true
|
|
109
266
|
}
|
|
110
|
-
], ngImport: i0, template: "@if (label()) {\r\n<label class=\"
|
|
267
|
+
], ngImport: i0, template: "@if (label()) {\r\n<label class=\"block text-sm font-medium leading-6 text-slate-900 mb-2\">{{ label() }}</label>\r\n}\r\n\r\n<div class=\"flex items-center w-full rounded-md border border-slate-300 bg-white px-3 py-1.5 shadow-sm transition-all focus-within:border-cerca-primary\"\r\n [class.bg-slate-50]=\"disabled\" [class.text-slate-500]=\"disabled\" [class.cursor-not-allowed]=\"disabled\"\r\n [class.border-cerca-alert]=\"error()\" [class.text-cerca-alert-text]=\"error()\"\r\n [class.focus-within:border-cerca-alert]=\"error()\">\r\n\r\n @if (prefix()) {\r\n <span class=\"mr-2 flex items-center\" [class.text-slate-500]=\"!error()\" [class.text-cerca-alert-text]=\"error()\">\r\n <ad-icon [name]=\"prefix()!\" size=\"sm\"></ad-icon>\r\n </span>\r\n }\r\n\r\n @if (type() === 'textarea') {\r\n <textarea [rows]=\"rows()\" [placeholder]=\"placeholder()\" [disabled]=\"disabled\" [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange($event)\" (blur)=\"onTouched()\"\r\n class=\"block w-full border-0 p-0 text-slate-900 placeholder:text-slate-400 focus:ring-0 outline-none sm:text-sm sm:leading-6 bg-transparent disabled:cursor-not-allowed resize-none\"></textarea>\r\n } @else {\r\n <input [type]=\"inputType()\" [placeholder]=\"placeholder()\" [disabled]=\"disabled\" [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange($event)\" (blur)=\"onTouched()\"\r\n class=\"block w-full border-0 p-0 text-slate-900 placeholder:text-slate-400 focus:ring-0 outline-none sm:text-sm sm:leading-6 bg-transparent disabled:cursor-not-allowed\" />\r\n }\r\n\r\n @if (type() === 'password') {\r\n <button type=\"button\" (click)=\"togglePasswordVisibility()\"\r\n class=\"ml-2 text-slate-500 hover:text-slate-700 focus:outline-none cursor-pointer\">\r\n <ad-icon [name]=\"passwordVisible() ? 'eye-invisible' : 'eye'\" size=\"sm\"></ad-icon>\r\n </button>\r\n }\r\n\r\n @if (type() !== 'password' && suffix()) {\r\n <span class=\"ml-2 text-slate-500 flex items-center\">\r\n <ad-icon [name]=\"suffix()!\" size=\"sm\"></ad-icon>\r\n </span>\r\n }\r\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AdIconComponent, selector: "ad-icon", inputs: ["name", "size", "color"] }] });
|
|
111
268
|
}
|
|
112
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
269
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdInputComponent, decorators: [{
|
|
113
270
|
type: Component,
|
|
114
|
-
args: [{ selector: '
|
|
271
|
+
args: [{ selector: 'ad-input', standalone: true, imports: [
|
|
115
272
|
CommonModule,
|
|
116
273
|
FormsModule,
|
|
117
|
-
|
|
118
|
-
NzIconModule
|
|
274
|
+
AdIconComponent
|
|
119
275
|
], providers: [
|
|
120
276
|
{
|
|
121
277
|
provide: NG_VALUE_ACCESSOR,
|
|
122
|
-
useExisting: forwardRef(() =>
|
|
278
|
+
useExisting: forwardRef(() => AdInputComponent),
|
|
123
279
|
multi: true
|
|
124
280
|
}
|
|
125
|
-
], template: "@if (label()) {\r\n<label class=\"
|
|
126
|
-
}], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], disabled: [{
|
|
281
|
+
], template: "@if (label()) {\r\n<label class=\"block text-sm font-medium leading-6 text-slate-900 mb-2\">{{ label() }}</label>\r\n}\r\n\r\n<div class=\"flex items-center w-full rounded-md border border-slate-300 bg-white px-3 py-1.5 shadow-sm transition-all focus-within:border-cerca-primary\"\r\n [class.bg-slate-50]=\"disabled\" [class.text-slate-500]=\"disabled\" [class.cursor-not-allowed]=\"disabled\"\r\n [class.border-cerca-alert]=\"error()\" [class.text-cerca-alert-text]=\"error()\"\r\n [class.focus-within:border-cerca-alert]=\"error()\">\r\n\r\n @if (prefix()) {\r\n <span class=\"mr-2 flex items-center\" [class.text-slate-500]=\"!error()\" [class.text-cerca-alert-text]=\"error()\">\r\n <ad-icon [name]=\"prefix()!\" size=\"sm\"></ad-icon>\r\n </span>\r\n }\r\n\r\n @if (type() === 'textarea') {\r\n <textarea [rows]=\"rows()\" [placeholder]=\"placeholder()\" [disabled]=\"disabled\" [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange($event)\" (blur)=\"onTouched()\"\r\n class=\"block w-full border-0 p-0 text-slate-900 placeholder:text-slate-400 focus:ring-0 outline-none sm:text-sm sm:leading-6 bg-transparent disabled:cursor-not-allowed resize-none\"></textarea>\r\n } @else {\r\n <input [type]=\"inputType()\" [placeholder]=\"placeholder()\" [disabled]=\"disabled\" [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange($event)\" (blur)=\"onTouched()\"\r\n class=\"block w-full border-0 p-0 text-slate-900 placeholder:text-slate-400 focus:ring-0 outline-none sm:text-sm sm:leading-6 bg-transparent disabled:cursor-not-allowed\" />\r\n }\r\n\r\n @if (type() === 'password') {\r\n <button type=\"button\" (click)=\"togglePasswordVisibility()\"\r\n class=\"ml-2 text-slate-500 hover:text-slate-700 focus:outline-none cursor-pointer\">\r\n <ad-icon [name]=\"passwordVisible() ? 'eye-invisible' : 'eye'\" size=\"sm\"></ad-icon>\r\n </button>\r\n }\r\n\r\n @if (type() !== 'password' && suffix()) {\r\n <span class=\"ml-2 text-slate-500 flex items-center\">\r\n <ad-icon [name]=\"suffix()!\" size=\"sm\"></ad-icon>\r\n </span>\r\n }\r\n</div>" }]
|
|
282
|
+
}], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], disabled: [{
|
|
127
283
|
type: Input
|
|
128
284
|
}], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], prefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefix", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }] } });
|
|
129
285
|
|
|
130
|
-
class
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
this._disabled = signal(false, ...(ngDevMode ? [{ debugName: "_disabled" }] : []));
|
|
139
|
-
this.onChange = () => { };
|
|
140
|
-
this.onTouched = () => { };
|
|
141
|
-
}
|
|
286
|
+
class AdSelectComponent {
|
|
287
|
+
options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
288
|
+
placeholder = input('Seleccionar opción', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
289
|
+
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
290
|
+
size = input('default', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
291
|
+
allowClear = input(true, ...(ngDevMode ? [{ debugName: "allowClear" }] : []));
|
|
292
|
+
showSearch = input(false, ...(ngDevMode ? [{ debugName: "showSearch" }] : []));
|
|
293
|
+
_disabled = signal(false, ...(ngDevMode ? [{ debugName: "_disabled" }] : []));
|
|
142
294
|
set disabled(value) { this._disabled.set(value); }
|
|
143
295
|
get disabled() { return this._disabled(); }
|
|
296
|
+
value;
|
|
297
|
+
onChange = () => { };
|
|
298
|
+
onTouched = () => { };
|
|
144
299
|
onValueChange(value) {
|
|
145
300
|
this.value = value;
|
|
146
301
|
this.onChange(value);
|
|
@@ -158,153 +313,1522 @@ class CcSelectComponent {
|
|
|
158
313
|
setDisabledState(isDisabled) {
|
|
159
314
|
this._disabled.set(isDisabled);
|
|
160
315
|
}
|
|
161
|
-
static
|
|
162
|
-
static
|
|
316
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
317
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdSelectComponent, isStandalone: true, selector: "ad-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, allowClear: { classPropertyName: "allowClear", publicName: "allowClear", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null } }, providers: [
|
|
163
318
|
{
|
|
164
319
|
provide: NG_VALUE_ACCESSOR,
|
|
165
|
-
useExisting: forwardRef(() =>
|
|
320
|
+
useExisting: forwardRef(() => AdSelectComponent),
|
|
166
321
|
multi: true
|
|
167
322
|
}
|
|
168
|
-
], ngImport: i0, template: "<div class=\"
|
|
323
|
+
], ngImport: i0, template: "<div class=\"w-full\">\r\n @if (label()) {\r\n <label class=\"block text-sm font-medium leading-6 text-slate-900 mb-2\">{{ label() }}</label>\r\n }\r\n <div class=\"relative\">\r\n <select [disabled]=\"disabled\" [(ngModel)]=\"value\" (ngModelChange)=\"onValueChange($event)\" (blur)=\"onTouched()\"\r\n class=\"block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-slate-900 shadow-sm ring-1 ring-inset ring-slate-300 focus:ring-2 focus:ring-inset focus:ring-sky-600 sm:text-sm sm:leading-6 bg-white disabled:bg-slate-50 disabled:text-slate-500 disabled:cursor-not-allowed\">\r\n @if (placeholder()) {\r\n <option [ngValue]=\"null\" disabled selected>{{ placeholder() }}</option>\r\n }\r\n @if (allowClear()) {\r\n <option [ngValue]=\"null\">-- Seleccionar --</option>\r\n }\r\n @for (option of options(); track option.value) {\r\n <option [ngValue]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
169
324
|
}
|
|
170
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
325
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdSelectComponent, decorators: [{
|
|
171
326
|
type: Component,
|
|
172
|
-
args: [{ selector: '
|
|
327
|
+
args: [{ selector: 'ad-select', standalone: true, imports: [CommonModule, FormsModule], providers: [
|
|
173
328
|
{
|
|
174
329
|
provide: NG_VALUE_ACCESSOR,
|
|
175
|
-
useExisting: forwardRef(() =>
|
|
330
|
+
useExisting: forwardRef(() => AdSelectComponent),
|
|
176
331
|
multi: true
|
|
177
332
|
}
|
|
178
|
-
], template: "<div class=\"
|
|
333
|
+
], template: "<div class=\"w-full\">\r\n @if (label()) {\r\n <label class=\"block text-sm font-medium leading-6 text-slate-900 mb-2\">{{ label() }}</label>\r\n }\r\n <div class=\"relative\">\r\n <select [disabled]=\"disabled\" [(ngModel)]=\"value\" (ngModelChange)=\"onValueChange($event)\" (blur)=\"onTouched()\"\r\n class=\"block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-slate-900 shadow-sm ring-1 ring-inset ring-slate-300 focus:ring-2 focus:ring-inset focus:ring-sky-600 sm:text-sm sm:leading-6 bg-white disabled:bg-slate-50 disabled:text-slate-500 disabled:cursor-not-allowed\">\r\n @if (placeholder()) {\r\n <option [ngValue]=\"null\" disabled selected>{{ placeholder() }}</option>\r\n }\r\n @if (allowClear()) {\r\n <option [ngValue]=\"null\">-- Seleccionar --</option>\r\n }\r\n @for (option of options(); track option.value) {\r\n <option [ngValue]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n</div>" }]
|
|
179
334
|
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], allowClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowClear", required: false }] }], showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], disabled: [{
|
|
180
335
|
type: Input
|
|
181
336
|
}] } });
|
|
182
337
|
|
|
183
|
-
class
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
338
|
+
class AdSwitchComponent {
|
|
339
|
+
options = input([
|
|
340
|
+
{ label: 'Inactivo', value: false },
|
|
341
|
+
{ label: 'Activo', value: true }
|
|
342
|
+
], ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
343
|
+
_disabled = signal(false, ...(ngDevMode ? [{ debugName: "_disabled" }] : []));
|
|
344
|
+
set disabled(value) { this._disabled.set(value); }
|
|
345
|
+
get disabled() { return this._disabled(); }
|
|
346
|
+
value = false;
|
|
347
|
+
onChange = () => { };
|
|
348
|
+
onTouched = () => { };
|
|
349
|
+
/**
|
|
350
|
+
* Get the current label based on the switch value
|
|
351
|
+
*/
|
|
352
|
+
get currentLabel() {
|
|
353
|
+
const option = this.options().find(opt => opt.value === this.value);
|
|
354
|
+
return option?.label || '';
|
|
355
|
+
}
|
|
356
|
+
toggle() {
|
|
357
|
+
if (this.disabled)
|
|
358
|
+
return;
|
|
359
|
+
this.onValueChange(!this.value);
|
|
360
|
+
}
|
|
361
|
+
onValueChange(value) {
|
|
362
|
+
this.value = value;
|
|
363
|
+
this.onChange(value);
|
|
364
|
+
this.onTouched();
|
|
365
|
+
}
|
|
366
|
+
writeValue(value) {
|
|
367
|
+
this.value = value ?? false;
|
|
187
368
|
}
|
|
188
|
-
|
|
189
|
-
|
|
369
|
+
registerOnChange(fn) {
|
|
370
|
+
this.onChange = fn;
|
|
371
|
+
}
|
|
372
|
+
registerOnTouched(fn) {
|
|
373
|
+
this.onTouched = fn;
|
|
374
|
+
}
|
|
375
|
+
setDisabledState(isDisabled) {
|
|
376
|
+
this._disabled.set(isDisabled);
|
|
377
|
+
}
|
|
378
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdSwitchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
379
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdSwitchComponent, isStandalone: true, selector: "ad-switch", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null } }, providers: [
|
|
380
|
+
{
|
|
381
|
+
provide: NG_VALUE_ACCESSOR,
|
|
382
|
+
useExisting: forwardRef(() => AdSwitchComponent),
|
|
383
|
+
multi: true
|
|
384
|
+
}
|
|
385
|
+
], ngImport: i0, template: "<div class=\"ad-switch-container\">\r\n <div class=\"flex items-center gap-3\">\r\n <button type=\"button\"\r\n class=\"relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-sky-600 focus:ring-offset-2\"\r\n [class.bg-sky-600]=\"value\" [class.bg-slate-200]=\"!value\" [class.opacity-50]=\"disabled\"\r\n [class.cursor-not-allowed]=\"disabled\" (click)=\"toggle()\" [attr.aria-checked]=\"value\" role=\"switch\">\r\n\r\n <span class=\"sr-only\">{{ currentLabel }}</span>\r\n\r\n <span aria-hidden=\"true\"\r\n class=\"pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out\"\r\n [class.translate-x-5]=\"value\" [class.translate-x-0]=\"!value\">\r\n </span>\r\n </button>\r\n\r\n @if (currentLabel) {\r\n <span class=\"text-sm font-medium text-slate-700 dark:text-slate-200\" [class.opacity-50]=\"disabled\">{{\r\n currentLabel }}</span>\r\n }\r\n </div>\r\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }] });
|
|
190
386
|
}
|
|
191
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
387
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdSwitchComponent, decorators: [{
|
|
192
388
|
type: Component,
|
|
193
|
-
args: [{ selector: '
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
389
|
+
args: [{ selector: 'ad-switch', standalone: true, imports: [CommonModule, FormsModule], providers: [
|
|
390
|
+
{
|
|
391
|
+
provide: NG_VALUE_ACCESSOR,
|
|
392
|
+
useExisting: forwardRef(() => AdSwitchComponent),
|
|
393
|
+
multi: true
|
|
394
|
+
}
|
|
395
|
+
], template: "<div class=\"ad-switch-container\">\r\n <div class=\"flex items-center gap-3\">\r\n <button type=\"button\"\r\n class=\"relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-sky-600 focus:ring-offset-2\"\r\n [class.bg-sky-600]=\"value\" [class.bg-slate-200]=\"!value\" [class.opacity-50]=\"disabled\"\r\n [class.cursor-not-allowed]=\"disabled\" (click)=\"toggle()\" [attr.aria-checked]=\"value\" role=\"switch\">\r\n\r\n <span class=\"sr-only\">{{ currentLabel }}</span>\r\n\r\n <span aria-hidden=\"true\"\r\n class=\"pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out\"\r\n [class.translate-x-5]=\"value\" [class.translate-x-0]=\"!value\">\r\n </span>\r\n </button>\r\n\r\n @if (currentLabel) {\r\n <span class=\"text-sm font-medium text-slate-700 dark:text-slate-200\" [class.opacity-50]=\"disabled\">{{\r\n currentLabel }}</span>\r\n }\r\n </div>\r\n</div>" }]
|
|
396
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], disabled: [{
|
|
197
397
|
type: Input
|
|
198
398
|
}] } });
|
|
199
399
|
|
|
200
|
-
class
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
this.
|
|
400
|
+
class DynamicFieldComponent {
|
|
401
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
402
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
403
|
+
registry = inject(FieldRendererRegistry);
|
|
404
|
+
get controlName() {
|
|
405
|
+
return this.field().name || this.field().key || '';
|
|
406
|
+
}
|
|
407
|
+
get renderType() {
|
|
408
|
+
return this.field().rendererKey || this.field().type || 'input';
|
|
409
|
+
}
|
|
410
|
+
get placeholder() {
|
|
411
|
+
return this.field().placeholder || this.field().nzConfig?.nzProps?.placeholder || '';
|
|
412
|
+
}
|
|
413
|
+
get isRequired() {
|
|
414
|
+
return this.field().required || !!this.field().validators?.some(v => v.name === 'required');
|
|
415
|
+
}
|
|
416
|
+
get rows() {
|
|
417
|
+
return this.field().props?.['rows'] || this.field().nzConfig?.nzProps?.rows || 3;
|
|
418
|
+
}
|
|
419
|
+
getRenderer(key) {
|
|
420
|
+
return this.registry.get(key);
|
|
206
421
|
}
|
|
207
|
-
|
|
208
|
-
|
|
422
|
+
getSwitchOptions() {
|
|
423
|
+
const f = this.field();
|
|
424
|
+
const checked = f.props?.['checkedChildren'] || 'Activo';
|
|
425
|
+
const unchecked = f.props?.['unCheckedChildren'] || 'Inactivo';
|
|
426
|
+
return [{ label: unchecked, value: false }, { label: checked, value: true }];
|
|
427
|
+
}
|
|
428
|
+
hasError() {
|
|
429
|
+
const control = this.form().get(this.controlName);
|
|
430
|
+
return control?.invalid && (control?.dirty || control?.touched);
|
|
431
|
+
}
|
|
432
|
+
getError(code) {
|
|
433
|
+
const control = this.form().get(this.controlName);
|
|
434
|
+
return control?.errors?.[code];
|
|
435
|
+
}
|
|
436
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: DynamicFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
437
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: DynamicFieldComponent, isStandalone: true, selector: "ad-dynamic-field", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
438
|
+
<div class="mb-4" [formGroup]="form()">
|
|
439
|
+
<!-- Label -->
|
|
440
|
+
@if (renderType !== 'checkbox' && renderType !== 'switch' && field().label) {
|
|
441
|
+
<label [for]="controlName" class="block text-sm font-medium leading-6 text-slate-900 dark:text-slate-200 mb-2">
|
|
442
|
+
{{ field().label }}
|
|
443
|
+
@if (isRequired) { <span class="text-cerca-rose">*</span> }
|
|
444
|
+
</label>
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
<!-- Control -->
|
|
448
|
+
<div class="relative">
|
|
449
|
+
@switch (renderType) {
|
|
450
|
+
@case ('input') {
|
|
451
|
+
<ad-input
|
|
452
|
+
[formControlName]="controlName"
|
|
453
|
+
[placeholder]="placeholder"
|
|
454
|
+
[type]="field().props?.['type'] || 'text'"
|
|
455
|
+
[prefix]="field().props?.['prefix']"
|
|
456
|
+
[suffix]="field().props?.['suffix']"
|
|
457
|
+
[disabled]="field().disabled || false">
|
|
458
|
+
</ad-input>
|
|
459
|
+
}
|
|
460
|
+
@case ('text-input') {
|
|
461
|
+
<ad-input
|
|
462
|
+
[formControlName]="controlName"
|
|
463
|
+
[placeholder]="placeholder"
|
|
464
|
+
type="text"
|
|
465
|
+
[prefix]="field().props?.['prefix']"
|
|
466
|
+
[suffix]="field().props?.['suffix']"
|
|
467
|
+
[disabled]="field().disabled || false">
|
|
468
|
+
</ad-input>
|
|
469
|
+
}
|
|
470
|
+
@case ('number-input') {
|
|
471
|
+
<ad-input
|
|
472
|
+
[formControlName]="controlName"
|
|
473
|
+
[placeholder]="placeholder"
|
|
474
|
+
type="number"
|
|
475
|
+
[prefix]="field().props?.['prefix']"
|
|
476
|
+
[suffix]="field().props?.['suffix']"
|
|
477
|
+
[disabled]="field().disabled || false">
|
|
478
|
+
</ad-input>
|
|
479
|
+
}
|
|
480
|
+
@case ('textarea') {
|
|
481
|
+
<ad-input
|
|
482
|
+
[formControlName]="controlName"
|
|
483
|
+
type="textarea"
|
|
484
|
+
[placeholder]="placeholder"
|
|
485
|
+
[rows]="rows"
|
|
486
|
+
[disabled]="field().disabled || false">
|
|
487
|
+
</ad-input>
|
|
488
|
+
}
|
|
489
|
+
@case ('select') {
|
|
490
|
+
<ad-select
|
|
491
|
+
[formControlName]="controlName"
|
|
492
|
+
[options]="field().options || []"
|
|
493
|
+
[placeholder]="placeholder">
|
|
494
|
+
</ad-select>
|
|
495
|
+
}
|
|
496
|
+
@case ('select-input') {
|
|
497
|
+
<ad-select
|
|
498
|
+
[formControlName]="controlName"
|
|
499
|
+
[options]="field().options || []"
|
|
500
|
+
[placeholder]="placeholder">
|
|
501
|
+
</ad-select>
|
|
502
|
+
}
|
|
503
|
+
@case ('switch') {
|
|
504
|
+
<ad-switch
|
|
505
|
+
[formControlName]="controlName"
|
|
506
|
+
[options]="getSwitchOptions()">
|
|
507
|
+
</ad-switch>
|
|
508
|
+
}
|
|
509
|
+
@case ('custom') {
|
|
510
|
+
@if (getRenderer(controlName); as component) {
|
|
511
|
+
<ng-container *ngComponentOutlet="component"></ng-container>
|
|
512
|
+
} @else {
|
|
513
|
+
<p class="text-sm text-red-500">No renderer found for {{ controlName }}</p>
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
@default {
|
|
517
|
+
<p class="text-sm text-red-500">Unsupported field type: {{ renderType }}</p>
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
</div>
|
|
521
|
+
|
|
522
|
+
<!-- Errors -->
|
|
523
|
+
@if (hasError()) {
|
|
524
|
+
<p class="mt-2 text-sm text-cerca-rose">
|
|
525
|
+
@if (getError('required')) { Campo requerido }
|
|
526
|
+
@if (getError('email')) { Email inválido }
|
|
527
|
+
@if (getError('min')) { Valor mínimo no alcanzado }
|
|
528
|
+
</p>
|
|
529
|
+
}
|
|
530
|
+
</div>
|
|
531
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: AdInputComponent, selector: "ad-input", inputs: ["type", "placeholder", "label", "error", "rows", "disabled", "size", "prefix", "suffix"] }, { kind: "component", type: AdSelectComponent, selector: "ad-select", inputs: ["options", "placeholder", "label", "size", "allowClear", "showSearch", "disabled"] }, { kind: "component", type: AdSwitchComponent, selector: "ad-switch", inputs: ["options", "disabled"] }] });
|
|
209
532
|
}
|
|
210
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
533
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: DynamicFieldComponent, decorators: [{
|
|
211
534
|
type: Component,
|
|
212
|
-
args: [{
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
535
|
+
args: [{
|
|
536
|
+
selector: 'ad-dynamic-field',
|
|
537
|
+
standalone: true,
|
|
538
|
+
imports: [CommonModule, ReactiveFormsModule, AdInputComponent, AdSelectComponent, AdSwitchComponent],
|
|
539
|
+
template: `
|
|
540
|
+
<div class="mb-4" [formGroup]="form()">
|
|
541
|
+
<!-- Label -->
|
|
542
|
+
@if (renderType !== 'checkbox' && renderType !== 'switch' && field().label) {
|
|
543
|
+
<label [for]="controlName" class="block text-sm font-medium leading-6 text-slate-900 dark:text-slate-200 mb-2">
|
|
544
|
+
{{ field().label }}
|
|
545
|
+
@if (isRequired) { <span class="text-cerca-rose">*</span> }
|
|
546
|
+
</label>
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
<!-- Control -->
|
|
550
|
+
<div class="relative">
|
|
551
|
+
@switch (renderType) {
|
|
552
|
+
@case ('input') {
|
|
553
|
+
<ad-input
|
|
554
|
+
[formControlName]="controlName"
|
|
555
|
+
[placeholder]="placeholder"
|
|
556
|
+
[type]="field().props?.['type'] || 'text'"
|
|
557
|
+
[prefix]="field().props?.['prefix']"
|
|
558
|
+
[suffix]="field().props?.['suffix']"
|
|
559
|
+
[disabled]="field().disabled || false">
|
|
560
|
+
</ad-input>
|
|
561
|
+
}
|
|
562
|
+
@case ('text-input') {
|
|
563
|
+
<ad-input
|
|
564
|
+
[formControlName]="controlName"
|
|
565
|
+
[placeholder]="placeholder"
|
|
566
|
+
type="text"
|
|
567
|
+
[prefix]="field().props?.['prefix']"
|
|
568
|
+
[suffix]="field().props?.['suffix']"
|
|
569
|
+
[disabled]="field().disabled || false">
|
|
570
|
+
</ad-input>
|
|
571
|
+
}
|
|
572
|
+
@case ('number-input') {
|
|
573
|
+
<ad-input
|
|
574
|
+
[formControlName]="controlName"
|
|
575
|
+
[placeholder]="placeholder"
|
|
576
|
+
type="number"
|
|
577
|
+
[prefix]="field().props?.['prefix']"
|
|
578
|
+
[suffix]="field().props?.['suffix']"
|
|
579
|
+
[disabled]="field().disabled || false">
|
|
580
|
+
</ad-input>
|
|
581
|
+
}
|
|
582
|
+
@case ('textarea') {
|
|
583
|
+
<ad-input
|
|
584
|
+
[formControlName]="controlName"
|
|
585
|
+
type="textarea"
|
|
586
|
+
[placeholder]="placeholder"
|
|
587
|
+
[rows]="rows"
|
|
588
|
+
[disabled]="field().disabled || false">
|
|
589
|
+
</ad-input>
|
|
590
|
+
}
|
|
591
|
+
@case ('select') {
|
|
592
|
+
<ad-select
|
|
593
|
+
[formControlName]="controlName"
|
|
594
|
+
[options]="field().options || []"
|
|
595
|
+
[placeholder]="placeholder">
|
|
596
|
+
</ad-select>
|
|
597
|
+
}
|
|
598
|
+
@case ('select-input') {
|
|
599
|
+
<ad-select
|
|
600
|
+
[formControlName]="controlName"
|
|
601
|
+
[options]="field().options || []"
|
|
602
|
+
[placeholder]="placeholder">
|
|
603
|
+
</ad-select>
|
|
604
|
+
}
|
|
605
|
+
@case ('switch') {
|
|
606
|
+
<ad-switch
|
|
607
|
+
[formControlName]="controlName"
|
|
608
|
+
[options]="getSwitchOptions()">
|
|
609
|
+
</ad-switch>
|
|
610
|
+
}
|
|
611
|
+
@case ('custom') {
|
|
612
|
+
@if (getRenderer(controlName); as component) {
|
|
613
|
+
<ng-container *ngComponentOutlet="component"></ng-container>
|
|
614
|
+
} @else {
|
|
615
|
+
<p class="text-sm text-red-500">No renderer found for {{ controlName }}</p>
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
@default {
|
|
619
|
+
<p class="text-sm text-red-500">Unsupported field type: {{ renderType }}</p>
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
</div>
|
|
623
|
+
|
|
624
|
+
<!-- Errors -->
|
|
625
|
+
@if (hasError()) {
|
|
626
|
+
<p class="mt-2 text-sm text-cerca-rose">
|
|
627
|
+
@if (getError('required')) { Campo requerido }
|
|
628
|
+
@if (getError('email')) { Email inválido }
|
|
629
|
+
@if (getError('min')) { Valor mínimo no alcanzado }
|
|
630
|
+
</p>
|
|
631
|
+
}
|
|
632
|
+
</div>
|
|
633
|
+
`
|
|
634
|
+
}]
|
|
635
|
+
}], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }] } });
|
|
636
|
+
|
|
637
|
+
class DynamicLayoutComponent {
|
|
638
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
639
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
640
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: DynamicLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
641
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.4", type: DynamicLayoutComponent, isStandalone: true, selector: "ad-dynamic-layout", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
642
|
+
<div [class]="field().gridClass || 'col-span-12'">
|
|
643
|
+
<ad-dynamic-field [field]="field()" [form]="form()"></ad-dynamic-field>
|
|
644
|
+
</div>
|
|
645
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: DynamicFieldComponent, selector: "ad-dynamic-field", inputs: ["field", "form"] }] });
|
|
646
|
+
}
|
|
647
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: DynamicLayoutComponent, decorators: [{
|
|
648
|
+
type: Component,
|
|
649
|
+
args: [{
|
|
650
|
+
selector: 'ad-dynamic-layout',
|
|
651
|
+
standalone: true,
|
|
652
|
+
imports: [
|
|
653
|
+
CommonModule,
|
|
654
|
+
ReactiveFormsModule,
|
|
655
|
+
DynamicFieldComponent
|
|
656
|
+
],
|
|
657
|
+
template: `
|
|
658
|
+
<div [class]="field().gridClass || 'col-span-12'">
|
|
659
|
+
<ad-dynamic-field [field]="field()" [form]="form()"></ad-dynamic-field>
|
|
660
|
+
</div>
|
|
661
|
+
`
|
|
662
|
+
}]
|
|
663
|
+
}], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }] } });
|
|
664
|
+
|
|
665
|
+
class AdLoadingComponent {
|
|
666
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
667
|
+
color = input('text-sky-600', ...(ngDevMode ? [{ debugName: "color" }] : []));
|
|
668
|
+
computedClasses = computed(() => {
|
|
669
|
+
let sizeClass = 'h-5 w-5';
|
|
670
|
+
switch (this.size()) {
|
|
671
|
+
case 'sm':
|
|
672
|
+
sizeClass = 'h-4 w-4';
|
|
673
|
+
break;
|
|
674
|
+
case 'lg':
|
|
675
|
+
sizeClass = 'h-8 w-8';
|
|
676
|
+
break;
|
|
677
|
+
}
|
|
678
|
+
return `animate-spin ${sizeClass} ${this.color()}`;
|
|
679
|
+
}, ...(ngDevMode ? [{ debugName: "computedClasses" }] : []));
|
|
680
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdLoadingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
681
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.4", type: AdLoadingComponent, isStandalone: true, selector: "ad-loading", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<svg [class]=\"computedClasses()\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\r\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\r\n <path class=\"opacity-75\" fill=\"currentColor\"\r\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\">\r\n </path>\r\n</svg>", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
682
|
+
}
|
|
683
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdLoadingComponent, decorators: [{
|
|
684
|
+
type: Component,
|
|
685
|
+
args: [{ selector: 'ad-loading', standalone: true, imports: [CommonModule], template: "<svg [class]=\"computedClasses()\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\r\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\r\n <path class=\"opacity-75\" fill=\"currentColor\"\r\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\">\r\n </path>\r\n</svg>" }]
|
|
686
|
+
}], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }] } });
|
|
687
|
+
|
|
688
|
+
class AdButtonComponent {
|
|
689
|
+
variant = input('primary', ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
690
|
+
type = input('button', ...(ngDevMode ? [{ debugName: "type" }] : []));
|
|
691
|
+
_disabled = signal(false, ...(ngDevMode ? [{ debugName: "_disabled" }] : []));
|
|
692
|
+
set disabled(value) { this._disabled.set(value); }
|
|
693
|
+
get disabled() { return this._disabled(); }
|
|
694
|
+
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
695
|
+
icon = input(undefined, ...(ngDevMode ? [{ debugName: "icon" }] : []));
|
|
696
|
+
size = input('default', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
697
|
+
block = input(false, ...(ngDevMode ? [{ debugName: "block" }] : []));
|
|
698
|
+
computedClasses = computed(() => {
|
|
699
|
+
const baseClasses = 'ad-btn inline-flex items-center justify-center gap-2 rounded-lg font-medium transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed';
|
|
700
|
+
const displayClass = this.block() ? 'w-full flex' : 'inline-flex';
|
|
701
|
+
const sizeClasses = {
|
|
702
|
+
'small': 'px-3 py-1.5 text-xs',
|
|
703
|
+
'default': 'px-4 py-2 text-sm',
|
|
704
|
+
'large': 'px-6 py-3 text-base'
|
|
705
|
+
};
|
|
706
|
+
const variantClasses = {
|
|
707
|
+
'primary': 'bg-cerca-primary text-white hover:bg-cerca-primary-hover active:bg-cerca-primary-active focus-visible:ring-cerca-primary shadow-sm',
|
|
708
|
+
'secondary': 'bg-white text-cerca-secondary border border-slate-300 hover:bg-slate-50 focus-visible:ring-slate-500 shadow-sm',
|
|
709
|
+
'ghost': 'text-cerca-secondary hover:bg-slate-100 focus-visible:ring-slate-500',
|
|
710
|
+
'outline': 'border-2 border-cerca-primary text-cerca-primary hover:bg-cerca-primary-light focus-visible:ring-cerca-primary',
|
|
711
|
+
'danger': 'bg-cerca-alert text-white hover:bg-red-600 focus-visible:ring-cerca-alert shadow-sm'
|
|
712
|
+
};
|
|
713
|
+
return `${baseClasses.replace('inline-flex', '')} ${displayClass} ${sizeClasses[this.size()]} ${variantClasses[this.variant()] || variantClasses['primary']}`;
|
|
714
|
+
}, ...(ngDevMode ? [{ debugName: "computedClasses" }] : []));
|
|
715
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
716
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdButtonComponent, isStandalone: true, selector: "ad-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, block: { classPropertyName: "block", publicName: "block", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<button [class]=\"computedClasses()\" [disabled]=\"disabled\" [type]=\"type()\">\r\n @if (loading()) {\r\n <ad-loading size=\"sm\" color=\"text-current\"></ad-loading>\r\n }\r\n @if (icon() && !loading()) {\r\n <ad-icon [name]=\"icon()!\" [size]=\"size() === 'small' ? 'sm' : size() === 'large' ? 'lg' : 'md'\"></ad-icon>\r\n }\r\n <ng-content></ng-content>\r\n</button>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AdIconComponent, selector: "ad-icon", inputs: ["name", "size", "color"] }, { kind: "component", type: AdLoadingComponent, selector: "ad-loading", inputs: ["size", "color"] }] });
|
|
717
|
+
}
|
|
718
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdButtonComponent, decorators: [{
|
|
719
|
+
type: Component,
|
|
720
|
+
args: [{ selector: 'ad-button', standalone: true, imports: [CommonModule, AdIconComponent, AdLoadingComponent], template: "<button [class]=\"computedClasses()\" [disabled]=\"disabled\" [type]=\"type()\">\r\n @if (loading()) {\r\n <ad-loading size=\"sm\" color=\"text-current\"></ad-loading>\r\n }\r\n @if (icon() && !loading()) {\r\n <ad-icon [name]=\"icon()!\" [size]=\"size() === 'small' ? 'sm' : size() === 'large' ? 'lg' : 'md'\"></ad-icon>\r\n }\r\n <ng-content></ng-content>\r\n</button>" }]
|
|
721
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], disabled: [{
|
|
220
722
|
type: Input
|
|
221
|
-
}] } });
|
|
723
|
+
}], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], block: [{ type: i0.Input, args: [{ isSignal: true, alias: "block", required: false }] }] } });
|
|
222
724
|
|
|
223
|
-
class
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
725
|
+
class AdFormSectionComponent {
|
|
726
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
727
|
+
title = computed(() => this.resource().title, ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
728
|
+
cols = computed(() => this.resource().cols ?? 12, ...(ngDevMode ? [{ debugName: "cols" }] : []));
|
|
729
|
+
loading = computed(() => this.resource().loading ?? false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
730
|
+
// Map for safe Tailwind class detection
|
|
731
|
+
colSpanMap = {
|
|
732
|
+
1: 'md:col-span-1',
|
|
733
|
+
2: 'md:col-span-2',
|
|
734
|
+
3: 'md:col-span-3',
|
|
735
|
+
4: 'md:col-span-4',
|
|
736
|
+
5: 'md:col-span-5',
|
|
737
|
+
6: 'md:col-span-6',
|
|
738
|
+
7: 'md:col-span-7',
|
|
739
|
+
8: 'md:col-span-8',
|
|
740
|
+
9: 'md:col-span-9',
|
|
741
|
+
10: 'md:col-span-10',
|
|
742
|
+
11: 'md:col-span-11',
|
|
743
|
+
12: 'md:col-span-12'
|
|
744
|
+
};
|
|
745
|
+
hostClasses = computed(() => {
|
|
746
|
+
const colClass = this.colSpanMap[this.cols()] || 'md:col-span-12';
|
|
747
|
+
return `block ${colClass}`;
|
|
748
|
+
}, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
|
|
749
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdFormSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
750
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdFormSectionComponent, isStandalone: true, selector: "ad-form-section", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
|
|
751
|
+
<div class="bg-white rounded-lg shadow-sm border border-stone-200 dark:border-cerca-primary dark:bg-cerca-navy h-full flex flex-col transition-colors duration-300">
|
|
752
|
+
|
|
753
|
+
@if (title()) {
|
|
754
|
+
<div class="px-6 py-4 border-b border-stone-100 dark:border-cerca-primary-hover">
|
|
755
|
+
<h3 class="text-lg font-semibold text-stone-800 dark:text-white">{{ title() }}</h3>
|
|
756
|
+
</div>
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
<div class="p-6 flex-1 space-y-4">
|
|
760
|
+
@if (loading()) {
|
|
761
|
+
<div class="animate-pulse space-y-4">
|
|
762
|
+
<div class="h-4 bg-stone-200 dark:bg-stone-700 rounded w-3/4"></div>
|
|
763
|
+
<div class="h-10 bg-stone-100 dark:bg-stone-800 rounded"></div>
|
|
764
|
+
<div class="h-4 bg-stone-200 dark:bg-stone-700 rounded w-1/2"></div>
|
|
765
|
+
<div class="h-24 bg-stone-100 dark:bg-stone-800 rounded"></div>
|
|
766
|
+
</div>
|
|
767
|
+
} @else {
|
|
768
|
+
<ng-content></ng-content>
|
|
769
|
+
}
|
|
770
|
+
</div>
|
|
771
|
+
</div>
|
|
772
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], encapsulation: i0.ViewEncapsulation.None });
|
|
773
|
+
}
|
|
774
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdFormSectionComponent, decorators: [{
|
|
775
|
+
type: Component,
|
|
776
|
+
args: [{
|
|
777
|
+
selector: 'ad-form-section',
|
|
778
|
+
standalone: true,
|
|
779
|
+
imports: [CommonModule],
|
|
780
|
+
template: `
|
|
781
|
+
<div class="bg-white rounded-lg shadow-sm border border-stone-200 dark:border-cerca-primary dark:bg-cerca-navy h-full flex flex-col transition-colors duration-300">
|
|
782
|
+
|
|
783
|
+
@if (title()) {
|
|
784
|
+
<div class="px-6 py-4 border-b border-stone-100 dark:border-cerca-primary-hover">
|
|
785
|
+
<h3 class="text-lg font-semibold text-stone-800 dark:text-white">{{ title() }}</h3>
|
|
786
|
+
</div>
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
<div class="p-6 flex-1 space-y-4">
|
|
790
|
+
@if (loading()) {
|
|
791
|
+
<div class="animate-pulse space-y-4">
|
|
792
|
+
<div class="h-4 bg-stone-200 dark:bg-stone-700 rounded w-3/4"></div>
|
|
793
|
+
<div class="h-10 bg-stone-100 dark:bg-stone-800 rounded"></div>
|
|
794
|
+
<div class="h-4 bg-stone-200 dark:bg-stone-700 rounded w-1/2"></div>
|
|
795
|
+
<div class="h-24 bg-stone-100 dark:bg-stone-800 rounded"></div>
|
|
796
|
+
</div>
|
|
797
|
+
} @else {
|
|
798
|
+
<ng-content></ng-content>
|
|
799
|
+
}
|
|
800
|
+
</div>
|
|
801
|
+
</div>
|
|
802
|
+
`,
|
|
803
|
+
encapsulation: ViewEncapsulation.None,
|
|
804
|
+
host: {
|
|
805
|
+
'[class]': 'hostClasses()'
|
|
806
|
+
}
|
|
807
|
+
}]
|
|
808
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }] } });
|
|
809
|
+
|
|
810
|
+
class AdFormRendererComponent {
|
|
811
|
+
// Maps for safe Tailwind class detection (JIT compatible)
|
|
812
|
+
mdColSpanMap = {
|
|
813
|
+
1: 'md:col-span-1',
|
|
814
|
+
2: 'md:col-span-2',
|
|
815
|
+
3: 'md:col-span-3',
|
|
816
|
+
4: 'md:col-span-4',
|
|
817
|
+
5: 'md:col-span-5',
|
|
818
|
+
6: 'md:col-span-6',
|
|
819
|
+
7: 'md:col-span-7',
|
|
820
|
+
8: 'md:col-span-8',
|
|
821
|
+
9: 'md:col-span-9',
|
|
822
|
+
10: 'md:col-span-10',
|
|
823
|
+
11: 'md:col-span-11',
|
|
824
|
+
12: 'md:col-span-12'
|
|
825
|
+
};
|
|
826
|
+
lgColSpanMap = {
|
|
827
|
+
1: 'lg:col-span-1',
|
|
828
|
+
2: 'lg:col-span-2',
|
|
829
|
+
3: 'lg:col-span-3',
|
|
830
|
+
4: 'lg:col-span-4',
|
|
831
|
+
5: 'lg:col-span-5',
|
|
832
|
+
6: 'lg:col-span-6',
|
|
833
|
+
7: 'lg:col-span-7',
|
|
834
|
+
8: 'lg:col-span-8',
|
|
835
|
+
9: 'lg:col-span-9',
|
|
836
|
+
10: 'lg:col-span-10',
|
|
837
|
+
11: 'lg:col-span-11',
|
|
838
|
+
12: 'lg:col-span-12'
|
|
839
|
+
};
|
|
840
|
+
xlColSpanMap = {
|
|
841
|
+
1: 'xl:col-span-1',
|
|
842
|
+
2: 'xl:col-span-2',
|
|
843
|
+
3: 'xl:col-span-3',
|
|
844
|
+
4: 'xl:col-span-4',
|
|
845
|
+
5: 'xl:col-span-5',
|
|
846
|
+
6: 'xl:col-span-6',
|
|
847
|
+
7: 'xl:col-span-7',
|
|
848
|
+
8: 'xl:col-span-8',
|
|
849
|
+
9: 'xl:col-span-9',
|
|
850
|
+
10: 'xl:col-span-10',
|
|
851
|
+
11: 'xl:col-span-11',
|
|
852
|
+
12: 'xl:col-span-12'
|
|
853
|
+
};
|
|
854
|
+
getGridClass(props) {
|
|
855
|
+
const classes = [];
|
|
856
|
+
// Base Span (Mobile/Default) mapped to MD because our grid starts at MD
|
|
857
|
+
if (props?.span) {
|
|
858
|
+
classes.push(this.mdColSpanMap[props.span] || 'md:col-span-12');
|
|
859
|
+
}
|
|
860
|
+
else {
|
|
861
|
+
classes.push('md:col-span-12'); // Default full width
|
|
862
|
+
}
|
|
863
|
+
// LG Override
|
|
864
|
+
if (props?.lg) {
|
|
865
|
+
classes.push(this.lgColSpanMap[props.lg]);
|
|
866
|
+
}
|
|
867
|
+
// XL Override
|
|
868
|
+
if (props?.xl) {
|
|
869
|
+
classes.push(this.xlColSpanMap[props.xl]);
|
|
870
|
+
}
|
|
871
|
+
return classes.join(' ');
|
|
872
|
+
}
|
|
873
|
+
nodes = input.required(...(ngDevMode ? [{ debugName: "nodes" }] : []));
|
|
874
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
875
|
+
isLayout(node) {
|
|
876
|
+
return 'layoutType' in node && !!node.children;
|
|
877
|
+
}
|
|
878
|
+
asField(node) {
|
|
879
|
+
return node;
|
|
228
880
|
}
|
|
229
|
-
|
|
230
|
-
return
|
|
881
|
+
asLayout(node) {
|
|
882
|
+
return node;
|
|
231
883
|
}
|
|
232
|
-
|
|
233
|
-
|
|
884
|
+
trackByFn(index, item) {
|
|
885
|
+
return item.key || item.name || index;
|
|
886
|
+
}
|
|
887
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdFormRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
888
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdFormRendererComponent, isStandalone: true, selector: "ad-form-renderer", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null } }, host: { styleAttribute: "display: contents" }, ngImport: i0, template: `
|
|
889
|
+
@for (node of nodes(); track $any(node).key || $any(node).name || $index) {
|
|
890
|
+
|
|
891
|
+
@if (isLayout(node)) {
|
|
892
|
+
<!-- Recursive Layout Rendering -->
|
|
893
|
+
@switch (node.layoutType) {
|
|
894
|
+
|
|
895
|
+
@case ('row') {
|
|
896
|
+
<div class="grid grid-cols-1 md:grid-cols-12 gap-6 items-start w-full md:col-span-12">
|
|
897
|
+
<ad-form-renderer [nodes]="node.children || []" [form]="form()"></ad-form-renderer>
|
|
898
|
+
</div>
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
@case ('col') {
|
|
902
|
+
<!-- 'col' wraps content in a div with grid classes. -->
|
|
903
|
+
<div [class]="getGridClass(node.layoutProps)">
|
|
904
|
+
<ad-form-renderer [nodes]="node.children || []" [form]="form()"></ad-form-renderer>
|
|
905
|
+
</div>
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
@case ('card') {
|
|
909
|
+
<!-- For card, we might want to also use the grid class on the wrapper?
|
|
910
|
+
AdFormSection uses 'cols' input to generate wrapper class.
|
|
911
|
+
We should probably update AdFormSection to accept full class string or improve mapping.
|
|
912
|
+
But AdFormSection just uses cols Input -> md:col-span-X.
|
|
913
|
+
Let's keep legacy behavior for card if simple span, or enhance AdFormSection later.
|
|
914
|
+
Actually, card usually sits inside a 'col'. If card is direct child of row, it needs width.
|
|
915
|
+
Usage in schema:
|
|
916
|
+
row -> children: [ { layoutType: 'col', children: [ { layoutType: 'card' } ] } ]
|
|
917
|
+
So card is inside col (which has width). Card itself usually takes full width of parent.
|
|
918
|
+
Wait, AdFormSection has [cols] input. Default 12.
|
|
919
|
+
If card is inside a col (which is e.g. span 8), then card should be span 12 (100% of parent).
|
|
920
|
+
The schema in demo has card INSIDE col.
|
|
921
|
+
So card shouldn't need sizing props if it's 100%.
|
|
922
|
+
But if card is direct child of row?
|
|
923
|
+
Safest is to let card be 12 (100% of container).
|
|
924
|
+
If User put card directly in row, they might expect it to size.
|
|
925
|
+
But let's assume standard pattern: Row -> Col -> Card.
|
|
926
|
+
-->
|
|
927
|
+
<ad-form-section [resource]="{ title: node.layoutProps?.title, cols: 12 }">
|
|
928
|
+
<ad-form-renderer [nodes]="node.children || []" [form]="form()"></ad-form-renderer>
|
|
929
|
+
</ad-form-section>
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
@case ('stack') {
|
|
933
|
+
<div class="flex flex-col" [style.gap.px]="node.layoutProps?.gap || 0">
|
|
934
|
+
<ad-form-renderer [nodes]="node.children || []" [form]="form()"></ad-form-renderer>
|
|
935
|
+
</div>
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
@default {
|
|
939
|
+
<!-- Fallback for unknown layout: render children directly -->
|
|
940
|
+
<!-- Explicitly cast to unknown then LayoutSchema to access children safely in default block -->
|
|
941
|
+
<ad-form-renderer [nodes]="asLayout(node).children || []" [form]="form()"></ad-form-renderer>
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
} @else {
|
|
945
|
+
<!-- Leaf Node: Field -->
|
|
946
|
+
<!-- Fields use getGridClass to support layoutProps: { span: X } directly on the field -->
|
|
947
|
+
<div [class]="getGridClass(node.layoutProps)">
|
|
948
|
+
<ad-dynamic-layout [field]="asField(node)" [form]="form()"></ad-dynamic-layout>
|
|
949
|
+
</div>
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
`, isInline: true, dependencies: [{ kind: "component", type: i0.forwardRef(() => AdFormRendererComponent), selector: "ad-form-renderer", inputs: ["nodes", "form"] }, { kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "component", type: i0.forwardRef(() => DynamicLayoutComponent), selector: "ad-dynamic-layout", inputs: ["field", "form"] }, { kind: "component", type: i0.forwardRef(() => AdFormSectionComponent), selector: "ad-form-section", inputs: ["resource"] }] });
|
|
234
953
|
}
|
|
235
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
954
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdFormRendererComponent, decorators: [{
|
|
236
955
|
type: Component,
|
|
237
|
-
args: [{
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
956
|
+
args: [{
|
|
957
|
+
selector: 'ad-form-renderer',
|
|
958
|
+
standalone: true,
|
|
959
|
+
imports: [
|
|
960
|
+
CommonModule,
|
|
961
|
+
ReactiveFormsModule,
|
|
962
|
+
DynamicLayoutComponent, // Renders individual fields (leaf nodes)
|
|
963
|
+
AdFormSectionComponent, // Renders 'card'
|
|
964
|
+
forwardRef(() => AdFormRendererComponent)
|
|
965
|
+
],
|
|
966
|
+
template: `
|
|
967
|
+
@for (node of nodes(); track $any(node).key || $any(node).name || $index) {
|
|
968
|
+
|
|
969
|
+
@if (isLayout(node)) {
|
|
970
|
+
<!-- Recursive Layout Rendering -->
|
|
971
|
+
@switch (node.layoutType) {
|
|
972
|
+
|
|
973
|
+
@case ('row') {
|
|
974
|
+
<div class="grid grid-cols-1 md:grid-cols-12 gap-6 items-start w-full md:col-span-12">
|
|
975
|
+
<ad-form-renderer [nodes]="node.children || []" [form]="form()"></ad-form-renderer>
|
|
976
|
+
</div>
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
@case ('col') {
|
|
980
|
+
<!-- 'col' wraps content in a div with grid classes. -->
|
|
981
|
+
<div [class]="getGridClass(node.layoutProps)">
|
|
982
|
+
<ad-form-renderer [nodes]="node.children || []" [form]="form()"></ad-form-renderer>
|
|
983
|
+
</div>
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
@case ('card') {
|
|
987
|
+
<!-- For card, we might want to also use the grid class on the wrapper?
|
|
988
|
+
AdFormSection uses 'cols' input to generate wrapper class.
|
|
989
|
+
We should probably update AdFormSection to accept full class string or improve mapping.
|
|
990
|
+
But AdFormSection just uses cols Input -> md:col-span-X.
|
|
991
|
+
Let's keep legacy behavior for card if simple span, or enhance AdFormSection later.
|
|
992
|
+
Actually, card usually sits inside a 'col'. If card is direct child of row, it needs width.
|
|
993
|
+
Usage in schema:
|
|
994
|
+
row -> children: [ { layoutType: 'col', children: [ { layoutType: 'card' } ] } ]
|
|
995
|
+
So card is inside col (which has width). Card itself usually takes full width of parent.
|
|
996
|
+
Wait, AdFormSection has [cols] input. Default 12.
|
|
997
|
+
If card is inside a col (which is e.g. span 8), then card should be span 12 (100% of parent).
|
|
998
|
+
The schema in demo has card INSIDE col.
|
|
999
|
+
So card shouldn't need sizing props if it's 100%.
|
|
1000
|
+
But if card is direct child of row?
|
|
1001
|
+
Safest is to let card be 12 (100% of container).
|
|
1002
|
+
If User put card directly in row, they might expect it to size.
|
|
1003
|
+
But let's assume standard pattern: Row -> Col -> Card.
|
|
1004
|
+
-->
|
|
1005
|
+
<ad-form-section [resource]="{ title: node.layoutProps?.title, cols: 12 }">
|
|
1006
|
+
<ad-form-renderer [nodes]="node.children || []" [form]="form()"></ad-form-renderer>
|
|
1007
|
+
</ad-form-section>
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
@case ('stack') {
|
|
1011
|
+
<div class="flex flex-col" [style.gap.px]="node.layoutProps?.gap || 0">
|
|
1012
|
+
<ad-form-renderer [nodes]="node.children || []" [form]="form()"></ad-form-renderer>
|
|
1013
|
+
</div>
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
@default {
|
|
1017
|
+
<!-- Fallback for unknown layout: render children directly -->
|
|
1018
|
+
<!-- Explicitly cast to unknown then LayoutSchema to access children safely in default block -->
|
|
1019
|
+
<ad-form-renderer [nodes]="asLayout(node).children || []" [form]="form()"></ad-form-renderer>
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
} @else {
|
|
1023
|
+
<!-- Leaf Node: Field -->
|
|
1024
|
+
<!-- Fields use getGridClass to support layoutProps: { span: X } directly on the field -->
|
|
1025
|
+
<div [class]="getGridClass(node.layoutProps)">
|
|
1026
|
+
<ad-dynamic-layout [field]="asField(node)" [form]="form()"></ad-dynamic-layout>
|
|
1027
|
+
</div>
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
`,
|
|
1031
|
+
host: {
|
|
1032
|
+
style: 'display: contents'
|
|
1033
|
+
}
|
|
1034
|
+
}]
|
|
1035
|
+
}], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: true }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }] } });
|
|
245
1036
|
|
|
246
|
-
class
|
|
1037
|
+
class FormEngineComponent {
|
|
1038
|
+
// Inputs (Signals)
|
|
1039
|
+
schema = input.required(...(ngDevMode ? [{ debugName: "schema" }] : []));
|
|
1040
|
+
model = input({}, ...(ngDevMode ? [{ debugName: "model" }] : []));
|
|
1041
|
+
showCancel = input(false, ...(ngDevMode ? [{ debugName: "showCancel" }] : []));
|
|
1042
|
+
showSubmit = input(true, ...(ngDevMode ? [{ debugName: "showSubmit" }] : []));
|
|
1043
|
+
// Outputs
|
|
1044
|
+
formSubmit = output();
|
|
1045
|
+
formCancel = output();
|
|
1046
|
+
// Dependencies
|
|
1047
|
+
engineService = inject(FormEngineService);
|
|
1048
|
+
// State
|
|
1049
|
+
form = computed(() => {
|
|
1050
|
+
const schema = this.schema();
|
|
1051
|
+
const model = this.model();
|
|
1052
|
+
// Note: model availability in computed might be tricky if model updates later.
|
|
1053
|
+
// But createFormGroup usually runs once.
|
|
1054
|
+
// Better: create form once, then patch.
|
|
1055
|
+
if (!schema)
|
|
1056
|
+
return new FormGroup({});
|
|
1057
|
+
return this.engineService.createFormGroup(schema, model);
|
|
1058
|
+
}, ...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
247
1059
|
constructor() {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
1060
|
+
// Effect to patch value when model changes AFTER form creation
|
|
1061
|
+
effect(() => {
|
|
1062
|
+
const currentModel = this.model();
|
|
1063
|
+
const currentForm = this.form();
|
|
1064
|
+
if (currentForm && currentModel && Object.keys(currentModel).length > 0) {
|
|
1065
|
+
currentForm.patchValue(currentModel);
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
253
1068
|
}
|
|
254
|
-
|
|
255
|
-
|
|
1069
|
+
ngOnInit() { }
|
|
1070
|
+
submit() {
|
|
1071
|
+
const f = this.form();
|
|
1072
|
+
if (f.valid) {
|
|
1073
|
+
this.formSubmit.emit(f.value);
|
|
1074
|
+
}
|
|
1075
|
+
else {
|
|
1076
|
+
Object.values(f.controls).forEach(control => {
|
|
1077
|
+
if (control.invalid) {
|
|
1078
|
+
control.markAsDirty();
|
|
1079
|
+
control.updateValueAndValidity({ onlySelf: true });
|
|
1080
|
+
}
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
onCancel() {
|
|
1085
|
+
this.formCancel.emit();
|
|
1086
|
+
}
|
|
1087
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: FormEngineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1088
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: FormEngineComponent, isStandalone: true, selector: "ad-form-engine", inputs: { schema: { classPropertyName: "schema", publicName: "schema", isSignal: true, isRequired: true, transformFunction: null }, model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, showCancel: { classPropertyName: "showCancel", publicName: "showCancel", isSignal: true, isRequired: false, transformFunction: null }, showSubmit: { classPropertyName: "showSubmit", publicName: "showSubmit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formSubmit: "formSubmit", formCancel: "formCancel" }, ngImport: i0, template: `
|
|
1089
|
+
@if (form()) {
|
|
1090
|
+
<form [formGroup]="form()" class="space-y-6" (ngSubmit)="submit()">
|
|
1091
|
+
|
|
1092
|
+
<!-- NEW: Recursive Schema Rendering -->
|
|
1093
|
+
@if (schema().fields) {
|
|
1094
|
+
<div class="grid grid-cols-1 md:grid-cols-12 gap-6 w-full">
|
|
1095
|
+
<ad-form-renderer [nodes]="schema().fields!" [form]="form()"></ad-form-renderer>
|
|
1096
|
+
</div>
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
<!-- LEGACY: Sections Rendering (Fallback) -->
|
|
1100
|
+
@if (!schema().fields && schema().sections) {
|
|
1101
|
+
@for (section of schema().sections; track $index) {
|
|
1102
|
+
<div [class]="section.gridClass || 'grid grid-cols-12 gap-6'">
|
|
1103
|
+
@if (section.title) {
|
|
1104
|
+
<div class="col-span-12">
|
|
1105
|
+
<h3 class="text-lg font-medium leading-6 text-slate-900">{{ section.title }}</h3>
|
|
1106
|
+
@if (section.description) {
|
|
1107
|
+
<p class="mt-1 text-sm text-slate-500">{{ section.description }}</p>
|
|
1108
|
+
}
|
|
1109
|
+
</div>
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
@for (field of section.fields; track field.key) {
|
|
1113
|
+
<ad-dynamic-layout [field]="field" [form]="form()"></ad-dynamic-layout>
|
|
1114
|
+
}
|
|
1115
|
+
</div>
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
<!-- Actions -->
|
|
1120
|
+
<div class="flex justify-end gap-x-4">
|
|
1121
|
+
@if (showCancel()) {
|
|
1122
|
+
<ad-button variant="secondary" type="button" (click)="onCancel()">{{ schema().cancelLabel || 'Cancelar' }}</ad-button>
|
|
1123
|
+
}
|
|
1124
|
+
@if (showSubmit()) {
|
|
1125
|
+
<ad-button variant="primary" type="submit">{{ schema().submitLabel || 'Guardar' }}</ad-button>
|
|
1126
|
+
}
|
|
1127
|
+
</div>
|
|
1128
|
+
</form>
|
|
1129
|
+
}
|
|
1130
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DynamicLayoutComponent, selector: "ad-dynamic-layout", inputs: ["field", "form"] }, { kind: "component", type: AdButtonComponent, selector: "ad-button", inputs: ["variant", "type", "disabled", "loading", "icon", "size", "block"] }, { kind: "component", type: AdFormRendererComponent, selector: "ad-form-renderer", inputs: ["nodes", "form"] }] });
|
|
256
1131
|
}
|
|
257
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
1132
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: FormEngineComponent, decorators: [{
|
|
258
1133
|
type: Component,
|
|
259
|
-
args: [{
|
|
260
|
-
|
|
1134
|
+
args: [{
|
|
1135
|
+
selector: 'ad-form-engine',
|
|
1136
|
+
standalone: true,
|
|
1137
|
+
imports: [CommonModule, ReactiveFormsModule, DynamicLayoutComponent, AdButtonComponent, AdFormRendererComponent],
|
|
1138
|
+
template: `
|
|
1139
|
+
@if (form()) {
|
|
1140
|
+
<form [formGroup]="form()" class="space-y-6" (ngSubmit)="submit()">
|
|
1141
|
+
|
|
1142
|
+
<!-- NEW: Recursive Schema Rendering -->
|
|
1143
|
+
@if (schema().fields) {
|
|
1144
|
+
<div class="grid grid-cols-1 md:grid-cols-12 gap-6 w-full">
|
|
1145
|
+
<ad-form-renderer [nodes]="schema().fields!" [form]="form()"></ad-form-renderer>
|
|
1146
|
+
</div>
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
<!-- LEGACY: Sections Rendering (Fallback) -->
|
|
1150
|
+
@if (!schema().fields && schema().sections) {
|
|
1151
|
+
@for (section of schema().sections; track $index) {
|
|
1152
|
+
<div [class]="section.gridClass || 'grid grid-cols-12 gap-6'">
|
|
1153
|
+
@if (section.title) {
|
|
1154
|
+
<div class="col-span-12">
|
|
1155
|
+
<h3 class="text-lg font-medium leading-6 text-slate-900">{{ section.title }}</h3>
|
|
1156
|
+
@if (section.description) {
|
|
1157
|
+
<p class="mt-1 text-sm text-slate-500">{{ section.description }}</p>
|
|
1158
|
+
}
|
|
1159
|
+
</div>
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
@for (field of section.fields; track field.key) {
|
|
1163
|
+
<ad-dynamic-layout [field]="field" [form]="form()"></ad-dynamic-layout>
|
|
1164
|
+
}
|
|
1165
|
+
</div>
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
<!-- Actions -->
|
|
1170
|
+
<div class="flex justify-end gap-x-4">
|
|
1171
|
+
@if (showCancel()) {
|
|
1172
|
+
<ad-button variant="secondary" type="button" (click)="onCancel()">{{ schema().cancelLabel || 'Cancelar' }}</ad-button>
|
|
1173
|
+
}
|
|
1174
|
+
@if (showSubmit()) {
|
|
1175
|
+
<ad-button variant="primary" type="submit">{{ schema().submitLabel || 'Guardar' }}</ad-button>
|
|
1176
|
+
}
|
|
1177
|
+
</div>
|
|
1178
|
+
</form>
|
|
1179
|
+
}
|
|
1180
|
+
`
|
|
1181
|
+
}]
|
|
1182
|
+
}], ctorParameters: () => [], propDecorators: { schema: [{ type: i0.Input, args: [{ isSignal: true, alias: "schema", required: true }] }], model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: false }] }], showCancel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCancel", required: false }] }], showSubmit: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSubmit", required: false }] }], formSubmit: [{ type: i0.Output, args: ["formSubmit"] }], formCancel: [{ type: i0.Output, args: ["formCancel"] }] } });
|
|
261
1183
|
|
|
262
|
-
class
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
this.
|
|
268
|
-
this.
|
|
269
|
-
|
|
1184
|
+
class AdModalWrapperComponent {
|
|
1185
|
+
resource;
|
|
1186
|
+
data = {};
|
|
1187
|
+
isOpen = signal(true, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
1188
|
+
modalResource = computed(() => ({
|
|
1189
|
+
isOpen: this.isOpen(),
|
|
1190
|
+
title: this.resource?.title,
|
|
1191
|
+
size: 'md',
|
|
1192
|
+
showFooter: false
|
|
1193
|
+
}), ...(ngDevMode ? [{ debugName: "modalResource" }] : []));
|
|
1194
|
+
resultSubject = new Subject();
|
|
1195
|
+
result$ = this.resultSubject.asObservable();
|
|
1196
|
+
onClose() {
|
|
1197
|
+
this.isOpen.set(false);
|
|
1198
|
+
this.resultSubject.next(null);
|
|
1199
|
+
this.resultSubject.complete();
|
|
270
1200
|
}
|
|
271
|
-
|
|
272
|
-
|
|
1201
|
+
onSubmit(result) {
|
|
1202
|
+
this.isOpen.set(false);
|
|
1203
|
+
this.resultSubject.next(result);
|
|
1204
|
+
this.resultSubject.complete();
|
|
273
1205
|
}
|
|
274
|
-
static
|
|
275
|
-
static
|
|
1206
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdModalWrapperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1207
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdModalWrapperComponent, isStandalone: true, selector: "ad-modal-wrapper", ngImport: i0, template: `
|
|
1208
|
+
<ad-modal
|
|
1209
|
+
[resource]="modalResource()"
|
|
1210
|
+
(close)="onClose()">
|
|
1211
|
+
|
|
1212
|
+
@if (resource.type === 'form' && resource.formConfig) {
|
|
1213
|
+
<ad-form-engine
|
|
1214
|
+
[schema]="resource.formConfig"
|
|
1215
|
+
[model]="data"
|
|
1216
|
+
[showCancel]="true"
|
|
1217
|
+
(formSubmit)="onSubmit($event)"
|
|
1218
|
+
(formCancel)="onClose()">
|
|
1219
|
+
</ad-form-engine>
|
|
1220
|
+
} @else {
|
|
1221
|
+
<div class="p-6 text-center text-slate-500">
|
|
1222
|
+
Renderer para el tipo "{{ resource.type }}" no implementado en el modal.
|
|
1223
|
+
</div>
|
|
1224
|
+
}
|
|
1225
|
+
</ad-modal>
|
|
1226
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AdModalComponent, selector: "ad-modal", inputs: ["resource"], outputs: ["close"] }, { kind: "component", type: FormEngineComponent, selector: "ad-form-engine", inputs: ["schema", "model", "showCancel", "showSubmit"], outputs: ["formSubmit", "formCancel"] }] });
|
|
276
1227
|
}
|
|
277
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
1228
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdModalWrapperComponent, decorators: [{
|
|
278
1229
|
type: Component,
|
|
279
|
-
args: [{
|
|
280
|
-
|
|
1230
|
+
args: [{
|
|
1231
|
+
selector: 'ad-modal-wrapper',
|
|
1232
|
+
standalone: true,
|
|
1233
|
+
imports: [CommonModule, AdModalComponent, FormEngineComponent],
|
|
1234
|
+
template: `
|
|
1235
|
+
<ad-modal
|
|
1236
|
+
[resource]="modalResource()"
|
|
1237
|
+
(close)="onClose()">
|
|
1238
|
+
|
|
1239
|
+
@if (resource.type === 'form' && resource.formConfig) {
|
|
1240
|
+
<ad-form-engine
|
|
1241
|
+
[schema]="resource.formConfig"
|
|
1242
|
+
[model]="data"
|
|
1243
|
+
[showCancel]="true"
|
|
1244
|
+
(formSubmit)="onSubmit($event)"
|
|
1245
|
+
(formCancel)="onClose()">
|
|
1246
|
+
</ad-form-engine>
|
|
1247
|
+
} @else {
|
|
1248
|
+
<div class="p-6 text-center text-slate-500">
|
|
1249
|
+
Renderer para el tipo "{{ resource.type }}" no implementado en el modal.
|
|
1250
|
+
</div>
|
|
1251
|
+
}
|
|
1252
|
+
</ad-modal>
|
|
1253
|
+
`
|
|
1254
|
+
}]
|
|
1255
|
+
}] });
|
|
1256
|
+
class AdModalService {
|
|
1257
|
+
appRef;
|
|
1258
|
+
injector;
|
|
1259
|
+
constructor(appRef, injector) {
|
|
1260
|
+
this.appRef = appRef;
|
|
1261
|
+
this.injector = injector;
|
|
1262
|
+
}
|
|
1263
|
+
open(resource, data) {
|
|
1264
|
+
const componentRef = createComponent(AdModalWrapperComponent, {
|
|
1265
|
+
environmentInjector: this.injector
|
|
1266
|
+
});
|
|
1267
|
+
// Set inputs
|
|
1268
|
+
componentRef.instance.resource = resource;
|
|
1269
|
+
if (data)
|
|
1270
|
+
componentRef.instance.data = data;
|
|
1271
|
+
// Attach to ApplicationRef so change detection works
|
|
1272
|
+
this.appRef.attachView(componentRef.hostView);
|
|
1273
|
+
// Append to DOM
|
|
1274
|
+
const domElement = componentRef.hostView.rootNodes[0];
|
|
1275
|
+
document.body.appendChild(domElement);
|
|
1276
|
+
// Cleanup on complete
|
|
1277
|
+
componentRef.instance.result$.subscribe({
|
|
1278
|
+
complete: () => {
|
|
1279
|
+
// Small delay to allow Angular modal to animate its close state
|
|
1280
|
+
setTimeout(() => {
|
|
1281
|
+
this.appRef.detachView(componentRef.hostView);
|
|
1282
|
+
componentRef.destroy();
|
|
1283
|
+
}, 300);
|
|
1284
|
+
}
|
|
1285
|
+
});
|
|
1286
|
+
return componentRef.instance.result$;
|
|
1287
|
+
}
|
|
1288
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdModalService, deps: [{ token: i0.ApplicationRef }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1289
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdModalService, providedIn: 'root' });
|
|
1290
|
+
}
|
|
1291
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdModalService, decorators: [{
|
|
1292
|
+
type: Injectable,
|
|
1293
|
+
args: [{
|
|
1294
|
+
providedIn: 'root'
|
|
1295
|
+
}]
|
|
1296
|
+
}], ctorParameters: () => [{ type: i0.ApplicationRef }, { type: i0.EnvironmentInjector }] });
|
|
1297
|
+
|
|
1298
|
+
class TableEngineComponent {
|
|
1299
|
+
// Signals
|
|
1300
|
+
schema = input.required(...(ngDevMode ? [{ debugName: "schema" }] : [])); // Optional if using columns directly, but Schema approach implies passing the whole schema object usually.
|
|
1301
|
+
// Actually, keeping flexible to support both direct cols or schema.
|
|
1302
|
+
// Let's support independent inputs for now to match old API but strict typed.
|
|
1303
|
+
// Re-defining inputs to match Core Schema
|
|
1304
|
+
columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
1305
|
+
data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
1306
|
+
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
1307
|
+
total = input(0, ...(ngDevMode ? [{ debugName: "total" }] : []));
|
|
1308
|
+
pageSize = input(10, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
|
|
1309
|
+
pageIndex = input(1, ...(ngDevMode ? [{ debugName: "pageIndex" }] : []));
|
|
1310
|
+
actions = input([], ...(ngDevMode ? [{ debugName: "actions" }] : [])); // Parameterized actions
|
|
1311
|
+
queryParamsChange = output();
|
|
1312
|
+
action = output();
|
|
1313
|
+
Math = Math;
|
|
1314
|
+
displayColumns = computed(() => {
|
|
1315
|
+
// Filter visible if property exists, or default true
|
|
1316
|
+
// CoreTableColumn doesn't have is_v displayColumns = computed(() => {
|
|
1317
|
+
// Use schema columns if available, otherwise fallback to columns input
|
|
1318
|
+
return this.schema().columns || this.columns();
|
|
1319
|
+
}, ...(ngDevMode ? [{ debugName: "displayColumns" }] : []));
|
|
1320
|
+
hasActions = computed(() => {
|
|
1321
|
+
const schemaActions = this.schema().actions || [];
|
|
1322
|
+
const inputActions = this.actions();
|
|
1323
|
+
return schemaActions.length > 0 || inputActions.length > 0;
|
|
1324
|
+
}, ...(ngDevMode ? [{ debugName: "hasActions" }] : []));
|
|
1325
|
+
// Helper to get combined actions
|
|
1326
|
+
getActions = computed(() => {
|
|
1327
|
+
const schemaActions = this.schema().actions || [];
|
|
1328
|
+
const inputActions = this.actions();
|
|
1329
|
+
return [...schemaActions, ...inputActions];
|
|
1330
|
+
}, ...(ngDevMode ? [{ debugName: "getActions" }] : []));
|
|
1331
|
+
mapVariant(color) {
|
|
1332
|
+
if (color === 'primary')
|
|
1333
|
+
return 'primary';
|
|
1334
|
+
if (color === 'secondary')
|
|
1335
|
+
return 'secondary';
|
|
1336
|
+
if (color === 'danger')
|
|
1337
|
+
return 'danger';
|
|
1338
|
+
return 'ghost';
|
|
1339
|
+
}
|
|
1340
|
+
onPageChange(newPageIndex) {
|
|
1341
|
+
if (newPageIndex < 1 || (newPageIndex - 1) * this.pageSize() >= this.total())
|
|
1342
|
+
return;
|
|
1343
|
+
this.queryParamsChange.emit({
|
|
1344
|
+
pageIndex: newPageIndex,
|
|
1345
|
+
pageSize: this.pageSize(),
|
|
1346
|
+
sort: [],
|
|
1347
|
+
filter: []
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
onActionClick(action, data) {
|
|
1351
|
+
this.action.emit({ action, data });
|
|
1352
|
+
}
|
|
1353
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: TableEngineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1354
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: TableEngineComponent, isStandalone: true, selector: "ad-table-engine", inputs: { schema: { classPropertyName: "schema", publicName: "schema", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, pageIndex: { classPropertyName: "pageIndex", publicName: "pageIndex", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { queryParamsChange: "queryParamsChange", action: "action" }, ngImport: i0, template: `
|
|
1355
|
+
<div class="flow-root">
|
|
1356
|
+
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
|
1357
|
+
<div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
|
|
1358
|
+
<div class="relative">
|
|
1359
|
+
@if (loading()) {
|
|
1360
|
+
<div class="absolute inset-0 bg-white/50 z-10 flex items-center justify-center">
|
|
1361
|
+
<svg class="animate-spin h-8 w-8 text-sky-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
1362
|
+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
1363
|
+
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
1364
|
+
</svg>
|
|
1365
|
+
</div>
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
<table class="min-w-full divide-y divide-slate-300">
|
|
1369
|
+
<thead>
|
|
1370
|
+
<tr>
|
|
1371
|
+
<!-- Checkbox Column if selectable (Future) -->
|
|
1372
|
+
|
|
1373
|
+
@for (column of displayColumns(); track column.key) {
|
|
1374
|
+
<th scope="col"
|
|
1375
|
+
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-slate-900 sm:pl-0"
|
|
1376
|
+
[style.width]="column.width || 'auto'">
|
|
1377
|
+
{{ column.label }}
|
|
1378
|
+
</th>
|
|
1379
|
+
}
|
|
1380
|
+
@if (hasActions()) {
|
|
1381
|
+
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-0">
|
|
1382
|
+
<span class="sr-only">Acciones</span>
|
|
1383
|
+
</th>
|
|
1384
|
+
}
|
|
1385
|
+
</tr>
|
|
1386
|
+
</thead>
|
|
1387
|
+
<tbody class="divide-y divide-slate-200 bg-white">
|
|
1388
|
+
@for (item of data(); track item) {
|
|
1389
|
+
<tr>
|
|
1390
|
+
@for (column of displayColumns(); track column.key) {
|
|
1391
|
+
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm text-slate-500 sm:pl-0">
|
|
1392
|
+
<!-- Simple rendering for now. Registry support can be added here -->
|
|
1393
|
+
{{ item[column.key] }}
|
|
1394
|
+
</td>
|
|
1395
|
+
}
|
|
1396
|
+
@if (hasActions()) {
|
|
1397
|
+
<td class="whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
|
|
1398
|
+
<div class="flex justify-end gap-2">
|
|
1399
|
+
@for (act of getActions(); track act.action) {
|
|
1400
|
+
<ad-button
|
|
1401
|
+
[variant]="mapVariant(act.color)"
|
|
1402
|
+
size="small"
|
|
1403
|
+
(click)="onActionClick(act.action, item)">
|
|
1404
|
+
@if (act.icon) {
|
|
1405
|
+
<ad-icon [name]="act.icon" class="mr-1"></ad-icon>
|
|
1406
|
+
}
|
|
1407
|
+
{{ act.label }}
|
|
1408
|
+
</ad-button>
|
|
1409
|
+
}
|
|
1410
|
+
</div>
|
|
1411
|
+
</td>
|
|
1412
|
+
}
|
|
1413
|
+
</tr>
|
|
1414
|
+
}
|
|
1415
|
+
@if (data().length === 0 && !loading()) {
|
|
1416
|
+
<tr>
|
|
1417
|
+
<td [attr.colspan]="displayColumns().length + (hasActions() ? 1 : 0)" class="py-8 text-center text-sm text-slate-500">
|
|
1418
|
+
No hay datos disponibles
|
|
1419
|
+
</td>
|
|
1420
|
+
</tr>
|
|
1421
|
+
}
|
|
1422
|
+
</tbody>
|
|
1423
|
+
</table>
|
|
1424
|
+
</div>
|
|
1425
|
+
</div>
|
|
1426
|
+
</div>
|
|
1427
|
+
|
|
1428
|
+
<!-- Pagination -->
|
|
1429
|
+
<div class="flex items-center justify-between border-t border-slate-200 bg-white px-4 py-3 sm:px-6 mt-4">
|
|
1430
|
+
<!-- Simplified Pagination for brevity, can be expanded -->
|
|
1431
|
+
<div class="flex flex-1 justify-between sm:hidden">
|
|
1432
|
+
<ad-button variant="secondary" [disabled]="pageIndex() === 1" (click)="onPageChange(pageIndex() - 1)">Anterior</ad-button>
|
|
1433
|
+
<ad-button variant="secondary" [disabled]="pageIndex() * pageSize() >= total()" (click)="onPageChange(pageIndex() + 1)">Siguiente</ad-button>
|
|
1434
|
+
</div>
|
|
1435
|
+
<div class="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
|
|
1436
|
+
<div>
|
|
1437
|
+
<p class="text-sm text-slate-700">
|
|
1438
|
+
Mostrando <span class="font-medium">{{ (pageIndex() - 1) * pageSize() + 1 }}</span> a <span class="font-medium">{{ Math.min(pageIndex() * pageSize(), total()) }}</span> de <span class="font-medium">{{ total() }}</span> resultados
|
|
1439
|
+
</p>
|
|
1440
|
+
</div>
|
|
1441
|
+
<div>
|
|
1442
|
+
<nav class="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
|
1443
|
+
<ad-button variant="secondary" class="rounded-l-md" [disabled]="pageIndex() === 1" (click)="onPageChange(pageIndex() - 1)">Ant</ad-button>
|
|
1444
|
+
<ad-button variant="secondary" class="rounded-r-md" [disabled]="pageIndex() * pageSize() >= total()" (click)="onPageChange(pageIndex() + 1)">Sig</ad-button>
|
|
1445
|
+
</nav>
|
|
1446
|
+
</div>
|
|
1447
|
+
</div>
|
|
1448
|
+
</div>
|
|
1449
|
+
</div>
|
|
1450
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AdButtonComponent, selector: "ad-button", inputs: ["variant", "type", "disabled", "loading", "icon", "size", "block"] }, { kind: "component", type: AdIconComponent, selector: "ad-icon", inputs: ["name", "size", "color"] }] });
|
|
1451
|
+
}
|
|
1452
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: TableEngineComponent, decorators: [{
|
|
1453
|
+
type: Component,
|
|
1454
|
+
args: [{
|
|
1455
|
+
selector: 'ad-table-engine',
|
|
1456
|
+
standalone: true,
|
|
1457
|
+
imports: [CommonModule, AdButtonComponent, AdIconComponent],
|
|
1458
|
+
template: `
|
|
1459
|
+
<div class="flow-root">
|
|
1460
|
+
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
|
1461
|
+
<div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
|
|
1462
|
+
<div class="relative">
|
|
1463
|
+
@if (loading()) {
|
|
1464
|
+
<div class="absolute inset-0 bg-white/50 z-10 flex items-center justify-center">
|
|
1465
|
+
<svg class="animate-spin h-8 w-8 text-sky-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
1466
|
+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
1467
|
+
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
1468
|
+
</svg>
|
|
1469
|
+
</div>
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
<table class="min-w-full divide-y divide-slate-300">
|
|
1473
|
+
<thead>
|
|
1474
|
+
<tr>
|
|
1475
|
+
<!-- Checkbox Column if selectable (Future) -->
|
|
1476
|
+
|
|
1477
|
+
@for (column of displayColumns(); track column.key) {
|
|
1478
|
+
<th scope="col"
|
|
1479
|
+
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-slate-900 sm:pl-0"
|
|
1480
|
+
[style.width]="column.width || 'auto'">
|
|
1481
|
+
{{ column.label }}
|
|
1482
|
+
</th>
|
|
1483
|
+
}
|
|
1484
|
+
@if (hasActions()) {
|
|
1485
|
+
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-0">
|
|
1486
|
+
<span class="sr-only">Acciones</span>
|
|
1487
|
+
</th>
|
|
1488
|
+
}
|
|
1489
|
+
</tr>
|
|
1490
|
+
</thead>
|
|
1491
|
+
<tbody class="divide-y divide-slate-200 bg-white">
|
|
1492
|
+
@for (item of data(); track item) {
|
|
1493
|
+
<tr>
|
|
1494
|
+
@for (column of displayColumns(); track column.key) {
|
|
1495
|
+
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm text-slate-500 sm:pl-0">
|
|
1496
|
+
<!-- Simple rendering for now. Registry support can be added here -->
|
|
1497
|
+
{{ item[column.key] }}
|
|
1498
|
+
</td>
|
|
1499
|
+
}
|
|
1500
|
+
@if (hasActions()) {
|
|
1501
|
+
<td class="whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
|
|
1502
|
+
<div class="flex justify-end gap-2">
|
|
1503
|
+
@for (act of getActions(); track act.action) {
|
|
1504
|
+
<ad-button
|
|
1505
|
+
[variant]="mapVariant(act.color)"
|
|
1506
|
+
size="small"
|
|
1507
|
+
(click)="onActionClick(act.action, item)">
|
|
1508
|
+
@if (act.icon) {
|
|
1509
|
+
<ad-icon [name]="act.icon" class="mr-1"></ad-icon>
|
|
1510
|
+
}
|
|
1511
|
+
{{ act.label }}
|
|
1512
|
+
</ad-button>
|
|
1513
|
+
}
|
|
1514
|
+
</div>
|
|
1515
|
+
</td>
|
|
1516
|
+
}
|
|
1517
|
+
</tr>
|
|
1518
|
+
}
|
|
1519
|
+
@if (data().length === 0 && !loading()) {
|
|
1520
|
+
<tr>
|
|
1521
|
+
<td [attr.colspan]="displayColumns().length + (hasActions() ? 1 : 0)" class="py-8 text-center text-sm text-slate-500">
|
|
1522
|
+
No hay datos disponibles
|
|
1523
|
+
</td>
|
|
1524
|
+
</tr>
|
|
1525
|
+
}
|
|
1526
|
+
</tbody>
|
|
1527
|
+
</table>
|
|
1528
|
+
</div>
|
|
1529
|
+
</div>
|
|
1530
|
+
</div>
|
|
1531
|
+
|
|
1532
|
+
<!-- Pagination -->
|
|
1533
|
+
<div class="flex items-center justify-between border-t border-slate-200 bg-white px-4 py-3 sm:px-6 mt-4">
|
|
1534
|
+
<!-- Simplified Pagination for brevity, can be expanded -->
|
|
1535
|
+
<div class="flex flex-1 justify-between sm:hidden">
|
|
1536
|
+
<ad-button variant="secondary" [disabled]="pageIndex() === 1" (click)="onPageChange(pageIndex() - 1)">Anterior</ad-button>
|
|
1537
|
+
<ad-button variant="secondary" [disabled]="pageIndex() * pageSize() >= total()" (click)="onPageChange(pageIndex() + 1)">Siguiente</ad-button>
|
|
1538
|
+
</div>
|
|
1539
|
+
<div class="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
|
|
1540
|
+
<div>
|
|
1541
|
+
<p class="text-sm text-slate-700">
|
|
1542
|
+
Mostrando <span class="font-medium">{{ (pageIndex() - 1) * pageSize() + 1 }}</span> a <span class="font-medium">{{ Math.min(pageIndex() * pageSize(), total()) }}</span> de <span class="font-medium">{{ total() }}</span> resultados
|
|
1543
|
+
</p>
|
|
1544
|
+
</div>
|
|
1545
|
+
<div>
|
|
1546
|
+
<nav class="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
|
1547
|
+
<ad-button variant="secondary" class="rounded-l-md" [disabled]="pageIndex() === 1" (click)="onPageChange(pageIndex() - 1)">Ant</ad-button>
|
|
1548
|
+
<ad-button variant="secondary" class="rounded-r-md" [disabled]="pageIndex() * pageSize() >= total()" (click)="onPageChange(pageIndex() + 1)">Sig</ad-button>
|
|
1549
|
+
</nav>
|
|
1550
|
+
</div>
|
|
1551
|
+
</div>
|
|
1552
|
+
</div>
|
|
1553
|
+
</div>
|
|
1554
|
+
`
|
|
1555
|
+
}]
|
|
1556
|
+
}], propDecorators: { schema: [{ type: i0.Input, args: [{ isSignal: true, alias: "schema", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], total: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], pageIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageIndex", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], queryParamsChange: [{ type: i0.Output, args: ["queryParamsChange"] }], action: [{ type: i0.Output, args: ["action"] }] } });
|
|
1557
|
+
|
|
1558
|
+
class AdBadgeComponent {
|
|
1559
|
+
variant = 'neutral';
|
|
1560
|
+
type = 'subtle';
|
|
1561
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1562
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.4", type: AdBadgeComponent, isStandalone: true, selector: "ad-badge", inputs: { variant: "variant", type: "type" }, ngImport: i0, template: "<span class=\"ad-badge\" [ngClass]=\"[variant, type]\">\r\n <ng-content></ng-content>\r\n</span>", styles: [".ad-badge{display:inline-flex;align-items:center;justify-content:center;padding:var(--badge-padding-v) var(--badge-padding-h);border-radius:var(--badge-radius);font-size:var(--badge-font-size);font-weight:var(--badge-font-weight);line-height:1;white-space:nowrap;border:1px solid transparent}.ad-badge.success.filled{background-color:var(--color-success-500);color:#fff}.ad-badge.success.subtle{background-color:var(--badge-success-bg);color:var(--badge-success-text);border-color:var(--badge-success-border)}.ad-badge.success.outline{background-color:transparent;color:var(--badge-success-text);border-color:var(--badge-success-border)}.ad-badge.warning.filled{background-color:var(--color-warning-500);color:#fff}.ad-badge.warning.subtle{background-color:var(--badge-warning-bg);color:var(--badge-warning-text);border-color:var(--badge-warning-border)}.ad-badge.warning.outline{background-color:transparent;color:var(--badge-warning-text);border-color:var(--badge-warning-border)}.ad-badge.error.filled{background-color:var(--color-error-500);color:#fff}.ad-badge.error.subtle{background-color:var(--badge-error-bg);color:var(--badge-error-text);border-color:var(--badge-error-border)}.ad-badge.error.outline{background-color:transparent;color:var(--badge-error-text);border-color:var(--badge-error-border)}.ad-badge.info.filled{background-color:var(--color-info-500);color:#fff}.ad-badge.info.subtle{background-color:var(--badge-info-bg);color:var(--badge-info-text);border-color:var(--badge-info-border)}.ad-badge.info.outline{background-color:transparent;color:var(--badge-info-text);border-color:var(--badge-info-border)}.ad-badge.neutral.filled{background-color:var(--color-text-primary);color:var(--color-bg-primary)}.ad-badge.neutral.subtle{background-color:var(--badge-neutral-bg);color:var(--badge-neutral-text);border-color:var(--badge-neutral-border)}.ad-badge.neutral.outline{background-color:transparent;color:var(--badge-neutral-text);border-color:var(--badge-neutral-border)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
|
|
1563
|
+
}
|
|
1564
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdBadgeComponent, decorators: [{
|
|
1565
|
+
type: Component,
|
|
1566
|
+
args: [{ selector: 'ad-badge', standalone: true, imports: [CommonModule], template: "<span class=\"ad-badge\" [ngClass]=\"[variant, type]\">\r\n <ng-content></ng-content>\r\n</span>", styles: [".ad-badge{display:inline-flex;align-items:center;justify-content:center;padding:var(--badge-padding-v) var(--badge-padding-h);border-radius:var(--badge-radius);font-size:var(--badge-font-size);font-weight:var(--badge-font-weight);line-height:1;white-space:nowrap;border:1px solid transparent}.ad-badge.success.filled{background-color:var(--color-success-500);color:#fff}.ad-badge.success.subtle{background-color:var(--badge-success-bg);color:var(--badge-success-text);border-color:var(--badge-success-border)}.ad-badge.success.outline{background-color:transparent;color:var(--badge-success-text);border-color:var(--badge-success-border)}.ad-badge.warning.filled{background-color:var(--color-warning-500);color:#fff}.ad-badge.warning.subtle{background-color:var(--badge-warning-bg);color:var(--badge-warning-text);border-color:var(--badge-warning-border)}.ad-badge.warning.outline{background-color:transparent;color:var(--badge-warning-text);border-color:var(--badge-warning-border)}.ad-badge.error.filled{background-color:var(--color-error-500);color:#fff}.ad-badge.error.subtle{background-color:var(--badge-error-bg);color:var(--badge-error-text);border-color:var(--badge-error-border)}.ad-badge.error.outline{background-color:transparent;color:var(--badge-error-text);border-color:var(--badge-error-border)}.ad-badge.info.filled{background-color:var(--color-info-500);color:#fff}.ad-badge.info.subtle{background-color:var(--badge-info-bg);color:var(--badge-info-text);border-color:var(--badge-info-border)}.ad-badge.info.outline{background-color:transparent;color:var(--badge-info-text);border-color:var(--badge-info-border)}.ad-badge.neutral.filled{background-color:var(--color-text-primary);color:var(--color-bg-primary)}.ad-badge.neutral.subtle{background-color:var(--badge-neutral-bg);color:var(--badge-neutral-text);border-color:var(--badge-neutral-border)}.ad-badge.neutral.outline{background-color:transparent;color:var(--badge-neutral-text);border-color:var(--badge-neutral-border)}\n"] }]
|
|
1567
|
+
}], propDecorators: { variant: [{
|
|
281
1568
|
type: Input
|
|
282
|
-
}],
|
|
1569
|
+
}], type: [{
|
|
283
1570
|
type: Input
|
|
284
|
-
}]
|
|
1571
|
+
}] } });
|
|
1572
|
+
|
|
1573
|
+
class AdLabelComponent {
|
|
1574
|
+
text = '';
|
|
1575
|
+
for = '';
|
|
1576
|
+
required = false;
|
|
1577
|
+
error = false;
|
|
1578
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdLabelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1579
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.4", type: AdLabelComponent, isStandalone: true, selector: "ad-label", inputs: { text: "text", for: "for", required: "required", error: "error" }, ngImport: i0, template: "<label [attr.for]=\"for\" class=\"ad-label\" [class.has-error]=\"error\">\r\n {{ text }}\r\n <span *ngIf=\"required\" class=\"required-indicator\" aria-hidden=\"true\">*</span>\r\n</label>", styles: [".ad-label{display:block;font-size:var(--label-font-size);font-weight:var(--label-font-weight);color:var(--label-color);margin-bottom:var(--label-margin-bottom);-webkit-user-select:none;user-select:none}.ad-label .required-indicator{color:var(--label-required-color);margin-left:var(--space-0-5)}.ad-label.has-error{color:var(--color-error-600)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
1580
|
+
}
|
|
1581
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdLabelComponent, decorators: [{
|
|
1582
|
+
type: Component,
|
|
1583
|
+
args: [{ selector: 'ad-label', standalone: true, imports: [CommonModule], template: "<label [attr.for]=\"for\" class=\"ad-label\" [class.has-error]=\"error\">\r\n {{ text }}\r\n <span *ngIf=\"required\" class=\"required-indicator\" aria-hidden=\"true\">*</span>\r\n</label>", styles: [".ad-label{display:block;font-size:var(--label-font-size);font-weight:var(--label-font-weight);color:var(--label-color);margin-bottom:var(--label-margin-bottom);-webkit-user-select:none;user-select:none}.ad-label .required-indicator{color:var(--label-required-color);margin-left:var(--space-0-5)}.ad-label.has-error{color:var(--color-error-600)}\n"] }]
|
|
1584
|
+
}], propDecorators: { text: [{
|
|
1585
|
+
type: Input
|
|
1586
|
+
}], for: [{
|
|
285
1587
|
type: Input
|
|
286
1588
|
}], required: [{
|
|
287
1589
|
type: Input
|
|
288
1590
|
}], error: [{
|
|
289
1591
|
type: Input
|
|
290
|
-
}], for: [{
|
|
291
|
-
type: Input
|
|
292
1592
|
}] } });
|
|
293
1593
|
|
|
294
|
-
class
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
1594
|
+
class AdminSectionCardComponent {
|
|
1595
|
+
// Input Resource
|
|
1596
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
1597
|
+
title = computed(() => this.resource().title, ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
1598
|
+
accentedTitle = computed(() => this.resource().accentedTitle, ...(ngDevMode ? [{ debugName: "accentedTitle" }] : []));
|
|
1599
|
+
cardAction = computed(() => this.resource().action, ...(ngDevMode ? [{ debugName: "cardAction" }] : []));
|
|
1600
|
+
loading = computed(() => this.resource().loading ?? false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
1601
|
+
// Outputs
|
|
1602
|
+
action = output();
|
|
1603
|
+
onAction() {
|
|
1604
|
+
if (!this.loading()) {
|
|
1605
|
+
this.action.emit();
|
|
1606
|
+
// Also call the callback if it exists
|
|
1607
|
+
this.cardAction()?.['onClick']?.();
|
|
1608
|
+
}
|
|
304
1609
|
}
|
|
1610
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdminSectionCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1611
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdminSectionCardComponent, isStandalone: true, selector: "ad-admin-section-card", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { action: "action" }, ngImport: i0, template: "<div\r\n class=\"bg-white dark:bg-cerca-primary-active rounded-xl shadow-sm border border-slate-200 dark:border-cerca-primary hover:shadow-md transition-shadow duration-300 overflow-hidden\">\r\n <!-- Header -->\r\n <div\r\n class=\"px-6 py-4 border-b border-slate-100 dark:border-cerca-primary flex justify-between items-center bg-slate-50/50 dark:bg-cerca-primary/50\">\r\n <!-- Title Section -->\r\n <div class=\"flex items-center gap-2\">\r\n <h2 class=\"text-lg font-medium text-cerca-secondary dark:text-slate-300\">\r\n {{ title() }} <span class=\"accent-text font-bold\">{{ accentedTitle() }}</span>\r\n </h2>\r\n </div>\r\n\r\n <!-- Actions -->\r\n @if (cardAction()?.label) {\r\n <ad-button (click)=\"onAction()\" [disabled]=\"loading()\" [loading]=\"loading()\" [icon]=\"cardAction()?.icon\">\r\n {{ cardAction()?.label }}\r\n </ad-button>\r\n }\r\n </div>\r\n\r\n <!-- Content Slot -->\r\n <div class=\"p-6 bg-slate-50 dark:bg-cerca-primary/20 text-cerca-secondary dark:text-slate-300\">\r\n <ng-content></ng-content>\r\n </div>\r\n</div>", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AdButtonComponent, selector: "ad-button", inputs: ["variant", "type", "disabled", "loading", "icon", "size", "block"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1612
|
+
}
|
|
1613
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdminSectionCardComponent, decorators: [{
|
|
1614
|
+
type: Component,
|
|
1615
|
+
args: [{ selector: 'ad-admin-section-card', standalone: true, imports: [CommonModule, AdButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"bg-white dark:bg-cerca-primary-active rounded-xl shadow-sm border border-slate-200 dark:border-cerca-primary hover:shadow-md transition-shadow duration-300 overflow-hidden\">\r\n <!-- Header -->\r\n <div\r\n class=\"px-6 py-4 border-b border-slate-100 dark:border-cerca-primary flex justify-between items-center bg-slate-50/50 dark:bg-cerca-primary/50\">\r\n <!-- Title Section -->\r\n <div class=\"flex items-center gap-2\">\r\n <h2 class=\"text-lg font-medium text-cerca-secondary dark:text-slate-300\">\r\n {{ title() }} <span class=\"accent-text font-bold\">{{ accentedTitle() }}</span>\r\n </h2>\r\n </div>\r\n\r\n <!-- Actions -->\r\n @if (cardAction()?.label) {\r\n <ad-button (click)=\"onAction()\" [disabled]=\"loading()\" [loading]=\"loading()\" [icon]=\"cardAction()?.icon\">\r\n {{ cardAction()?.label }}\r\n </ad-button>\r\n }\r\n </div>\r\n\r\n <!-- Content Slot -->\r\n <div class=\"p-6 bg-slate-50 dark:bg-cerca-primary/20 text-cerca-secondary dark:text-slate-300\">\r\n <ng-content></ng-content>\r\n </div>\r\n</div>" }]
|
|
1616
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], action: [{ type: i0.Output, args: ["action"] }] } });
|
|
1617
|
+
|
|
1618
|
+
const AdminSectionCardActionSchema = z.object({
|
|
1619
|
+
label: z.string(),
|
|
1620
|
+
icon: z.string().optional(),
|
|
1621
|
+
onClick: z.custom().optional(),
|
|
1622
|
+
});
|
|
1623
|
+
const AdminSectionCardResourceSchema = z.object({
|
|
1624
|
+
title: z.string(),
|
|
1625
|
+
accentedTitle: z.string(),
|
|
1626
|
+
action: AdminSectionCardActionSchema.optional(),
|
|
1627
|
+
loading: z.boolean().default(false).optional(),
|
|
1628
|
+
});
|
|
1629
|
+
|
|
1630
|
+
class AdCardComponent {
|
|
1631
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
1632
|
+
title = computed(() => this.resource().title, ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
1633
|
+
accentedTitle = computed(() => this.resource().accentedTitle, ...(ngDevMode ? [{ debugName: "accentedTitle" }] : []));
|
|
1634
|
+
actionLabel = computed(() => this.resource().actionLabel, ...(ngDevMode ? [{ debugName: "actionLabel" }] : []));
|
|
1635
|
+
actionIcon = computed(() => this.resource().actionIcon || 'plus', ...(ngDevMode ? [{ debugName: "actionIcon" }] : []));
|
|
1636
|
+
loading = computed(() => this.resource().loading || false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
1637
|
+
bordered = computed(() => this.resource().bordered ?? true, ...(ngDevMode ? [{ debugName: "bordered" }] : []));
|
|
1638
|
+
// Convert padding to string if it's a number (e.g., 24 -> '24px')
|
|
1639
|
+
paddingStyle = computed(() => {
|
|
1640
|
+
const p = this.resource().padding;
|
|
1641
|
+
if (typeof p === 'number')
|
|
1642
|
+
return `${p}px`;
|
|
1643
|
+
return p || '24px';
|
|
1644
|
+
}, ...(ngDevMode ? [{ debugName: "paddingStyle" }] : []));
|
|
1645
|
+
action = output();
|
|
1646
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1647
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdCardComponent, isStandalone: true, selector: "ad-card", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { action: "action" }, ngImport: i0, template: "<div class=\"bg-white overflow-hidden rounded-lg transition-all duration-200\" [class.shadow-md]=\"bordered()\"\r\n [class.border]=\"bordered()\" [class.border-slate-200]=\"bordered()\" [class.shadow-none]=\"!bordered()\">\r\n\r\n @if (title() || actionLabel()) {\r\n <div class=\"px-4 py-3 sm:px-6 relative flex justify-between items-center min-h-[48px]\">\r\n <!-- Title -->\r\n <h3 class=\"text-lg font-bold text-slate-900 flex items-center\">\r\n {{ title() }}\r\n @if (accentedTitle()) {\r\n <span class=\"accent-text\">\r\n {{ accentedTitle() }}\r\n </span>\r\n }\r\n </h3>\r\n\r\n <!-- Action -->\r\n @if (actionLabel()) {\r\n <ad-button variant=\"primary\" [icon]=\"actionIcon()\" (click)=\"action.emit()\">\r\n {{ actionLabel() }}\r\n </ad-button>\r\n }\r\n\r\n <!-- Gradient bottom border for header -->\r\n <div class=\"absolute bottom-0 left-0 w-full h-[1px] bg-gradient-to-r from-sky-600 to-sky-400\"></div>\r\n </div>\r\n }\r\n\r\n <div class=\"px-4 py-5 sm:p-6\" [class.opacity-50]=\"loading()\">\r\n @if (loading()) {\r\n <div class=\"flex justify-center py-10\">\r\n <ad-loading size=\"lg\"></ad-loading>\r\n </div>\r\n } @else {\r\n <ng-content></ng-content>\r\n }\r\n </div>\r\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AdButtonComponent, selector: "ad-button", inputs: ["variant", "type", "disabled", "loading", "icon", "size", "block"] }, { kind: "component", type: AdLoadingComponent, selector: "ad-loading", inputs: ["size", "color"] }] });
|
|
1648
|
+
}
|
|
1649
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdCardComponent, decorators: [{
|
|
1650
|
+
type: Component,
|
|
1651
|
+
args: [{ selector: 'ad-card', standalone: true, imports: [CommonModule, AdButtonComponent, AdLoadingComponent], template: "<div class=\"bg-white overflow-hidden rounded-lg transition-all duration-200\" [class.shadow-md]=\"bordered()\"\r\n [class.border]=\"bordered()\" [class.border-slate-200]=\"bordered()\" [class.shadow-none]=\"!bordered()\">\r\n\r\n @if (title() || actionLabel()) {\r\n <div class=\"px-4 py-3 sm:px-6 relative flex justify-between items-center min-h-[48px]\">\r\n <!-- Title -->\r\n <h3 class=\"text-lg font-bold text-slate-900 flex items-center\">\r\n {{ title() }}\r\n @if (accentedTitle()) {\r\n <span class=\"accent-text\">\r\n {{ accentedTitle() }}\r\n </span>\r\n }\r\n </h3>\r\n\r\n <!-- Action -->\r\n @if (actionLabel()) {\r\n <ad-button variant=\"primary\" [icon]=\"actionIcon()\" (click)=\"action.emit()\">\r\n {{ actionLabel() }}\r\n </ad-button>\r\n }\r\n\r\n <!-- Gradient bottom border for header -->\r\n <div class=\"absolute bottom-0 left-0 w-full h-[1px] bg-gradient-to-r from-sky-600 to-sky-400\"></div>\r\n </div>\r\n }\r\n\r\n <div class=\"px-4 py-5 sm:p-6\" [class.opacity-50]=\"loading()\">\r\n @if (loading()) {\r\n <div class=\"flex justify-center py-10\">\r\n <ad-loading size=\"lg\"></ad-loading>\r\n </div>\r\n } @else {\r\n <ng-content></ng-content>\r\n }\r\n </div>\r\n</div>" }]
|
|
1652
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], action: [{ type: i0.Output, args: ["action"] }] } });
|
|
1653
|
+
|
|
1654
|
+
const CardResourceSchema = z.object({
|
|
1655
|
+
title: z.string(),
|
|
1656
|
+
accentedTitle: z.string().optional(),
|
|
1657
|
+
actionLabel: z.string().optional(),
|
|
1658
|
+
actionIcon: z.string().default('plus').optional(),
|
|
1659
|
+
loading: z.boolean().default(false).optional(),
|
|
1660
|
+
bordered: z.boolean().default(true).optional(),
|
|
1661
|
+
padding: z.union([z.string(), z.number()]).default('24px').optional(),
|
|
1662
|
+
});
|
|
1663
|
+
|
|
1664
|
+
class AdModalTriggerComponent {
|
|
1665
|
+
// Inputs (Signals) based on US-DEV-007
|
|
1666
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
1667
|
+
screenResource = computed(() => this.resource().resource, ...(ngDevMode ? [{ debugName: "screenResource" }] : []));
|
|
1668
|
+
data = computed(() => this.resource().data, ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
1669
|
+
triggerLabel = computed(() => this.resource().triggerLabel, ...(ngDevMode ? [{ debugName: "triggerLabel" }] : []));
|
|
1670
|
+
triggerIcon = computed(() => this.resource().triggerIcon, ...(ngDevMode ? [{ debugName: "triggerIcon" }] : []));
|
|
1671
|
+
loading = computed(() => this.resource().loading || false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
1672
|
+
variant = computed(() => this.resource().variant || 'primary', ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
1673
|
+
disabled = computed(() => this.resource().disabled || false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
1674
|
+
// Outputs
|
|
1675
|
+
confirm = output();
|
|
1676
|
+
cancel = output();
|
|
1677
|
+
modalService = inject(AdModalService);
|
|
1678
|
+
openModal() {
|
|
1679
|
+
this.modalService.open(this.screenResource(), this.data()).subscribe(result => {
|
|
1680
|
+
if (result) {
|
|
1681
|
+
this.confirm.emit(result);
|
|
1682
|
+
}
|
|
1683
|
+
else {
|
|
1684
|
+
this.cancel.emit();
|
|
1685
|
+
}
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1688
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdModalTriggerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1689
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.4", type: AdModalTriggerComponent, isStandalone: true, selector: "ad-modal-trigger", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { confirm: "confirm", cancel: "cancel" }, ngImport: i0, template: "<!-- Bot\u00F3n Disparador -->\r\n<ad-button (click)=\"openModal()\" [variant]=\"variant()\" [disabled]=\"disabled()\" [loading]=\"loading()\"\r\n [icon]=\"triggerIcon()\" [size]=\"'default'\">\r\n {{ triggerLabel() }}\r\n</ad-button>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AdButtonComponent, selector: "ad-button", inputs: ["variant", "type", "disabled", "loading", "icon", "size", "block"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1690
|
+
}
|
|
1691
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdModalTriggerComponent, decorators: [{
|
|
1692
|
+
type: Component,
|
|
1693
|
+
args: [{ selector: 'ad-modal-trigger', standalone: true, imports: [CommonModule, AdButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Bot\u00F3n Disparador -->\r\n<ad-button (click)=\"openModal()\" [variant]=\"variant()\" [disabled]=\"disabled()\" [loading]=\"loading()\"\r\n [icon]=\"triggerIcon()\" [size]=\"'default'\">\r\n {{ triggerLabel() }}\r\n</ad-button>" }]
|
|
1694
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], confirm: [{ type: i0.Output, args: ["confirm"] }], cancel: [{ type: i0.Output, args: ["cancel"] }] } });
|
|
1695
|
+
|
|
1696
|
+
/**
|
|
1697
|
+
* Componente Molecular Description Header
|
|
1698
|
+
*
|
|
1699
|
+
* Molécula que compone múltiples átomos (títulos, botones, iconos) para
|
|
1700
|
+
* crear un header descriptivo reutilizable con títulos acentuados,
|
|
1701
|
+
* subtítulos y botones de acción dinámicos.
|
|
1702
|
+
*
|
|
1703
|
+
* @example
|
|
1704
|
+
* ```html
|
|
1705
|
+
* <ad-description-header [resource]="headerResource"></ad-description-header>
|
|
1706
|
+
* ```
|
|
1707
|
+
*/
|
|
1708
|
+
class AdDescriptionHeaderComponent {
|
|
1709
|
+
/** Recurso de configuración del header */
|
|
1710
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
1711
|
+
title = computed(() => this.resource().title, ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
1712
|
+
accentedTitle = computed(() => this.resource().accentedTitle, ...(ngDevMode ? [{ debugName: "accentedTitle" }] : []));
|
|
1713
|
+
subtitle = computed(() => this.resource().subtitle, ...(ngDevMode ? [{ debugName: "subtitle" }] : []));
|
|
1714
|
+
buttons = computed(() => this.resource().buttons, ...(ngDevMode ? [{ debugName: "buttons" }] : []));
|
|
1715
|
+
showDivider = computed(() => this.resource().showDivider, ...(ngDevMode ? [{ debugName: "showDivider" }] : []));
|
|
1716
|
+
getModalTriggerResource(button) {
|
|
1717
|
+
return {
|
|
1718
|
+
resource: button.modalResource,
|
|
1719
|
+
data: button.modalData,
|
|
1720
|
+
triggerLabel: button.label,
|
|
1721
|
+
triggerIcon: button.icon,
|
|
1722
|
+
variant: button.variant,
|
|
1723
|
+
disabled: button.disabled
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
/**
|
|
1727
|
+
* Maneja el clic en un botón
|
|
1728
|
+
* @param onClick Callback del botón
|
|
1729
|
+
*/
|
|
1730
|
+
handleButtonClick(onClick) {
|
|
1731
|
+
if (onClick) {
|
|
1732
|
+
onClick();
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
/**
|
|
1736
|
+
* Maneja la confirmación de un modal
|
|
1737
|
+
* @param onConfirm Callback de confirmación
|
|
1738
|
+
* @param result Resultado del modal
|
|
1739
|
+
*/
|
|
1740
|
+
handleModalConfirm(onConfirm, result) {
|
|
1741
|
+
if (onConfirm) {
|
|
1742
|
+
onConfirm(result);
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
/**
|
|
1746
|
+
* Maneja la cancelación de un modal
|
|
1747
|
+
* @param onCancel Callback de cancelación
|
|
1748
|
+
*/
|
|
1749
|
+
handleModalCancel(onCancel) {
|
|
1750
|
+
if (onCancel) {
|
|
1751
|
+
onCancel();
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdDescriptionHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1755
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdDescriptionHeaderComponent, isStandalone: true, selector: "ad-description-header", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"premium-header-card\">\r\n <div class=\"header-main\">\r\n <div class=\"title-group\">\r\n <h1 class=\"premium-title\">\r\n {{ title() }}\r\n @if (accentedTitle()) {\r\n <span class=\"accent-text\">\r\n {{ accentedTitle() }}\r\n </span>\r\n }\r\n </h1>\r\n @if (subtitle()) {\r\n <p class=\"premium-subtitle\">\r\n {{ subtitle() }}\r\n </p>\r\n }\r\n </div>\r\n @if (buttons() && buttons()!.length > 0) {\r\n <div class=\"header-actions\">\r\n @for (button of buttons(); track $index) {\r\n @if (button.isModalTrigger && button.modalResource) {\r\n <ad-modal-trigger [resource]=\"getModalTriggerResource(button)\"\r\n (confirm)=\"handleModalConfirm(button.onModalConfirm, $event)\"\r\n (cancel)=\"handleModalCancel(button.onModalCancel)\">\r\n </ad-modal-trigger>\r\n } @else {\r\n <ad-button [variant]=\"button.variant || 'primary'\" [type]=\"button.type || 'button'\"\r\n [disabled]=\"button.disabled || false\" (click)=\"handleButtonClick(button.onClick)\" [icon]=\"button.icon\">\r\n {{ button.label }}\r\n </ad-button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<!-- Divider is no longer needed with the card style -->\r\n@if (showDivider() && false) {\r\n<div class=\"ad-description-header__divider\"></div>\r\n}", styles: [":root{--color-primary: #002855;--color-primary-hover: #003366;--color-primary-active: #001a38;--color-primary-light: #F1F5F9;--color-primary-accent: #5BC2E7;--color-background: #F8FAFC;--color-surface: #FFFFFF;--color-border: #F1F5F9;--color-secondary: #475569;--color-secondary-light: #94A3B8;--color-success: #A2D033;--color-success-bg: rgba(162, 208, 51, .05);--color-success-text: #7A9F26;--color-alert: #EF4444;--color-alert-bg: rgba(239, 68, 68, .05);--color-alert-text: #DC2626;--color-warning: #F59E0B;--color-warning-bg: rgba(245, 158, 11, .05);--color-warning-text: #D97706;--color-slate-900: #0f172a;--color-slate-800: #1e293b;--color-slate-700: #334155;--color-slate-500: #64748b;--color-slate-400: #94a3b8;--color-slate-200: #e2e8f0;--color-slate-100: #f1f5f9;--color-slate-50: #f8fafc;--color-white: #ffffff;--radius-cerca: 1.25rem;--radius-cerca-sm: .75rem;--radius-cerca-lg: 2rem;--shadow-premium: 0 20px 25px -5px rgba(0, 0, 0, .02), 0 8px 10px -6px rgba(0, 0, 0, .02);--shadow-premium-hover: 0 30px 40px -5px rgba(0, 0, 0, .05), 0 15px 20px -5px rgba(0, 0, 0, .03);--shadow-glass: 0 8px 32px 0 rgba(31, 38, 135, .07);--shadow-sidebar: 4px 0 24px 0 rgba(0, 0, 0, .05);--shadow-glow-primary: 0 0 20px rgba(91, 194, 231, .15);--gradient-premium: linear-gradient(135deg, #002855 0%, #001a38 100%);--gradient-glass: linear-gradient(135deg, rgba(255, 255, 255, .1), rgba(255, 255, 255, .05));--gradient-accent: linear-gradient(135deg, #5BC2E7 0%, #002855 100%);--ant-primary-color: var(--color-primary);--ant-primary-color-hover: var(--color-primary-hover);--ant-primary-color-active: var(--color-primary-active);--ant-primary-color-outline: rgba(0, 40, 85, .2);--ant-success-color: var(--color-success);--ant-success-color-hover: #b3e040;--ant-success-color-active: #8fb82b;--ant-success-color-outline: rgba(162, 208, 51, .2);--ant-info-color: var(--color-primary);--ant-link-color: var(--color-primary-accent);--ant-link-color-hover: #4db3d9;--ant-link-color-active: var(--color-primary)}:root{--font-sans: \"Inter\", system-ui, sans-serif;--font-display: \"Outfit\", sans-serif}:root,[data-theme=light]{--color-bg-primary: var(--color-surface);--color-bg-secondary: var(--color-background);--color-text-primary: var(--color-slate-900);--color-text-secondary: var(--color-secondary);--color-text-muted: var(--color-secondary-light);--color-border-subtle: var(--color-slate-200);--color-border-strong: var(--color-slate-300);--color-brand: var(--color-primary);--color-brand-hover: var(--color-primary-hover);--color-focus-ring: var(--ant-primary-color-outline);--color-success: var(--color-success);--color-danger: var(--color-alert);--surface-glass-bg: rgba(255, 255, 255, .7);--surface-glass-border: rgba(255, 255, 255, .3);--surface-glass-blur: 12px;--surface-glass-shadow: var(--shadow-glass);--font-heading-xl: 32px;--font-heading-lg: 24px;--font-heading-md: 20px;--font-body-lg: 18px;--font-body-md: 16px;--font-caption: 12px;--font-family-base: var(--font-sans);--font-weight-regular: 400;--font-weight-medium: 500;--font-weight-semibold: 600;--font-weight-bold: 700;--radius-sm: var(--radius-cerca-sm);--radius-md: var(--radius-cerca);--radius-lg: var(--radius-cerca-lg);--radius-xl: 3rem;--radius-full: 9999px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .1);--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .1)}[data-theme=dark]{--color-bg-primary: var(--color-slate-900);--color-bg-secondary: var(--color-slate-800);--color-text-primary: var(--color-white);--color-text-secondary: var(--color-slate-400);--color-text-muted: var(--color-slate-500);--color-border-subtle: var(--color-slate-700);--color-border-strong: var(--color-slate-600);--color-brand: var(--color-primary-light);--color-brand-hover: var(--color-primary-accent);--color-focus-ring: rgba(59, 130, 246, .5);--surface-glass-bg: rgba(15, 23, 42, .8);--surface-glass-border: rgba(255, 255, 255, .1);--surface-glass-blur: 16px;--surface-glass-shadow: 0 10px 15px -3px rgba(0, 0, 0, .3)}:root{--h1-size: var(--font-size-h1);--h1-weight: var(--font-weight-semibold);--h2-size: var(--font-size-h2);--h2-weight: var(--font-weight-semibold);--h3-size: var(--font-size-h3);--h3-weight: var(--font-weight-semibold);--body-size: var(--font-size-body);--body-weight: var(--font-weight-regular);--sm-size: var(--font-size-sm);--sm-weight: var(--font-weight-regular);--caption-size: var(--font-size-caption);--caption-weight: var(--font-weight-regular)}:root{--btn-height-md: 44px;--btn-radius: var(--radius-md);--btn-font-weight: var(--font-weight-medium);--btn-bg-primary: var(--color-brand);--btn-text-primary: #FFFFFF;--btn-shadow-default: var(--shadow-sm);--btn-shadow-hover: var(--shadow-md);--btn-transition: .15s ease;--btn-focus-ring: 0 0 0 2px var(--color-focus-ring)}:root{--card-bg: var(--color-bg-primary);--card-radius: var(--radius-lg);--card-shadow: var(--shadow-sm);--card-shadow-hover: var(--shadow-md)}:root{--input-height-md: 44px;--input-bg: var(--color-bg-primary);--input-radius: var(--radius-md);--input-border-default: var(--color-border-subtle);--input-border-hover: var(--color-border-strong);--input-border-focus: var(--color-brand);--input-border-error: var(--color-danger);--input-transition: .12s ease-in-out;--input-focus-ring: 0 0 0 3px var(--color-focus-ring);--input-error-ring: 0 0 0 3px rgba(239, 68, 68, .15)}.ad-badge-tokens{--badge-radius: var(--radius-sm);--badge-padding-v: var(--space-1);--badge-padding-h: var(--space-2);--badge-font-size: var(--font-size-xs);--badge-font-weight: var(--font-weight-medium);--badge-success-bg: #D1FAE5;--badge-success-text: #065F46;--badge-success-border: #A7F3D0;--badge-warning-bg: #FEF3C7;--badge-warning-text: #92400E;--badge-warning-border: #FDE68A;--badge-error-bg: #FFE4E6;--badge-error-text: #9F1239;--badge-error-border: #FECDD3;--badge-info-bg: var(--color-info-50);--badge-info-text: var(--color-info-700);--badge-info-border: var(--color-info-200);--badge-neutral-bg: var(--color-slate-100);--badge-neutral-text: var(--color-slate-700);--badge-neutral-border: var(--color-slate-200)}.ad-label-tokens{--label-font-size: var(--font-size-sm);--label-font-weight: var(--font-weight-medium);--label-color: var(--color-text-secondary);--label-required-color: var(--color-error-500);--label-margin-bottom: var(--space-2)}.ad-select-tokens{--select-bg: var(--color-bg-primary);--select-border: var(--color-border-subtle);--select-border-hover: var(--color-border-strong);--select-border-focus: var(--color-brand-primary);--select-shadow-focus: var(--shadow-focus);--select-radius: var(--radius-md);--select-height: 44px;--select-padding-h: var(--space-4);--select-dropdown-bg: var(--color-bg-primary);--select-dropdown-shadow: var(--shadow-md);--select-dropdown-max-height: 240px;--select-option-padding: var(--space-3) var(--space-4);--select-option-hover: var(--color-bg-secondary);--select-option-selected-bg: var(--color-brand-50);--select-option-selected-text: var(--color-brand-primary)}.ad-form-field-tokens{--form-field-margin-bottom: var(--space-6);--form-field-label-margin: var(--space-2);--form-field-message-margin: var(--space-1);--form-field-message-font-size: var(--font-size-xs);--form-field-message-color: var(--color-text-muted);--form-field-error-color: var(--color-error-600)}.ad-header-tokens{--header-height: 72px;--header-bg: var(--color-surface);--header-border-color: var(--color-border);--header-padding: 0 var(--space-6);--header-shadow: 0 1px 2px rgba(0, 0, 0, .05);--header-z-index: 100;--header-logo-height: 32px;--header-user-gap: var(--space-4)}.ad-sidebar-tokens{--sidebar-width: 280px;--sidebar-collapsed-width: 80px;--sidebar-bg: var(--color-slate-900);--sidebar-border-color: var(--color-slate-800);--sidebar-padding: var(--space-4);--sidebar-z-index: 101;--sidebar-transition: width .3s cubic-bezier(.4, 0, .2, 1);--sidebar-item-height: 48px;--sidebar-item-radius: var(--radius-lg);--sidebar-item-padding: 0 var(--space-4);--sidebar-item-gap: var(--space-3);--sidebar-accent-color: var(--color-primary);--sidebar-text-color: var(--color-surface);--sidebar-text-muted: var(--color-slate-400)}.ad-data-table-tokens{--table-bg: var(--color-bg-primary);--table-header-bg: var(--color-bg-secondary);--table-border-color: var(--color-border-subtle);--table-header-color: var(--color-text-muted);--table-row-hover: rgba(var(--color-brand-primary-rgb), .04);--table-cell-padding: var(--space-4);--table-font-size: var(--font-size-sm);--table-radius: var(--radius-lg)}:root{--modal-bg: var(--color-surface);--modal-overlay-bg: rgba(0, 0, 0, .5);--modal-radius: var(--radius-cerca);--modal-shadow: var(--shadow-premium);--modal-z-index: 1000;--modal-header-padding: 12px 24px;--modal-body-padding: 24px;--modal-footer-padding: 16px 24px;--modal-sm-width: 400px;--modal-md-width: 600px;--modal-lg-width: 900px}.premium-header-card{background:#fff;padding:1.5rem 2rem;border-radius:16px;box-shadow:var(--shadow-premium, 0 4px 20px -2px rgba(0, 0, 0, .1));margin-bottom:2rem;position:relative;overflow:hidden;border:1px solid rgba(0,0,0,.03)}.premium-header-card:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:4px;background:linear-gradient(to right,var(--color-primary),var(--color-primary-accent, #00d2ff))}.header-main{display:flex;justify-content:space-between;align-items:center;gap:1.5rem;flex-wrap:wrap}@media(max-width:768px){.header-main{flex-direction:column;align-items:stretch}}.title-group{display:flex;flex-direction:column;gap:.25rem}.premium-title{font-size:1.5rem;font-weight:800;letter-spacing:-.04em;margin:0;color:var(--color-slate-900, #1e293b);line-height:1.2}.premium-title .accent-text{background:linear-gradient(135deg,var(--color-primary) 0%,var(--color-primary-accent, #00d2ff) 100%);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;margin-left:.3rem}.premium-subtitle{margin-top:0rem;color:var(--color-slate-500, #64748b);font-size:.9rem;font-weight:500;letter-spacing:-.01em}.header-actions{display:flex;gap:var(--spacing-sm);align-items:center}@media(max-width:768px){.header-actions{width:100%;justify-content:flex-start}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AdButtonComponent, selector: "ad-button", inputs: ["variant", "type", "disabled", "loading", "icon", "size", "block"] }, { kind: "component", type: AdModalTriggerComponent, selector: "ad-modal-trigger", inputs: ["resource"], outputs: ["confirm", "cancel"] }] });
|
|
1756
|
+
}
|
|
1757
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdDescriptionHeaderComponent, decorators: [{
|
|
1758
|
+
type: Component,
|
|
1759
|
+
args: [{ selector: 'ad-description-header', standalone: true, imports: [CommonModule, AdButtonComponent, AdModalTriggerComponent], template: "<div class=\"premium-header-card\">\r\n <div class=\"header-main\">\r\n <div class=\"title-group\">\r\n <h1 class=\"premium-title\">\r\n {{ title() }}\r\n @if (accentedTitle()) {\r\n <span class=\"accent-text\">\r\n {{ accentedTitle() }}\r\n </span>\r\n }\r\n </h1>\r\n @if (subtitle()) {\r\n <p class=\"premium-subtitle\">\r\n {{ subtitle() }}\r\n </p>\r\n }\r\n </div>\r\n @if (buttons() && buttons()!.length > 0) {\r\n <div class=\"header-actions\">\r\n @for (button of buttons(); track $index) {\r\n @if (button.isModalTrigger && button.modalResource) {\r\n <ad-modal-trigger [resource]=\"getModalTriggerResource(button)\"\r\n (confirm)=\"handleModalConfirm(button.onModalConfirm, $event)\"\r\n (cancel)=\"handleModalCancel(button.onModalCancel)\">\r\n </ad-modal-trigger>\r\n } @else {\r\n <ad-button [variant]=\"button.variant || 'primary'\" [type]=\"button.type || 'button'\"\r\n [disabled]=\"button.disabled || false\" (click)=\"handleButtonClick(button.onClick)\" [icon]=\"button.icon\">\r\n {{ button.label }}\r\n </ad-button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<!-- Divider is no longer needed with the card style -->\r\n@if (showDivider() && false) {\r\n<div class=\"ad-description-header__divider\"></div>\r\n}", styles: [":root{--color-primary: #002855;--color-primary-hover: #003366;--color-primary-active: #001a38;--color-primary-light: #F1F5F9;--color-primary-accent: #5BC2E7;--color-background: #F8FAFC;--color-surface: #FFFFFF;--color-border: #F1F5F9;--color-secondary: #475569;--color-secondary-light: #94A3B8;--color-success: #A2D033;--color-success-bg: rgba(162, 208, 51, .05);--color-success-text: #7A9F26;--color-alert: #EF4444;--color-alert-bg: rgba(239, 68, 68, .05);--color-alert-text: #DC2626;--color-warning: #F59E0B;--color-warning-bg: rgba(245, 158, 11, .05);--color-warning-text: #D97706;--color-slate-900: #0f172a;--color-slate-800: #1e293b;--color-slate-700: #334155;--color-slate-500: #64748b;--color-slate-400: #94a3b8;--color-slate-200: #e2e8f0;--color-slate-100: #f1f5f9;--color-slate-50: #f8fafc;--color-white: #ffffff;--radius-cerca: 1.25rem;--radius-cerca-sm: .75rem;--radius-cerca-lg: 2rem;--shadow-premium: 0 20px 25px -5px rgba(0, 0, 0, .02), 0 8px 10px -6px rgba(0, 0, 0, .02);--shadow-premium-hover: 0 30px 40px -5px rgba(0, 0, 0, .05), 0 15px 20px -5px rgba(0, 0, 0, .03);--shadow-glass: 0 8px 32px 0 rgba(31, 38, 135, .07);--shadow-sidebar: 4px 0 24px 0 rgba(0, 0, 0, .05);--shadow-glow-primary: 0 0 20px rgba(91, 194, 231, .15);--gradient-premium: linear-gradient(135deg, #002855 0%, #001a38 100%);--gradient-glass: linear-gradient(135deg, rgba(255, 255, 255, .1), rgba(255, 255, 255, .05));--gradient-accent: linear-gradient(135deg, #5BC2E7 0%, #002855 100%);--ant-primary-color: var(--color-primary);--ant-primary-color-hover: var(--color-primary-hover);--ant-primary-color-active: var(--color-primary-active);--ant-primary-color-outline: rgba(0, 40, 85, .2);--ant-success-color: var(--color-success);--ant-success-color-hover: #b3e040;--ant-success-color-active: #8fb82b;--ant-success-color-outline: rgba(162, 208, 51, .2);--ant-info-color: var(--color-primary);--ant-link-color: var(--color-primary-accent);--ant-link-color-hover: #4db3d9;--ant-link-color-active: var(--color-primary)}:root{--font-sans: \"Inter\", system-ui, sans-serif;--font-display: \"Outfit\", sans-serif}:root,[data-theme=light]{--color-bg-primary: var(--color-surface);--color-bg-secondary: var(--color-background);--color-text-primary: var(--color-slate-900);--color-text-secondary: var(--color-secondary);--color-text-muted: var(--color-secondary-light);--color-border-subtle: var(--color-slate-200);--color-border-strong: var(--color-slate-300);--color-brand: var(--color-primary);--color-brand-hover: var(--color-primary-hover);--color-focus-ring: var(--ant-primary-color-outline);--color-success: var(--color-success);--color-danger: var(--color-alert);--surface-glass-bg: rgba(255, 255, 255, .7);--surface-glass-border: rgba(255, 255, 255, .3);--surface-glass-blur: 12px;--surface-glass-shadow: var(--shadow-glass);--font-heading-xl: 32px;--font-heading-lg: 24px;--font-heading-md: 20px;--font-body-lg: 18px;--font-body-md: 16px;--font-caption: 12px;--font-family-base: var(--font-sans);--font-weight-regular: 400;--font-weight-medium: 500;--font-weight-semibold: 600;--font-weight-bold: 700;--radius-sm: var(--radius-cerca-sm);--radius-md: var(--radius-cerca);--radius-lg: var(--radius-cerca-lg);--radius-xl: 3rem;--radius-full: 9999px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .1);--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .1)}[data-theme=dark]{--color-bg-primary: var(--color-slate-900);--color-bg-secondary: var(--color-slate-800);--color-text-primary: var(--color-white);--color-text-secondary: var(--color-slate-400);--color-text-muted: var(--color-slate-500);--color-border-subtle: var(--color-slate-700);--color-border-strong: var(--color-slate-600);--color-brand: var(--color-primary-light);--color-brand-hover: var(--color-primary-accent);--color-focus-ring: rgba(59, 130, 246, .5);--surface-glass-bg: rgba(15, 23, 42, .8);--surface-glass-border: rgba(255, 255, 255, .1);--surface-glass-blur: 16px;--surface-glass-shadow: 0 10px 15px -3px rgba(0, 0, 0, .3)}:root{--h1-size: var(--font-size-h1);--h1-weight: var(--font-weight-semibold);--h2-size: var(--font-size-h2);--h2-weight: var(--font-weight-semibold);--h3-size: var(--font-size-h3);--h3-weight: var(--font-weight-semibold);--body-size: var(--font-size-body);--body-weight: var(--font-weight-regular);--sm-size: var(--font-size-sm);--sm-weight: var(--font-weight-regular);--caption-size: var(--font-size-caption);--caption-weight: var(--font-weight-regular)}:root{--btn-height-md: 44px;--btn-radius: var(--radius-md);--btn-font-weight: var(--font-weight-medium);--btn-bg-primary: var(--color-brand);--btn-text-primary: #FFFFFF;--btn-shadow-default: var(--shadow-sm);--btn-shadow-hover: var(--shadow-md);--btn-transition: .15s ease;--btn-focus-ring: 0 0 0 2px var(--color-focus-ring)}:root{--card-bg: var(--color-bg-primary);--card-radius: var(--radius-lg);--card-shadow: var(--shadow-sm);--card-shadow-hover: var(--shadow-md)}:root{--input-height-md: 44px;--input-bg: var(--color-bg-primary);--input-radius: var(--radius-md);--input-border-default: var(--color-border-subtle);--input-border-hover: var(--color-border-strong);--input-border-focus: var(--color-brand);--input-border-error: var(--color-danger);--input-transition: .12s ease-in-out;--input-focus-ring: 0 0 0 3px var(--color-focus-ring);--input-error-ring: 0 0 0 3px rgba(239, 68, 68, .15)}.ad-badge-tokens{--badge-radius: var(--radius-sm);--badge-padding-v: var(--space-1);--badge-padding-h: var(--space-2);--badge-font-size: var(--font-size-xs);--badge-font-weight: var(--font-weight-medium);--badge-success-bg: #D1FAE5;--badge-success-text: #065F46;--badge-success-border: #A7F3D0;--badge-warning-bg: #FEF3C7;--badge-warning-text: #92400E;--badge-warning-border: #FDE68A;--badge-error-bg: #FFE4E6;--badge-error-text: #9F1239;--badge-error-border: #FECDD3;--badge-info-bg: var(--color-info-50);--badge-info-text: var(--color-info-700);--badge-info-border: var(--color-info-200);--badge-neutral-bg: var(--color-slate-100);--badge-neutral-text: var(--color-slate-700);--badge-neutral-border: var(--color-slate-200)}.ad-label-tokens{--label-font-size: var(--font-size-sm);--label-font-weight: var(--font-weight-medium);--label-color: var(--color-text-secondary);--label-required-color: var(--color-error-500);--label-margin-bottom: var(--space-2)}.ad-select-tokens{--select-bg: var(--color-bg-primary);--select-border: var(--color-border-subtle);--select-border-hover: var(--color-border-strong);--select-border-focus: var(--color-brand-primary);--select-shadow-focus: var(--shadow-focus);--select-radius: var(--radius-md);--select-height: 44px;--select-padding-h: var(--space-4);--select-dropdown-bg: var(--color-bg-primary);--select-dropdown-shadow: var(--shadow-md);--select-dropdown-max-height: 240px;--select-option-padding: var(--space-3) var(--space-4);--select-option-hover: var(--color-bg-secondary);--select-option-selected-bg: var(--color-brand-50);--select-option-selected-text: var(--color-brand-primary)}.ad-form-field-tokens{--form-field-margin-bottom: var(--space-6);--form-field-label-margin: var(--space-2);--form-field-message-margin: var(--space-1);--form-field-message-font-size: var(--font-size-xs);--form-field-message-color: var(--color-text-muted);--form-field-error-color: var(--color-error-600)}.ad-header-tokens{--header-height: 72px;--header-bg: var(--color-surface);--header-border-color: var(--color-border);--header-padding: 0 var(--space-6);--header-shadow: 0 1px 2px rgba(0, 0, 0, .05);--header-z-index: 100;--header-logo-height: 32px;--header-user-gap: var(--space-4)}.ad-sidebar-tokens{--sidebar-width: 280px;--sidebar-collapsed-width: 80px;--sidebar-bg: var(--color-slate-900);--sidebar-border-color: var(--color-slate-800);--sidebar-padding: var(--space-4);--sidebar-z-index: 101;--sidebar-transition: width .3s cubic-bezier(.4, 0, .2, 1);--sidebar-item-height: 48px;--sidebar-item-radius: var(--radius-lg);--sidebar-item-padding: 0 var(--space-4);--sidebar-item-gap: var(--space-3);--sidebar-accent-color: var(--color-primary);--sidebar-text-color: var(--color-surface);--sidebar-text-muted: var(--color-slate-400)}.ad-data-table-tokens{--table-bg: var(--color-bg-primary);--table-header-bg: var(--color-bg-secondary);--table-border-color: var(--color-border-subtle);--table-header-color: var(--color-text-muted);--table-row-hover: rgba(var(--color-brand-primary-rgb), .04);--table-cell-padding: var(--space-4);--table-font-size: var(--font-size-sm);--table-radius: var(--radius-lg)}:root{--modal-bg: var(--color-surface);--modal-overlay-bg: rgba(0, 0, 0, .5);--modal-radius: var(--radius-cerca);--modal-shadow: var(--shadow-premium);--modal-z-index: 1000;--modal-header-padding: 12px 24px;--modal-body-padding: 24px;--modal-footer-padding: 16px 24px;--modal-sm-width: 400px;--modal-md-width: 600px;--modal-lg-width: 900px}.premium-header-card{background:#fff;padding:1.5rem 2rem;border-radius:16px;box-shadow:var(--shadow-premium, 0 4px 20px -2px rgba(0, 0, 0, .1));margin-bottom:2rem;position:relative;overflow:hidden;border:1px solid rgba(0,0,0,.03)}.premium-header-card:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:4px;background:linear-gradient(to right,var(--color-primary),var(--color-primary-accent, #00d2ff))}.header-main{display:flex;justify-content:space-between;align-items:center;gap:1.5rem;flex-wrap:wrap}@media(max-width:768px){.header-main{flex-direction:column;align-items:stretch}}.title-group{display:flex;flex-direction:column;gap:.25rem}.premium-title{font-size:1.5rem;font-weight:800;letter-spacing:-.04em;margin:0;color:var(--color-slate-900, #1e293b);line-height:1.2}.premium-title .accent-text{background:linear-gradient(135deg,var(--color-primary) 0%,var(--color-primary-accent, #00d2ff) 100%);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;margin-left:.3rem}.premium-subtitle{margin-top:0rem;color:var(--color-slate-500, #64748b);font-size:.9rem;font-weight:500;letter-spacing:-.01em}.header-actions{display:flex;gap:var(--spacing-sm);align-items:center}@media(max-width:768px){.header-actions{width:100%;justify-content:flex-start}}\n"] }]
|
|
1760
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }] } });
|
|
1761
|
+
|
|
1762
|
+
const DescriptionHeaderButtonSchema = z.object({
|
|
1763
|
+
label: z.string(),
|
|
1764
|
+
variant: z.enum(['primary', 'secondary', 'ghost', 'outline', 'danger']).optional(),
|
|
1765
|
+
type: z.enum(['button', 'submit', 'reset']).optional(),
|
|
1766
|
+
icon: z.string().optional(),
|
|
1767
|
+
onClick: z.custom().optional(),
|
|
1768
|
+
disabled: z.boolean().optional(),
|
|
1769
|
+
isModalTrigger: z.boolean().optional(),
|
|
1770
|
+
modalResource: z.custom().optional(),
|
|
1771
|
+
modalData: z.any().optional(),
|
|
1772
|
+
onModalConfirm: z.custom().optional(),
|
|
1773
|
+
onModalCancel: z.custom().optional(),
|
|
1774
|
+
});
|
|
1775
|
+
const DescriptionHeaderResourceSchema = z.object({
|
|
1776
|
+
title: z.string(),
|
|
1777
|
+
accentedTitle: z.string().optional(),
|
|
1778
|
+
subtitle: z.string().optional(),
|
|
1779
|
+
buttons: z.array(DescriptionHeaderButtonSchema).optional(),
|
|
1780
|
+
showDivider: z.boolean().optional(),
|
|
1781
|
+
});
|
|
1782
|
+
|
|
1783
|
+
class AdFormFieldComponent {
|
|
1784
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
1785
|
+
label = computed(() => this.resource().label || '', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
1786
|
+
hint = computed(() => this.resource().hint || '', ...(ngDevMode ? [{ debugName: "hint" }] : []));
|
|
1787
|
+
errorMessage = computed(() => this.resource().errorMessage || null, ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
|
|
1788
|
+
required = computed(() => this.resource().required || false, ...(ngDevMode ? [{ debugName: "required" }] : []));
|
|
1789
|
+
error = computed(() => this.resource().error || false, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
1790
|
+
forAttr = computed(() => this.resource().for || '', ...(ngDevMode ? [{ debugName: "forAttr" }] : []));
|
|
1791
|
+
hasError = computed(() => !!this.errorMessage(), ...(ngDevMode ? [{ debugName: "hasError" }] : []));
|
|
1792
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdFormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1793
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdFormFieldComponent, isStandalone: true, selector: "ad-form-field", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"ad-form-field\" [class.has-error]=\"hasError()\">\r\n @if (label()) {\r\n <ad-label [text]=\"label()\" [for]=\"forAttr()\" [required]=\"required()\" [error]=\"hasError()\">\r\n </ad-label>\r\n }\r\n\r\n <div class=\"ad-form-field-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n @if (hint() || errorMessage()) {\r\n <div class=\"ad-form-field-info\">\r\n @if (errorMessage()) {\r\n <span class=\"ad-form-field-error\">{{ errorMessage() }}</span>\r\n }\r\n @if (hint() && !errorMessage()) {\r\n <span class=\"ad-form-field-hint\">{{ hint() }}</span>\r\n }\r\n </div>\r\n }\r\n</div>", styles: [".ad-form-field{display:flex;flex-direction:column;margin-bottom:var(--form-field-margin-bottom);width:100%}.ad-form-field .ad-form-field-content{position:relative;display:flex;flex-direction:column}.ad-form-field .ad-form-field-info{margin-top:var(--form-field-message-margin);min-height:1.25rem}.ad-form-field .ad-form-field-error{color:var(--form-field-error-color);font-size:var(--form-field-message-font-size);font-weight:var(--font-weight-medium);display:block;animation:fadeIn .2s ease-out}.ad-form-field .ad-form-field-hint{color:var(--form-field-message-color);font-size:var(--form-field-message-font-size);display:block}@keyframes fadeIn{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AdLabelComponent, selector: "ad-label", inputs: ["text", "for", "required", "error"] }] });
|
|
1794
|
+
}
|
|
1795
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdFormFieldComponent, decorators: [{
|
|
1796
|
+
type: Component,
|
|
1797
|
+
args: [{ selector: 'ad-form-field', standalone: true, imports: [CommonModule, AdLabelComponent], template: "<div class=\"ad-form-field\" [class.has-error]=\"hasError()\">\r\n @if (label()) {\r\n <ad-label [text]=\"label()\" [for]=\"forAttr()\" [required]=\"required()\" [error]=\"hasError()\">\r\n </ad-label>\r\n }\r\n\r\n <div class=\"ad-form-field-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n @if (hint() || errorMessage()) {\r\n <div class=\"ad-form-field-info\">\r\n @if (errorMessage()) {\r\n <span class=\"ad-form-field-error\">{{ errorMessage() }}</span>\r\n }\r\n @if (hint() && !errorMessage()) {\r\n <span class=\"ad-form-field-hint\">{{ hint() }}</span>\r\n }\r\n </div>\r\n }\r\n</div>", styles: [".ad-form-field{display:flex;flex-direction:column;margin-bottom:var(--form-field-margin-bottom);width:100%}.ad-form-field .ad-form-field-content{position:relative;display:flex;flex-direction:column}.ad-form-field .ad-form-field-info{margin-top:var(--form-field-message-margin);min-height:1.25rem}.ad-form-field .ad-form-field-error{color:var(--form-field-error-color);font-size:var(--form-field-message-font-size);font-weight:var(--font-weight-medium);display:block;animation:fadeIn .2s ease-out}.ad-form-field .ad-form-field-hint{color:var(--form-field-message-color);font-size:var(--form-field-message-font-size);display:block}@keyframes fadeIn{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}\n"] }]
|
|
1798
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }] } });
|
|
1799
|
+
|
|
1800
|
+
const FormFieldResourceSchema = z.object({
|
|
1801
|
+
label: z.string().optional(),
|
|
1802
|
+
hint: z.string().optional(),
|
|
1803
|
+
errorMessage: z.string().nullable().optional(),
|
|
1804
|
+
required: z.boolean().default(false).optional(),
|
|
1805
|
+
error: z.boolean().default(false).optional(),
|
|
1806
|
+
for: z.string().optional()
|
|
1807
|
+
});
|
|
1808
|
+
|
|
1809
|
+
const ModalTriggerResourceSchema = z.object({
|
|
1810
|
+
resource: z.any(), // Assuming ScreenResource for now
|
|
1811
|
+
data: z.any().optional(),
|
|
1812
|
+
triggerLabel: z.string(),
|
|
1813
|
+
triggerIcon: z.string().optional(),
|
|
1814
|
+
loading: z.boolean().default(false).optional(),
|
|
1815
|
+
variant: z.enum(['primary', 'secondary', 'ghost', 'outline', 'danger']).default('primary').optional(),
|
|
1816
|
+
disabled: z.boolean().default(false).optional()
|
|
1817
|
+
});
|
|
1818
|
+
|
|
1819
|
+
class AdSearchBarComponent {
|
|
1820
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
1821
|
+
placeholder = computed(() => this.resource().placeholder || 'Buscar...', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
1822
|
+
debounce = computed(() => this.resource().debounce ?? 300, ...(ngDevMode ? [{ debugName: "debounce" }] : []));
|
|
1823
|
+
loading = computed(() => this.resource().loading || false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
1824
|
+
variant = computed(() => this.resource().variant || 'standalone', ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
1825
|
+
search = output();
|
|
1826
|
+
searchQuery = '';
|
|
1827
|
+
searchSubject = new Subject();
|
|
1828
|
+
subscription = new Subscription();
|
|
305
1829
|
ngOnInit() {
|
|
306
1830
|
this.subscription = this.searchSubject
|
|
307
|
-
.pipe(debounceTime(this.debounce), distinctUntilChanged())
|
|
1831
|
+
.pipe(debounceTime(this.debounce()), distinctUntilChanged())
|
|
308
1832
|
.subscribe(query => {
|
|
309
1833
|
this.search.emit(query);
|
|
310
1834
|
});
|
|
@@ -319,138 +1843,82 @@ class CcSearchBarComponent {
|
|
|
319
1843
|
ngOnDestroy() {
|
|
320
1844
|
this.subscription.unsubscribe();
|
|
321
1845
|
}
|
|
322
|
-
static
|
|
323
|
-
static
|
|
1846
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdSearchBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1847
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdSearchBarComponent, isStandalone: true, selector: "ad-search-bar", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { search: "search" }, ngImport: i0, template: "<div class=\"ad-search-bar\" [ngClass]=\"variant()\">\r\n <div class=\"ad-search-icon-wrapper\">\r\n @if (!loading()) {\r\n <ad-icon name=\"search\" size=\"sm\"></ad-icon>\r\n }\r\n @if (loading()) {\r\n <div class=\"ad-search-loader\"></div>\r\n }\r\n </div>\r\n\r\n <input type=\"text\" class=\"ad-search-input\" [placeholder]=\"placeholder()\" [(ngModel)]=\"searchQuery\"\r\n (ngModelChange)=\"onQueryChange()\">\r\n\r\n @if (searchQuery && !loading()) {\r\n <button class=\"ad-search-clear\" (click)=\"clear()\" type=\"button\">\r\n <ad-icon name=\"close\" size=\"xs\"></ad-icon>\r\n </button>\r\n }\r\n</div>", styles: [".ad-search-bar{display:flex;align-items:center;gap:var(--space-2);height:var(--input-height-md);padding:0 var(--space-3);border-radius:var(--radius-md);transition:all .15s ease-in-out;width:100%}.ad-search-bar.standalone{background-color:var(--color-bg-primary);border:1px solid var(--color-border-subtle);box-shadow:var(--shadow-sm)}.ad-search-bar.standalone:focus-within{border-color:var(--color-brand-primary);box-shadow:var(--shadow-focus)}.ad-search-bar.header{background-color:#ffffff1a;border:1px solid rgba(255,255,255,.2);color:#fff}.ad-search-bar.header .ad-search-input{color:#fff}.ad-search-bar.header .ad-search-input::placeholder{color:#fff9}.ad-search-bar.header .ad-search-icon-wrapper{color:#fffc}.ad-search-icon-wrapper{display:flex;color:var(--color-text-muted)}.ad-search-input{flex:1;border:none;background:transparent;font-size:var(--font-size-md);color:var(--color-text-primary);outline:none;padding:0}.ad-search-input::placeholder{color:var(--color-text-muted)}.ad-search-clear{display:flex;background:transparent;border:none;color:var(--color-text-muted);cursor:pointer;padding:var(--space-1);border-radius:var(--radius-full);transition:background-color .15s ease}.ad-search-clear:hover{background-color:var(--color-bg-secondary);color:var(--color-text-primary)}.ad-search-loader{width:18px;height:18px;border:2px solid currentColor;border-top-color:transparent;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AdIconComponent, selector: "ad-icon", inputs: ["name", "size", "color"] }] });
|
|
324
1848
|
}
|
|
325
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
1849
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdSearchBarComponent, decorators: [{
|
|
326
1850
|
type: Component,
|
|
327
|
-
args: [{ selector: '
|
|
328
|
-
}], propDecorators: {
|
|
329
|
-
type: Input
|
|
330
|
-
}], debounce: [{
|
|
331
|
-
type: Input
|
|
332
|
-
}], loading: [{
|
|
333
|
-
type: Input
|
|
334
|
-
}], variant: [{
|
|
335
|
-
type: Input
|
|
336
|
-
}], search: [{
|
|
337
|
-
type: Output
|
|
338
|
-
}] } });
|
|
1851
|
+
args: [{ selector: 'ad-search-bar', standalone: true, imports: [CommonModule, FormsModule, AdIconComponent], template: "<div class=\"ad-search-bar\" [ngClass]=\"variant()\">\r\n <div class=\"ad-search-icon-wrapper\">\r\n @if (!loading()) {\r\n <ad-icon name=\"search\" size=\"sm\"></ad-icon>\r\n }\r\n @if (loading()) {\r\n <div class=\"ad-search-loader\"></div>\r\n }\r\n </div>\r\n\r\n <input type=\"text\" class=\"ad-search-input\" [placeholder]=\"placeholder()\" [(ngModel)]=\"searchQuery\"\r\n (ngModelChange)=\"onQueryChange()\">\r\n\r\n @if (searchQuery && !loading()) {\r\n <button class=\"ad-search-clear\" (click)=\"clear()\" type=\"button\">\r\n <ad-icon name=\"close\" size=\"xs\"></ad-icon>\r\n </button>\r\n }\r\n</div>", styles: [".ad-search-bar{display:flex;align-items:center;gap:var(--space-2);height:var(--input-height-md);padding:0 var(--space-3);border-radius:var(--radius-md);transition:all .15s ease-in-out;width:100%}.ad-search-bar.standalone{background-color:var(--color-bg-primary);border:1px solid var(--color-border-subtle);box-shadow:var(--shadow-sm)}.ad-search-bar.standalone:focus-within{border-color:var(--color-brand-primary);box-shadow:var(--shadow-focus)}.ad-search-bar.header{background-color:#ffffff1a;border:1px solid rgba(255,255,255,.2);color:#fff}.ad-search-bar.header .ad-search-input{color:#fff}.ad-search-bar.header .ad-search-input::placeholder{color:#fff9}.ad-search-bar.header .ad-search-icon-wrapper{color:#fffc}.ad-search-icon-wrapper{display:flex;color:var(--color-text-muted)}.ad-search-input{flex:1;border:none;background:transparent;font-size:var(--font-size-md);color:var(--color-text-primary);outline:none;padding:0}.ad-search-input::placeholder{color:var(--color-text-muted)}.ad-search-clear{display:flex;background:transparent;border:none;color:var(--color-text-muted);cursor:pointer;padding:var(--space-1);border-radius:var(--radius-full);transition:background-color .15s ease}.ad-search-clear:hover{background-color:var(--color-bg-secondary);color:var(--color-text-primary)}.ad-search-loader{width:18px;height:18px;border:2px solid currentColor;border-top-color:transparent;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}\n"] }]
|
|
1852
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], search: [{ type: i0.Output, args: ["search"] }] } });
|
|
339
1853
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
this.userClick = new EventEmitter();
|
|
347
|
-
this.notificationClick = new EventEmitter();
|
|
348
|
-
this.userAction = new EventEmitter();
|
|
349
|
-
}
|
|
350
|
-
onUserClick() {
|
|
351
|
-
this.userClick.emit();
|
|
352
|
-
this.userAction.emit('profile');
|
|
353
|
-
}
|
|
354
|
-
get initials() {
|
|
355
|
-
if (!this.user?.name)
|
|
356
|
-
return '?';
|
|
357
|
-
return this.user.name
|
|
358
|
-
.split(' ')
|
|
359
|
-
.map(n => n[0])
|
|
360
|
-
.join('')
|
|
361
|
-
.toUpperCase()
|
|
362
|
-
.slice(0, 2);
|
|
363
|
-
}
|
|
364
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: CcHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
365
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.4", type: CcHeaderComponent, isStandalone: true, selector: "cc-header", inputs: { user: "user", notificationsCount: "notificationsCount", showMenuButton: "showMenuButton", hasLogoContent: "hasLogoContent" }, outputs: { toggleSidebar: "toggleSidebar", userClick: "userClick", notificationClick: "notificationClick", userAction: "userAction" }, ngImport: i0, template: "<header class=\"cc-header\">\r\n <div class=\"cc-header-left\">\r\n <button *ngIf=\"showMenuButton\" class=\"cc-header-menu-btn\" (click)=\"toggleSidebar.emit()\" type=\"button\">\r\n <cc-icon name=\"menu\" size=\"md\"></cc-icon>\r\n </button>\r\n\r\n <div class=\"cc-header-logo\">\r\n <ng-content select=\"[logo]\"></ng-content>\r\n <span class=\"cc-header-logo-fallback\" *ngIf=\"!hasLogoContent\">\r\n CERCA\r\n </span>\r\n </div>\r\n\r\n <div class=\"cc-header-breadcrumb\">\r\n <ng-content select=\"[breadcrumb]\"></ng-content>\r\n </div>\r\n </div>\r\n\r\n <div class=\"cc-header-right\">\r\n <button class=\"cc-header-action-btn\" (click)=\"notificationClick.emit()\">\r\n <cc-icon name=\"notifications\" size=\"md\"></cc-icon>\r\n <cc-badge *ngIf=\"notificationsCount > 0\" variant=\"error\" type=\"filled\" class=\"cc-header-badge\">\r\n {{ notificationsCount > 99 ? '99+' : notificationsCount }}\r\n </cc-badge>\r\n </button>\r\n\r\n <div class=\"cc-header-divider\"></div>\r\n\r\n <div class=\"cc-header-user\" (click)=\"onUserClick()\" *ngIf=\"user\">\r\n <div class=\"cc-header-user-info\">\r\n <span class=\"cc-header-user-name\">{{ user.name }}</span>\r\n <span class=\"cc-header-user-role\">{{ user.role }}</span>\r\n </div>\r\n\r\n <div class=\"cc-header-avatar\">\r\n <img *ngIf=\"user.avatarUrl\" [src]=\"user.avatarUrl\" [alt]=\"user.name\">\r\n <span *ngIf=\"!user.avatarUrl\">{{ initials }}</span>\r\n </div>\r\n\r\n <cc-icon name=\"expand_more\" size=\"sm\" class=\"cc-header-user-arrow\"></cc-icon>\r\n </div>\r\n </div>\r\n</header>", styles: [":root,[data-theme=light]{--color-bg-primary: #FFFFFF;--color-bg-secondary: #FAFAF9;--color-text-primary: #1C1917;--color-text-secondary: #57534E;--color-text-muted: #A8A29E;--color-border-subtle: #E7E5E4;--color-border-strong: #D6D3D1;--color-brand: #0284C7;--color-brand-hover: #0369A1;--color-focus-ring: rgba(2, 132, 199, .2);--color-success: #10B981;--color-danger: #F43F5E;--surface-glass-bg: rgba(255, 255, 255, .7);--surface-glass-border: rgba(255, 255, 255, .3);--surface-glass-blur: 12px;--surface-glass-shadow: 0 4px 6px -1px rgba(0, 0, 0, .1);--font-heading-xl: 32px;--font-heading-lg: 24px;--font-heading-md: 20px;--font-body-lg: 18px;--font-body-md: 16px;--font-caption: 12px;--font-family-base: Inter, sans-serif;--font-weight-regular: 400;--font-weight-medium: 500;--font-weight-semibold: 600;--font-weight-bold: 700;--radius-sm: 6px;--radius-md: 8px;--radius-lg: 14px;--radius-xl: 18px;--radius-full: 9999px;--font-size-xs: 12px;--font-size-sm: 14px;--font-size-md: 16px;--font-size-lg: 18px;--font-size-xl: 20px;--font-size-2xl: 24px;--font-size-3xl: 32px;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-6: 24px;--space-8: calc(var(--space-4) * 2);--shadow-sm: 0 1px 2px rgba(0, 0, 0, .06);--shadow-md: 0 4px 12px rgba(0, 0, 0, .08);--shadow-lg: 0 12px 32px rgba(0, 0, 0, .12)}[data-theme=dark]{--color-bg-primary: #1C1917;--color-bg-secondary: #292524;--color-text-primary: #FFFFFF;--color-text-secondary: #A8A29E;--color-text-muted: #78716C;--color-border-subtle: #44403C;--color-border-strong: #57534E;--color-brand: #0EA5E9;--color-brand-hover: #7DD3FC;--color-focus-ring: rgba(59, 130, 246, .5);--surface-glass-bg: rgba(15, 23, 42, .8);--surface-glass-border: rgba(255, 255, 255, .1);--surface-glass-blur: 16px;--surface-glass-shadow: 0 10px 15px -3px rgba(0, 0, 0, .3)}:root{--h1-size: var(--font-size-h1);--h1-weight: var(--font-weight-semibold);--h2-size: var(--font-size-h2);--h2-weight: var(--font-weight-semibold);--h3-size: var(--font-size-h3);--h3-weight: var(--font-weight-semibold);--body-size: var(--font-size-body);--body-weight: var(--font-weight-regular);--sm-size: var(--font-size-sm);--sm-weight: var(--font-weight-regular);--caption-size: var(--font-size-caption);--caption-weight: var(--font-weight-regular)}:root{--btn-height-md: 44px;--btn-radius: var(--radius-md);--btn-font-weight: var(--font-weight-medium);--btn-bg-primary: var(--color-brand);--btn-text-primary: #FFFFFF;--btn-shadow-default: var(--shadow-sm);--btn-shadow-hover: var(--shadow-md);--btn-transition: .15s ease;--btn-focus-ring: 0 0 0 2px var(--color-focus-ring)}:root{--card-bg: var(--color-bg-primary);--card-radius: var(--radius-lg);--card-shadow: var(--shadow-sm);--card-shadow-hover: var(--shadow-md)}:root{--input-height-md: 44px;--input-bg: var(--color-bg-primary);--input-radius: var(--radius-md);--input-border-default: var(--color-border-subtle);--input-border-hover: var(--color-border-strong);--input-border-focus: var(--color-brand);--input-border-error: var(--color-danger);--input-transition: .12s ease-in-out;--input-focus-ring: 0 0 0 3px var(--color-focus-ring);--input-error-ring: 0 0 0 3px rgba(239, 68, 68, .15)}.cc-badge-tokens{--badge-radius: var(--radius-sm);--badge-padding-v: var(--space-1);--badge-padding-h: var(--space-2);--badge-font-size: var(--font-size-xs);--badge-font-weight: var(--font-weight-medium);--badge-success-bg: #D1FAE5;--badge-success-text: #065F46;--badge-success-border: #A7F3D0;--badge-warning-bg: #FEF3C7;--badge-warning-text: #92400E;--badge-warning-border: #FDE68A;--badge-error-bg: #FFE4E6;--badge-error-text: #9F1239;--badge-error-border: #FECDD3;--badge-info-bg: var(--color-info-50);--badge-info-text: var(--color-info-700);--badge-info-border: var(--color-info-200);--badge-neutral-bg: #F5F5F4;--badge-neutral-text: #44403C;--badge-neutral-border: #E7E5E4}.cc-label-tokens{--label-font-size: var(--font-size-sm);--label-font-weight: var(--font-weight-medium);--label-color: var(--color-text-secondary);--label-required-color: var(--color-error-500);--label-margin-bottom: var(--space-2)}.cc-select-tokens{--select-bg: var(--color-bg-primary);--select-border: var(--color-border-subtle);--select-border-hover: var(--color-border-strong);--select-border-focus: var(--color-brand-primary);--select-shadow-focus: var(--shadow-focus);--select-radius: var(--radius-md);--select-height: 44px;--select-padding-h: var(--space-4);--select-dropdown-bg: var(--color-bg-primary);--select-dropdown-shadow: var(--shadow-md);--select-dropdown-max-height: 240px;--select-option-padding: var(--space-3) var(--space-4);--select-option-hover: var(--color-bg-secondary);--select-option-selected-bg: var(--color-brand-50);--select-option-selected-text: var(--color-brand-primary)}.cc-form-field-tokens{--form-field-margin-bottom: var(--space-6);--form-field-label-margin: var(--space-2);--form-field-message-margin: var(--space-1);--form-field-message-font-size: var(--font-size-xs);--form-field-message-color: var(--color-text-muted);--form-field-error-color: var(--color-error-600)}.cc-header-tokens{--header-height: 72px;--header-bg: #FFFFFF;--header-border-color: #F5F5F4;--header-padding: 0 var(--space-6);--header-shadow: 0 1px 2px rgba(0, 0, 0, .05);--header-z-index: 100;--header-logo-height: 32px;--header-user-gap: var(--space-4)}.cc-sidebar-tokens{--sidebar-width: 280px;--sidebar-collapsed-width: 80px;--sidebar-bg: #1C1917;--sidebar-border-color: #292524;--sidebar-padding: var(--space-4);--sidebar-z-index: 101;--sidebar-transition: width .3s cubic-bezier(.4, 0, .2, 1);--sidebar-item-height: 48px;--sidebar-item-radius: var(--radius-lg);--sidebar-item-padding: 0 var(--space-4);--sidebar-item-gap: var(--space-3);--sidebar-accent-color: #0EA5E9;--sidebar-text-color: #FFFFFF;--sidebar-text-muted: #A8A29E}.cc-data-table-tokens{--table-bg: var(--color-bg-primary);--table-header-bg: var(--color-bg-secondary);--table-border-color: var(--color-border-subtle);--table-header-color: var(--color-text-muted);--table-row-hover: rgba(var(--color-brand-primary-rgb), .04);--table-cell-padding: var(--space-4);--table-font-size: var(--font-size-sm);--table-radius: var(--radius-lg)}.cc-modal-tokens{--modal-bg: var(--color-bg-primary);--modal-overlay-bg: rgba(0, 0, 0, .5);--modal-radius: var(--radius-xl);--modal-shadow: var(--shadow-xl);--modal-z-index: 1000;--modal-header-padding: var(--space-6);--modal-body-padding: var(--space-6);--modal-footer-padding: var(--space-4) var(--space-6);--modal-sm-width: 400px;--modal-md-width: 600px;--modal-lg-width: 900px}.cc-header{height:var(--header-height);background:var(--surface-glass-bg);backdrop-filter:blur(var(--surface-glass-blur));-webkit-backdrop-filter:blur(var(--surface-glass-blur));border-bottom:1px solid var(--surface-glass-border);padding:var(--header-padding);display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100;box-shadow:var(--surface-glass-shadow);transition:all .3s ease}.cc-header-left,.cc-header-right{display:flex;align-items:center;gap:var(--space-4)}.cc-header-menu-btn{background:transparent;border:none;color:var(--color-text-primary);cursor:pointer;padding:var(--space-2);border-radius:var(--radius-md);display:flex;transition:background-color .15s ease}.cc-header-menu-btn:hover{background-color:var(--color-bg-secondary)}@media(min-width:1024px){.cc-header-menu-btn{display:none}}.cc-header-logo{display:flex;align-items:center;height:var(--header-logo-height)}.cc-header-logo .cc-header-logo-fallback{font-weight:var(--font-weight-bold);font-size:var(--font-size-xl);letter-spacing:-.025em;color:var(--color-brand-primary)}.cc-header-action-btn{position:relative;background:transparent;border:none;color:var(--color-text-muted);cursor:pointer;padding:var(--space-2);border-radius:var(--radius-full);display:flex;transition:all .15s ease}.cc-header-action-btn:hover{background-color:var(--color-bg-secondary);color:var(--color-text-primary)}.cc-header-action-btn .cc-header-badge{position:absolute;top:4px;right:4px;font-size:10px;padding:2px 4px;min-width:16px;height:16px;display:flex;align-items:center;justify-content:center}.cc-header-divider{width:1px;height:24px;background-color:var(--color-border-subtle);margin:0 var(--space-2)}.cc-header-user{display:flex;align-items:center;gap:var(--space-3);cursor:pointer;padding:var(--space-1) var(--space-2);border-radius:var(--radius-lg);transition:background-color .15s ease}.cc-header-user:hover{background-color:var(--color-bg-secondary)}.cc-header-user-info{display:none;flex-direction:column;text-align:right}@media(min-width:768px){.cc-header-user-info{display:flex}}.cc-header-user-info .cc-header-user-name{font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);color:var(--color-text-primary);line-height:1.2}.cc-header-user-info .cc-header-user-role{font-size:var(--font-size-xs);color:var(--color-text-muted)}.cc-header-avatar{width:36px;height:36px;border-radius:var(--radius-full);background:#0ea5e9;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:var(--font-weight-bold);font-size:var(--font-size-sm);overflow:hidden;box-shadow:0 0 0 2px var(--header-bg),0 0 0 4px var(--color-border-subtle)}.cc-header-avatar img{width:100%;height:100%;object-fit:cover}.cc-header-user-arrow{color:var(--color-text-muted)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: CcIconComponent, selector: "cc-icon", inputs: ["name", "size", "color"] }, { kind: "component", type: CcBadgeComponent, selector: "cc-badge", inputs: ["variant", "type"] }] }); }
|
|
366
|
-
}
|
|
367
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: CcHeaderComponent, decorators: [{
|
|
368
|
-
type: Component,
|
|
369
|
-
args: [{ selector: 'cc-header', standalone: true, imports: [CommonModule, CcIconComponent, CcBadgeComponent], template: "<header class=\"cc-header\">\r\n <div class=\"cc-header-left\">\r\n <button *ngIf=\"showMenuButton\" class=\"cc-header-menu-btn\" (click)=\"toggleSidebar.emit()\" type=\"button\">\r\n <cc-icon name=\"menu\" size=\"md\"></cc-icon>\r\n </button>\r\n\r\n <div class=\"cc-header-logo\">\r\n <ng-content select=\"[logo]\"></ng-content>\r\n <span class=\"cc-header-logo-fallback\" *ngIf=\"!hasLogoContent\">\r\n CERCA\r\n </span>\r\n </div>\r\n\r\n <div class=\"cc-header-breadcrumb\">\r\n <ng-content select=\"[breadcrumb]\"></ng-content>\r\n </div>\r\n </div>\r\n\r\n <div class=\"cc-header-right\">\r\n <button class=\"cc-header-action-btn\" (click)=\"notificationClick.emit()\">\r\n <cc-icon name=\"notifications\" size=\"md\"></cc-icon>\r\n <cc-badge *ngIf=\"notificationsCount > 0\" variant=\"error\" type=\"filled\" class=\"cc-header-badge\">\r\n {{ notificationsCount > 99 ? '99+' : notificationsCount }}\r\n </cc-badge>\r\n </button>\r\n\r\n <div class=\"cc-header-divider\"></div>\r\n\r\n <div class=\"cc-header-user\" (click)=\"onUserClick()\" *ngIf=\"user\">\r\n <div class=\"cc-header-user-info\">\r\n <span class=\"cc-header-user-name\">{{ user.name }}</span>\r\n <span class=\"cc-header-user-role\">{{ user.role }}</span>\r\n </div>\r\n\r\n <div class=\"cc-header-avatar\">\r\n <img *ngIf=\"user.avatarUrl\" [src]=\"user.avatarUrl\" [alt]=\"user.name\">\r\n <span *ngIf=\"!user.avatarUrl\">{{ initials }}</span>\r\n </div>\r\n\r\n <cc-icon name=\"expand_more\" size=\"sm\" class=\"cc-header-user-arrow\"></cc-icon>\r\n </div>\r\n </div>\r\n</header>", styles: [":root,[data-theme=light]{--color-bg-primary: #FFFFFF;--color-bg-secondary: #FAFAF9;--color-text-primary: #1C1917;--color-text-secondary: #57534E;--color-text-muted: #A8A29E;--color-border-subtle: #E7E5E4;--color-border-strong: #D6D3D1;--color-brand: #0284C7;--color-brand-hover: #0369A1;--color-focus-ring: rgba(2, 132, 199, .2);--color-success: #10B981;--color-danger: #F43F5E;--surface-glass-bg: rgba(255, 255, 255, .7);--surface-glass-border: rgba(255, 255, 255, .3);--surface-glass-blur: 12px;--surface-glass-shadow: 0 4px 6px -1px rgba(0, 0, 0, .1);--font-heading-xl: 32px;--font-heading-lg: 24px;--font-heading-md: 20px;--font-body-lg: 18px;--font-body-md: 16px;--font-caption: 12px;--font-family-base: Inter, sans-serif;--font-weight-regular: 400;--font-weight-medium: 500;--font-weight-semibold: 600;--font-weight-bold: 700;--radius-sm: 6px;--radius-md: 8px;--radius-lg: 14px;--radius-xl: 18px;--radius-full: 9999px;--font-size-xs: 12px;--font-size-sm: 14px;--font-size-md: 16px;--font-size-lg: 18px;--font-size-xl: 20px;--font-size-2xl: 24px;--font-size-3xl: 32px;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-6: 24px;--space-8: calc(var(--space-4) * 2);--shadow-sm: 0 1px 2px rgba(0, 0, 0, .06);--shadow-md: 0 4px 12px rgba(0, 0, 0, .08);--shadow-lg: 0 12px 32px rgba(0, 0, 0, .12)}[data-theme=dark]{--color-bg-primary: #1C1917;--color-bg-secondary: #292524;--color-text-primary: #FFFFFF;--color-text-secondary: #A8A29E;--color-text-muted: #78716C;--color-border-subtle: #44403C;--color-border-strong: #57534E;--color-brand: #0EA5E9;--color-brand-hover: #7DD3FC;--color-focus-ring: rgba(59, 130, 246, .5);--surface-glass-bg: rgba(15, 23, 42, .8);--surface-glass-border: rgba(255, 255, 255, .1);--surface-glass-blur: 16px;--surface-glass-shadow: 0 10px 15px -3px rgba(0, 0, 0, .3)}:root{--h1-size: var(--font-size-h1);--h1-weight: var(--font-weight-semibold);--h2-size: var(--font-size-h2);--h2-weight: var(--font-weight-semibold);--h3-size: var(--font-size-h3);--h3-weight: var(--font-weight-semibold);--body-size: var(--font-size-body);--body-weight: var(--font-weight-regular);--sm-size: var(--font-size-sm);--sm-weight: var(--font-weight-regular);--caption-size: var(--font-size-caption);--caption-weight: var(--font-weight-regular)}:root{--btn-height-md: 44px;--btn-radius: var(--radius-md);--btn-font-weight: var(--font-weight-medium);--btn-bg-primary: var(--color-brand);--btn-text-primary: #FFFFFF;--btn-shadow-default: var(--shadow-sm);--btn-shadow-hover: var(--shadow-md);--btn-transition: .15s ease;--btn-focus-ring: 0 0 0 2px var(--color-focus-ring)}:root{--card-bg: var(--color-bg-primary);--card-radius: var(--radius-lg);--card-shadow: var(--shadow-sm);--card-shadow-hover: var(--shadow-md)}:root{--input-height-md: 44px;--input-bg: var(--color-bg-primary);--input-radius: var(--radius-md);--input-border-default: var(--color-border-subtle);--input-border-hover: var(--color-border-strong);--input-border-focus: var(--color-brand);--input-border-error: var(--color-danger);--input-transition: .12s ease-in-out;--input-focus-ring: 0 0 0 3px var(--color-focus-ring);--input-error-ring: 0 0 0 3px rgba(239, 68, 68, .15)}.cc-badge-tokens{--badge-radius: var(--radius-sm);--badge-padding-v: var(--space-1);--badge-padding-h: var(--space-2);--badge-font-size: var(--font-size-xs);--badge-font-weight: var(--font-weight-medium);--badge-success-bg: #D1FAE5;--badge-success-text: #065F46;--badge-success-border: #A7F3D0;--badge-warning-bg: #FEF3C7;--badge-warning-text: #92400E;--badge-warning-border: #FDE68A;--badge-error-bg: #FFE4E6;--badge-error-text: #9F1239;--badge-error-border: #FECDD3;--badge-info-bg: var(--color-info-50);--badge-info-text: var(--color-info-700);--badge-info-border: var(--color-info-200);--badge-neutral-bg: #F5F5F4;--badge-neutral-text: #44403C;--badge-neutral-border: #E7E5E4}.cc-label-tokens{--label-font-size: var(--font-size-sm);--label-font-weight: var(--font-weight-medium);--label-color: var(--color-text-secondary);--label-required-color: var(--color-error-500);--label-margin-bottom: var(--space-2)}.cc-select-tokens{--select-bg: var(--color-bg-primary);--select-border: var(--color-border-subtle);--select-border-hover: var(--color-border-strong);--select-border-focus: var(--color-brand-primary);--select-shadow-focus: var(--shadow-focus);--select-radius: var(--radius-md);--select-height: 44px;--select-padding-h: var(--space-4);--select-dropdown-bg: var(--color-bg-primary);--select-dropdown-shadow: var(--shadow-md);--select-dropdown-max-height: 240px;--select-option-padding: var(--space-3) var(--space-4);--select-option-hover: var(--color-bg-secondary);--select-option-selected-bg: var(--color-brand-50);--select-option-selected-text: var(--color-brand-primary)}.cc-form-field-tokens{--form-field-margin-bottom: var(--space-6);--form-field-label-margin: var(--space-2);--form-field-message-margin: var(--space-1);--form-field-message-font-size: var(--font-size-xs);--form-field-message-color: var(--color-text-muted);--form-field-error-color: var(--color-error-600)}.cc-header-tokens{--header-height: 72px;--header-bg: #FFFFFF;--header-border-color: #F5F5F4;--header-padding: 0 var(--space-6);--header-shadow: 0 1px 2px rgba(0, 0, 0, .05);--header-z-index: 100;--header-logo-height: 32px;--header-user-gap: var(--space-4)}.cc-sidebar-tokens{--sidebar-width: 280px;--sidebar-collapsed-width: 80px;--sidebar-bg: #1C1917;--sidebar-border-color: #292524;--sidebar-padding: var(--space-4);--sidebar-z-index: 101;--sidebar-transition: width .3s cubic-bezier(.4, 0, .2, 1);--sidebar-item-height: 48px;--sidebar-item-radius: var(--radius-lg);--sidebar-item-padding: 0 var(--space-4);--sidebar-item-gap: var(--space-3);--sidebar-accent-color: #0EA5E9;--sidebar-text-color: #FFFFFF;--sidebar-text-muted: #A8A29E}.cc-data-table-tokens{--table-bg: var(--color-bg-primary);--table-header-bg: var(--color-bg-secondary);--table-border-color: var(--color-border-subtle);--table-header-color: var(--color-text-muted);--table-row-hover: rgba(var(--color-brand-primary-rgb), .04);--table-cell-padding: var(--space-4);--table-font-size: var(--font-size-sm);--table-radius: var(--radius-lg)}.cc-modal-tokens{--modal-bg: var(--color-bg-primary);--modal-overlay-bg: rgba(0, 0, 0, .5);--modal-radius: var(--radius-xl);--modal-shadow: var(--shadow-xl);--modal-z-index: 1000;--modal-header-padding: var(--space-6);--modal-body-padding: var(--space-6);--modal-footer-padding: var(--space-4) var(--space-6);--modal-sm-width: 400px;--modal-md-width: 600px;--modal-lg-width: 900px}.cc-header{height:var(--header-height);background:var(--surface-glass-bg);backdrop-filter:blur(var(--surface-glass-blur));-webkit-backdrop-filter:blur(var(--surface-glass-blur));border-bottom:1px solid var(--surface-glass-border);padding:var(--header-padding);display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100;box-shadow:var(--surface-glass-shadow);transition:all .3s ease}.cc-header-left,.cc-header-right{display:flex;align-items:center;gap:var(--space-4)}.cc-header-menu-btn{background:transparent;border:none;color:var(--color-text-primary);cursor:pointer;padding:var(--space-2);border-radius:var(--radius-md);display:flex;transition:background-color .15s ease}.cc-header-menu-btn:hover{background-color:var(--color-bg-secondary)}@media(min-width:1024px){.cc-header-menu-btn{display:none}}.cc-header-logo{display:flex;align-items:center;height:var(--header-logo-height)}.cc-header-logo .cc-header-logo-fallback{font-weight:var(--font-weight-bold);font-size:var(--font-size-xl);letter-spacing:-.025em;color:var(--color-brand-primary)}.cc-header-action-btn{position:relative;background:transparent;border:none;color:var(--color-text-muted);cursor:pointer;padding:var(--space-2);border-radius:var(--radius-full);display:flex;transition:all .15s ease}.cc-header-action-btn:hover{background-color:var(--color-bg-secondary);color:var(--color-text-primary)}.cc-header-action-btn .cc-header-badge{position:absolute;top:4px;right:4px;font-size:10px;padding:2px 4px;min-width:16px;height:16px;display:flex;align-items:center;justify-content:center}.cc-header-divider{width:1px;height:24px;background-color:var(--color-border-subtle);margin:0 var(--space-2)}.cc-header-user{display:flex;align-items:center;gap:var(--space-3);cursor:pointer;padding:var(--space-1) var(--space-2);border-radius:var(--radius-lg);transition:background-color .15s ease}.cc-header-user:hover{background-color:var(--color-bg-secondary)}.cc-header-user-info{display:none;flex-direction:column;text-align:right}@media(min-width:768px){.cc-header-user-info{display:flex}}.cc-header-user-info .cc-header-user-name{font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);color:var(--color-text-primary);line-height:1.2}.cc-header-user-info .cc-header-user-role{font-size:var(--font-size-xs);color:var(--color-text-muted)}.cc-header-avatar{width:36px;height:36px;border-radius:var(--radius-full);background:#0ea5e9;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:var(--font-weight-bold);font-size:var(--font-size-sm);overflow:hidden;box-shadow:0 0 0 2px var(--header-bg),0 0 0 4px var(--color-border-subtle)}.cc-header-avatar img{width:100%;height:100%;object-fit:cover}.cc-header-user-arrow{color:var(--color-text-muted)}\n"] }]
|
|
370
|
-
}], propDecorators: { user: [{
|
|
371
|
-
type: Input
|
|
372
|
-
}], notificationsCount: [{
|
|
373
|
-
type: Input
|
|
374
|
-
}], showMenuButton: [{
|
|
375
|
-
type: Input
|
|
376
|
-
}], hasLogoContent: [{
|
|
377
|
-
type: Input
|
|
378
|
-
}], toggleSidebar: [{
|
|
379
|
-
type: Output
|
|
380
|
-
}], userClick: [{
|
|
381
|
-
type: Output
|
|
382
|
-
}], notificationClick: [{
|
|
383
|
-
type: Output
|
|
384
|
-
}], userAction: [{
|
|
385
|
-
type: Output
|
|
386
|
-
}] } });
|
|
1854
|
+
const SearchBarResourceSchema = z.object({
|
|
1855
|
+
placeholder: z.string().default('Buscar...').optional(),
|
|
1856
|
+
debounce: z.number().default(300).optional(),
|
|
1857
|
+
loading: z.boolean().default(false).optional(),
|
|
1858
|
+
variant: z.enum(['standalone', 'header']).default('standalone').optional(),
|
|
1859
|
+
});
|
|
387
1860
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.4", type: CcSidebarComponent, isStandalone: true, selector: "cc-sidebar", inputs: { menuItems: "menuItems", collapsed: "collapsed", activeRoute: "activeRoute" }, outputs: { navigate: "navigate", toggleCollapse: "toggleCollapse" }, ngImport: i0, template: "<aside class=\"cc-sidebar\" [class.collapsed]=\"collapsed\">\r\n <div class=\"cc-sidebar-header\">\r\n <div class=\"cc-sidebar-logo\">\r\n <ng-content select=\"[logo]\"></ng-content>\r\n </div>\r\n <button class=\"cc-sidebar-toggle\" (click)=\"toggleCollapse.emit()\" type=\"button\">\r\n <cc-icon [name]=\"collapsed ? 'chevron_right' : 'chevron_left'\" size=\"sm\"></cc-icon>\r\n </button>\r\n </div>\r\n\r\n <nav class=\"cc-sidebar-nav\">\r\n <div class=\"cc-sidebar-group\" *ngFor=\"let item of menuItems\">\r\n <a class=\"cc-sidebar-item\" [routerLink]=\"item.route\" routerLinkActive=\"active\"\r\n [routerLinkActiveOptions]=\"{ exact: item.exact || false }\" [title]=\"collapsed ? item.label : ''\"\r\n (click)=\"onItemClick(item)\">\r\n\r\n <cc-icon [name]=\"item.icon\" size=\"md\" class=\"cc-sidebar-item-icon\"></cc-icon>\r\n <span class=\"cc-sidebar-item-label\" *ngIf=\"!collapsed\">{{ item.label }}</span>\r\n\r\n <span class=\"cc-sidebar-item-badge\" *ngIf=\"item.badge && !collapsed\">\r\n {{ item.badge }}\r\n </span>\r\n </a>\r\n </div>\r\n </nav>\r\n\r\n <div class=\"cc-sidebar-footer\">\r\n <ng-content select=\"[footer]\"></ng-content>\r\n </div>\r\n</aside>", styles: [":root,[data-theme=light]{--color-bg-primary: #FFFFFF;--color-bg-secondary: #FAFAF9;--color-text-primary: #1C1917;--color-text-secondary: #57534E;--color-text-muted: #A8A29E;--color-border-subtle: #E7E5E4;--color-border-strong: #D6D3D1;--color-brand: #0284C7;--color-brand-hover: #0369A1;--color-focus-ring: rgba(2, 132, 199, .2);--color-success: #10B981;--color-danger: #F43F5E;--surface-glass-bg: rgba(255, 255, 255, .7);--surface-glass-border: rgba(255, 255, 255, .3);--surface-glass-blur: 12px;--surface-glass-shadow: 0 4px 6px -1px rgba(0, 0, 0, .1);--font-heading-xl: 32px;--font-heading-lg: 24px;--font-heading-md: 20px;--font-body-lg: 18px;--font-body-md: 16px;--font-caption: 12px;--font-family-base: Inter, sans-serif;--font-weight-regular: 400;--font-weight-medium: 500;--font-weight-semibold: 600;--font-weight-bold: 700;--radius-sm: 6px;--radius-md: 8px;--radius-lg: 14px;--radius-xl: 18px;--radius-full: 9999px;--font-size-xs: 12px;--font-size-sm: 14px;--font-size-md: 16px;--font-size-lg: 18px;--font-size-xl: 20px;--font-size-2xl: 24px;--font-size-3xl: 32px;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-6: 24px;--space-8: calc(var(--space-4) * 2);--shadow-sm: 0 1px 2px rgba(0, 0, 0, .06);--shadow-md: 0 4px 12px rgba(0, 0, 0, .08);--shadow-lg: 0 12px 32px rgba(0, 0, 0, .12)}[data-theme=dark]{--color-bg-primary: #1C1917;--color-bg-secondary: #292524;--color-text-primary: #FFFFFF;--color-text-secondary: #A8A29E;--color-text-muted: #78716C;--color-border-subtle: #44403C;--color-border-strong: #57534E;--color-brand: #0EA5E9;--color-brand-hover: #7DD3FC;--color-focus-ring: rgba(59, 130, 246, .5);--surface-glass-bg: rgba(15, 23, 42, .8);--surface-glass-border: rgba(255, 255, 255, .1);--surface-glass-blur: 16px;--surface-glass-shadow: 0 10px 15px -3px rgba(0, 0, 0, .3)}:root{--h1-size: var(--font-size-h1);--h1-weight: var(--font-weight-semibold);--h2-size: var(--font-size-h2);--h2-weight: var(--font-weight-semibold);--h3-size: var(--font-size-h3);--h3-weight: var(--font-weight-semibold);--body-size: var(--font-size-body);--body-weight: var(--font-weight-regular);--sm-size: var(--font-size-sm);--sm-weight: var(--font-weight-regular);--caption-size: var(--font-size-caption);--caption-weight: var(--font-weight-regular)}:root{--btn-height-md: 44px;--btn-radius: var(--radius-md);--btn-font-weight: var(--font-weight-medium);--btn-bg-primary: var(--color-brand);--btn-text-primary: #FFFFFF;--btn-shadow-default: var(--shadow-sm);--btn-shadow-hover: var(--shadow-md);--btn-transition: .15s ease;--btn-focus-ring: 0 0 0 2px var(--color-focus-ring)}:root{--card-bg: var(--color-bg-primary);--card-radius: var(--radius-lg);--card-shadow: var(--shadow-sm);--card-shadow-hover: var(--shadow-md)}:root{--input-height-md: 44px;--input-bg: var(--color-bg-primary);--input-radius: var(--radius-md);--input-border-default: var(--color-border-subtle);--input-border-hover: var(--color-border-strong);--input-border-focus: var(--color-brand);--input-border-error: var(--color-danger);--input-transition: .12s ease-in-out;--input-focus-ring: 0 0 0 3px var(--color-focus-ring);--input-error-ring: 0 0 0 3px rgba(239, 68, 68, .15)}.cc-badge-tokens{--badge-radius: var(--radius-sm);--badge-padding-v: var(--space-1);--badge-padding-h: var(--space-2);--badge-font-size: var(--font-size-xs);--badge-font-weight: var(--font-weight-medium);--badge-success-bg: #D1FAE5;--badge-success-text: #065F46;--badge-success-border: #A7F3D0;--badge-warning-bg: #FEF3C7;--badge-warning-text: #92400E;--badge-warning-border: #FDE68A;--badge-error-bg: #FFE4E6;--badge-error-text: #9F1239;--badge-error-border: #FECDD3;--badge-info-bg: var(--color-info-50);--badge-info-text: var(--color-info-700);--badge-info-border: var(--color-info-200);--badge-neutral-bg: #F5F5F4;--badge-neutral-text: #44403C;--badge-neutral-border: #E7E5E4}.cc-label-tokens{--label-font-size: var(--font-size-sm);--label-font-weight: var(--font-weight-medium);--label-color: var(--color-text-secondary);--label-required-color: var(--color-error-500);--label-margin-bottom: var(--space-2)}.cc-select-tokens{--select-bg: var(--color-bg-primary);--select-border: var(--color-border-subtle);--select-border-hover: var(--color-border-strong);--select-border-focus: var(--color-brand-primary);--select-shadow-focus: var(--shadow-focus);--select-radius: var(--radius-md);--select-height: 44px;--select-padding-h: var(--space-4);--select-dropdown-bg: var(--color-bg-primary);--select-dropdown-shadow: var(--shadow-md);--select-dropdown-max-height: 240px;--select-option-padding: var(--space-3) var(--space-4);--select-option-hover: var(--color-bg-secondary);--select-option-selected-bg: var(--color-brand-50);--select-option-selected-text: var(--color-brand-primary)}.cc-form-field-tokens{--form-field-margin-bottom: var(--space-6);--form-field-label-margin: var(--space-2);--form-field-message-margin: var(--space-1);--form-field-message-font-size: var(--font-size-xs);--form-field-message-color: var(--color-text-muted);--form-field-error-color: var(--color-error-600)}.cc-header-tokens{--header-height: 72px;--header-bg: #FFFFFF;--header-border-color: #F5F5F4;--header-padding: 0 var(--space-6);--header-shadow: 0 1px 2px rgba(0, 0, 0, .05);--header-z-index: 100;--header-logo-height: 32px;--header-user-gap: var(--space-4)}.cc-sidebar-tokens{--sidebar-width: 280px;--sidebar-collapsed-width: 80px;--sidebar-bg: #1C1917;--sidebar-border-color: #292524;--sidebar-padding: var(--space-4);--sidebar-z-index: 101;--sidebar-transition: width .3s cubic-bezier(.4, 0, .2, 1);--sidebar-item-height: 48px;--sidebar-item-radius: var(--radius-lg);--sidebar-item-padding: 0 var(--space-4);--sidebar-item-gap: var(--space-3);--sidebar-accent-color: #0EA5E9;--sidebar-text-color: #FFFFFF;--sidebar-text-muted: #A8A29E}.cc-data-table-tokens{--table-bg: var(--color-bg-primary);--table-header-bg: var(--color-bg-secondary);--table-border-color: var(--color-border-subtle);--table-header-color: var(--color-text-muted);--table-row-hover: rgba(var(--color-brand-primary-rgb), .04);--table-cell-padding: var(--space-4);--table-font-size: var(--font-size-sm);--table-radius: var(--radius-lg)}.cc-modal-tokens{--modal-bg: var(--color-bg-primary);--modal-overlay-bg: rgba(0, 0, 0, .5);--modal-radius: var(--radius-xl);--modal-shadow: var(--shadow-xl);--modal-z-index: 1000;--modal-header-padding: var(--space-6);--modal-body-padding: var(--space-6);--modal-footer-padding: var(--space-4) var(--space-6);--modal-sm-width: 400px;--modal-md-width: 600px;--modal-lg-width: 900px}.cc-sidebar{width:var(--sidebar-width);height:100vh;background:var(--neutral-900)}@supports (backdrop-filter: blur(1px)){.cc-sidebar{background:var(--surface-glass-bg);backdrop-filter:blur(var(--surface-glass-blur));-webkit-backdrop-filter:blur(var(--surface-glass-blur))}}.cc-sidebar{border-right:1px solid var(--surface-glass-border);display:flex;flex-direction:column;transition:var(--sidebar-transition);overflow-x:hidden;position:sticky;top:0;z-index:110}.cc-sidebar.collapsed{width:var(--sidebar-collapsed-width)}.cc-sidebar.collapsed .cc-sidebar-header{padding:var(--space-4) 0;justify-content:center}.cc-sidebar.collapsed .cc-sidebar-logo{display:none}.cc-sidebar.collapsed .cc-sidebar-toggle{position:static}.cc-sidebar.collapsed .cc-sidebar-item{justify-content:center;padding:0}.cc-sidebar-header{height:var(--header-height);padding:0 var(--space-6);display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--surface-glass-border);position:relative;background:transparent}.cc-sidebar-logo{display:flex;align-items:center}.cc-sidebar-toggle{background:var(--color-bg-secondary);border:1px solid var(--color-border-subtle);color:var(--color-text-muted);width:24px;height:24px;border-radius:var(--radius-full);display:flex;align-items:center;justify-content:center;cursor:pointer;position:absolute;right:-12px;top:calc(var(--header-height) / 2 - 12px);z-index:2;transition:all .15s ease}.cc-sidebar-toggle:hover{background-color:var(--color-brand);border-color:var(--color-brand);color:#fff}.cc-sidebar-nav{flex:1;padding:var(--space-4);display:flex;flex-direction:column;gap:var(--space-2);overflow-y:auto}.cc-sidebar-item{height:48px;padding:0 var(--space-4);display:flex;align-items:center;gap:var(--space-3);border-radius:var(--radius-lg);color:var(--color-text-secondary);text-decoration:none;font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);transition:all .2s cubic-bezier(.4,0,.2,1);position:relative}.cc-sidebar-item:hover{background-color:var(--color-bg-secondary);color:var(--color-text-primary)}.cc-sidebar-item.active{background-color:var(--color-brand);color:#fff;box-shadow:0 4px 12px rgba(var(--brand-600),.2)}.cc-sidebar-item.active .cc-sidebar-item-icon{color:#fff}.cc-sidebar-item.active:after{content:\"\";position:absolute;left:-4px;top:25%;height:50%;width:4px;background:#fff;border-radius:0 4px 4px 0}.cc-sidebar-item-icon{flex-shrink:0;color:inherit;font-size:24px}.cc-sidebar-item-label{white-space:nowrap;opacity:1;transition:opacity .2s ease}.cc-sidebar-item-badge{margin-left:auto;background-color:var(--color-danger);color:#fff;font-size:var(--font-size-xs);padding:2px 6px;border-radius:var(--radius-full)}.cc-sidebar-footer{padding:var(--space-4);border-top:1px solid var(--surface-glass-border)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: CcIconComponent, selector: "cc-icon", inputs: ["name", "size", "color"] }] }); }
|
|
1861
|
+
const StatCardColorSchema = z.enum(['blue', 'green', 'red', 'yellow', 'purple', 'orange']);
|
|
1862
|
+
const StatCardResourceSchema = z.object({
|
|
1863
|
+
title: z.string(),
|
|
1864
|
+
value: z.union([z.string(), z.number()]),
|
|
1865
|
+
icon: z.string().optional(),
|
|
1866
|
+
color: StatCardColorSchema.optional(),
|
|
1867
|
+
loading: z.boolean().default(false).optional(),
|
|
1868
|
+
});
|
|
1869
|
+
const STAT_CARD_COLOR_MAP = {
|
|
1870
|
+
blue: { bg: 'bg-blue-50', label: 'text-blue-500' },
|
|
1871
|
+
green: { bg: 'bg-green-50', label: 'text-green-500' },
|
|
1872
|
+
red: { bg: 'bg-red-50', label: 'text-red-500' },
|
|
1873
|
+
yellow: { bg: 'bg-yellow-50', label: 'text-yellow-600' },
|
|
1874
|
+
purple: { bg: 'bg-purple-50', label: 'text-purple-500' },
|
|
1875
|
+
orange: { bg: 'bg-orange-50', label: 'text-orange-500' },
|
|
1876
|
+
};
|
|
1877
|
+
|
|
1878
|
+
class AdStatCardComponent {
|
|
1879
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
1880
|
+
title = computed(() => this.resource().title, ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
1881
|
+
value = computed(() => this.resource().value, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
1882
|
+
icon = computed(() => this.resource().icon, ...(ngDevMode ? [{ debugName: "icon" }] : []));
|
|
1883
|
+
colorClass = computed(() => {
|
|
1884
|
+
const color = this.resource().color ?? 'blue';
|
|
1885
|
+
return STAT_CARD_COLOR_MAP[color].bg;
|
|
1886
|
+
}, ...(ngDevMode ? [{ debugName: "colorClass" }] : []));
|
|
1887
|
+
labelColorClass = computed(() => {
|
|
1888
|
+
const color = this.resource().color ?? 'blue';
|
|
1889
|
+
return STAT_CARD_COLOR_MAP[color].label;
|
|
1890
|
+
}, ...(ngDevMode ? [{ debugName: "labelColorClass" }] : []));
|
|
1891
|
+
isLoading = computed(() => this.resource().loading ?? false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
1892
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdStatCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1893
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdStatCardComponent, isStandalone: true, selector: "ad-stat-card", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"bg-white rounded-2xl shadow-sm border border-slate-100 p-4 min-w-[160px]\">\r\n <div class=\"rounded-xl p-4 flex flex-col gap-3\" [ngClass]=\"colorClass()\">\r\n\r\n <!-- T\u00EDtulo -->\r\n <span class=\"text-[11px] font-semibold tracking-widest uppercase\" [ngClass]=\"labelColorClass()\">\r\n {{ title() }}\r\n </span>\r\n\r\n <!-- Icono + Valor (alineados a la derecha) -->\r\n @if (isLoading()) {\r\n <div class=\"h-9 w-20 rounded-lg animate-pulse opacity-30\" [ngClass]=\"labelColorClass()\"></div>\r\n } @else {\r\n <div class=\"flex items-center justify-between gap-2\">\r\n @if (icon()) {\r\n <ad-icon [name]=\"icon()!\" size=\"md\" [ngClass]=\"labelColorClass()\"></ad-icon>\r\n }\r\n <span class=\"text-3xl font-bold text-slate-800 leading-none ml-auto\">\r\n {{ value() }}\r\n </span>\r\n </div>\r\n }\r\n\r\n </div>\r\n</div>", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: AdIconComponent, selector: "ad-icon", inputs: ["name", "size", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
401
1894
|
}
|
|
402
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
1895
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdStatCardComponent, decorators: [{
|
|
403
1896
|
type: Component,
|
|
404
|
-
args: [{ selector: 'cc-sidebar', standalone: true, imports: [CommonModule, RouterLink, RouterLinkActive, CcIconComponent], template: "<aside class=\"cc-sidebar\" [class.collapsed]=\"collapsed\">\r\n <div class=\"cc-sidebar-header\">\r\n <div class=\"cc-sidebar-logo\">\r\n <ng-content select=\"[logo]\"></ng-content>\r\n </div>\r\n <button class=\"cc-sidebar-toggle\" (click)=\"toggleCollapse.emit()\" type=\"button\">\r\n <cc-icon [name]=\"collapsed ? 'chevron_right' : 'chevron_left'\" size=\"sm\"></cc-icon>\r\n </button>\r\n </div>\r\n\r\n <nav class=\"cc-sidebar-nav\">\r\n <div class=\"cc-sidebar-group\" *ngFor=\"let item of menuItems\">\r\n <a class=\"cc-sidebar-item\" [routerLink]=\"item.route\" routerLinkActive=\"active\"\r\n [routerLinkActiveOptions]=\"{ exact: item.exact || false }\" [title]=\"collapsed ? item.label : ''\"\r\n (click)=\"onItemClick(item)\">\r\n\r\n <cc-icon [name]=\"item.icon\" size=\"md\" class=\"cc-sidebar-item-icon\"></cc-icon>\r\n <span class=\"cc-sidebar-item-label\" *ngIf=\"!collapsed\">{{ item.label }}</span>\r\n\r\n <span class=\"cc-sidebar-item-badge\" *ngIf=\"item.badge && !collapsed\">\r\n {{ item.badge }}\r\n </span>\r\n </a>\r\n </div>\r\n </nav>\r\n\r\n <div class=\"cc-sidebar-footer\">\r\n <ng-content select=\"[footer]\"></ng-content>\r\n </div>\r\n</aside>", styles: [":root,[data-theme=light]{--color-bg-primary: #FFFFFF;--color-bg-secondary: #FAFAF9;--color-text-primary: #1C1917;--color-text-secondary: #57534E;--color-text-muted: #A8A29E;--color-border-subtle: #E7E5E4;--color-border-strong: #D6D3D1;--color-brand: #0284C7;--color-brand-hover: #0369A1;--color-focus-ring: rgba(2, 132, 199, .2);--color-success: #10B981;--color-danger: #F43F5E;--surface-glass-bg: rgba(255, 255, 255, .7);--surface-glass-border: rgba(255, 255, 255, .3);--surface-glass-blur: 12px;--surface-glass-shadow: 0 4px 6px -1px rgba(0, 0, 0, .1);--font-heading-xl: 32px;--font-heading-lg: 24px;--font-heading-md: 20px;--font-body-lg: 18px;--font-body-md: 16px;--font-caption: 12px;--font-family-base: Inter, sans-serif;--font-weight-regular: 400;--font-weight-medium: 500;--font-weight-semibold: 600;--font-weight-bold: 700;--radius-sm: 6px;--radius-md: 8px;--radius-lg: 14px;--radius-xl: 18px;--radius-full: 9999px;--font-size-xs: 12px;--font-size-sm: 14px;--font-size-md: 16px;--font-size-lg: 18px;--font-size-xl: 20px;--font-size-2xl: 24px;--font-size-3xl: 32px;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-6: 24px;--space-8: calc(var(--space-4) * 2);--shadow-sm: 0 1px 2px rgba(0, 0, 0, .06);--shadow-md: 0 4px 12px rgba(0, 0, 0, .08);--shadow-lg: 0 12px 32px rgba(0, 0, 0, .12)}[data-theme=dark]{--color-bg-primary: #1C1917;--color-bg-secondary: #292524;--color-text-primary: #FFFFFF;--color-text-secondary: #A8A29E;--color-text-muted: #78716C;--color-border-subtle: #44403C;--color-border-strong: #57534E;--color-brand: #0EA5E9;--color-brand-hover: #7DD3FC;--color-focus-ring: rgba(59, 130, 246, .5);--surface-glass-bg: rgba(15, 23, 42, .8);--surface-glass-border: rgba(255, 255, 255, .1);--surface-glass-blur: 16px;--surface-glass-shadow: 0 10px 15px -3px rgba(0, 0, 0, .3)}:root{--h1-size: var(--font-size-h1);--h1-weight: var(--font-weight-semibold);--h2-size: var(--font-size-h2);--h2-weight: var(--font-weight-semibold);--h3-size: var(--font-size-h3);--h3-weight: var(--font-weight-semibold);--body-size: var(--font-size-body);--body-weight: var(--font-weight-regular);--sm-size: var(--font-size-sm);--sm-weight: var(--font-weight-regular);--caption-size: var(--font-size-caption);--caption-weight: var(--font-weight-regular)}:root{--btn-height-md: 44px;--btn-radius: var(--radius-md);--btn-font-weight: var(--font-weight-medium);--btn-bg-primary: var(--color-brand);--btn-text-primary: #FFFFFF;--btn-shadow-default: var(--shadow-sm);--btn-shadow-hover: var(--shadow-md);--btn-transition: .15s ease;--btn-focus-ring: 0 0 0 2px var(--color-focus-ring)}:root{--card-bg: var(--color-bg-primary);--card-radius: var(--radius-lg);--card-shadow: var(--shadow-sm);--card-shadow-hover: var(--shadow-md)}:root{--input-height-md: 44px;--input-bg: var(--color-bg-primary);--input-radius: var(--radius-md);--input-border-default: var(--color-border-subtle);--input-border-hover: var(--color-border-strong);--input-border-focus: var(--color-brand);--input-border-error: var(--color-danger);--input-transition: .12s ease-in-out;--input-focus-ring: 0 0 0 3px var(--color-focus-ring);--input-error-ring: 0 0 0 3px rgba(239, 68, 68, .15)}.cc-badge-tokens{--badge-radius: var(--radius-sm);--badge-padding-v: var(--space-1);--badge-padding-h: var(--space-2);--badge-font-size: var(--font-size-xs);--badge-font-weight: var(--font-weight-medium);--badge-success-bg: #D1FAE5;--badge-success-text: #065F46;--badge-success-border: #A7F3D0;--badge-warning-bg: #FEF3C7;--badge-warning-text: #92400E;--badge-warning-border: #FDE68A;--badge-error-bg: #FFE4E6;--badge-error-text: #9F1239;--badge-error-border: #FECDD3;--badge-info-bg: var(--color-info-50);--badge-info-text: var(--color-info-700);--badge-info-border: var(--color-info-200);--badge-neutral-bg: #F5F5F4;--badge-neutral-text: #44403C;--badge-neutral-border: #E7E5E4}.cc-label-tokens{--label-font-size: var(--font-size-sm);--label-font-weight: var(--font-weight-medium);--label-color: var(--color-text-secondary);--label-required-color: var(--color-error-500);--label-margin-bottom: var(--space-2)}.cc-select-tokens{--select-bg: var(--color-bg-primary);--select-border: var(--color-border-subtle);--select-border-hover: var(--color-border-strong);--select-border-focus: var(--color-brand-primary);--select-shadow-focus: var(--shadow-focus);--select-radius: var(--radius-md);--select-height: 44px;--select-padding-h: var(--space-4);--select-dropdown-bg: var(--color-bg-primary);--select-dropdown-shadow: var(--shadow-md);--select-dropdown-max-height: 240px;--select-option-padding: var(--space-3) var(--space-4);--select-option-hover: var(--color-bg-secondary);--select-option-selected-bg: var(--color-brand-50);--select-option-selected-text: var(--color-brand-primary)}.cc-form-field-tokens{--form-field-margin-bottom: var(--space-6);--form-field-label-margin: var(--space-2);--form-field-message-margin: var(--space-1);--form-field-message-font-size: var(--font-size-xs);--form-field-message-color: var(--color-text-muted);--form-field-error-color: var(--color-error-600)}.cc-header-tokens{--header-height: 72px;--header-bg: #FFFFFF;--header-border-color: #F5F5F4;--header-padding: 0 var(--space-6);--header-shadow: 0 1px 2px rgba(0, 0, 0, .05);--header-z-index: 100;--header-logo-height: 32px;--header-user-gap: var(--space-4)}.cc-sidebar-tokens{--sidebar-width: 280px;--sidebar-collapsed-width: 80px;--sidebar-bg: #1C1917;--sidebar-border-color: #292524;--sidebar-padding: var(--space-4);--sidebar-z-index: 101;--sidebar-transition: width .3s cubic-bezier(.4, 0, .2, 1);--sidebar-item-height: 48px;--sidebar-item-radius: var(--radius-lg);--sidebar-item-padding: 0 var(--space-4);--sidebar-item-gap: var(--space-3);--sidebar-accent-color: #0EA5E9;--sidebar-text-color: #FFFFFF;--sidebar-text-muted: #A8A29E}.cc-data-table-tokens{--table-bg: var(--color-bg-primary);--table-header-bg: var(--color-bg-secondary);--table-border-color: var(--color-border-subtle);--table-header-color: var(--color-text-muted);--table-row-hover: rgba(var(--color-brand-primary-rgb), .04);--table-cell-padding: var(--space-4);--table-font-size: var(--font-size-sm);--table-radius: var(--radius-lg)}.cc-modal-tokens{--modal-bg: var(--color-bg-primary);--modal-overlay-bg: rgba(0, 0, 0, .5);--modal-radius: var(--radius-xl);--modal-shadow: var(--shadow-xl);--modal-z-index: 1000;--modal-header-padding: var(--space-6);--modal-body-padding: var(--space-6);--modal-footer-padding: var(--space-4) var(--space-6);--modal-sm-width: 400px;--modal-md-width: 600px;--modal-lg-width: 900px}.cc-sidebar{width:var(--sidebar-width);height:100vh;background:var(--neutral-900)}@supports (backdrop-filter: blur(1px)){.cc-sidebar{background:var(--surface-glass-bg);backdrop-filter:blur(var(--surface-glass-blur));-webkit-backdrop-filter:blur(var(--surface-glass-blur))}}.cc-sidebar{border-right:1px solid var(--surface-glass-border);display:flex;flex-direction:column;transition:var(--sidebar-transition);overflow-x:hidden;position:sticky;top:0;z-index:110}.cc-sidebar.collapsed{width:var(--sidebar-collapsed-width)}.cc-sidebar.collapsed .cc-sidebar-header{padding:var(--space-4) 0;justify-content:center}.cc-sidebar.collapsed .cc-sidebar-logo{display:none}.cc-sidebar.collapsed .cc-sidebar-toggle{position:static}.cc-sidebar.collapsed .cc-sidebar-item{justify-content:center;padding:0}.cc-sidebar-header{height:var(--header-height);padding:0 var(--space-6);display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--surface-glass-border);position:relative;background:transparent}.cc-sidebar-logo{display:flex;align-items:center}.cc-sidebar-toggle{background:var(--color-bg-secondary);border:1px solid var(--color-border-subtle);color:var(--color-text-muted);width:24px;height:24px;border-radius:var(--radius-full);display:flex;align-items:center;justify-content:center;cursor:pointer;position:absolute;right:-12px;top:calc(var(--header-height) / 2 - 12px);z-index:2;transition:all .15s ease}.cc-sidebar-toggle:hover{background-color:var(--color-brand);border-color:var(--color-brand);color:#fff}.cc-sidebar-nav{flex:1;padding:var(--space-4);display:flex;flex-direction:column;gap:var(--space-2);overflow-y:auto}.cc-sidebar-item{height:48px;padding:0 var(--space-4);display:flex;align-items:center;gap:var(--space-3);border-radius:var(--radius-lg);color:var(--color-text-secondary);text-decoration:none;font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);transition:all .2s cubic-bezier(.4,0,.2,1);position:relative}.cc-sidebar-item:hover{background-color:var(--color-bg-secondary);color:var(--color-text-primary)}.cc-sidebar-item.active{background-color:var(--color-brand);color:#fff;box-shadow:0 4px 12px rgba(var(--brand-600),.2)}.cc-sidebar-item.active .cc-sidebar-item-icon{color:#fff}.cc-sidebar-item.active:after{content:\"\";position:absolute;left:-4px;top:25%;height:50%;width:4px;background:#fff;border-radius:0 4px 4px 0}.cc-sidebar-item-icon{flex-shrink:0;color:inherit;font-size:24px}.cc-sidebar-item-label{white-space:nowrap;opacity:1;transition:opacity .2s ease}.cc-sidebar-item-badge{margin-left:auto;background-color:var(--color-danger);color:#fff;font-size:var(--font-size-xs);padding:2px 6px;border-radius:var(--radius-full)}.cc-sidebar-footer{padding:var(--space-4);border-top:1px solid var(--surface-glass-border)}\n"] }]
|
|
405
|
-
}], propDecorators: {
|
|
406
|
-
type: Input
|
|
407
|
-
}], collapsed: [{
|
|
408
|
-
type: Input
|
|
409
|
-
}], activeRoute: [{
|
|
410
|
-
type: Input
|
|
411
|
-
}], navigate: [{
|
|
412
|
-
type: Output
|
|
413
|
-
}], toggleCollapse: [{
|
|
414
|
-
type: Output
|
|
415
|
-
}] } });
|
|
1897
|
+
args: [{ selector: 'ad-stat-card', standalone: true, imports: [NgClass, AdIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"bg-white rounded-2xl shadow-sm border border-slate-100 p-4 min-w-[160px]\">\r\n <div class=\"rounded-xl p-4 flex flex-col gap-3\" [ngClass]=\"colorClass()\">\r\n\r\n <!-- T\u00EDtulo -->\r\n <span class=\"text-[11px] font-semibold tracking-widest uppercase\" [ngClass]=\"labelColorClass()\">\r\n {{ title() }}\r\n </span>\r\n\r\n <!-- Icono + Valor (alineados a la derecha) -->\r\n @if (isLoading()) {\r\n <div class=\"h-9 w-20 rounded-lg animate-pulse opacity-30\" [ngClass]=\"labelColorClass()\"></div>\r\n } @else {\r\n <div class=\"flex items-center justify-between gap-2\">\r\n @if (icon()) {\r\n <ad-icon [name]=\"icon()!\" size=\"md\" [ngClass]=\"labelColorClass()\"></ad-icon>\r\n }\r\n <span class=\"text-3xl font-bold text-slate-800 leading-none ml-auto\">\r\n {{ value() }}\r\n </span>\r\n </div>\r\n }\r\n\r\n </div>\r\n</div>" }]
|
|
1898
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }] } });
|
|
416
1899
|
|
|
417
|
-
class
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
1900
|
+
class AdDataTableComponent {
|
|
1901
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
1902
|
+
data = computed(() => this.resource().data || [], ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
1903
|
+
columns = computed(() => this.resource().columns || [], ...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
1904
|
+
loading = computed(() => this.resource().loading || false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
1905
|
+
showSearch = computed(() => this.resource().showSearch ?? true, ...(ngDevMode ? [{ debugName: "showSearch" }] : []));
|
|
1906
|
+
searchPlaceholder = computed(() => this.resource().searchPlaceholder || 'Buscar en la tabla...', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : []));
|
|
1907
|
+
rowClick = output();
|
|
1908
|
+
search = output();
|
|
1909
|
+
actionClick = output();
|
|
1910
|
+
customCellTemplate;
|
|
1911
|
+
rowActionsTemplate; // Fixed missing ContentChild
|
|
428
1912
|
get skeletonRows() {
|
|
429
1913
|
return Array(5).fill(0);
|
|
430
1914
|
}
|
|
431
|
-
static
|
|
432
|
-
static
|
|
1915
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdDataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1916
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdDataTableComponent, isStandalone: true, selector: "ad-data-table", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { rowClick: "rowClick", search: "search", actionClick: "actionClick" }, queries: [{ propertyName: "customCellTemplate", first: true, predicate: ["customCell"], descendants: true }, { propertyName: "rowActionsTemplate", first: true, predicate: ["rowActions"], descendants: true }], ngImport: i0, template: "<div class=\"ad-data-table-container\">\r\n <div class=\"ad-data-table-wrapper\">\r\n <table class=\"ad-data-table\">\r\n <thead>\r\n <tr>\r\n @for (col of columns(); track col.key) {\r\n <th>\r\n {{ col.label }}\r\n </th>\r\n }\r\n </thead>\r\n\r\n <tbody>\r\n @for (row of data(); track $index) {\r\n <tr>\r\n @for (col of columns(); track col.key) {\r\n <td>\r\n {{ row[col.key] }}\r\n </td>\r\n }\r\n </tr>\r\n } @empty {\r\n <tr>\r\n <td [attr.colspan]=\"columns().length\">\r\n No se encontraron resultados\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n</div>", styles: [".ad-data-table-container{display:flex;flex-direction:column;gap:var(--space-4);width:100%}.ad-data-table-header{display:flex;justify-content:space-between;align-items:center;gap:var(--space-4)}.ad-data-table-wrapper{background-color:var(--table-bg);border:1px solid var(--table-border-color);border-radius:var(--table-radius);overflow:hidden;box-shadow:var(--shadow-sm)}.ad-data-table{width:100%;border-collapse:collapse;text-align:left;font-size:var(--table-font-size)}.ad-data-table thead{background-color:var(--color-bg-secondary)}.ad-data-table thead th{padding:var(--space-4) var(--space-6);font-weight:var(--font-weight-bold);font-size:var(--font-size-xs);color:var(--color-text-muted);text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--color-border-subtle)}.ad-data-table thead th.sortable{cursor:pointer}.ad-data-table thead th.sortable:hover{color:var(--color-text-primary)}.ad-data-table tbody tr{border-bottom:1px solid var(--color-border-subtle);transition:all .2s ease;cursor:pointer;height:52px}.ad-data-table tbody tr:last-child{border-bottom:none}.ad-data-table tbody tr:hover{background-color:rgba(var(--brand-600),.02)}.ad-data-table tbody tr:hover td{color:var(--color-brand)}.ad-data-table tbody tr.active{background-color:var(--color-bg-secondary);box-shadow:inset 3px 0 0 0 var(--color-brand)}.ad-data-table tbody td{padding:var(--space-3) var(--space-6);color:var(--color-text-primary);font-size:var(--font-size-sm)}.ad-table-th-content{display:flex;align-items:center;gap:var(--space-2)}.ad-table-empty-content{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:var(--space-12);color:var(--color-text-muted);gap:var(--space-4)}.ad-table-empty-content p{font-size:var(--font-size-lg);font-weight:var(--font-weight-medium)}.ad-table-skeleton-bar{height:12px;background:linear-gradient(90deg,var(--color-bg-secondary) 25%,var(--color-border-subtle) 50%,var(--color-bg-secondary) 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite;border-radius:var(--radius-sm);width:100%}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
433
1917
|
}
|
|
434
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
1918
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdDataTableComponent, decorators: [{
|
|
435
1919
|
type: Component,
|
|
436
|
-
args: [{ selector: '
|
|
437
|
-
}], propDecorators: {
|
|
438
|
-
type: Input
|
|
439
|
-
}], columns: [{
|
|
440
|
-
type: Input
|
|
441
|
-
}], loading: [{
|
|
442
|
-
type: Input
|
|
443
|
-
}], showSearch: [{
|
|
444
|
-
type: Input
|
|
445
|
-
}], searchPlaceholder: [{
|
|
446
|
-
type: Input
|
|
447
|
-
}], rowClick: [{
|
|
448
|
-
type: Output
|
|
449
|
-
}], search: [{
|
|
450
|
-
type: Output
|
|
451
|
-
}], actionClick: [{
|
|
452
|
-
type: Output
|
|
453
|
-
}], customCellTemplate: [{
|
|
1920
|
+
args: [{ selector: 'ad-data-table', standalone: true, imports: [CommonModule], template: "<div class=\"ad-data-table-container\">\r\n <div class=\"ad-data-table-wrapper\">\r\n <table class=\"ad-data-table\">\r\n <thead>\r\n <tr>\r\n @for (col of columns(); track col.key) {\r\n <th>\r\n {{ col.label }}\r\n </th>\r\n }\r\n </thead>\r\n\r\n <tbody>\r\n @for (row of data(); track $index) {\r\n <tr>\r\n @for (col of columns(); track col.key) {\r\n <td>\r\n {{ row[col.key] }}\r\n </td>\r\n }\r\n </tr>\r\n } @empty {\r\n <tr>\r\n <td [attr.colspan]=\"columns().length\">\r\n No se encontraron resultados\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n</div>", styles: [".ad-data-table-container{display:flex;flex-direction:column;gap:var(--space-4);width:100%}.ad-data-table-header{display:flex;justify-content:space-between;align-items:center;gap:var(--space-4)}.ad-data-table-wrapper{background-color:var(--table-bg);border:1px solid var(--table-border-color);border-radius:var(--table-radius);overflow:hidden;box-shadow:var(--shadow-sm)}.ad-data-table{width:100%;border-collapse:collapse;text-align:left;font-size:var(--table-font-size)}.ad-data-table thead{background-color:var(--color-bg-secondary)}.ad-data-table thead th{padding:var(--space-4) var(--space-6);font-weight:var(--font-weight-bold);font-size:var(--font-size-xs);color:var(--color-text-muted);text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--color-border-subtle)}.ad-data-table thead th.sortable{cursor:pointer}.ad-data-table thead th.sortable:hover{color:var(--color-text-primary)}.ad-data-table tbody tr{border-bottom:1px solid var(--color-border-subtle);transition:all .2s ease;cursor:pointer;height:52px}.ad-data-table tbody tr:last-child{border-bottom:none}.ad-data-table tbody tr:hover{background-color:rgba(var(--brand-600),.02)}.ad-data-table tbody tr:hover td{color:var(--color-brand)}.ad-data-table tbody tr.active{background-color:var(--color-bg-secondary);box-shadow:inset 3px 0 0 0 var(--color-brand)}.ad-data-table tbody td{padding:var(--space-3) var(--space-6);color:var(--color-text-primary);font-size:var(--font-size-sm)}.ad-table-th-content{display:flex;align-items:center;gap:var(--space-2)}.ad-table-empty-content{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:var(--space-12);color:var(--color-text-muted);gap:var(--space-4)}.ad-table-empty-content p{font-size:var(--font-size-lg);font-weight:var(--font-weight-medium)}.ad-table-skeleton-bar{height:12px;background:linear-gradient(90deg,var(--color-bg-secondary) 25%,var(--color-border-subtle) 50%,var(--color-bg-secondary) 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite;border-radius:var(--radius-sm);width:100%}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"] }]
|
|
1921
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], search: [{ type: i0.Output, args: ["search"] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }], customCellTemplate: [{
|
|
454
1922
|
type: ContentChild,
|
|
455
1923
|
args: ['customCell']
|
|
456
1924
|
}], rowActionsTemplate: [{
|
|
@@ -458,65 +1926,104 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImpor
|
|
|
458
1926
|
args: ['rowActions']
|
|
459
1927
|
}] } });
|
|
460
1928
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
1929
|
+
const DataTableColumnSchema = z.object({
|
|
1930
|
+
key: z.string(),
|
|
1931
|
+
label: z.string(),
|
|
1932
|
+
type: z.enum(['text', 'number', 'date', 'badge', 'custom']).optional(),
|
|
1933
|
+
sortable: z.boolean().optional(),
|
|
1934
|
+
});
|
|
1935
|
+
const DataTableResourceSchema = z.object({
|
|
1936
|
+
data: z.array(z.any()).default([]),
|
|
1937
|
+
columns: z.array(DataTableColumnSchema).default([]),
|
|
1938
|
+
loading: z.boolean().default(false).optional(),
|
|
1939
|
+
showSearch: z.boolean().default(true).optional(),
|
|
1940
|
+
searchPlaceholder: z.string().default('Buscar en la tabla...').optional(),
|
|
1941
|
+
});
|
|
1942
|
+
|
|
1943
|
+
class AdHeaderComponent {
|
|
1944
|
+
// Inputs
|
|
1945
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
1946
|
+
user = computed(() => this.resource().user, ...(ngDevMode ? [{ debugName: "user" }] : []));
|
|
1947
|
+
notificationsCount = computed(() => this.resource().notificationsCount ?? 0, ...(ngDevMode ? [{ debugName: "notificationsCount" }] : []));
|
|
1948
|
+
// Outputs
|
|
1949
|
+
toggleSidebar = output();
|
|
1950
|
+
toggleMobileMenu = output();
|
|
1951
|
+
logout = output();
|
|
1952
|
+
navigateProfile = output();
|
|
1953
|
+
toggleTheme = output();
|
|
1954
|
+
// State
|
|
1955
|
+
isUserMenuOpen = signal(false, ...(ngDevMode ? [{ debugName: "isUserMenuOpen" }] : []));
|
|
1956
|
+
isDarkMode = signal(false, ...(ngDevMode ? [{ debugName: "isDarkMode" }] : []));
|
|
1957
|
+
onToggleSidebar() {
|
|
1958
|
+
this.toggleSidebar.emit();
|
|
469
1959
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
this.close.emit();
|
|
473
|
-
}
|
|
1960
|
+
onToggleMobileMenu() {
|
|
1961
|
+
this.toggleMobileMenu.emit();
|
|
474
1962
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
1963
|
+
toggleUserMenu() {
|
|
1964
|
+
this.isUserMenuOpen.update(v => !v);
|
|
1965
|
+
}
|
|
1966
|
+
closeUserMenu() {
|
|
1967
|
+
this.isUserMenuOpen.set(false);
|
|
1968
|
+
}
|
|
1969
|
+
onLogoutClick() {
|
|
1970
|
+
this.logout.emit();
|
|
1971
|
+
this.closeUserMenu();
|
|
1972
|
+
}
|
|
1973
|
+
onProfileClick() {
|
|
1974
|
+
this.navigateProfile.emit();
|
|
1975
|
+
this.closeUserMenu();
|
|
1976
|
+
}
|
|
1977
|
+
onToggleThemeClick() {
|
|
1978
|
+
this.isDarkMode.update(v => !v);
|
|
1979
|
+
const isDark = this.isDarkMode();
|
|
1980
|
+
if (isDark) {
|
|
1981
|
+
document.documentElement.classList.add('dark');
|
|
478
1982
|
}
|
|
1983
|
+
else {
|
|
1984
|
+
document.documentElement.classList.remove('dark');
|
|
1985
|
+
}
|
|
1986
|
+
this.toggleTheme.emit(isDark);
|
|
1987
|
+
this.closeUserMenu();
|
|
479
1988
|
}
|
|
480
|
-
static
|
|
481
|
-
static
|
|
1989
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1990
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdHeaderComponent, isStandalone: true, selector: "ad-header", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { toggleSidebar: "toggleSidebar", toggleMobileMenu: "toggleMobileMenu", logout: "logout", navigateProfile: "navigateProfile", toggleTheme: "toggleTheme" }, ngImport: i0, template: "<header class=\"sticky top-0 z-20 flex items-center justify-between px-6 h-16 \r\n bg-white/80 backdrop-blur-xl border-b border-white/20\r\n shadow-[0_4px_30px_rgba(0,0,0,0.05)] transition-all duration-300\">\r\n <div class=\"flex items-center gap-4 flex-1\">\r\n <!-- Mobile Menu -->\r\n <button (click)=\"onToggleMobileMenu()\"\r\n class=\"md:hidden p-2 text-slate-600 hover:bg-slate-100 rounded-xl transition-all active:scale-95 shadow-sm bg-white border border-slate-100\">\r\n <span class=\"material-icons-outlined\">menu</span>\r\n </button>\r\n\r\n <!-- Desktop Toggle -->\r\n <button (click)=\"onToggleSidebar()\"\r\n class=\"hidden md:flex p-2 text-slate-600 hover:bg-slate-100 rounded-xl transition-all active:scale-95 shadow-sm bg-white border border-slate-100\">\r\n <span class=\"material-icons-outlined\">menu_open</span>\r\n </button>\r\n\r\n <!-- Search Bar -->\r\n <div\r\n class=\"relative flex items-center transition-all duration-300 w-48 md:w-64 focus-within:w-full focus-within:max-w-md\">\r\n <span\r\n class=\"material-icons-outlined absolute left-3 transition-colors text-slate-400 group-focus-within:text-blue-500\">search</span>\r\n <input type=\"text\" placeholder=\"Buscar en Cerca...\"\r\n class=\"w-full bg-slate-50 border border-slate-200 rounded-xl py-2 pl-10 pr-4 text-sm focus:outline-none focus:ring-4 focus:ring-blue-500/10 focus:bg-white transition-all shadow-inner placeholder:text-slate-400 text-slate-600\" />\r\n </div>\r\n </div>\r\n\r\n <!-- Header Right -->\r\n <div class=\"flex items-center gap-3\">\r\n <!-- Notifications -->\r\n <button\r\n class=\"relative p-2.5 text-slate-500 hover:bg-slate-100 rounded-xl transition-all bg-white border border-slate-100 shadow-sm group\">\r\n <span class=\"material-icons-outlined group-hover:text-blue-500 transition-colors\">notifications</span>\r\n @if (notificationsCount() > 0) {\r\n <span class=\"absolute top-2 right-2 w-2.5 h-2.5 bg-red-500 rounded-full border-2 border-white\"></span>\r\n }\r\n </button>\r\n\r\n <div class=\"h-8 w-[1px] bg-slate-200 mx-1\"></div>\r\n\r\n <!-- User Profile -->\r\n <div class=\"flex items-center gap-3 pl-1 group cursor-pointer\" (click)=\"toggleUserMenu()\">\r\n <div class=\"text-right hidden sm:block\">\r\n <p class=\"text-sm font-bold text-slate-700 leading-none group-hover:text-blue-600 transition-colors\">\r\n {{ user().name }}</p>\r\n <p class=\"text-[10px] text-slate-400 font-bold mt-1 tracking-tighter uppercase\">{{ user().role\r\n }}</p>\r\n </div>\r\n <!-- Gradient Avatar -->\r\n <div\r\n class=\"h-10 w-10 rounded-xl bg-gradient-to-tr from-blue-600 to-blue-400 flex items-center justify-center text-white shadow-lg shadow-blue-200 transition-transform group-hover:scale-105\">\r\n @if (user().avatarUrl) {\r\n <img [src]=\"user().avatarUrl\" alt=\"Avatar\"\r\n class=\"h-full w-full rounded-xl object-cover opacity-90 hover:opacity-100\">\r\n } @else {\r\n <span class=\"material-icons-outlined text-sm\">person</span>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Dropdown Menu (Existing logic) -->\r\n @if (isUserMenuOpen()) {\r\n <div class=\"fixed inset-0 z-40\" (click)=\"closeUserMenu()\"></div>\r\n <div\r\n class=\"absolute top-16 right-6 w-48 bg-white dark:bg-cerca-navy rounded-xl shadow-xl py-1 border border-slate-100 ring-1 ring-black ring-opacity-5 animate-fade-in-down z-50\">\r\n <button (click)=\"onProfileClick()\"\r\n class=\"w-full text-left px-4 py-2 text-sm text-slate-700 hover:bg-slate-50 hover:text-blue-600 transition-colors flex items-center font-medium\">\r\n <span class=\"material-icons-outlined text-lg mr-2\">person</span> Perfil\r\n </button>\r\n <button (click)=\"onToggleThemeClick()\"\r\n class=\"w-full text-left px-4 py-2 text-sm text-slate-700 hover:bg-slate-50 hover:text-blue-600 transition-colors flex items-center font-medium\">\r\n <span class=\"material-icons-outlined text-lg mr-2\">{{ isDarkMode() ? 'light_mode' : 'dark_mode'\r\n }}</span> {{ isDarkMode() ? 'Modo Claro' : 'Modo Oscuro' }}\r\n </button>\r\n <div class=\"border-t border-slate-100 my-1\"></div>\r\n <button (click)=\"onLogoutClick()\"\r\n class=\"w-full text-left px-4 py-2 text-sm text-rose-600 hover:bg-rose-50 transition-colors flex items-center font-medium\">\r\n <span class=\"material-icons-outlined text-lg mr-2\">logout</span> Cerrar Sesi\u00F3n\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n</header>", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
482
1991
|
}
|
|
483
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
1992
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdHeaderComponent, decorators: [{
|
|
484
1993
|
type: Component,
|
|
485
|
-
args: [{ selector: '
|
|
486
|
-
}], propDecorators: {
|
|
487
|
-
type: Input
|
|
488
|
-
}], title: [{
|
|
489
|
-
type: Input
|
|
490
|
-
}], size: [{
|
|
491
|
-
type: Input
|
|
492
|
-
}], closeOnOverlay: [{
|
|
493
|
-
type: Input
|
|
494
|
-
}], showFooter: [{
|
|
495
|
-
type: Input
|
|
496
|
-
}], close: [{
|
|
497
|
-
type: Output
|
|
498
|
-
}], onEscape: [{
|
|
499
|
-
type: HostListener,
|
|
500
|
-
args: ['document:keydown.escape']
|
|
501
|
-
}] } });
|
|
1994
|
+
args: [{ selector: 'ad-header', standalone: true, imports: [CommonModule], template: "<header class=\"sticky top-0 z-20 flex items-center justify-between px-6 h-16 \r\n bg-white/80 backdrop-blur-xl border-b border-white/20\r\n shadow-[0_4px_30px_rgba(0,0,0,0.05)] transition-all duration-300\">\r\n <div class=\"flex items-center gap-4 flex-1\">\r\n <!-- Mobile Menu -->\r\n <button (click)=\"onToggleMobileMenu()\"\r\n class=\"md:hidden p-2 text-slate-600 hover:bg-slate-100 rounded-xl transition-all active:scale-95 shadow-sm bg-white border border-slate-100\">\r\n <span class=\"material-icons-outlined\">menu</span>\r\n </button>\r\n\r\n <!-- Desktop Toggle -->\r\n <button (click)=\"onToggleSidebar()\"\r\n class=\"hidden md:flex p-2 text-slate-600 hover:bg-slate-100 rounded-xl transition-all active:scale-95 shadow-sm bg-white border border-slate-100\">\r\n <span class=\"material-icons-outlined\">menu_open</span>\r\n </button>\r\n\r\n <!-- Search Bar -->\r\n <div\r\n class=\"relative flex items-center transition-all duration-300 w-48 md:w-64 focus-within:w-full focus-within:max-w-md\">\r\n <span\r\n class=\"material-icons-outlined absolute left-3 transition-colors text-slate-400 group-focus-within:text-blue-500\">search</span>\r\n <input type=\"text\" placeholder=\"Buscar en Cerca...\"\r\n class=\"w-full bg-slate-50 border border-slate-200 rounded-xl py-2 pl-10 pr-4 text-sm focus:outline-none focus:ring-4 focus:ring-blue-500/10 focus:bg-white transition-all shadow-inner placeholder:text-slate-400 text-slate-600\" />\r\n </div>\r\n </div>\r\n\r\n <!-- Header Right -->\r\n <div class=\"flex items-center gap-3\">\r\n <!-- Notifications -->\r\n <button\r\n class=\"relative p-2.5 text-slate-500 hover:bg-slate-100 rounded-xl transition-all bg-white border border-slate-100 shadow-sm group\">\r\n <span class=\"material-icons-outlined group-hover:text-blue-500 transition-colors\">notifications</span>\r\n @if (notificationsCount() > 0) {\r\n <span class=\"absolute top-2 right-2 w-2.5 h-2.5 bg-red-500 rounded-full border-2 border-white\"></span>\r\n }\r\n </button>\r\n\r\n <div class=\"h-8 w-[1px] bg-slate-200 mx-1\"></div>\r\n\r\n <!-- User Profile -->\r\n <div class=\"flex items-center gap-3 pl-1 group cursor-pointer\" (click)=\"toggleUserMenu()\">\r\n <div class=\"text-right hidden sm:block\">\r\n <p class=\"text-sm font-bold text-slate-700 leading-none group-hover:text-blue-600 transition-colors\">\r\n {{ user().name }}</p>\r\n <p class=\"text-[10px] text-slate-400 font-bold mt-1 tracking-tighter uppercase\">{{ user().role\r\n }}</p>\r\n </div>\r\n <!-- Gradient Avatar -->\r\n <div\r\n class=\"h-10 w-10 rounded-xl bg-gradient-to-tr from-blue-600 to-blue-400 flex items-center justify-center text-white shadow-lg shadow-blue-200 transition-transform group-hover:scale-105\">\r\n @if (user().avatarUrl) {\r\n <img [src]=\"user().avatarUrl\" alt=\"Avatar\"\r\n class=\"h-full w-full rounded-xl object-cover opacity-90 hover:opacity-100\">\r\n } @else {\r\n <span class=\"material-icons-outlined text-sm\">person</span>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Dropdown Menu (Existing logic) -->\r\n @if (isUserMenuOpen()) {\r\n <div class=\"fixed inset-0 z-40\" (click)=\"closeUserMenu()\"></div>\r\n <div\r\n class=\"absolute top-16 right-6 w-48 bg-white dark:bg-cerca-navy rounded-xl shadow-xl py-1 border border-slate-100 ring-1 ring-black ring-opacity-5 animate-fade-in-down z-50\">\r\n <button (click)=\"onProfileClick()\"\r\n class=\"w-full text-left px-4 py-2 text-sm text-slate-700 hover:bg-slate-50 hover:text-blue-600 transition-colors flex items-center font-medium\">\r\n <span class=\"material-icons-outlined text-lg mr-2\">person</span> Perfil\r\n </button>\r\n <button (click)=\"onToggleThemeClick()\"\r\n class=\"w-full text-left px-4 py-2 text-sm text-slate-700 hover:bg-slate-50 hover:text-blue-600 transition-colors flex items-center font-medium\">\r\n <span class=\"material-icons-outlined text-lg mr-2\">{{ isDarkMode() ? 'light_mode' : 'dark_mode'\r\n }}</span> {{ isDarkMode() ? 'Modo Claro' : 'Modo Oscuro' }}\r\n </button>\r\n <div class=\"border-t border-slate-100 my-1\"></div>\r\n <button (click)=\"onLogoutClick()\"\r\n class=\"w-full text-left px-4 py-2 text-sm text-rose-600 hover:bg-rose-50 transition-colors flex items-center font-medium\">\r\n <span class=\"material-icons-outlined text-lg mr-2\">logout</span> Cerrar Sesi\u00F3n\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n</header>" }]
|
|
1995
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], toggleSidebar: [{ type: i0.Output, args: ["toggleSidebar"] }], toggleMobileMenu: [{ type: i0.Output, args: ["toggleMobileMenu"] }], logout: [{ type: i0.Output, args: ["logout"] }], navigateProfile: [{ type: i0.Output, args: ["navigateProfile"] }], toggleTheme: [{ type: i0.Output, args: ["toggleTheme"] }] } });
|
|
502
1996
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
}
|
|
1997
|
+
const UserSchema = z.object({
|
|
1998
|
+
name: z.string(),
|
|
1999
|
+
role: z.string(),
|
|
2000
|
+
avatarUrl: z.string().optional(),
|
|
2001
|
+
});
|
|
2002
|
+
const HeaderResourceSchema = z.object({
|
|
2003
|
+
user: UserSchema,
|
|
2004
|
+
notificationsCount: z.number().default(0).optional(),
|
|
2005
|
+
});
|
|
2006
|
+
|
|
2007
|
+
class AdLoginComponent {
|
|
2008
|
+
fb = inject(FormBuilder);
|
|
2009
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
2010
|
+
title = computed(() => this.resource().title ?? 'Bienvenido', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
2011
|
+
titleAccent = computed(() => this.resource().titleAccent, ...(ngDevMode ? [{ debugName: "titleAccent" }] : []));
|
|
2012
|
+
subtitle = computed(() => this.resource().subtitle ?? 'Inicia sesión para continuar', ...(ngDevMode ? [{ debugName: "subtitle" }] : []));
|
|
2013
|
+
logo = computed(() => this.resource().logo, ...(ngDevMode ? [{ debugName: "logo" }] : []));
|
|
2014
|
+
icon = computed(() => this.resource().icon, ...(ngDevMode ? [{ debugName: "icon" }] : []));
|
|
2015
|
+
loading = computed(() => this.resource().loading ?? false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
2016
|
+
errorMessage = computed(() => this.resource().errorMessage ?? null, ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
|
|
2017
|
+
supportEmail = computed(() => this.resource().supportEmail ?? 'soporte@cerca.com.co', ...(ngDevMode ? [{ debugName: "supportEmail" }] : []));
|
|
2018
|
+
recoverPasswordUrl = computed(() => this.resource().recoverPasswordUrl, ...(ngDevMode ? [{ debugName: "recoverPasswordUrl" }] : []));
|
|
2019
|
+
forgotPasswordLabel = computed(() => this.resource().forgotPasswordLabel ?? '¿Olvidaste tu clave?', ...(ngDevMode ? [{ debugName: "forgotPasswordLabel" }] : []));
|
|
2020
|
+
loginSubmit = output();
|
|
2021
|
+
forgotPasswordClick = output();
|
|
2022
|
+
loginForm = this.fb.group({
|
|
2023
|
+
email: ['', [Validators.required, Validators.email]],
|
|
2024
|
+
password: ['', [Validators.required]],
|
|
2025
|
+
remember: [true]
|
|
2026
|
+
});
|
|
520
2027
|
submitForm() {
|
|
521
2028
|
if (this.loginForm.valid) {
|
|
522
2029
|
const { email, password, remember } = this.loginForm.getRawValue();
|
|
@@ -535,127 +2042,445 @@ class CcLoginComponent {
|
|
|
535
2042
|
const control = this.loginForm.get(field);
|
|
536
2043
|
return (control && control.invalid && (control.dirty || control.touched)) || false;
|
|
537
2044
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
}
|
|
541
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: CcLoginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
542
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: CcLoginComponent, isStandalone: true, selector: "cc-login", inputs: { title: "title", titleAccent: "titleAccent", subtitle: "subtitle", logoUrl: "logoUrl", icon: "icon", loading: "loading", errorMessage: "errorMessage", supportEmail: "supportEmail", recoverPasswordUrl: "recoverPasswordUrl", forgotPasswordLabel: "forgotPasswordLabel" }, outputs: { loginSubmit: "loginSubmit", forgotPasswordClick: "forgotPasswordClick" }, ngImport: i0, template: "<div class=\"login-container\">\r\n <div class=\"login-card\">\r\n <div class=\"login-header\">\r\n @if (logoUrl) {\r\n <img [src]=\"logoUrl\" alt=\"Logo\" class=\"logo\" />\r\n } @else if (icon) {\r\n <div class=\"logo-box\">\r\n <span nz-icon [nzType]=\"icon\" nzTheme=\"fill\"></span>\r\n </div>\r\n }\r\n <h2 class=\"title\">\r\n {{ title }}\r\n @if (titleAccent) {\r\n <span class=\"accent\">{{ titleAccent }}</span>\r\n }\r\n </h2>\r\n <p class=\"subtitle text-uppercase\">{{ subtitle }}</p>\r\n </div>\r\n\r\n @if (errorMessage) {\r\n <nz-alert nzType=\"error\" [nzMessage]=\"errorMessage\" nzShowIcon class=\"error-alert\"></nz-alert>\r\n }\r\n\r\n <form [formGroup]=\"loginForm\" (ngSubmit)=\"submitForm()\" class=\"login-form\">\r\n <div class=\"form-group\">\r\n <cc-input formControlName=\"email\" placeholder=\"correo@ejemplo.com\" label=\"Correo Electr\u00F3nico\"\r\n type=\"email\" prefix=\"mail\" [error]=\"fieldInvalid('email')\">\r\n </cc-input>\r\n </div>\r\n\r\n <div class=\"form-group\">\r\n <cc-input formControlName=\"password\" placeholder=\"********\" label=\"Contrase\u00F1a\" type=\"password\"\r\n prefix=\"lock\" [error]=\"fieldInvalid('password')\">\r\n </cc-input>\r\n </div>\r\n\r\n <div class=\"form-actions-row\">\r\n <label nz-checkbox formControlName=\"remember\">Recordarme</label>\r\n @if (recoverPasswordUrl) {\r\n <a [href]=\"recoverPasswordUrl\" class=\"forgot-password\">{{ forgotPasswordLabel }}</a>\r\n } @else {\r\n <a class=\"forgot-password\" (click)=\"forgotPasswordClick.emit()\">{{ forgotPasswordLabel }}</a>\r\n }\r\n </div>\r\n\r\n <cc-button [loading]=\"loading\" variant=\"primary\" type=\"submit\" class=\"submit-button\"\r\n [disabled]=\"loginForm.invalid || loading\">\r\n Iniciar Sesi\u00F3n\r\n </cc-button>\r\n </form>\r\n\r\n <div class=\"login-footer\">\r\n <p>\u00BFNecesitas ayuda? Contacta a <a [href]=\"'mailto:' + supportEmail\">{{ supportEmail }}</a></p>\r\n </div>\r\n </div>\r\n</div>", styles: [":host{display:block;height:100%;width:100%}.login-container{display:flex;justify-content:center;align-items:center;min-height:100vh;width:100vw;overflow:hidden;background:radial-gradient(circle at top left,#0284c7,#001529);padding:1rem;box-sizing:border-box}.login-card{width:100%;max-width:380px;padding:24px;background:#fff;border-radius:8px;box-shadow:0 12px 48px #0000004d;animation:fadeIn .5s ease-out}.login-header{text-align:center;margin-bottom:24px}.login-header .logo-box{width:40px;height:40px;background:#0284c7;color:#fff;font-size:20px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;margin-bottom:12px}.login-header .logo{max-height:60px;margin-bottom:1rem;object-fit:contain}.login-header .title{font-size:20px;font-weight:700;color:#001529;margin:0;line-height:1.2}.login-header .title .accent{color:#0284c7;font-style:italic}.login-header .subtitle{font-size:10px;letter-spacing:2px;color:#8c8c8c;margin-top:4px}.error-alert{margin-bottom:16px;border-radius:4px}.login-form{display:flex;flex-direction:column;gap:16px}.form-group{display:flex;flex-direction:column;gap:4px}.error-message{color:#ff4d4f;font-size:12px;margin-top:2px;animation:slideDown .2s ease-out}.form-actions-row{display:flex;justify-content:space-between;align-items:center;font-size:12px;margin-bottom:8px}.form-actions-row ::ng-deep .ant-checkbox-wrapper span{color:#000000d9}.form-actions-row .forgot-password{color:#0284c7;text-decoration:none;cursor:pointer}.form-actions-row .forgot-password:hover{color:#0050b3;text-decoration:underline}.submit-button{width:100%;margin-top:8px}.submit-button ::ng-deep button{width:100%;height:36px;font-size:14px;font-weight:600;border-radius:4px}.login-footer{margin-top:24px;text-align:center;color:#bfbfbf;font-size:10px}.login-footer p{margin:2px 0}.login-footer a{color:#8c8c8c;text-decoration:none}.login-footer a:hover{color:#0284c7}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes slideDown{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CcInputComponent, selector: "cc-input", inputs: ["type", "placeholder", "label", "error", "disabled", "size", "prefix", "suffix"] }, { kind: "component", type: CcButtonComponent, selector: "cc-button", inputs: ["variant", "type", "disabled", "loading", "icon", "size"] }, { kind: "ngmodule", type: NzAlertModule }, { kind: "component", type: i2$2.NzAlertComponent, selector: "nz-alert", inputs: ["nzAction", "nzCloseText", "nzIconType", "nzMessage", "nzDescription", "nzType", "nzCloseable", "nzShowIcon", "nzBanner", "nzNoAnimation", "nzIcon"], outputs: ["nzOnClose"], exportAs: ["nzAlert"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i3$1.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzCheckboxModule }, { kind: "component", type: i4.NzCheckboxComponent, selector: "[nz-checkbox]", inputs: ["nzValue", "nzAutoFocus", "nzDisabled", "nzIndeterminate", "nzChecked", "nzId", "nzName"], outputs: ["nzCheckedChange"], exportAs: ["nzCheckbox"] }] }); }
|
|
2045
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdLoginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2046
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdLoginComponent, isStandalone: true, selector: "ad-login", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { loginSubmit: "loginSubmit", forgotPasswordClick: "forgotPasswordClick" }, ngImport: i0, template: "<div class=\"w-full max-w-md space-y-8 bg-white p-8 rounded-xl shadow-lg border border-slate-100\">\r\n <div class=\"text-center\">\r\n @if (logo()) {\r\n <img [src]=\"logo()\" alt=\"Logo\" class=\"mx-auto h-12 w-auto\" />\r\n } @else if (icon()) {\r\n <div class=\"mx-auto h-12 w-12 flex items-center justify-center rounded-full bg-sky-100 text-sky-600\">\r\n <!-- Fallback icon or remove nz-icon -->\r\n <span class=\"text-2xl font-bold\">C</span>\r\n </div>\r\n }\r\n <h2 class=\"mt-6 text-3xl font-extrabold text-cerca-navy\">\r\n {{ title() }}\r\n @if (titleAccent()) {\r\n <span class=\"accent-text\">{{ titleAccent() }}</span>\r\n }\r\n </h2>\r\n <p class=\"mt-2 text-sm text-slate-600 uppercase tracking-wide\">{{ subtitle() }}</p>\r\n </div>\r\n\r\n @if (errorMessage()) {\r\n <div class=\"bg-red-50 border-l-4 border-red-500 p-4 mb-4 rounded-md\">\r\n <div class=\"flex\">\r\n <div class=\"ml-3\">\r\n <p class=\"text-sm text-red-700\">{{ errorMessage() }}</p>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <form [formGroup]=\"loginForm\" class=\"mt-8 space-y-6\" (ngSubmit)=\"submitForm()\">\r\n <div class=\"space-y-4\">\r\n <div class=\"form-group\">\r\n <ad-input formControlName=\"email\" placeholder=\"correo@ejemplo.com\" label=\"Correo Electr\u00F3nico\"\r\n type=\"email\" prefix=\"user\" [error]=\"fieldInvalid('email')\">\r\n </ad-input>\r\n @if (fieldInvalid('email')) {\r\n <p class=\"mt-1 text-sm text-red-600\">\r\n @if (loginForm.get('email')?.hasError('required')) { El campo es requerido }\r\n @else { Ingrese un correo v\u00E1lido }\r\n </p>\r\n }\r\n </div>\r\n\r\n <div class=\"form-group\">\r\n <ad-input formControlName=\"password\" placeholder=\"********\" label=\"Contrase\u00F1a\" type=\"password\"\r\n prefix=\"lock\" [error]=\"fieldInvalid('password')\">\r\n </ad-input>\r\n @if (fieldInvalid('password')) {\r\n <p class=\"mt-1 text-sm text-red-600\">\r\n La contrase\u00F1a es requerida\r\n </p>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"flex items-center justify-between\">\r\n <div class=\"flex items-center\">\r\n <input id=\"remember-me\" formControlName=\"remember\" type=\"checkbox\"\r\n class=\"h-4 w-4 rounded border-slate-300 text-sky-600 focus:ring-sky-600\">\r\n <label for=\"remember-me\" class=\"ml-2 block text-sm text-slate-900\">Recordarme</label>\r\n </div>\r\n\r\n @if (recoverPasswordUrl()) {\r\n <a [href]=\"recoverPasswordUrl()\" class=\"text-sm font-medium text-sky-600 hover:text-sky-500\">\r\n {{ forgotPasswordLabel() }}\r\n </a>\r\n } @else {\r\n <a class=\"text-sm font-medium text-sky-600 hover:text-sky-500 cursor-pointer\"\r\n (click)=\"forgotPasswordClick.emit()\">\r\n {{ forgotPasswordLabel() }}\r\n </a>\r\n }\r\n </div>\r\n\r\n <div>\r\n <div>\r\n <ad-button [loading]=\"loading()\" variant=\"primary\" type=\"submit\" [block]=\"true\"\r\n class=\"w-full justify-center\" [disabled]=\"loginForm.invalid || loading()\">\r\n Iniciar Sesi\u00F3n\r\n </ad-button>\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"mt-6 text-center text-xs text-slate-400\">\r\n <p>\u00BFNecesitas ayuda? Contacta a <a [href]=\"'mailto:' + supportEmail()\"\r\n class=\"hover:text-sky-600 transition-colors\">{{ supportEmail() }}</a></p>\r\n </div>\r\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: AdInputComponent, selector: "ad-input", inputs: ["type", "placeholder", "label", "error", "rows", "disabled", "size", "prefix", "suffix"] }, { kind: "component", type: AdButtonComponent, selector: "ad-button", inputs: ["variant", "type", "disabled", "loading", "icon", "size", "block"] }] });
|
|
543
2047
|
}
|
|
544
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
2048
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdLoginComponent, decorators: [{
|
|
545
2049
|
type: Component,
|
|
546
|
-
args: [{ selector: '
|
|
2050
|
+
args: [{ selector: 'ad-login', standalone: true, imports: [
|
|
547
2051
|
CommonModule,
|
|
548
2052
|
ReactiveFormsModule,
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
NzCheckboxModule,
|
|
554
|
-
NzFormDirective,
|
|
555
|
-
NzFormControlComponent,
|
|
556
|
-
NzFormLabelComponent,
|
|
557
|
-
NzFormItemComponent
|
|
558
|
-
], template: "<div class=\"login-container\">\r\n <div class=\"login-card\">\r\n <div class=\"login-header\">\r\n @if (logoUrl) {\r\n <img [src]=\"logoUrl\" alt=\"Logo\" class=\"logo\" />\r\n } @else if (icon) {\r\n <div class=\"logo-box\">\r\n <span nz-icon [nzType]=\"icon\" nzTheme=\"fill\"></span>\r\n </div>\r\n }\r\n <h2 class=\"title\">\r\n {{ title }}\r\n @if (titleAccent) {\r\n <span class=\"accent\">{{ titleAccent }}</span>\r\n }\r\n </h2>\r\n <p class=\"subtitle text-uppercase\">{{ subtitle }}</p>\r\n </div>\r\n\r\n @if (errorMessage) {\r\n <nz-alert nzType=\"error\" [nzMessage]=\"errorMessage\" nzShowIcon class=\"error-alert\"></nz-alert>\r\n }\r\n\r\n <form [formGroup]=\"loginForm\" (ngSubmit)=\"submitForm()\" class=\"login-form\">\r\n <div class=\"form-group\">\r\n <cc-input formControlName=\"email\" placeholder=\"correo@ejemplo.com\" label=\"Correo Electr\u00F3nico\"\r\n type=\"email\" prefix=\"mail\" [error]=\"fieldInvalid('email')\">\r\n </cc-input>\r\n </div>\r\n\r\n <div class=\"form-group\">\r\n <cc-input formControlName=\"password\" placeholder=\"********\" label=\"Contrase\u00F1a\" type=\"password\"\r\n prefix=\"lock\" [error]=\"fieldInvalid('password')\">\r\n </cc-input>\r\n </div>\r\n\r\n <div class=\"form-actions-row\">\r\n <label nz-checkbox formControlName=\"remember\">Recordarme</label>\r\n @if (recoverPasswordUrl) {\r\n <a [href]=\"recoverPasswordUrl\" class=\"forgot-password\">{{ forgotPasswordLabel }}</a>\r\n } @else {\r\n <a class=\"forgot-password\" (click)=\"forgotPasswordClick.emit()\">{{ forgotPasswordLabel }}</a>\r\n }\r\n </div>\r\n\r\n <cc-button [loading]=\"loading\" variant=\"primary\" type=\"submit\" class=\"submit-button\"\r\n [disabled]=\"loginForm.invalid || loading\">\r\n Iniciar Sesi\u00F3n\r\n </cc-button>\r\n </form>\r\n\r\n <div class=\"login-footer\">\r\n <p>\u00BFNecesitas ayuda? Contacta a <a [href]=\"'mailto:' + supportEmail\">{{ supportEmail }}</a></p>\r\n </div>\r\n </div>\r\n</div>", styles: [":host{display:block;height:100%;width:100%}.login-container{display:flex;justify-content:center;align-items:center;min-height:100vh;width:100vw;overflow:hidden;background:radial-gradient(circle at top left,#0284c7,#001529);padding:1rem;box-sizing:border-box}.login-card{width:100%;max-width:380px;padding:24px;background:#fff;border-radius:8px;box-shadow:0 12px 48px #0000004d;animation:fadeIn .5s ease-out}.login-header{text-align:center;margin-bottom:24px}.login-header .logo-box{width:40px;height:40px;background:#0284c7;color:#fff;font-size:20px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;margin-bottom:12px}.login-header .logo{max-height:60px;margin-bottom:1rem;object-fit:contain}.login-header .title{font-size:20px;font-weight:700;color:#001529;margin:0;line-height:1.2}.login-header .title .accent{color:#0284c7;font-style:italic}.login-header .subtitle{font-size:10px;letter-spacing:2px;color:#8c8c8c;margin-top:4px}.error-alert{margin-bottom:16px;border-radius:4px}.login-form{display:flex;flex-direction:column;gap:16px}.form-group{display:flex;flex-direction:column;gap:4px}.error-message{color:#ff4d4f;font-size:12px;margin-top:2px;animation:slideDown .2s ease-out}.form-actions-row{display:flex;justify-content:space-between;align-items:center;font-size:12px;margin-bottom:8px}.form-actions-row ::ng-deep .ant-checkbox-wrapper span{color:#000000d9}.form-actions-row .forgot-password{color:#0284c7;text-decoration:none;cursor:pointer}.form-actions-row .forgot-password:hover{color:#0050b3;text-decoration:underline}.submit-button{width:100%;margin-top:8px}.submit-button ::ng-deep button{width:100%;height:36px;font-size:14px;font-weight:600;border-radius:4px}.login-footer{margin-top:24px;text-align:center;color:#bfbfbf;font-size:10px}.login-footer p{margin:2px 0}.login-footer a{color:#8c8c8c;text-decoration:none}.login-footer a:hover{color:#0284c7}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes slideDown{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}\n"] }]
|
|
559
|
-
}], propDecorators: { title: [{
|
|
560
|
-
type: Input
|
|
561
|
-
}], titleAccent: [{
|
|
562
|
-
type: Input
|
|
563
|
-
}], subtitle: [{
|
|
564
|
-
type: Input
|
|
565
|
-
}], logoUrl: [{
|
|
566
|
-
type: Input
|
|
567
|
-
}], icon: [{
|
|
568
|
-
type: Input
|
|
569
|
-
}], loading: [{
|
|
570
|
-
type: Input
|
|
571
|
-
}], errorMessage: [{
|
|
572
|
-
type: Input
|
|
573
|
-
}], supportEmail: [{
|
|
574
|
-
type: Input
|
|
575
|
-
}], recoverPasswordUrl: [{
|
|
576
|
-
type: Input
|
|
577
|
-
}], forgotPasswordLabel: [{
|
|
578
|
-
type: Input
|
|
579
|
-
}], loginSubmit: [{
|
|
580
|
-
type: Output
|
|
581
|
-
}], forgotPasswordClick: [{
|
|
582
|
-
type: Output
|
|
583
|
-
}] } });
|
|
2053
|
+
AdInputComponent,
|
|
2054
|
+
AdButtonComponent
|
|
2055
|
+
], template: "<div class=\"w-full max-w-md space-y-8 bg-white p-8 rounded-xl shadow-lg border border-slate-100\">\r\n <div class=\"text-center\">\r\n @if (logo()) {\r\n <img [src]=\"logo()\" alt=\"Logo\" class=\"mx-auto h-12 w-auto\" />\r\n } @else if (icon()) {\r\n <div class=\"mx-auto h-12 w-12 flex items-center justify-center rounded-full bg-sky-100 text-sky-600\">\r\n <!-- Fallback icon or remove nz-icon -->\r\n <span class=\"text-2xl font-bold\">C</span>\r\n </div>\r\n }\r\n <h2 class=\"mt-6 text-3xl font-extrabold text-cerca-navy\">\r\n {{ title() }}\r\n @if (titleAccent()) {\r\n <span class=\"accent-text\">{{ titleAccent() }}</span>\r\n }\r\n </h2>\r\n <p class=\"mt-2 text-sm text-slate-600 uppercase tracking-wide\">{{ subtitle() }}</p>\r\n </div>\r\n\r\n @if (errorMessage()) {\r\n <div class=\"bg-red-50 border-l-4 border-red-500 p-4 mb-4 rounded-md\">\r\n <div class=\"flex\">\r\n <div class=\"ml-3\">\r\n <p class=\"text-sm text-red-700\">{{ errorMessage() }}</p>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <form [formGroup]=\"loginForm\" class=\"mt-8 space-y-6\" (ngSubmit)=\"submitForm()\">\r\n <div class=\"space-y-4\">\r\n <div class=\"form-group\">\r\n <ad-input formControlName=\"email\" placeholder=\"correo@ejemplo.com\" label=\"Correo Electr\u00F3nico\"\r\n type=\"email\" prefix=\"user\" [error]=\"fieldInvalid('email')\">\r\n </ad-input>\r\n @if (fieldInvalid('email')) {\r\n <p class=\"mt-1 text-sm text-red-600\">\r\n @if (loginForm.get('email')?.hasError('required')) { El campo es requerido }\r\n @else { Ingrese un correo v\u00E1lido }\r\n </p>\r\n }\r\n </div>\r\n\r\n <div class=\"form-group\">\r\n <ad-input formControlName=\"password\" placeholder=\"********\" label=\"Contrase\u00F1a\" type=\"password\"\r\n prefix=\"lock\" [error]=\"fieldInvalid('password')\">\r\n </ad-input>\r\n @if (fieldInvalid('password')) {\r\n <p class=\"mt-1 text-sm text-red-600\">\r\n La contrase\u00F1a es requerida\r\n </p>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"flex items-center justify-between\">\r\n <div class=\"flex items-center\">\r\n <input id=\"remember-me\" formControlName=\"remember\" type=\"checkbox\"\r\n class=\"h-4 w-4 rounded border-slate-300 text-sky-600 focus:ring-sky-600\">\r\n <label for=\"remember-me\" class=\"ml-2 block text-sm text-slate-900\">Recordarme</label>\r\n </div>\r\n\r\n @if (recoverPasswordUrl()) {\r\n <a [href]=\"recoverPasswordUrl()\" class=\"text-sm font-medium text-sky-600 hover:text-sky-500\">\r\n {{ forgotPasswordLabel() }}\r\n </a>\r\n } @else {\r\n <a class=\"text-sm font-medium text-sky-600 hover:text-sky-500 cursor-pointer\"\r\n (click)=\"forgotPasswordClick.emit()\">\r\n {{ forgotPasswordLabel() }}\r\n </a>\r\n }\r\n </div>\r\n\r\n <div>\r\n <div>\r\n <ad-button [loading]=\"loading()\" variant=\"primary\" type=\"submit\" [block]=\"true\"\r\n class=\"w-full justify-center\" [disabled]=\"loginForm.invalid || loading()\">\r\n Iniciar Sesi\u00F3n\r\n </ad-button>\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"mt-6 text-center text-xs text-slate-400\">\r\n <p>\u00BFNecesitas ayuda? Contacta a <a [href]=\"'mailto:' + supportEmail()\"\r\n class=\"hover:text-sky-600 transition-colors\">{{ supportEmail() }}</a></p>\r\n </div>\r\n</div>" }]
|
|
2056
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], loginSubmit: [{ type: i0.Output, args: ["loginSubmit"] }], forgotPasswordClick: [{ type: i0.Output, args: ["forgotPasswordClick"] }] } });
|
|
584
2057
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
2058
|
+
const LoginResourceSchema = z.object({
|
|
2059
|
+
title: z.string().default('Bienvenido').optional(),
|
|
2060
|
+
titleAccent: z.string().optional(),
|
|
2061
|
+
subtitle: z.string().default('Inicia sesión para continuar').optional(),
|
|
2062
|
+
logo: z.string().optional(),
|
|
2063
|
+
icon: z.string().optional(),
|
|
2064
|
+
loading: z.boolean().default(false).optional(),
|
|
2065
|
+
errorMessage: z.string().nullable().optional(),
|
|
2066
|
+
supportEmail: z.string().default('soporte@cerca.com.co').optional(),
|
|
2067
|
+
recoverPasswordUrl: z.string().optional(),
|
|
2068
|
+
forgotPasswordLabel: z.string().default('¿Olvidaste tu clave?').optional(),
|
|
2069
|
+
});
|
|
2070
|
+
|
|
2071
|
+
const ModalResourceSchema = z.object({
|
|
2072
|
+
isOpen: z.boolean().default(false).optional(),
|
|
2073
|
+
title: z.string().default('').optional(),
|
|
2074
|
+
accentedTitle: z.string().optional(),
|
|
2075
|
+
size: z.enum(['sm', 'md', 'lg']).default('md').optional(),
|
|
2076
|
+
closeOnOverlay: z.boolean().default(true).optional(),
|
|
2077
|
+
showFooter: z.boolean().default(true).optional()
|
|
2078
|
+
});
|
|
2079
|
+
|
|
2080
|
+
class AdSidebarComponent {
|
|
2081
|
+
router;
|
|
2082
|
+
// Inputs as Signals
|
|
2083
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
2084
|
+
menuItems = computed(() => this.resource().menuItems, ...(ngDevMode ? [{ debugName: "menuItems" }] : []));
|
|
2085
|
+
collapsed = computed(() => this.resource().collapsed ?? false, ...(ngDevMode ? [{ debugName: "collapsed" }] : []));
|
|
2086
|
+
// Outputs
|
|
2087
|
+
toggleCollapse = output();
|
|
2088
|
+
navigate = output();
|
|
2089
|
+
// State
|
|
2090
|
+
expandedItems = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedItems" }] : []));
|
|
2091
|
+
constructor(router) {
|
|
2092
|
+
this.router = router;
|
|
2093
|
+
}
|
|
2094
|
+
onItemClick(item) {
|
|
2095
|
+
if (item.children && item.children.length > 0) {
|
|
2096
|
+
this.toggleSubmenu(item);
|
|
2097
|
+
}
|
|
2098
|
+
else if (item.route) {
|
|
2099
|
+
this.navigate.emit(item);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
toggleSubmenu(item) {
|
|
2103
|
+
if (this.collapsed()) {
|
|
2104
|
+
this.toggleCollapse.emit(); // Expand sidebar if clicking a submenu parent while collapsed
|
|
2105
|
+
// layout logic usually handles this, but good to emit
|
|
2106
|
+
}
|
|
2107
|
+
this.expandedItems.update(current => {
|
|
2108
|
+
const newSet = new Set(current);
|
|
2109
|
+
if (newSet.has(item.label)) {
|
|
2110
|
+
newSet.delete(item.label);
|
|
2111
|
+
}
|
|
2112
|
+
else {
|
|
2113
|
+
newSet.add(item.label);
|
|
2114
|
+
}
|
|
2115
|
+
return newSet;
|
|
2116
|
+
});
|
|
2117
|
+
}
|
|
2118
|
+
isExpanded(item) {
|
|
2119
|
+
return this.expandedItems().has(item.label);
|
|
589
2120
|
}
|
|
590
|
-
|
|
591
|
-
|
|
2121
|
+
hasActiveChild(item) {
|
|
2122
|
+
if (!item.children)
|
|
2123
|
+
return false;
|
|
2124
|
+
return item.children.some((child) => {
|
|
2125
|
+
if (child.route) {
|
|
2126
|
+
return this.router.isActive(child.route, {
|
|
2127
|
+
paths: 'subset',
|
|
2128
|
+
queryParams: 'ignored',
|
|
2129
|
+
fragment: 'ignored',
|
|
2130
|
+
matrixParams: 'ignored'
|
|
2131
|
+
});
|
|
2132
|
+
}
|
|
2133
|
+
return false;
|
|
2134
|
+
});
|
|
2135
|
+
}
|
|
2136
|
+
onToggle() {
|
|
2137
|
+
this.toggleCollapse.emit();
|
|
2138
|
+
}
|
|
2139
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdSidebarComponent, deps: [{ token: i1$2.Router }], target: i0.ɵɵFactoryTarget.Component });
|
|
2140
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdSidebarComponent, isStandalone: true, selector: "ad-sidebar", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { toggleCollapse: "toggleCollapse", navigate: "navigate" }, ngImport: i0, template: "<aside\r\n class=\"flex flex-col bg-[#002B5B] text-white transition-all duration-300 ease-in-out h-full z-30 shadow-[10px_0_40px_-15px_rgba(0,0,0,0.3)] border-r border-white/5\"\r\n [class.w-72]=\"!collapsed()\" [class.w-20]=\"collapsed()\">\r\n\r\n <!-- Logo Area -->\r\n <div\r\n class=\"p-4 flex items-center justify-center border-b border-white/5 h-20 transition-all duration-300 flex-shrink-0\">\r\n @if (collapsed()) {\r\n <!-- Isotipo (C) -->\r\n <div\r\n class=\"w-10 h-10 bg-blue-500 rounded-lg flex items-center justify-center font-bold text-lg shadow-lg animate-in fade-in zoom-in-75\">\r\n C\r\n </div>\r\n } @else {\r\n <!-- Logo Completo -->\r\n <div class=\"flex items-center gap-2 animate-in fade-in slide-in-from-left-4 duration-500\">\r\n <span class=\"text-xl font-bold tracking-tight text-blue-400\">Cerca</span>\r\n <span\r\n class=\"text-[9px] font-bold bg-white/10 px-1.5 py-0.5 rounded tracking-widest text-slate-300 border border-white/10\">ADMIN</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Menu de Navegaci\u00F3n -->\r\n <div\r\n class=\"flex-1 overflow-y-auto py-6 px-3 space-y-2 scrollbar-thin scrollbar-thumb-slate-700 scrollbar-track-transparent [&::-webkit-scrollbar]:hidden [-ms-overflow-style:'none'] [scrollbar-width:'none']\">\r\n @for (item of menuItems(); track item.label) {\r\n <!-- Group Header -->\r\n @if (item.isHeader && !collapsed()) {\r\n <h2 class=\"text-[10px] font-bold text-slate-400 tracking-[0.2em] px-4 mb-3 mt-6 uppercase opacity-70\">\r\n {{ item.label }}\r\n </h2>\r\n }\r\n\r\n @if (!item.isHeader) {\r\n <!-- Item Wrapper -->\r\n <div class=\"relative group px-1\">\r\n <!-- Standard Item or Parent -->\r\n @if (!item.children || item.children.length === 0) {\r\n <a [routerLink]=\"item.route\"\r\n [routerLinkActive]=\"['bg-[#0081C9]', 'text-white', 'shadow-[0_10px_20px_-5px_rgba(0,129,201,0.4)]']\"\r\n [routerLinkActiveOptions]=\"{ exact: item.exact || false }\" (click)=\"onItemClick(item)\"\r\n class=\"w-full flex items-center px-4 py-3 rounded-xl transition-all duration-300 group cursor-pointer text-slate-300 hover:bg-white/5 hover:text-white\"\r\n [class.justify-center]=\"collapsed()\" [class.justify-between]=\"!collapsed()\" #rla=\"routerLinkActive\">\r\n\r\n <div class=\"flex items-center gap-3\">\r\n <span class=\"transition-colors\" [class.text-white]=\"rla.isActive\"\r\n [class.text-slate-400]=\"!rla.isActive\" [class.group-hover:text-blue-300]=\"!rla.isActive\">\r\n <ad-icon [name]=\"item.icon!\" size=\"md\"></ad-icon>\r\n </span>\r\n @if (!collapsed()) {\r\n <span class=\"font-medium text-sm whitespace-nowrap\">{{ item.label }}</span>\r\n }\r\n </div>\r\n\r\n @if (item.badge && !collapsed()) {\r\n <span\r\n class=\"bg-[#4CC9FE] text-[#002B5B] text-[10px] font-bold h-5 w-5 flex items-center justify-center rounded-md shadow-sm\">\r\n {{ item.badge }}\r\n </span>\r\n }\r\n </a>\r\n } @else {\r\n <!-- Parent Item with Submenu -->\r\n <div (click)=\"toggleSubmenu(item)\"\r\n class=\"w-full flex items-center px-4 py-3 rounded-xl transition-all duration-300 cursor-pointer hover:bg-white/5 hover:text-white\"\r\n [class.bg-white/5]=\"isExpanded(item)\" [class.text-white]=\"isExpanded(item) && !hasActiveChild(item)\"\r\n [class.text-[#4CC9FE]]=\"hasActiveChild(item)\"\r\n [class.text-slate-300]=\"!isExpanded(item) && !hasActiveChild(item)\" [class.justify-center]=\"collapsed()\"\r\n [class.justify-between]=\"!collapsed()\">\r\n\r\n <div class=\"flex items-center gap-3\">\r\n <span class=\"transition-colors\" [class.text-white]=\"isExpanded(item) && !hasActiveChild(item)\"\r\n [class.text-[#4CC9FE]]=\"hasActiveChild(item)\"\r\n [class.text-slate-400]=\"!isExpanded(item) && !hasActiveChild(item)\"\r\n [class.group-hover:text-blue-300]=\"!isExpanded(item) && !hasActiveChild(item)\">\r\n <ad-icon [name]=\"item.icon!\" size=\"md\"></ad-icon>\r\n </span>\r\n @if (!collapsed()) {\r\n <span class=\"font-medium text-sm whitespace-nowrap\">{{ item.label }}</span>\r\n }\r\n </div>\r\n\r\n @if (!collapsed()) {\r\n <span class=\"transition-transform duration-300\" [class.rotate-180]=\"isExpanded(item)\">\r\n <span class=\"material-icons-outlined text-sm\">expand_more</span>\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Submenu -->\r\n @if (isExpanded(item) && !collapsed()) {\r\n <ul class=\"mt-1 ml-9 border-l border-white/10 space-y-1 animate-slide-down\">\r\n @for (subItem of item.children; track subItem.route) {\r\n <li>\r\n <a [routerLink]=\"subItem.route\" [routerLinkActive]=\"['text-white', 'font-medium']\"\r\n [routerLinkActiveOptions]=\"{ exact: subItem.exact || false }\" (click)=\"onItemClick(subItem)\"\r\n class=\"w-full block text-left px-4 py-2 text-xs text-slate-400 hover:text-white transition-colors rounded-lg\">\r\n {{ subItem.label }}\r\n </a>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n }\r\n\r\n <!-- Tooltip for collapsed state -->\r\n @if (collapsed()) {\r\n <div\r\n class=\"fixed left-20 ml-2 px-3 py-1.5 bg-slate-900 text-white text-xs rounded-md opacity-0 group-hover:opacity-100 pointer-events-none transition-all translate-x-[-10px] group-hover:translate-x-0 whitespace-nowrap z-50 shadow-2xl\">\r\n {{ item.label }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"p-4 border-t border-white/5 bg-black/10 transition-all duration-300\">\r\n <div class=\"flex items-center h-10 rounded-lg bg-white/5 border border-white/5 transition-all duration-300\"\r\n [class.justify-center]=\"collapsed()\" [class.px-4]=\"!collapsed()\">\r\n <span class=\"text-[10px] font-medium text-slate-400 tracking-widest uppercase whitespace-nowrap\">\r\n {{ collapsed() ? 'v2' : 'v2.0.0 Design' }}\r\n </span>\r\n </div>\r\n </div>\r\n</aside>", styles: ["@keyframes slideDown{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.animate-slide-down{animation:slideDown .2s ease-out forwards}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: AdIconComponent, selector: "ad-icon", inputs: ["name", "size", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
592
2141
|
}
|
|
593
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
2142
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdSidebarComponent, decorators: [{
|
|
594
2143
|
type: Component,
|
|
595
|
-
args: [{ selector: '
|
|
596
|
-
}], propDecorators: {
|
|
597
|
-
type: Input
|
|
598
|
-
}], size: [{
|
|
599
|
-
type: Input
|
|
600
|
-
}] } });
|
|
2144
|
+
args: [{ selector: 'ad-sidebar', standalone: true, imports: [CommonModule, RouterLink, RouterLinkActive, AdIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<aside\r\n class=\"flex flex-col bg-[#002B5B] text-white transition-all duration-300 ease-in-out h-full z-30 shadow-[10px_0_40px_-15px_rgba(0,0,0,0.3)] border-r border-white/5\"\r\n [class.w-72]=\"!collapsed()\" [class.w-20]=\"collapsed()\">\r\n\r\n <!-- Logo Area -->\r\n <div\r\n class=\"p-4 flex items-center justify-center border-b border-white/5 h-20 transition-all duration-300 flex-shrink-0\">\r\n @if (collapsed()) {\r\n <!-- Isotipo (C) -->\r\n <div\r\n class=\"w-10 h-10 bg-blue-500 rounded-lg flex items-center justify-center font-bold text-lg shadow-lg animate-in fade-in zoom-in-75\">\r\n C\r\n </div>\r\n } @else {\r\n <!-- Logo Completo -->\r\n <div class=\"flex items-center gap-2 animate-in fade-in slide-in-from-left-4 duration-500\">\r\n <span class=\"text-xl font-bold tracking-tight text-blue-400\">Cerca</span>\r\n <span\r\n class=\"text-[9px] font-bold bg-white/10 px-1.5 py-0.5 rounded tracking-widest text-slate-300 border border-white/10\">ADMIN</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Menu de Navegaci\u00F3n -->\r\n <div\r\n class=\"flex-1 overflow-y-auto py-6 px-3 space-y-2 scrollbar-thin scrollbar-thumb-slate-700 scrollbar-track-transparent [&::-webkit-scrollbar]:hidden [-ms-overflow-style:'none'] [scrollbar-width:'none']\">\r\n @for (item of menuItems(); track item.label) {\r\n <!-- Group Header -->\r\n @if (item.isHeader && !collapsed()) {\r\n <h2 class=\"text-[10px] font-bold text-slate-400 tracking-[0.2em] px-4 mb-3 mt-6 uppercase opacity-70\">\r\n {{ item.label }}\r\n </h2>\r\n }\r\n\r\n @if (!item.isHeader) {\r\n <!-- Item Wrapper -->\r\n <div class=\"relative group px-1\">\r\n <!-- Standard Item or Parent -->\r\n @if (!item.children || item.children.length === 0) {\r\n <a [routerLink]=\"item.route\"\r\n [routerLinkActive]=\"['bg-[#0081C9]', 'text-white', 'shadow-[0_10px_20px_-5px_rgba(0,129,201,0.4)]']\"\r\n [routerLinkActiveOptions]=\"{ exact: item.exact || false }\" (click)=\"onItemClick(item)\"\r\n class=\"w-full flex items-center px-4 py-3 rounded-xl transition-all duration-300 group cursor-pointer text-slate-300 hover:bg-white/5 hover:text-white\"\r\n [class.justify-center]=\"collapsed()\" [class.justify-between]=\"!collapsed()\" #rla=\"routerLinkActive\">\r\n\r\n <div class=\"flex items-center gap-3\">\r\n <span class=\"transition-colors\" [class.text-white]=\"rla.isActive\"\r\n [class.text-slate-400]=\"!rla.isActive\" [class.group-hover:text-blue-300]=\"!rla.isActive\">\r\n <ad-icon [name]=\"item.icon!\" size=\"md\"></ad-icon>\r\n </span>\r\n @if (!collapsed()) {\r\n <span class=\"font-medium text-sm whitespace-nowrap\">{{ item.label }}</span>\r\n }\r\n </div>\r\n\r\n @if (item.badge && !collapsed()) {\r\n <span\r\n class=\"bg-[#4CC9FE] text-[#002B5B] text-[10px] font-bold h-5 w-5 flex items-center justify-center rounded-md shadow-sm\">\r\n {{ item.badge }}\r\n </span>\r\n }\r\n </a>\r\n } @else {\r\n <!-- Parent Item with Submenu -->\r\n <div (click)=\"toggleSubmenu(item)\"\r\n class=\"w-full flex items-center px-4 py-3 rounded-xl transition-all duration-300 cursor-pointer hover:bg-white/5 hover:text-white\"\r\n [class.bg-white/5]=\"isExpanded(item)\" [class.text-white]=\"isExpanded(item) && !hasActiveChild(item)\"\r\n [class.text-[#4CC9FE]]=\"hasActiveChild(item)\"\r\n [class.text-slate-300]=\"!isExpanded(item) && !hasActiveChild(item)\" [class.justify-center]=\"collapsed()\"\r\n [class.justify-between]=\"!collapsed()\">\r\n\r\n <div class=\"flex items-center gap-3\">\r\n <span class=\"transition-colors\" [class.text-white]=\"isExpanded(item) && !hasActiveChild(item)\"\r\n [class.text-[#4CC9FE]]=\"hasActiveChild(item)\"\r\n [class.text-slate-400]=\"!isExpanded(item) && !hasActiveChild(item)\"\r\n [class.group-hover:text-blue-300]=\"!isExpanded(item) && !hasActiveChild(item)\">\r\n <ad-icon [name]=\"item.icon!\" size=\"md\"></ad-icon>\r\n </span>\r\n @if (!collapsed()) {\r\n <span class=\"font-medium text-sm whitespace-nowrap\">{{ item.label }}</span>\r\n }\r\n </div>\r\n\r\n @if (!collapsed()) {\r\n <span class=\"transition-transform duration-300\" [class.rotate-180]=\"isExpanded(item)\">\r\n <span class=\"material-icons-outlined text-sm\">expand_more</span>\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Submenu -->\r\n @if (isExpanded(item) && !collapsed()) {\r\n <ul class=\"mt-1 ml-9 border-l border-white/10 space-y-1 animate-slide-down\">\r\n @for (subItem of item.children; track subItem.route) {\r\n <li>\r\n <a [routerLink]=\"subItem.route\" [routerLinkActive]=\"['text-white', 'font-medium']\"\r\n [routerLinkActiveOptions]=\"{ exact: subItem.exact || false }\" (click)=\"onItemClick(subItem)\"\r\n class=\"w-full block text-left px-4 py-2 text-xs text-slate-400 hover:text-white transition-colors rounded-lg\">\r\n {{ subItem.label }}\r\n </a>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n }\r\n\r\n <!-- Tooltip for collapsed state -->\r\n @if (collapsed()) {\r\n <div\r\n class=\"fixed left-20 ml-2 px-3 py-1.5 bg-slate-900 text-white text-xs rounded-md opacity-0 group-hover:opacity-100 pointer-events-none transition-all translate-x-[-10px] group-hover:translate-x-0 whitespace-nowrap z-50 shadow-2xl\">\r\n {{ item.label }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"p-4 border-t border-white/5 bg-black/10 transition-all duration-300\">\r\n <div class=\"flex items-center h-10 rounded-lg bg-white/5 border border-white/5 transition-all duration-300\"\r\n [class.justify-center]=\"collapsed()\" [class.px-4]=\"!collapsed()\">\r\n <span class=\"text-[10px] font-medium text-slate-400 tracking-widest uppercase whitespace-nowrap\">\r\n {{ collapsed() ? 'v2' : 'v2.0.0 Design' }}\r\n </span>\r\n </div>\r\n </div>\r\n</aside>", styles: ["@keyframes slideDown{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.animate-slide-down{animation:slideDown .2s ease-out forwards}\n"] }]
|
|
2145
|
+
}], ctorParameters: () => [{ type: i1$2.Router }], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], toggleCollapse: [{ type: i0.Output, args: ["toggleCollapse"] }], navigate: [{ type: i0.Output, args: ["navigate"] }] } });
|
|
601
2146
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
2147
|
+
const NavItemSchema = z.lazy(() => z.object({
|
|
2148
|
+
label: z.string(),
|
|
2149
|
+
icon: z.string().optional(),
|
|
2150
|
+
route: z.string().optional(),
|
|
2151
|
+
badge: z.union([z.string(), z.number()]).optional(),
|
|
2152
|
+
badgeColor: z.string().optional(),
|
|
2153
|
+
exact: z.boolean().optional(),
|
|
2154
|
+
children: z.array(NavItemSchema).optional(),
|
|
2155
|
+
isHeader: z.boolean().optional(),
|
|
2156
|
+
}));
|
|
2157
|
+
const SidebarResourceSchema = z.object({
|
|
2158
|
+
menuItems: z.array(NavItemSchema),
|
|
2159
|
+
collapsed: z.boolean().default(false).optional(),
|
|
2160
|
+
});
|
|
2161
|
+
|
|
2162
|
+
class AdTableComponent {
|
|
2163
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
2164
|
+
data = computed(() => this.resource().data, ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
2165
|
+
columns = computed(() => this.resource().columns, ...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
2166
|
+
total = computed(() => this.resource().total, ...(ngDevMode ? [{ debugName: "total" }] : []));
|
|
2167
|
+
loading = computed(() => this.resource().loading ?? false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
2168
|
+
pageIndex = computed(() => this.resource().pageIndex ?? 1, ...(ngDevMode ? [{ debugName: "pageIndex" }] : []));
|
|
2169
|
+
pageSize = computed(() => this.resource().pageSize ?? 10, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
|
|
2170
|
+
searchPlaceholder = computed(() => this.resource().searchPlaceholder ?? 'Buscar...', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : []));
|
|
2171
|
+
pageChange = output();
|
|
2172
|
+
search = output();
|
|
2173
|
+
searchInput = new FormControl('');
|
|
2174
|
+
destroy$ = new Subject();
|
|
2175
|
+
datePipe = inject(DatePipe);
|
|
2176
|
+
currencyPipe = inject(CurrencyPipe);
|
|
2177
|
+
decimalPipe = inject(DecimalPipe);
|
|
2178
|
+
percentPipe = inject(PercentPipe);
|
|
2179
|
+
totalPages = computed(() => Math.ceil(this.total() / this.pageSize()), ...(ngDevMode ? [{ debugName: "totalPages" }] : []));
|
|
2180
|
+
isFirstPage = computed(() => this.pageIndex() === 1, ...(ngDevMode ? [{ debugName: "isFirstPage" }] : []));
|
|
2181
|
+
isLastPage = computed(() => this.pageIndex() >= this.totalPages(), ...(ngDevMode ? [{ debugName: "isLastPage" }] : []));
|
|
2182
|
+
ngOnInit() {
|
|
2183
|
+
this.searchInput.valueChanges
|
|
2184
|
+
.pipe(debounceTime$1(300), distinctUntilChanged$1(), takeUntil(this.destroy$))
|
|
2185
|
+
.subscribe((value) => {
|
|
2186
|
+
this.search.emit(value || '');
|
|
2187
|
+
});
|
|
607
2188
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
2189
|
+
ngOnDestroy() {
|
|
2190
|
+
this.destroy$.next();
|
|
2191
|
+
this.destroy$.complete();
|
|
611
2192
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
2193
|
+
onPageChange(newPage) {
|
|
2194
|
+
if (newPage >= 1 && newPage <= this.totalPages()) {
|
|
2195
|
+
this.pageChange.emit(newPage);
|
|
2196
|
+
}
|
|
615
2197
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
return '
|
|
621
|
-
|
|
2198
|
+
getAlignClass(align) {
|
|
2199
|
+
switch (align) {
|
|
2200
|
+
case 'center': return 'text-center';
|
|
2201
|
+
case 'right': return 'text-right';
|
|
2202
|
+
default: return 'text-left';
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
getCellValue(row, col) {
|
|
2206
|
+
const value = row[col.key];
|
|
2207
|
+
// 1. Prioritize function execution if context is available
|
|
2208
|
+
if (col.function_to_exec && this.resource().context) {
|
|
2209
|
+
const context = this.resource().context;
|
|
2210
|
+
if (typeof context[col.function_to_exec] === 'function') {
|
|
2211
|
+
return context[col.function_to_exec](row, col);
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
// 2. Apply pipe if specified
|
|
2215
|
+
if (col.pipe_to_apply && value !== null && value !== undefined) {
|
|
2216
|
+
return this.applyPipe(value, col.pipe_to_apply);
|
|
2217
|
+
}
|
|
2218
|
+
return value;
|
|
2219
|
+
}
|
|
2220
|
+
applyPipe(value, pipeConfig) {
|
|
2221
|
+
const [pipeName, ...args] = pipeConfig.split(':');
|
|
2222
|
+
switch (pipeName.toLowerCase()) {
|
|
2223
|
+
case 'date':
|
|
2224
|
+
return this.datePipe.transform(value, args[0] || 'mediumDate');
|
|
2225
|
+
case 'currency':
|
|
2226
|
+
return this.currencyPipe.transform(value, args[0] || 'USD', args[1] || 'symbol', args[2]);
|
|
2227
|
+
case 'number':
|
|
2228
|
+
case 'decimal':
|
|
2229
|
+
return this.decimalPipe.transform(value, args[0]);
|
|
2230
|
+
case 'percent':
|
|
2231
|
+
return this.percentPipe.transform(value, args[0]);
|
|
2232
|
+
default:
|
|
2233
|
+
return value;
|
|
2234
|
+
}
|
|
622
2235
|
}
|
|
623
|
-
static
|
|
624
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.4", type: CcStackComponent, isStandalone: true, selector: "cc-stack", inputs: { gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, justify: { classPropertyName: "justify", publicName: "justify", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.gap": "this.gapStyle", "style.align-items": "this.alignStyle", "style.justify-content": "this.justifyStyle" } }, ngImport: i0, template: "<ng-content></ng-content>", styles: [":host{display:flex;flex-direction:column;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
|
|
2236
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2237
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdTableComponent, isStandalone: true, selector: "ad-table", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { pageChange: "pageChange", search: "search" }, providers: [DatePipe, CurrencyPipe, DecimalPipe, PercentPipe], ngImport: i0, template: "<div class=\"flex flex-col h-full w-full bg-white rounded-xl shadow-sm border border-stone-200 overflow-hidden\">\r\n <!-- Header: Search & Actions -->\r\n <div class=\"flex items-center justify-between p-4 border-b border-stone-100 bg-stone-50/50 backdrop-blur-sm\">\r\n <div class=\"relative w-full max-w-sm group\">\r\n <div class=\"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none\">\r\n <svg class=\"h-4 w-4 text-stone-400 group-focus-within:text-sky-500 transition-colors\"\r\n xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\r\n <path fill-rule=\"evenodd\"\r\n d=\"M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n </div>\r\n <input [formControl]=\"searchInput\" type=\"text\"\r\n class=\"block w-full pl-10 pr-3 py-2 border border-stone-300 rounded-lg leading-5 bg-white placeholder-stone-400 focus:outline-none focus:placeholder-stone-300 focus:border-sky-500 focus:ring-1 focus:ring-sky-500 sm:text-sm transition-shadow duration-200\"\r\n [placeholder]=\"searchPlaceholder()\" />\r\n </div>\r\n <div class=\"ml-4 flex items-center\">\r\n <span\r\n class=\"text-xs font-medium text-stone-500 bg-stone-100 px-2 py-1 rounded-full border border-stone-200\">\r\n Total: <span class=\"text-stone-800 font-bold\">{{ total() }}</span>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!-- Table Container -->\r\n <div class=\"flex-1 overflow-auto relative\">\r\n <!-- Loading Overlay -->\r\n @if (loading()) {\r\n <div class=\"absolute inset-0 z-10 bg-white/60 backdrop-blur-[1px] flex justify-center items-center\">\r\n <div class=\"flex items-center gap-2 px-4 py-2 bg-white rounded-lg shadow-lg border border-stone-100\">\r\n <ad-loading size=\"md\"></ad-loading>\r\n <span class=\"text-sm font-medium text-stone-600\">Cargando datos...</span>\r\n </div>\r\n </div>\r\n }\r\n\r\n <table class=\"min-w-full divide-y divide-stone-200\">\r\n <thead class=\"bg-stone-50 sticky top-0 z-0 is-header\">\r\n <tr>\r\n @for (col of columns(); track col.key) {\r\n <th scope=\"col\"\r\n class=\"px-6 py-3 text-xs font-semibold text-stone-500 uppercase tracking-wider whitespace-nowrap\"\r\n [style.width]=\"col.width\" [class]=\"getAlignClass(col.align)\">\r\n {{ col.label }}\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody class=\"bg-white divide-y divide-stone-100\">\r\n @if (data().length === 0 && !loading()) {\r\n <tr>\r\n <td [attr.colspan]=\"columns().length\" class=\"px-6 py-12 text-center\">\r\n <div class=\"flex flex-col items-center justify-center text-stone-400\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\" class=\"w-12 h-12 mb-3 opacity-50\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n d=\"M20.25 7.5l-.625 10.632a2.25 2.25 0 01-2.247 2.118H6.622a2.25 2.25 0 01-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z\" />\r\n </svg>\r\n <p class=\"text-base font-medium text-stone-900\">Sin datos disponibles</p>\r\n <p class=\"text-sm\">No se encontraron registros para mostrar.</p>\r\n </div>\r\n </td>\r\n </tr>\r\n } @else {\r\n @for (row of data(); track row) {\r\n <tr class=\"hover:bg-sky-50/50 transition-colors duration-150 group\">\r\n @for (col of columns(); track col.key) {\r\n <td class=\"px-6 py-4 whitespace-nowrap text-sm text-stone-700 border-b border-transparent group-hover:border-sky-100\"\r\n [class]=\"getAlignClass(col.align)\">\r\n {{ getCellValue(row, col) }}\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <!-- Footer: Pagination -->\r\n <div class=\"bg-white px-4 py-3 flex items-center justify-between border-t border-stone-200 sm:px-6\">\r\n <div class=\"flex-1 flex justify-between sm:hidden\">\r\n <button [disabled]=\"isFirstPage()\" (click)=\"onPageChange(pageIndex() - 1)\"\r\n class=\"relative inline-flex items-center px-4 py-2 border border-stone-300 text-sm font-medium rounded-md text-stone-700 bg-white hover:bg-stone-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\">\r\n Anterior\r\n </button>\r\n <button [disabled]=\"isLastPage()\" (click)=\"onPageChange(pageIndex() + 1)\"\r\n class=\"ml-3 relative inline-flex items-center px-4 py-2 border border-stone-300 text-sm font-medium rounded-md text-stone-700 bg-white hover:bg-stone-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\">\r\n Siguiente\r\n </button>\r\n </div>\r\n <div class=\"hidden sm:flex-1 sm:flex sm:items-center sm:justify-between\">\r\n <div>\r\n <p class=\"text-sm text-stone-500\">\r\n Mostrando p\u00E1gina <span class=\"font-medium text-stone-900\">{{ pageIndex() }}</span> de <span\r\n class=\"font-medium text-stone-900\">{{ totalPages() }}</span>\r\n </p>\r\n </div>\r\n <div>\r\n <nav class=\"relative z-0 inline-flex rounded-md shadow-sm -space-x-px\" aria-label=\"Pagination\">\r\n <button [disabled]=\"isFirstPage()\" (click)=\"onPageChange(pageIndex() - 1)\"\r\n class=\"relative inline-flex items-center px-2 py-2 rounded-l-md border border-stone-300 bg-white text-sm font-medium text-stone-500 hover:bg-stone-50 disabled:opacity-50 disabled:cursor-not-allowed focus:z-10 focus:outline-none focus:ring-1 focus:ring-sky-500 focus:border-sky-500 transition-colors\">\r\n <span class=\"sr-only\">Anterior</span>\r\n <!-- Heroicon: chevron-left -->\r\n <svg class=\"h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\r\n aria-hidden=\"true\">\r\n <path fill-rule=\"evenodd\"\r\n d=\"M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n </button>\r\n <button [disabled]=\"isLastPage()\" (click)=\"onPageChange(pageIndex() + 1)\"\r\n class=\"relative inline-flex items-center px-2 py-2 rounded-r-md border border-stone-300 bg-white text-sm font-medium text-stone-500 hover:bg-stone-50 disabled:opacity-50 disabled:cursor-not-allowed focus:z-10 focus:outline-none focus:ring-1 focus:ring-sky-500 focus:border-sky-500 transition-colors\">\r\n <span class=\"sr-only\">Siguiente</span>\r\n <!-- Heroicon: chevron-right -->\r\n <svg class=\"h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\r\n aria-hidden=\"true\">\r\n <path fill-rule=\"evenodd\"\r\n d=\"M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n </button>\r\n </nav>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: AdLoadingComponent, selector: "ad-loading", inputs: ["size", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
625
2238
|
}
|
|
626
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
2239
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdTableComponent, decorators: [{
|
|
627
2240
|
type: Component,
|
|
628
|
-
args: [{ selector: '
|
|
629
|
-
}], propDecorators: {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
2241
|
+
args: [{ selector: 'ad-table', standalone: true, imports: [CommonModule, ReactiveFormsModule, AdLoadingComponent], providers: [DatePipe, CurrencyPipe, DecimalPipe, PercentPipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex flex-col h-full w-full bg-white rounded-xl shadow-sm border border-stone-200 overflow-hidden\">\r\n <!-- Header: Search & Actions -->\r\n <div class=\"flex items-center justify-between p-4 border-b border-stone-100 bg-stone-50/50 backdrop-blur-sm\">\r\n <div class=\"relative w-full max-w-sm group\">\r\n <div class=\"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none\">\r\n <svg class=\"h-4 w-4 text-stone-400 group-focus-within:text-sky-500 transition-colors\"\r\n xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\r\n <path fill-rule=\"evenodd\"\r\n d=\"M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n </div>\r\n <input [formControl]=\"searchInput\" type=\"text\"\r\n class=\"block w-full pl-10 pr-3 py-2 border border-stone-300 rounded-lg leading-5 bg-white placeholder-stone-400 focus:outline-none focus:placeholder-stone-300 focus:border-sky-500 focus:ring-1 focus:ring-sky-500 sm:text-sm transition-shadow duration-200\"\r\n [placeholder]=\"searchPlaceholder()\" />\r\n </div>\r\n <div class=\"ml-4 flex items-center\">\r\n <span\r\n class=\"text-xs font-medium text-stone-500 bg-stone-100 px-2 py-1 rounded-full border border-stone-200\">\r\n Total: <span class=\"text-stone-800 font-bold\">{{ total() }}</span>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!-- Table Container -->\r\n <div class=\"flex-1 overflow-auto relative\">\r\n <!-- Loading Overlay -->\r\n @if (loading()) {\r\n <div class=\"absolute inset-0 z-10 bg-white/60 backdrop-blur-[1px] flex justify-center items-center\">\r\n <div class=\"flex items-center gap-2 px-4 py-2 bg-white rounded-lg shadow-lg border border-stone-100\">\r\n <ad-loading size=\"md\"></ad-loading>\r\n <span class=\"text-sm font-medium text-stone-600\">Cargando datos...</span>\r\n </div>\r\n </div>\r\n }\r\n\r\n <table class=\"min-w-full divide-y divide-stone-200\">\r\n <thead class=\"bg-stone-50 sticky top-0 z-0 is-header\">\r\n <tr>\r\n @for (col of columns(); track col.key) {\r\n <th scope=\"col\"\r\n class=\"px-6 py-3 text-xs font-semibold text-stone-500 uppercase tracking-wider whitespace-nowrap\"\r\n [style.width]=\"col.width\" [class]=\"getAlignClass(col.align)\">\r\n {{ col.label }}\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody class=\"bg-white divide-y divide-stone-100\">\r\n @if (data().length === 0 && !loading()) {\r\n <tr>\r\n <td [attr.colspan]=\"columns().length\" class=\"px-6 py-12 text-center\">\r\n <div class=\"flex flex-col items-center justify-center text-stone-400\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\r\n stroke=\"currentColor\" class=\"w-12 h-12 mb-3 opacity-50\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\r\n d=\"M20.25 7.5l-.625 10.632a2.25 2.25 0 01-2.247 2.118H6.622a2.25 2.25 0 01-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z\" />\r\n </svg>\r\n <p class=\"text-base font-medium text-stone-900\">Sin datos disponibles</p>\r\n <p class=\"text-sm\">No se encontraron registros para mostrar.</p>\r\n </div>\r\n </td>\r\n </tr>\r\n } @else {\r\n @for (row of data(); track row) {\r\n <tr class=\"hover:bg-sky-50/50 transition-colors duration-150 group\">\r\n @for (col of columns(); track col.key) {\r\n <td class=\"px-6 py-4 whitespace-nowrap text-sm text-stone-700 border-b border-transparent group-hover:border-sky-100\"\r\n [class]=\"getAlignClass(col.align)\">\r\n {{ getCellValue(row, col) }}\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <!-- Footer: Pagination -->\r\n <div class=\"bg-white px-4 py-3 flex items-center justify-between border-t border-stone-200 sm:px-6\">\r\n <div class=\"flex-1 flex justify-between sm:hidden\">\r\n <button [disabled]=\"isFirstPage()\" (click)=\"onPageChange(pageIndex() - 1)\"\r\n class=\"relative inline-flex items-center px-4 py-2 border border-stone-300 text-sm font-medium rounded-md text-stone-700 bg-white hover:bg-stone-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\">\r\n Anterior\r\n </button>\r\n <button [disabled]=\"isLastPage()\" (click)=\"onPageChange(pageIndex() + 1)\"\r\n class=\"ml-3 relative inline-flex items-center px-4 py-2 border border-stone-300 text-sm font-medium rounded-md text-stone-700 bg-white hover:bg-stone-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\">\r\n Siguiente\r\n </button>\r\n </div>\r\n <div class=\"hidden sm:flex-1 sm:flex sm:items-center sm:justify-between\">\r\n <div>\r\n <p class=\"text-sm text-stone-500\">\r\n Mostrando p\u00E1gina <span class=\"font-medium text-stone-900\">{{ pageIndex() }}</span> de <span\r\n class=\"font-medium text-stone-900\">{{ totalPages() }}</span>\r\n </p>\r\n </div>\r\n <div>\r\n <nav class=\"relative z-0 inline-flex rounded-md shadow-sm -space-x-px\" aria-label=\"Pagination\">\r\n <button [disabled]=\"isFirstPage()\" (click)=\"onPageChange(pageIndex() - 1)\"\r\n class=\"relative inline-flex items-center px-2 py-2 rounded-l-md border border-stone-300 bg-white text-sm font-medium text-stone-500 hover:bg-stone-50 disabled:opacity-50 disabled:cursor-not-allowed focus:z-10 focus:outline-none focus:ring-1 focus:ring-sky-500 focus:border-sky-500 transition-colors\">\r\n <span class=\"sr-only\">Anterior</span>\r\n <!-- Heroicon: chevron-left -->\r\n <svg class=\"h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\r\n aria-hidden=\"true\">\r\n <path fill-rule=\"evenodd\"\r\n d=\"M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n </button>\r\n <button [disabled]=\"isLastPage()\" (click)=\"onPageChange(pageIndex() + 1)\"\r\n class=\"relative inline-flex items-center px-2 py-2 rounded-r-md border border-stone-300 bg-white text-sm font-medium text-stone-500 hover:bg-stone-50 disabled:opacity-50 disabled:cursor-not-allowed focus:z-10 focus:outline-none focus:ring-1 focus:ring-sky-500 focus:border-sky-500 transition-colors\">\r\n <span class=\"sr-only\">Siguiente</span>\r\n <!-- Heroicon: chevron-right -->\r\n <svg class=\"h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\r\n aria-hidden=\"true\">\r\n <path fill-rule=\"evenodd\"\r\n d=\"M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n </button>\r\n </nav>\r\n </div>\r\n </div>\r\n </div>\r\n</div>" }]
|
|
2242
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], search: [{ type: i0.Output, args: ["search"] }] } });
|
|
2243
|
+
|
|
2244
|
+
const AdTableColumnSchema = z.object({
|
|
2245
|
+
key: z.string(),
|
|
2246
|
+
label: z.string(),
|
|
2247
|
+
width: z.string().optional(),
|
|
2248
|
+
align: z.enum(['left', 'center', 'right']).optional(),
|
|
2249
|
+
pipe_to_apply: z.string().optional(),
|
|
2250
|
+
function_to_exec: z.string().optional(),
|
|
2251
|
+
});
|
|
2252
|
+
const TableResourceSchema = z.object({
|
|
2253
|
+
data: z.array(z.any()),
|
|
2254
|
+
columns: z.array(AdTableColumnSchema),
|
|
2255
|
+
total: z.number(),
|
|
2256
|
+
loading: z.boolean().default(false).optional(),
|
|
2257
|
+
pageIndex: z.number().default(1).optional(),
|
|
2258
|
+
pageSize: z.number().default(10).optional(),
|
|
2259
|
+
searchPlaceholder: z.string().default('Buscar...').optional(),
|
|
2260
|
+
context: z.any().optional(),
|
|
2261
|
+
});
|
|
2262
|
+
|
|
2263
|
+
class AdDocViewerComponent {
|
|
2264
|
+
injector;
|
|
2265
|
+
// Inputs
|
|
2266
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
2267
|
+
showCode = input(true, ...(ngDevMode ? [{ debugName: "showCode" }] : []));
|
|
2268
|
+
showApi = input(true, ...(ngDevMode ? [{ debugName: "showApi" }] : []));
|
|
2269
|
+
id = computed(() => this.resource().id, ...(ngDevMode ? [{ debugName: "id" }] : []));
|
|
2270
|
+
name = computed(() => this.resource().name, ...(ngDevMode ? [{ debugName: "name" }] : []));
|
|
2271
|
+
category = computed(() => this.resource().category, ...(ngDevMode ? [{ debugName: "category" }] : []));
|
|
2272
|
+
description = computed(() => this.resource().description, ...(ngDevMode ? [{ debugName: "description" }] : []));
|
|
2273
|
+
selector = computed(() => this.resource().selector, ...(ngDevMode ? [{ debugName: "selector" }] : []));
|
|
2274
|
+
codeSnippet = computed(() => this.resource().codeSnippet, ...(ngDevMode ? [{ debugName: "codeSnippet" }] : []));
|
|
2275
|
+
api = computed(() => this.resource().api, ...(ngDevMode ? [{ debugName: "api" }] : []));
|
|
2276
|
+
variants = computed(() => this.resource().variants, ...(ngDevMode ? [{ debugName: "variants" }] : []));
|
|
2277
|
+
// Outputs
|
|
2278
|
+
tabChange = output();
|
|
2279
|
+
// Estado interno
|
|
2280
|
+
activeTab = signal('preview', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
|
|
2281
|
+
activeVariant = signal('', ...(ngDevMode ? [{ debugName: "activeVariant" }] : []));
|
|
2282
|
+
copied = signal(false, ...(ngDevMode ? [{ debugName: "copied" }] : []));
|
|
2283
|
+
viewReady = signal(false, ...(ngDevMode ? [{ debugName: "viewReady" }] : []));
|
|
2284
|
+
// Tabs disponibles
|
|
2285
|
+
tabs = computed(() => [
|
|
2286
|
+
{ id: 'preview', label: 'Preview' },
|
|
2287
|
+
...(this.showApi() ? [{ id: 'api', label: 'API' }] : []),
|
|
2288
|
+
...(this.showCode() ? [{ id: 'code', label: 'Código' }] : []),
|
|
2289
|
+
], ...(ngDevMode ? [{ debugName: "tabs" }] : []));
|
|
2290
|
+
previewHost;
|
|
2291
|
+
constructor(injector) {
|
|
2292
|
+
this.injector = injector;
|
|
2293
|
+
effect(() => {
|
|
2294
|
+
const res = this.resource();
|
|
2295
|
+
const tab = this.activeTab();
|
|
2296
|
+
// viewReady se activará en ngAfterViewInit
|
|
2297
|
+
if (this.viewReady() && tab === 'preview') {
|
|
2298
|
+
this.renderPreview(res);
|
|
2299
|
+
}
|
|
2300
|
+
});
|
|
2301
|
+
}
|
|
2302
|
+
ngAfterViewInit() {
|
|
2303
|
+
this.viewReady.set(true);
|
|
2304
|
+
if (this.activeTab() === 'preview') {
|
|
2305
|
+
this.renderPreview(this.resource());
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
setTab(tab) {
|
|
2309
|
+
this.activeTab.set(tab);
|
|
2310
|
+
this.tabChange.emit(tab);
|
|
2311
|
+
if (tab === 'preview') {
|
|
2312
|
+
// Pequeño delay para que el ViewChild esté disponible tras el @if
|
|
2313
|
+
setTimeout(() => this.renderPreview(this.resource()), 0);
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
setVariant(variant) {
|
|
2317
|
+
this.activeVariant.set(variant.label);
|
|
2318
|
+
this.renderPreview(this.resource(), variant.resource);
|
|
2319
|
+
}
|
|
2320
|
+
copyCode() {
|
|
2321
|
+
navigator.clipboard.writeText(this.resource().codeSnippet).then(() => {
|
|
2322
|
+
this.copied.set(true);
|
|
2323
|
+
setTimeout(() => this.copied.set(false), 2000);
|
|
2324
|
+
});
|
|
2325
|
+
}
|
|
2326
|
+
renderPreview(res, overrideResource) {
|
|
2327
|
+
if (!this.previewHost)
|
|
2328
|
+
return;
|
|
2329
|
+
this.previewHost.clear();
|
|
2330
|
+
try {
|
|
2331
|
+
const ref = createComponent(res.component, {
|
|
2332
|
+
environmentInjector: this.injector,
|
|
2333
|
+
elementInjector: this.previewHost.injector,
|
|
2334
|
+
});
|
|
2335
|
+
const inputs = overrideResource ?? res.previewResource ?? {};
|
|
2336
|
+
Object.entries(inputs).forEach(([key, val]) => {
|
|
2337
|
+
try {
|
|
2338
|
+
ref.setInput(key, val);
|
|
2339
|
+
}
|
|
2340
|
+
catch { /* input no encontrado, se ignora */ }
|
|
2341
|
+
});
|
|
2342
|
+
this.previewHost.insert(ref.hostView);
|
|
2343
|
+
}
|
|
2344
|
+
catch (e) {
|
|
2345
|
+
console.warn('[ad-doc-viewer] No se pudo renderizar el preview:', e);
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdDocViewerComponent, deps: [{ token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Component });
|
|
2349
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdDocViewerComponent, isStandalone: true, selector: "ad-doc-viewer", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null }, showCode: { classPropertyName: "showCode", publicName: "showCode", isSignal: true, isRequired: false, transformFunction: null }, showApi: { classPropertyName: "showApi", publicName: "showApi", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { tabChange: "tabChange" }, viewQueries: [{ propertyName: "previewHost", first: true, predicate: ["previewHost"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "<section class=\"flex flex-col gap-6 p-6 bg-white rounded-2xl border border-stone-200 shadow-sm\">\r\n\r\n <!-- Header del componente -->\r\n <div class=\"flex items-start justify-between\">\r\n <div class=\"flex flex-col gap-1\">\r\n <div class=\"flex items-center gap-2 flex-wrap\">\r\n <span\r\n class=\"text-xs font-semibold px-2 py-0.5 rounded-full bg-sky-100 text-sky-700 uppercase tracking-wide\">\r\n {{ category() }}\r\n </span>\r\n <code class=\"text-xs px-2 py-0.5 rounded-md bg-stone-100 text-stone-600 font-mono\">\r\n {{ selector() }}\r\n </code>\r\n </div>\r\n <h2 class=\"text-xl font-bold text-stone-900 mt-1\">{{ name() }}</h2>\r\n <p class=\"text-sm text-stone-500 max-w-xl\">{{ description() }}</p>\r\n </div>\r\n </div>\r\n\r\n <!-- Tabs de navegaci\u00F3n -->\r\n <div class=\"flex gap-1 border-b border-stone-200\">\r\n @for (tab of tabs(); track tab.id) {\r\n <button\r\n class=\"px-4 py-2 text-sm font-medium transition-colors rounded-t-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-sky-500\"\r\n [class]=\"activeTab() === tab.id\r\n ? 'text-sky-600 border-b-2 border-sky-600 -mb-px bg-sky-50'\r\n : 'text-stone-500 hover:text-stone-700 hover:bg-stone-50'\" (click)=\"setTab(tab.id)\"\r\n [attr.aria-selected]=\"activeTab() === tab.id\" role=\"tab\">\r\n {{ tab.label }}\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Panel: Preview -->\r\n @if (activeTab() === 'preview') {\r\n <div class=\"flex flex-col gap-4\">\r\n <!-- Canvas con fondo ajedrezado -->\r\n <div class=\"flex items-center justify-center min-h-40 rounded-xl border border-dashed border-stone-300\r\n p-8 overflow-auto\"\r\n style=\"background-image: linear-gradient(45deg, #f5f5f4 25%, transparent 25%, transparent 75%, #f5f5f4 75%, #f5f5f4), linear-gradient(45deg, #f5f5f4 25%, transparent 25%, transparent 75%, #f5f5f4 75%, #f5f5f4); background-size: 16px 16px; background-position: 0 0, 8px 8px;\">\r\n <ng-container #previewHost></ng-container>\r\n </div>\r\n\r\n <!-- Variantes -->\r\n @if (variants()?.length) {\r\n <div class=\"flex flex-wrap gap-2\">\r\n <span\r\n class=\"text-xs font-semibold text-stone-400 uppercase tracking-wider self-center mr-1\">Variante:</span>\r\n @for (variant of variants()!; track variant.label) {\r\n <button\r\n class=\"px-3 py-1.5 text-xs font-medium rounded-lg border transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-sky-500\"\r\n [class]=\"activeVariant() === variant.label\r\n ? 'bg-sky-600 border-sky-600 text-white shadow-sm'\r\n : 'border-stone-300 text-stone-600 hover:border-sky-400 hover:text-sky-600 bg-white'\"\r\n (click)=\"setVariant(variant)\">\r\n {{ variant.label }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Panel: API -->\r\n @if (activeTab() === 'api' && showApi()) {\r\n <div class=\"flex flex-col gap-6\">\r\n\r\n <!-- Inputs -->\r\n @if (api().inputs.length) {\r\n <div class=\"flex flex-col gap-2\">\r\n <h3 class=\"text-xs font-semibold text-stone-500 uppercase tracking-widest\">Inputs</h3>\r\n <div class=\"overflow-hidden rounded-xl border border-stone-200\">\r\n <table class=\"w-full text-sm\">\r\n <thead class=\"bg-stone-50 text-stone-500 text-left\">\r\n <tr>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Nombre</th>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Tipo</th>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Requerido</th>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Default</th>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Descripci\u00F3n</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (inp of api().inputs; track inp.name) {\r\n <tr class=\"border-t border-stone-100 hover:bg-stone-50 transition-colors\">\r\n <td class=\"px-4 py-3\">\r\n <code class=\"text-sky-600 font-mono text-xs\">{{ inp.name }}</code>\r\n </td>\r\n <td class=\"px-4 py-3\">\r\n <code class=\"text-emerald-600 font-mono text-xs\">{{ inp.type }}</code>\r\n </td>\r\n <td class=\"px-4 py-3\">\r\n @if (inp.required) {\r\n <span\r\n class=\"text-xs px-1.5 py-0.5 rounded-full bg-rose-100 text-rose-600 font-medium\">S\u00ED</span>\r\n } @else {\r\n <span class=\"text-xs px-1.5 py-0.5 rounded-full bg-stone-100 text-stone-500\">No</span>\r\n }\r\n </td>\r\n <td class=\"px-4 py-3 text-stone-400 font-mono text-xs\">{{ inp.defaultValue || '\u2014' }}</td>\r\n <td class=\"px-4 py-3 text-stone-600 text-xs\">{{ inp.description }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Outputs -->\r\n @if (api().outputs.length) {\r\n <div class=\"flex flex-col gap-2\">\r\n <h3 class=\"text-xs font-semibold text-stone-500 uppercase tracking-widest\">Outputs</h3>\r\n <div class=\"overflow-hidden rounded-xl border border-stone-200\">\r\n <table class=\"w-full text-sm\">\r\n <thead class=\"bg-stone-50 text-stone-500 text-left\">\r\n <tr>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Nombre</th>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Tipo de Evento</th>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Descripci\u00F3n</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (out of api().outputs; track out.name) {\r\n <tr class=\"border-t border-stone-100 hover:bg-stone-50 transition-colors\">\r\n <td class=\"px-4 py-3\">\r\n <code class=\"text-amber-600 font-mono text-xs\">({{ out.name }})</code>\r\n </td>\r\n <td class=\"px-4 py-3\">\r\n <code class=\"text-emerald-600 font-mono text-xs\">{{ out.eventType }}</code>\r\n </td>\r\n <td class=\"px-4 py-3 text-stone-600 text-xs\">{{ out.description }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (!api().inputs.length && !api().outputs.length) {\r\n <p class=\"text-sm text-stone-400 italic\">No hay API documentada para este componente.</p>\r\n }\r\n\r\n </div>\r\n }\r\n\r\n <!-- Panel: C\u00F3digo -->\r\n @if (activeTab() === 'code' && showCode()) {\r\n <div class=\"relative rounded-xl overflow-hidden border border-stone-200\">\r\n <!-- Toolbar del bloque de c\u00F3digo -->\r\n <div class=\"flex items-center justify-between px-4 py-2.5 bg-stone-800\">\r\n <span class=\"text-xs text-stone-400 font-mono uppercase tracking-wider\">HTML</span>\r\n <button\r\n class=\"text-xs flex items-center gap-1.5 transition-colors px-2 py-1 rounded focus:outline-none focus-visible:ring-2 focus-visible:ring-sky-500\"\r\n [class]=\"copied() ? 'text-emerald-400 font-medium' : 'text-stone-400 hover:text-white'\"\r\n (click)=\"copyCode()\">\r\n @if (copied()) {\r\n <span>\u2713 Copiado</span>\r\n } @else {\r\n <span>Copiar</span>\r\n }\r\n </button>\r\n </div>\r\n <!-- Bloque de c\u00F3digo -->\r\n <pre\r\n class=\"bg-stone-900 p-5 overflow-x-auto text-sm font-mono text-stone-200 leading-relaxed whitespace-pre m-0\">{{ codeSnippet() }}</pre>\r\n </div>\r\n }\r\n\r\n</section>", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2350
|
+
}
|
|
2351
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdDocViewerComponent, decorators: [{
|
|
2352
|
+
type: Component,
|
|
2353
|
+
args: [{ selector: 'ad-doc-viewer', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"flex flex-col gap-6 p-6 bg-white rounded-2xl border border-stone-200 shadow-sm\">\r\n\r\n <!-- Header del componente -->\r\n <div class=\"flex items-start justify-between\">\r\n <div class=\"flex flex-col gap-1\">\r\n <div class=\"flex items-center gap-2 flex-wrap\">\r\n <span\r\n class=\"text-xs font-semibold px-2 py-0.5 rounded-full bg-sky-100 text-sky-700 uppercase tracking-wide\">\r\n {{ category() }}\r\n </span>\r\n <code class=\"text-xs px-2 py-0.5 rounded-md bg-stone-100 text-stone-600 font-mono\">\r\n {{ selector() }}\r\n </code>\r\n </div>\r\n <h2 class=\"text-xl font-bold text-stone-900 mt-1\">{{ name() }}</h2>\r\n <p class=\"text-sm text-stone-500 max-w-xl\">{{ description() }}</p>\r\n </div>\r\n </div>\r\n\r\n <!-- Tabs de navegaci\u00F3n -->\r\n <div class=\"flex gap-1 border-b border-stone-200\">\r\n @for (tab of tabs(); track tab.id) {\r\n <button\r\n class=\"px-4 py-2 text-sm font-medium transition-colors rounded-t-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-sky-500\"\r\n [class]=\"activeTab() === tab.id\r\n ? 'text-sky-600 border-b-2 border-sky-600 -mb-px bg-sky-50'\r\n : 'text-stone-500 hover:text-stone-700 hover:bg-stone-50'\" (click)=\"setTab(tab.id)\"\r\n [attr.aria-selected]=\"activeTab() === tab.id\" role=\"tab\">\r\n {{ tab.label }}\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Panel: Preview -->\r\n @if (activeTab() === 'preview') {\r\n <div class=\"flex flex-col gap-4\">\r\n <!-- Canvas con fondo ajedrezado -->\r\n <div class=\"flex items-center justify-center min-h-40 rounded-xl border border-dashed border-stone-300\r\n p-8 overflow-auto\"\r\n style=\"background-image: linear-gradient(45deg, #f5f5f4 25%, transparent 25%, transparent 75%, #f5f5f4 75%, #f5f5f4), linear-gradient(45deg, #f5f5f4 25%, transparent 25%, transparent 75%, #f5f5f4 75%, #f5f5f4); background-size: 16px 16px; background-position: 0 0, 8px 8px;\">\r\n <ng-container #previewHost></ng-container>\r\n </div>\r\n\r\n <!-- Variantes -->\r\n @if (variants()?.length) {\r\n <div class=\"flex flex-wrap gap-2\">\r\n <span\r\n class=\"text-xs font-semibold text-stone-400 uppercase tracking-wider self-center mr-1\">Variante:</span>\r\n @for (variant of variants()!; track variant.label) {\r\n <button\r\n class=\"px-3 py-1.5 text-xs font-medium rounded-lg border transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-sky-500\"\r\n [class]=\"activeVariant() === variant.label\r\n ? 'bg-sky-600 border-sky-600 text-white shadow-sm'\r\n : 'border-stone-300 text-stone-600 hover:border-sky-400 hover:text-sky-600 bg-white'\"\r\n (click)=\"setVariant(variant)\">\r\n {{ variant.label }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Panel: API -->\r\n @if (activeTab() === 'api' && showApi()) {\r\n <div class=\"flex flex-col gap-6\">\r\n\r\n <!-- Inputs -->\r\n @if (api().inputs.length) {\r\n <div class=\"flex flex-col gap-2\">\r\n <h3 class=\"text-xs font-semibold text-stone-500 uppercase tracking-widest\">Inputs</h3>\r\n <div class=\"overflow-hidden rounded-xl border border-stone-200\">\r\n <table class=\"w-full text-sm\">\r\n <thead class=\"bg-stone-50 text-stone-500 text-left\">\r\n <tr>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Nombre</th>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Tipo</th>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Requerido</th>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Default</th>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Descripci\u00F3n</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (inp of api().inputs; track inp.name) {\r\n <tr class=\"border-t border-stone-100 hover:bg-stone-50 transition-colors\">\r\n <td class=\"px-4 py-3\">\r\n <code class=\"text-sky-600 font-mono text-xs\">{{ inp.name }}</code>\r\n </td>\r\n <td class=\"px-4 py-3\">\r\n <code class=\"text-emerald-600 font-mono text-xs\">{{ inp.type }}</code>\r\n </td>\r\n <td class=\"px-4 py-3\">\r\n @if (inp.required) {\r\n <span\r\n class=\"text-xs px-1.5 py-0.5 rounded-full bg-rose-100 text-rose-600 font-medium\">S\u00ED</span>\r\n } @else {\r\n <span class=\"text-xs px-1.5 py-0.5 rounded-full bg-stone-100 text-stone-500\">No</span>\r\n }\r\n </td>\r\n <td class=\"px-4 py-3 text-stone-400 font-mono text-xs\">{{ inp.defaultValue || '\u2014' }}</td>\r\n <td class=\"px-4 py-3 text-stone-600 text-xs\">{{ inp.description }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Outputs -->\r\n @if (api().outputs.length) {\r\n <div class=\"flex flex-col gap-2\">\r\n <h3 class=\"text-xs font-semibold text-stone-500 uppercase tracking-widest\">Outputs</h3>\r\n <div class=\"overflow-hidden rounded-xl border border-stone-200\">\r\n <table class=\"w-full text-sm\">\r\n <thead class=\"bg-stone-50 text-stone-500 text-left\">\r\n <tr>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Nombre</th>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Tipo de Evento</th>\r\n <th class=\"px-4 py-2.5 font-medium text-xs\">Descripci\u00F3n</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (out of api().outputs; track out.name) {\r\n <tr class=\"border-t border-stone-100 hover:bg-stone-50 transition-colors\">\r\n <td class=\"px-4 py-3\">\r\n <code class=\"text-amber-600 font-mono text-xs\">({{ out.name }})</code>\r\n </td>\r\n <td class=\"px-4 py-3\">\r\n <code class=\"text-emerald-600 font-mono text-xs\">{{ out.eventType }}</code>\r\n </td>\r\n <td class=\"px-4 py-3 text-stone-600 text-xs\">{{ out.description }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (!api().inputs.length && !api().outputs.length) {\r\n <p class=\"text-sm text-stone-400 italic\">No hay API documentada para este componente.</p>\r\n }\r\n\r\n </div>\r\n }\r\n\r\n <!-- Panel: C\u00F3digo -->\r\n @if (activeTab() === 'code' && showCode()) {\r\n <div class=\"relative rounded-xl overflow-hidden border border-stone-200\">\r\n <!-- Toolbar del bloque de c\u00F3digo -->\r\n <div class=\"flex items-center justify-between px-4 py-2.5 bg-stone-800\">\r\n <span class=\"text-xs text-stone-400 font-mono uppercase tracking-wider\">HTML</span>\r\n <button\r\n class=\"text-xs flex items-center gap-1.5 transition-colors px-2 py-1 rounded focus:outline-none focus-visible:ring-2 focus-visible:ring-sky-500\"\r\n [class]=\"copied() ? 'text-emerald-400 font-medium' : 'text-stone-400 hover:text-white'\"\r\n (click)=\"copyCode()\">\r\n @if (copied()) {\r\n <span>\u2713 Copiado</span>\r\n } @else {\r\n <span>Copiar</span>\r\n }\r\n </button>\r\n </div>\r\n <!-- Bloque de c\u00F3digo -->\r\n <pre\r\n class=\"bg-stone-900 p-5 overflow-x-auto text-sm font-mono text-stone-200 leading-relaxed whitespace-pre m-0\">{{ codeSnippet() }}</pre>\r\n </div>\r\n }\r\n\r\n</section>" }]
|
|
2354
|
+
}], ctorParameters: () => [{ type: i0.EnvironmentInjector }], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], showCode: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCode", required: false }] }], showApi: [{ type: i0.Input, args: [{ isSignal: true, alias: "showApi", required: false }] }], tabChange: [{ type: i0.Output, args: ["tabChange"] }], previewHost: [{
|
|
2355
|
+
type: ViewChild,
|
|
2356
|
+
args: ['previewHost', { read: ViewContainerRef }]
|
|
638
2357
|
}] } });
|
|
639
2358
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
2359
|
+
const ComponentApiInputSchema = z.object({
|
|
2360
|
+
name: z.string(),
|
|
2361
|
+
type: z.string(),
|
|
2362
|
+
required: z.boolean(),
|
|
2363
|
+
defaultValue: z.string(),
|
|
2364
|
+
description: z.string(),
|
|
2365
|
+
});
|
|
2366
|
+
const ComponentApiOutputSchema = z.object({
|
|
2367
|
+
name: z.string(),
|
|
2368
|
+
eventType: z.string(),
|
|
2369
|
+
description: z.string(),
|
|
2370
|
+
});
|
|
2371
|
+
const ComponentVariantSchema = z.object({
|
|
2372
|
+
label: z.string(),
|
|
2373
|
+
resource: z.record(z.string(), z.unknown()),
|
|
2374
|
+
});
|
|
2375
|
+
const DocViewerResourceSchema = z.object({
|
|
2376
|
+
/** Metadatos de identificación */
|
|
2377
|
+
id: z.string(),
|
|
2378
|
+
name: z.string(),
|
|
2379
|
+
category: z.enum(['atom', 'molecule', 'organism', 'template']),
|
|
2380
|
+
description: z.string(),
|
|
2381
|
+
/** Selector Angular del componente */
|
|
2382
|
+
selector: z.string(),
|
|
2383
|
+
/** Referencia al componente Angular para preview dinámico */
|
|
2384
|
+
component: z.custom(),
|
|
2385
|
+
/** Ejemplo de código de integración (string) */
|
|
2386
|
+
codeSnippet: z.string(),
|
|
2387
|
+
/** API del componente */
|
|
2388
|
+
api: z.object({
|
|
2389
|
+
inputs: z.array(ComponentApiInputSchema),
|
|
2390
|
+
outputs: z.array(ComponentApiOutputSchema),
|
|
2391
|
+
}),
|
|
2392
|
+
/** Recurso de ejemplo pre-configurado para el preview (inputs individuales) */
|
|
2393
|
+
previewResource: z.record(z.string(), z.unknown()).optional(),
|
|
2394
|
+
/** Variantes (states) a mostrar en el preview */
|
|
2395
|
+
variants: z.array(ComponentVariantSchema).optional(),
|
|
2396
|
+
});
|
|
2397
|
+
|
|
2398
|
+
class AdAdminLayoutComponent {
|
|
2399
|
+
// Inputs as Signals
|
|
2400
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
2401
|
+
user = computed(() => this.resource().user, ...(ngDevMode ? [{ debugName: "user" }] : []));
|
|
2402
|
+
menuItems = computed(() => this.resource().menuItems, ...(ngDevMode ? [{ debugName: "menuItems" }] : []));
|
|
2403
|
+
notificationsCount = computed(() => this.resource().notificationsCount ?? 0, ...(ngDevMode ? [{ debugName: "notificationsCount" }] : []));
|
|
2404
|
+
// Derived Resources
|
|
2405
|
+
headerResource = computed(() => ({
|
|
2406
|
+
user: this.user(),
|
|
2407
|
+
notificationsCount: this.notificationsCount()
|
|
2408
|
+
}), ...(ngDevMode ? [{ debugName: "headerResource" }] : []));
|
|
2409
|
+
sidebarResource = computed(() => ({
|
|
2410
|
+
menuItems: this.menuItems(),
|
|
2411
|
+
collapsed: this.isSidebarCollapsed()
|
|
2412
|
+
}), ...(ngDevMode ? [{ debugName: "sidebarResource" }] : []));
|
|
2413
|
+
// Outputs
|
|
2414
|
+
logout = output();
|
|
2415
|
+
navigateProfile = output();
|
|
2416
|
+
toggleTheme = output();
|
|
2417
|
+
// State Signals
|
|
2418
|
+
isMobileMenuOpen = signal(false, ...(ngDevMode ? [{ debugName: "isMobileMenuOpen" }] : []));
|
|
2419
|
+
isSidebarCollapsed = signal(false, ...(ngDevMode ? [{ debugName: "isSidebarCollapsed" }] : []));
|
|
2420
|
+
toggleMobileMenu() {
|
|
2421
|
+
this.isMobileMenuOpen.update(v => !v);
|
|
2422
|
+
}
|
|
2423
|
+
closeMobileMenu() {
|
|
2424
|
+
this.isMobileMenuOpen.set(false);
|
|
644
2425
|
}
|
|
2426
|
+
toggleSidebar() {
|
|
2427
|
+
this.isSidebarCollapsed.update(v => !v);
|
|
2428
|
+
}
|
|
2429
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdAdminLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2430
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdAdminLayoutComponent, isStandalone: true, selector: "ad-admin-layout", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { logout: "logout", navigateProfile: "navigateProfile", toggleTheme: "toggleTheme" }, ngImport: i0, template: "<div class=\"flex h-screen bg-[#F4F7FE] font-sans overflow-hidden transition-colors duration-300\">\r\n <!-- Sidebar -->\r\n <ad-sidebar class=\"hidden md:flex h-full z-30\" [resource]=\"sidebarResource()\" (toggleCollapse)=\"toggleSidebar()\">\r\n </ad-sidebar>\r\n\r\n <!-- Main Content Wrapper -->\r\n <div class=\"flex-1 flex flex-col relative overflow-hidden\">\r\n\r\n <!-- HEADER JOINING SIDEBAR AND CONTENT -->\r\n <ad-header [resource]=\"headerResource()\" (toggleSidebar)=\"toggleSidebar()\"\r\n (toggleMobileMenu)=\"toggleMobileMenu()\" (logout)=\"logout.emit()\" (navigateProfile)=\"navigateProfile.emit()\"\r\n (toggleTheme)=\"toggleTheme.emit($event)\">\r\n </ad-header>\r\n\r\n <!-- DASHBOARD CONTENT AREA / WRAPPER -->\r\n <main class=\"flex-1 overflow-y-auto p-6 md:p-10 bg-gradient-to-b from-white/50 to-transparent scroll-smooth\">\r\n <!-- The routed content will be projected here. \r\n The user's snippet had specific dashboard stats here.\r\n We provide the container, and the Router Outlet content (e.g. DashboardComponent) \r\n should implement the Grid/Cards.\r\n However, to match the \"Card on Canvas\" look for general pages, we can wrap the router outlet.\r\n -->\r\n <div class=\"max-w-7xl mx-auto h-full animate-fade-in-up\">\r\n <ad-card [resource]=\"{ title: '' }\">\r\n <ng-content></ng-content>\r\n </ad-card>\r\n </div>\r\n </main>\r\n\r\n <!-- Mobile Sidebar Overlay -->\r\n @if (isMobileMenuOpen()) {\r\n <div class=\"relative z-50 md:hidden\" role=\"dialog\" aria-modal=\"true\">\r\n <div class=\"fixed inset-0 bg-slate-900/80 transition-opacity backdrop-blur-sm\" (click)=\"closeMobileMenu()\">\r\n </div>\r\n <div class=\"fixed inset-0 flex\">\r\n <div\r\n class=\"relative flex w-full max-w-xs flex-1 flex-col bg-[#002B5B] pb-4 pt-5 transition-transform shadow-2xl\">\r\n <div class=\"flex items-center justify-between px-4 pb-4 border-b border-white/10\">\r\n <div class=\"flex items-center text-white\">\r\n <span class=\"text-xl font-bold tracking-tight\">Cerca</span>\r\n <span\r\n class=\"ml-2 text-[10px] font-bold bg-white/10 px-1.5 py-0.5 rounded tracking-widest text-slate-300 border border-white/10\">ADMIN</span>\r\n </div>\r\n <button (click)=\"closeMobileMenu()\" class=\"text-slate-400 hover:text-white\">\r\n <span class=\"material-icons-outlined\">close</span>\r\n </button>\r\n </div>\r\n <nav class=\"flex-1 overflow-y-auto px-4 py-6 space-y-2\">\r\n @for (item of menuItems(); track item.route) {\r\n <a [routerLink]=\"item.route\" (click)=\"closeMobileMenu()\"\r\n [routerLinkActive]=\"['bg-[#0081C9]', 'text-white', 'shadow-lg']\"\r\n [routerLinkActiveOptions]=\"{ exact: item.exact || false }\"\r\n class=\"group flex items-center px-4 py-3 text-sm font-medium text-slate-300 rounded-xl hover:bg-white/5 hover:text-white transition-all duration-200\">\r\n <span class=\"material-icons-outlined text-[20px] mr-3 transition-colors\"\r\n [class.text-white]=\"false\" [class.group-hover:text-blue-300]=\"true\">\r\n {{ item.icon }}\r\n </span>\r\n {{ item.label }}\r\n </a>\r\n }\r\n </nav>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</div>", styles: ["@keyframes fade-in-down{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.animate-fade-in-down{animation:fade-in-down .2s ease-out}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: AdSidebarComponent, selector: "ad-sidebar", inputs: ["resource"], outputs: ["toggleCollapse", "navigate"] }, { kind: "component", type: AdCardComponent, selector: "ad-card", inputs: ["resource"], outputs: ["action"] }, { kind: "component", type: AdHeaderComponent, selector: "ad-header", inputs: ["resource"], outputs: ["toggleSidebar", "toggleMobileMenu", "logout", "navigateProfile", "toggleTheme"] }] });
|
|
2431
|
+
}
|
|
2432
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdAdminLayoutComponent, decorators: [{
|
|
2433
|
+
type: Component,
|
|
2434
|
+
args: [{ selector: 'ad-admin-layout', standalone: true, imports: [
|
|
2435
|
+
CommonModule,
|
|
2436
|
+
RouterLink,
|
|
2437
|
+
RouterLinkActive,
|
|
2438
|
+
AdSidebarComponent,
|
|
2439
|
+
AdCardComponent,
|
|
2440
|
+
AdHeaderComponent
|
|
2441
|
+
], template: "<div class=\"flex h-screen bg-[#F4F7FE] font-sans overflow-hidden transition-colors duration-300\">\r\n <!-- Sidebar -->\r\n <ad-sidebar class=\"hidden md:flex h-full z-30\" [resource]=\"sidebarResource()\" (toggleCollapse)=\"toggleSidebar()\">\r\n </ad-sidebar>\r\n\r\n <!-- Main Content Wrapper -->\r\n <div class=\"flex-1 flex flex-col relative overflow-hidden\">\r\n\r\n <!-- HEADER JOINING SIDEBAR AND CONTENT -->\r\n <ad-header [resource]=\"headerResource()\" (toggleSidebar)=\"toggleSidebar()\"\r\n (toggleMobileMenu)=\"toggleMobileMenu()\" (logout)=\"logout.emit()\" (navigateProfile)=\"navigateProfile.emit()\"\r\n (toggleTheme)=\"toggleTheme.emit($event)\">\r\n </ad-header>\r\n\r\n <!-- DASHBOARD CONTENT AREA / WRAPPER -->\r\n <main class=\"flex-1 overflow-y-auto p-6 md:p-10 bg-gradient-to-b from-white/50 to-transparent scroll-smooth\">\r\n <!-- The routed content will be projected here. \r\n The user's snippet had specific dashboard stats here.\r\n We provide the container, and the Router Outlet content (e.g. DashboardComponent) \r\n should implement the Grid/Cards.\r\n However, to match the \"Card on Canvas\" look for general pages, we can wrap the router outlet.\r\n -->\r\n <div class=\"max-w-7xl mx-auto h-full animate-fade-in-up\">\r\n <ad-card [resource]=\"{ title: '' }\">\r\n <ng-content></ng-content>\r\n </ad-card>\r\n </div>\r\n </main>\r\n\r\n <!-- Mobile Sidebar Overlay -->\r\n @if (isMobileMenuOpen()) {\r\n <div class=\"relative z-50 md:hidden\" role=\"dialog\" aria-modal=\"true\">\r\n <div class=\"fixed inset-0 bg-slate-900/80 transition-opacity backdrop-blur-sm\" (click)=\"closeMobileMenu()\">\r\n </div>\r\n <div class=\"fixed inset-0 flex\">\r\n <div\r\n class=\"relative flex w-full max-w-xs flex-1 flex-col bg-[#002B5B] pb-4 pt-5 transition-transform shadow-2xl\">\r\n <div class=\"flex items-center justify-between px-4 pb-4 border-b border-white/10\">\r\n <div class=\"flex items-center text-white\">\r\n <span class=\"text-xl font-bold tracking-tight\">Cerca</span>\r\n <span\r\n class=\"ml-2 text-[10px] font-bold bg-white/10 px-1.5 py-0.5 rounded tracking-widest text-slate-300 border border-white/10\">ADMIN</span>\r\n </div>\r\n <button (click)=\"closeMobileMenu()\" class=\"text-slate-400 hover:text-white\">\r\n <span class=\"material-icons-outlined\">close</span>\r\n </button>\r\n </div>\r\n <nav class=\"flex-1 overflow-y-auto px-4 py-6 space-y-2\">\r\n @for (item of menuItems(); track item.route) {\r\n <a [routerLink]=\"item.route\" (click)=\"closeMobileMenu()\"\r\n [routerLinkActive]=\"['bg-[#0081C9]', 'text-white', 'shadow-lg']\"\r\n [routerLinkActiveOptions]=\"{ exact: item.exact || false }\"\r\n class=\"group flex items-center px-4 py-3 text-sm font-medium text-slate-300 rounded-xl hover:bg-white/5 hover:text-white transition-all duration-200\">\r\n <span class=\"material-icons-outlined text-[20px] mr-3 transition-colors\"\r\n [class.text-white]=\"false\" [class.group-hover:text-blue-300]=\"true\">\r\n {{ item.icon }}\r\n </span>\r\n {{ item.label }}\r\n </a>\r\n }\r\n </nav>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</div>", styles: ["@keyframes fade-in-down{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.animate-fade-in-down{animation:fade-in-down .2s ease-out}\n"] }]
|
|
2442
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], logout: [{ type: i0.Output, args: ["logout"] }], navigateProfile: [{ type: i0.Output, args: ["navigateProfile"] }], toggleTheme: [{ type: i0.Output, args: ["toggleTheme"] }] } });
|
|
2443
|
+
|
|
2444
|
+
const AdminLayoutResourceSchema = z.object({
|
|
2445
|
+
user: UserSchema,
|
|
2446
|
+
menuItems: z.array(NavItemSchema),
|
|
2447
|
+
notificationsCount: z.number().default(0).optional(),
|
|
2448
|
+
});
|
|
2449
|
+
|
|
2450
|
+
class AdAuthLayoutComponent {
|
|
2451
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
2452
|
+
backgroundType = computed(() => this.resource().backgroundType ?? 'gradient', ...(ngDevMode ? [{ debugName: "backgroundType" }] : []));
|
|
2453
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdAuthLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2454
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.4", type: AdAuthLayoutComponent, isStandalone: true, selector: "ad-auth-layout", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"ad-auth-layout\" [ngClass]=\"'bg-' + backgroundType()\">\r\n <div class=\"ad-auth-container\">\r\n <div class=\"ad-auth-card\">\r\n <div class=\"ad-auth-logo\">\r\n <!-- Espacio para logo -->\r\n <div class=\"ad-auth-logo-placeholder\">CERCA</div>\r\n </div>\r\n\r\n <div class=\"ad-auth-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".ad-auth-layout{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:var(--space-4)}.ad-auth-layout.bg-gradient{background:radial-gradient(circle at top left,var(--color-brand-900),var(--neutral-900))}.ad-auth-layout.bg-simple{background-color:var(--color-bg-secondary)}.ad-auth-container{width:100%;max-width:440px}.ad-auth-card{background-color:var(--color-bg-primary);border:1px solid var(--color-border-subtle);border-radius:var(--radius-2xl);padding:var(--space-8);box-shadow:var(--shadow-2xl)}.ad-auth-logo{display:flex;justify-content:center;margin-bottom:var(--space-8)}.ad-auth-logo .ad-auth-logo-placeholder{font-size:var(--font-size-2xl);font-weight:var(--font-weight-bold);color:var(--color-brand-600);letter-spacing:-.05em}.ad-auth-content{display:flex;flex-direction:column;gap:var(--space-6)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
|
|
2455
|
+
}
|
|
2456
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdAuthLayoutComponent, decorators: [{
|
|
2457
|
+
type: Component,
|
|
2458
|
+
args: [{ selector: 'ad-auth-layout', standalone: true, imports: [CommonModule], template: "<div class=\"ad-auth-layout\" [ngClass]=\"'bg-' + backgroundType()\">\r\n <div class=\"ad-auth-container\">\r\n <div class=\"ad-auth-card\">\r\n <div class=\"ad-auth-logo\">\r\n <!-- Espacio para logo -->\r\n <div class=\"ad-auth-logo-placeholder\">CERCA</div>\r\n </div>\r\n\r\n <div class=\"ad-auth-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".ad-auth-layout{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:var(--space-4)}.ad-auth-layout.bg-gradient{background:radial-gradient(circle at top left,var(--color-brand-900),var(--neutral-900))}.ad-auth-layout.bg-simple{background-color:var(--color-bg-secondary)}.ad-auth-container{width:100%;max-width:440px}.ad-auth-card{background-color:var(--color-bg-primary);border:1px solid var(--color-border-subtle);border-radius:var(--radius-2xl);padding:var(--space-8);box-shadow:var(--shadow-2xl)}.ad-auth-logo{display:flex;justify-content:center;margin-bottom:var(--space-8)}.ad-auth-logo .ad-auth-logo-placeholder{font-size:var(--font-size-2xl);font-weight:var(--font-weight-bold);color:var(--color-brand-600);letter-spacing:-.05em}.ad-auth-content{display:flex;flex-direction:column;gap:var(--space-6)}\n"] }]
|
|
2459
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }] } });
|
|
2460
|
+
|
|
2461
|
+
const AuthLayoutResourceSchema = z.object({
|
|
2462
|
+
backgroundType: z.enum(['gradient', 'image', 'simple']).default('gradient').optional(),
|
|
2463
|
+
});
|
|
2464
|
+
|
|
2465
|
+
class AdGridComponent {
|
|
2466
|
+
cols = 1;
|
|
2467
|
+
colsMd;
|
|
2468
|
+
colsLg;
|
|
2469
|
+
gap = 4;
|
|
645
2470
|
get classes() {
|
|
646
2471
|
return [
|
|
647
|
-
`
|
|
648
|
-
this.colsMd ? `
|
|
649
|
-
this.colsLg ? `
|
|
650
|
-
`
|
|
2472
|
+
`ad-grid-cols-${this.cols}`,
|
|
2473
|
+
this.colsMd ? `ad-grid-cols-md-${this.colsMd}` : '',
|
|
2474
|
+
this.colsLg ? `ad-grid-cols-lg-${this.colsLg}` : '',
|
|
2475
|
+
`ad-grid-gap-${this.gap}`
|
|
651
2476
|
].filter(Boolean).join(' ');
|
|
652
2477
|
}
|
|
653
|
-
static
|
|
654
|
-
static
|
|
2478
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2479
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.4", type: AdGridComponent, isStandalone: true, selector: "ad-grid", inputs: { cols: "cols", colsMd: "colsMd", colsLg: "colsLg", gap: "gap" }, host: { properties: { "class": "this.classes" } }, ngImport: i0, template: "<div class=\"ad-grid\">\r\n <ng-content></ng-content>\r\n</div>", styles: [".ad-grid{display:grid;width:100%}.ad-grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.ad-grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ad-grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.ad-grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.ad-grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.ad-grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.ad-grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.ad-grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.ad-grid-cols-9{grid-template-columns:repeat(9,minmax(0,1fr))}.ad-grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.ad-grid-cols-11{grid-template-columns:repeat(11,minmax(0,1fr))}.ad-grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}@media(min-width:768px){.ad-grid-cols-md-1{grid-template-columns:repeat(1,minmax(0,1fr))}.ad-grid-cols-md-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ad-grid-cols-md-3{grid-template-columns:repeat(3,minmax(0,1fr))}.ad-grid-cols-md-4{grid-template-columns:repeat(4,minmax(0,1fr))}.ad-grid-cols-md-5{grid-template-columns:repeat(5,minmax(0,1fr))}.ad-grid-cols-md-6{grid-template-columns:repeat(6,minmax(0,1fr))}.ad-grid-cols-md-7{grid-template-columns:repeat(7,minmax(0,1fr))}.ad-grid-cols-md-8{grid-template-columns:repeat(8,minmax(0,1fr))}.ad-grid-cols-md-9{grid-template-columns:repeat(9,minmax(0,1fr))}.ad-grid-cols-md-10{grid-template-columns:repeat(10,minmax(0,1fr))}.ad-grid-cols-md-11{grid-template-columns:repeat(11,minmax(0,1fr))}.ad-grid-cols-md-12{grid-template-columns:repeat(12,minmax(0,1fr))}}@media(min-width:1024px){.ad-grid-cols-lg-1{grid-template-columns:repeat(1,minmax(0,1fr))}.ad-grid-cols-lg-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ad-grid-cols-lg-3{grid-template-columns:repeat(3,minmax(0,1fr))}.ad-grid-cols-lg-4{grid-template-columns:repeat(4,minmax(0,1fr))}.ad-grid-cols-lg-5{grid-template-columns:repeat(5,minmax(0,1fr))}.ad-grid-cols-lg-6{grid-template-columns:repeat(6,minmax(0,1fr))}.ad-grid-cols-lg-7{grid-template-columns:repeat(7,minmax(0,1fr))}.ad-grid-cols-lg-8{grid-template-columns:repeat(8,minmax(0,1fr))}.ad-grid-cols-lg-9{grid-template-columns:repeat(9,minmax(0,1fr))}.ad-grid-cols-lg-10{grid-template-columns:repeat(10,minmax(0,1fr))}.ad-grid-cols-lg-11{grid-template-columns:repeat(11,minmax(0,1fr))}.ad-grid-cols-lg-12{grid-template-columns:repeat(12,minmax(0,1fr))}}.ad-grid-gap-1{gap:var(--space-1)}.ad-grid-gap-2{gap:var(--space-2)}.ad-grid-gap-3{gap:var(--space-3)}.ad-grid-gap-4{gap:var(--space-4)}.ad-grid-gap-5{gap:var(--space-5)}.ad-grid-gap-6{gap:var(--space-6)}.ad-grid-gap-7{gap:var(--space-7)}.ad-grid-gap-8{gap:var(--space-8)}.ad-grid-gap-9{gap:var(--space-9)}.ad-grid-gap-10{gap:var(--space-10)}.ad-grid-gap-11{gap:var(--space-11)}.ad-grid-gap-12{gap:var(--space-12)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
655
2480
|
}
|
|
656
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
2481
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdGridComponent, decorators: [{
|
|
657
2482
|
type: Component,
|
|
658
|
-
args: [{ selector: '
|
|
2483
|
+
args: [{ selector: 'ad-grid', standalone: true, imports: [CommonModule], template: "<div class=\"ad-grid\">\r\n <ng-content></ng-content>\r\n</div>", styles: [".ad-grid{display:grid;width:100%}.ad-grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.ad-grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ad-grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.ad-grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.ad-grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.ad-grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.ad-grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.ad-grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.ad-grid-cols-9{grid-template-columns:repeat(9,minmax(0,1fr))}.ad-grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.ad-grid-cols-11{grid-template-columns:repeat(11,minmax(0,1fr))}.ad-grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}@media(min-width:768px){.ad-grid-cols-md-1{grid-template-columns:repeat(1,minmax(0,1fr))}.ad-grid-cols-md-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ad-grid-cols-md-3{grid-template-columns:repeat(3,minmax(0,1fr))}.ad-grid-cols-md-4{grid-template-columns:repeat(4,minmax(0,1fr))}.ad-grid-cols-md-5{grid-template-columns:repeat(5,minmax(0,1fr))}.ad-grid-cols-md-6{grid-template-columns:repeat(6,minmax(0,1fr))}.ad-grid-cols-md-7{grid-template-columns:repeat(7,minmax(0,1fr))}.ad-grid-cols-md-8{grid-template-columns:repeat(8,minmax(0,1fr))}.ad-grid-cols-md-9{grid-template-columns:repeat(9,minmax(0,1fr))}.ad-grid-cols-md-10{grid-template-columns:repeat(10,minmax(0,1fr))}.ad-grid-cols-md-11{grid-template-columns:repeat(11,minmax(0,1fr))}.ad-grid-cols-md-12{grid-template-columns:repeat(12,minmax(0,1fr))}}@media(min-width:1024px){.ad-grid-cols-lg-1{grid-template-columns:repeat(1,minmax(0,1fr))}.ad-grid-cols-lg-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ad-grid-cols-lg-3{grid-template-columns:repeat(3,minmax(0,1fr))}.ad-grid-cols-lg-4{grid-template-columns:repeat(4,minmax(0,1fr))}.ad-grid-cols-lg-5{grid-template-columns:repeat(5,minmax(0,1fr))}.ad-grid-cols-lg-6{grid-template-columns:repeat(6,minmax(0,1fr))}.ad-grid-cols-lg-7{grid-template-columns:repeat(7,minmax(0,1fr))}.ad-grid-cols-lg-8{grid-template-columns:repeat(8,minmax(0,1fr))}.ad-grid-cols-lg-9{grid-template-columns:repeat(9,minmax(0,1fr))}.ad-grid-cols-lg-10{grid-template-columns:repeat(10,minmax(0,1fr))}.ad-grid-cols-lg-11{grid-template-columns:repeat(11,minmax(0,1fr))}.ad-grid-cols-lg-12{grid-template-columns:repeat(12,minmax(0,1fr))}}.ad-grid-gap-1{gap:var(--space-1)}.ad-grid-gap-2{gap:var(--space-2)}.ad-grid-gap-3{gap:var(--space-3)}.ad-grid-gap-4{gap:var(--space-4)}.ad-grid-gap-5{gap:var(--space-5)}.ad-grid-gap-6{gap:var(--space-6)}.ad-grid-gap-7{gap:var(--space-7)}.ad-grid-gap-8{gap:var(--space-8)}.ad-grid-gap-9{gap:var(--space-9)}.ad-grid-gap-10{gap:var(--space-10)}.ad-grid-gap-11{gap:var(--space-11)}.ad-grid-gap-12{gap:var(--space-12)}\n"] }]
|
|
659
2484
|
}], propDecorators: { cols: [{
|
|
660
2485
|
type: Input
|
|
661
2486
|
}], colsMd: [{
|
|
@@ -669,163 +2494,372 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImpor
|
|
|
669
2494
|
args: ['class']
|
|
670
2495
|
}] } });
|
|
671
2496
|
|
|
672
|
-
class
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
this.justify = input('start', ...(ngDevMode ? [{ debugName: "justify" }] : []));
|
|
677
|
-
this.wrap = input(false, ...(ngDevMode ? [{ debugName: "wrap" }] : []));
|
|
678
|
-
}
|
|
2497
|
+
class AdStackComponent {
|
|
2498
|
+
gap = input(4, ...(ngDevMode ? [{ debugName: "gap" }] : []));
|
|
2499
|
+
align = input('stretch', ...(ngDevMode ? [{ debugName: "align" }] : []));
|
|
2500
|
+
justify = input('start', ...(ngDevMode ? [{ debugName: "justify" }] : []));
|
|
679
2501
|
get gapStyle() {
|
|
680
2502
|
const g = this.gap();
|
|
681
2503
|
return typeof g === 'number' ? `var(--space-${g})` : g;
|
|
682
2504
|
}
|
|
683
2505
|
get alignStyle() {
|
|
684
|
-
const map = { start: 'flex-start', center: 'center', end: 'flex-end',
|
|
2506
|
+
const map = { start: 'flex-start', center: 'center', end: 'flex-end', stretch: 'stretch' };
|
|
685
2507
|
return map[this.align()];
|
|
686
2508
|
}
|
|
687
2509
|
get justifyStyle() {
|
|
688
|
-
const map = { start: 'flex-start', center: 'center', end: 'flex-end', between: 'space-between'
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
return
|
|
2510
|
+
const map = { start: 'flex-start', center: 'center', end: 'flex-end', between: 'space-between' };
|
|
2511
|
+
const j = this.justify();
|
|
2512
|
+
if (j === 'between')
|
|
2513
|
+
return 'space-between';
|
|
2514
|
+
return map[j] || 'flex-start';
|
|
693
2515
|
}
|
|
694
|
-
static
|
|
695
|
-
static
|
|
2516
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdStackComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2517
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.4", type: AdStackComponent, isStandalone: true, selector: "ad-stack", inputs: { gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, justify: { classPropertyName: "justify", publicName: "justify", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.gap": "this.gapStyle", "style.align-items": "this.alignStyle", "style.justify-content": "this.justifyStyle" } }, ngImport: i0, template: "<ng-content></ng-content>", styles: [":host{display:flex;flex-direction:column;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
696
2518
|
}
|
|
697
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
2519
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdStackComponent, decorators: [{
|
|
698
2520
|
type: Component,
|
|
699
|
-
args: [{ selector: '
|
|
700
|
-
}], propDecorators: { gap: [{ type: i0.Input, args: [{ isSignal: true, alias: "gap", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], justify: [{ type: i0.Input, args: [{ isSignal: true, alias: "justify", required: false }] }],
|
|
2521
|
+
args: [{ selector: 'ad-stack', standalone: true, imports: [CommonModule], template: "<ng-content></ng-content>", styles: [":host{display:flex;flex-direction:column;width:100%}\n"] }]
|
|
2522
|
+
}], propDecorators: { gap: [{ type: i0.Input, args: [{ isSignal: true, alias: "gap", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], justify: [{ type: i0.Input, args: [{ isSignal: true, alias: "justify", required: false }] }], gapStyle: [{
|
|
701
2523
|
type: HostBinding,
|
|
702
|
-
args: ['style
|
|
2524
|
+
args: ['style.gap']
|
|
703
2525
|
}], alignStyle: [{
|
|
704
2526
|
type: HostBinding,
|
|
705
|
-
args: ['style
|
|
2527
|
+
args: ['style.align-items']
|
|
706
2528
|
}], justifyStyle: [{
|
|
707
2529
|
type: HostBinding,
|
|
708
|
-
args: ['style
|
|
709
|
-
}], wrapStyle: [{
|
|
710
|
-
type: HostBinding,
|
|
711
|
-
args: ['style.--inline-wrap']
|
|
2530
|
+
args: ['style.justify-content']
|
|
712
2531
|
}] } });
|
|
713
2532
|
|
|
714
|
-
class
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
}
|
|
721
|
-
toggleSidebar() {
|
|
722
|
-
this.isSidebarCollapsed = !this.isSidebarCollapsed;
|
|
723
|
-
}
|
|
724
|
-
toggleMobileMenu() {
|
|
725
|
-
this.isMobileMenuOpen = !this.isMobileMenuOpen;
|
|
726
|
-
}
|
|
727
|
-
onNavItemClick(item) {
|
|
728
|
-
if (this.isMobileMenuOpen) {
|
|
729
|
-
this.isMobileMenuOpen = false;
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
onUserAction(action) {
|
|
733
|
-
console.log('User action:', action);
|
|
734
|
-
}
|
|
735
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: CcAdminLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
736
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.4", type: CcAdminLayoutComponent, isStandalone: true, selector: "cc-admin-layout", inputs: { user: "user", menuItems: "menuItems", notificationsCount: "notificationsCount" }, ngImport: i0, template: "<div class=\"cc-admin-layout\" [class.sidebar-collapsed]=\"isSidebarCollapsed\">\r\n\r\n <cc-sidebar class=\"cc-admin-sidebar\" [class.mobile-open]=\"isMobileMenuOpen\" [menuItems]=\"menuItems\"\r\n [collapsed]=\"isSidebarCollapsed\" (toggleCollapse)=\"toggleSidebar()\" (navigate)=\"onNavItemClick($event)\">\r\n </cc-sidebar>\r\n\r\n <div class=\"cc-admin-main\">\r\n <cc-header [user]=\"user\" [notificationsCount]=\"notificationsCount\" (toggleSidebar)=\"toggleMobileMenu()\"\r\n (userAction)=\"onUserAction($event)\">\r\n </cc-header>\r\n\r\n <main class=\"cc-admin-content\">\r\n <div class=\"cc-admin-content-container\">\r\n <ng-content></ng-content>\r\n </div>\r\n </main>\r\n </div>\r\n\r\n <!-- Overlay para m\u00F3vil -->\r\n <div class=\"cc-admin-overlay\" *ngIf=\"isMobileMenuOpen\" (click)=\"isMobileMenuOpen = false\"></div>\r\n</div>", styles: [".cc-admin-layout{display:flex;min-height:100vh;background-color:var(--color-bg-secondary);--sidebar-width: 280px;--sidebar-collapsed-width: 80px}.cc-admin-layout.sidebar-collapsed{--sidebar-width: var(--sidebar-collapsed-width)}.cc-admin-sidebar{position:fixed;inset-y:0;left:0;z-index:40;width:var(--sidebar-width);transition:width .3s cubic-bezier(.4,0,.2,1);box-shadow:4px 0 24px #0000000d}.cc-admin-sidebar.mobile-open{display:block;box-shadow:var(--shadow-xl)}.cc-admin-main{flex:1;display:flex;flex-direction:column;min-width:0;padding-left:0;transition:padding-left .3s cubic-bezier(.4,0,.2,1)}@media(min-width:1024px){.cc-admin-main{padding-left:var(--sidebar-width)}}.cc-admin-content{flex:1;padding:var(--space-6) var(--space-4);background-color:var(--color-bg-secondary);min-height:calc(100vh - var(--header-height))}@media(min-width:1024px){.cc-admin-content{padding:var(--space-8) var(--space-6)}}.cc-admin-content-container{max-width:1280px;margin:0 auto;width:100%}.cc-admin-overlay{position:fixed;inset:0;background-color:#00000080;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:30}@media(min-width:1024px){.cc-admin-overlay{display:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: CcHeaderComponent, selector: "cc-header", inputs: ["user", "notificationsCount", "showMenuButton", "hasLogoContent"], outputs: ["toggleSidebar", "userClick", "notificationClick", "userAction"] }, { kind: "component", type: CcSidebarComponent, selector: "cc-sidebar", inputs: ["menuItems", "collapsed", "activeRoute"], outputs: ["navigate", "toggleCollapse"] }] }); }
|
|
2533
|
+
class AdDashboardTemplateComponent {
|
|
2534
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
2535
|
+
title = computed(() => this.resource().title ?? 'Escritorio', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
2536
|
+
subtitle = computed(() => this.resource().subtitle, ...(ngDevMode ? [{ debugName: "subtitle" }] : []));
|
|
2537
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdDashboardTemplateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2538
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdDashboardTemplateComponent, isStandalone: true, selector: "ad-dashboard-template", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"ad-dashboard-template\">\r\n <header class=\"ad-dashboard-header\">\r\n <ad-stack [gap]=\"1\">\r\n <h1 class=\"ad-dashboard-title\">{{ title() }}</h1>\r\n @if (subtitle()) {\r\n <p class=\"ad-dashboard-subtitle\">{{ subtitle() }}</p>\r\n }\r\n </ad-stack>\r\n <div class=\"ad-dashboard-actions\">\r\n <ng-content select=\"[actions]\"></ng-content>\r\n </div>\r\n </header>\r\n\r\n <ad-grid [cols]=\"1\" [colsMd]=\"2\" [colsLg]=\"4\" [gap]=\"6\" class=\"ad-dashboard-metrics\">\r\n <ng-content select=\"[metrics]\"></ng-content>\r\n </ad-grid>\r\n\r\n <ad-grid [cols]=\"1\" [colsLg]=\"3\" [gap]=\"6\" class=\"ad-dashboard-main\">\r\n <div class=\"ad-dashboard-primary-content\">\r\n <ng-content select=\"[main-content]\"></ng-content>\r\n </div>\r\n <aside class=\"ad-dashboard-secondary-content\">\r\n <ng-content select=\"[sidebar-content]\"></ng-content>\r\n </aside>\r\n </ad-grid>\r\n</div>", styles: [".ad-dashboard-template{display:flex;flex-direction:column;gap:var(--space-8)}.ad-dashboard-header{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-4)}.ad-dashboard-title{font-size:var(--font-size-3xl);font-weight:var(--font-weight-bold);color:var(--color-text-primary);line-height:1}.ad-dashboard-subtitle{color:var(--color-text-muted);font-size:var(--font-size-md)}.ad-dashboard-metrics{margin-bottom:var(--space-4)}@media(min-width:1024px){.ad-dashboard-primary-content{grid-column:span 2}}.ad-dashboard-secondary-content{display:flex;flex-direction:column;gap:var(--space-6)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AdGridComponent, selector: "ad-grid", inputs: ["cols", "colsMd", "colsLg", "gap"] }, { kind: "component", type: AdStackComponent, selector: "ad-stack", inputs: ["gap", "align", "justify"] }] });
|
|
737
2539
|
}
|
|
738
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
2540
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdDashboardTemplateComponent, decorators: [{
|
|
739
2541
|
type: Component,
|
|
740
|
-
args: [{ selector: '
|
|
741
|
-
}], propDecorators: {
|
|
742
|
-
type: Input
|
|
743
|
-
}], menuItems: [{
|
|
744
|
-
type: Input
|
|
745
|
-
}], notificationsCount: [{
|
|
746
|
-
type: Input
|
|
747
|
-
}] } });
|
|
2542
|
+
args: [{ selector: 'ad-dashboard-template', standalone: true, imports: [CommonModule, AdGridComponent, AdStackComponent], template: "<div class=\"ad-dashboard-template\">\r\n <header class=\"ad-dashboard-header\">\r\n <ad-stack [gap]=\"1\">\r\n <h1 class=\"ad-dashboard-title\">{{ title() }}</h1>\r\n @if (subtitle()) {\r\n <p class=\"ad-dashboard-subtitle\">{{ subtitle() }}</p>\r\n }\r\n </ad-stack>\r\n <div class=\"ad-dashboard-actions\">\r\n <ng-content select=\"[actions]\"></ng-content>\r\n </div>\r\n </header>\r\n\r\n <ad-grid [cols]=\"1\" [colsMd]=\"2\" [colsLg]=\"4\" [gap]=\"6\" class=\"ad-dashboard-metrics\">\r\n <ng-content select=\"[metrics]\"></ng-content>\r\n </ad-grid>\r\n\r\n <ad-grid [cols]=\"1\" [colsLg]=\"3\" [gap]=\"6\" class=\"ad-dashboard-main\">\r\n <div class=\"ad-dashboard-primary-content\">\r\n <ng-content select=\"[main-content]\"></ng-content>\r\n </div>\r\n <aside class=\"ad-dashboard-secondary-content\">\r\n <ng-content select=\"[sidebar-content]\"></ng-content>\r\n </aside>\r\n </ad-grid>\r\n</div>", styles: [".ad-dashboard-template{display:flex;flex-direction:column;gap:var(--space-8)}.ad-dashboard-header{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-4)}.ad-dashboard-title{font-size:var(--font-size-3xl);font-weight:var(--font-weight-bold);color:var(--color-text-primary);line-height:1}.ad-dashboard-subtitle{color:var(--color-text-muted);font-size:var(--font-size-md)}.ad-dashboard-metrics{margin-bottom:var(--space-4)}@media(min-width:1024px){.ad-dashboard-primary-content{grid-column:span 2}}.ad-dashboard-secondary-content{display:flex;flex-direction:column;gap:var(--space-6)}\n"] }]
|
|
2543
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }] } });
|
|
748
2544
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
2545
|
+
const DashboardTemplateResourceSchema = z.object({
|
|
2546
|
+
title: z.string().default('Escritorio').optional(),
|
|
2547
|
+
subtitle: z.string().optional(),
|
|
2548
|
+
});
|
|
2549
|
+
|
|
2550
|
+
class AdDocumentationWrapperComponent {
|
|
2551
|
+
wrapperResource = input.required({ ...(ngDevMode ? { debugName: "wrapperResource" } : {}), alias: 'resource' });
|
|
2552
|
+
title = computed(() => this.wrapperResource().title, ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
2553
|
+
description = computed(() => this.wrapperResource().description, ...(ngDevMode ? [{ debugName: "description" }] : []));
|
|
2554
|
+
code = computed(() => this.wrapperResource().code, ...(ngDevMode ? [{ debugName: "code" }] : []));
|
|
2555
|
+
componentResource = computed(() => this.wrapperResource().componentResource, ...(ngDevMode ? [{ debugName: "componentResource" }] : []));
|
|
2556
|
+
status = computed(() => this.wrapperResource().status ?? 'stable', ...(ngDevMode ? [{ debugName: "status" }] : []));
|
|
2557
|
+
activeTab = signal('preview', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
|
|
2558
|
+
copyToClipboard(text) {
|
|
2559
|
+
navigator.clipboard.writeText(text);
|
|
2560
|
+
// Could add toast notification here
|
|
752
2561
|
}
|
|
753
|
-
static
|
|
754
|
-
static
|
|
2562
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdDocumentationWrapperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2563
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdDocumentationWrapperComponent, isStandalone: true, selector: "ad-documentation-wrapper", inputs: { wrapperResource: { classPropertyName: "wrapperResource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
2564
|
+
<div class="space-y-6">
|
|
2565
|
+
<!-- Header -->
|
|
2566
|
+
<div class="flex items-center justify-between border-b-2 border-stone-100 dark:border-cerca-primary-hover pb-2">
|
|
2567
|
+
<h2 class="text-2xl font-bold text-stone-800 dark:text-white">{{ title() }}</h2>
|
|
2568
|
+
@if (status() === 'new') {
|
|
2569
|
+
<span class="bg-emerald-100 text-emerald-800 text-xs font-medium px-2.5 py-0.5 rounded dark:bg-emerald-900 dark:text-emerald-300">New</span>
|
|
2570
|
+
} @else if (status() === 'updated') {
|
|
2571
|
+
<span class="bg-sky-100 text-sky-800 text-xs font-medium px-2.5 py-0.5 rounded dark:bg-sky-900 dark:text-sky-300">Updated</span>
|
|
2572
|
+
}
|
|
2573
|
+
</div>
|
|
2574
|
+
|
|
2575
|
+
<!-- Description -->
|
|
2576
|
+
<div class="p-4 bg-yellow-50 border-l-4 border-yellow-400 text-stone-700 dark:bg-yellow-900/10 dark:text-yellow-100 dark:border-yellow-600">
|
|
2577
|
+
<p>{{ description() }}</p>
|
|
2578
|
+
</div>
|
|
2579
|
+
|
|
2580
|
+
<!-- Tabs -->
|
|
2581
|
+
<div class="border-b border-stone-200 dark:border-cerca-primary">
|
|
2582
|
+
<nav class="-mb-px flex space-x-8" aria-label="Tabs">
|
|
2583
|
+
<button
|
|
2584
|
+
(click)="activeTab.set('preview')"
|
|
2585
|
+
[class.border-sky-500]="activeTab() === 'preview'"
|
|
2586
|
+
[class.text-sky-600]="activeTab() === 'preview'"
|
|
2587
|
+
[class.dark:text-sky-400]="activeTab() === 'preview'"
|
|
2588
|
+
[class.border-transparent]="activeTab() !== 'preview'"
|
|
2589
|
+
[class.text-stone-500]="activeTab() !== 'preview'"
|
|
2590
|
+
[class.hover:text-stone-700]="activeTab() !== 'preview'"
|
|
2591
|
+
[class.hover:border-stone-300]="activeTab() !== 'preview'"
|
|
2592
|
+
class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm transition-colors duration-200">
|
|
2593
|
+
Preview
|
|
2594
|
+
</button>
|
|
2595
|
+
|
|
2596
|
+
@if (code()) {
|
|
2597
|
+
<button
|
|
2598
|
+
(click)="activeTab.set('code')"
|
|
2599
|
+
[class.border-sky-500]="activeTab() === 'code'"
|
|
2600
|
+
[class.text-sky-600]="activeTab() === 'code'"
|
|
2601
|
+
[class.dark:text-sky-400]="activeTab() === 'code'"
|
|
2602
|
+
[class.border-transparent]="activeTab() !== 'code'"
|
|
2603
|
+
[class.text-stone-500]="activeTab() !== 'code'"
|
|
2604
|
+
[class.hover:text-stone-700]="activeTab() !== 'code'"
|
|
2605
|
+
[class.hover:border-stone-300]="activeTab() !== 'code'"
|
|
2606
|
+
class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm transition-colors duration-200">
|
|
2607
|
+
Code
|
|
2608
|
+
</button>
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
@if (componentResource()) {
|
|
2612
|
+
<button
|
|
2613
|
+
(click)="activeTab.set('resource')"
|
|
2614
|
+
[class.border-sky-500]="activeTab() === 'resource'"
|
|
2615
|
+
[class.text-sky-600]="activeTab() === 'resource'"
|
|
2616
|
+
[class.dark:text-sky-400]="activeTab() === 'resource'"
|
|
2617
|
+
[class.border-transparent]="activeTab() !== 'resource'"
|
|
2618
|
+
[class.text-stone-500]="activeTab() !== 'resource'"
|
|
2619
|
+
[class.hover:text-stone-700]="activeTab() !== 'resource'"
|
|
2620
|
+
[class.hover:border-stone-300]="activeTab() !== 'resource'"
|
|
2621
|
+
class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm transition-colors duration-200">
|
|
2622
|
+
Resource
|
|
2623
|
+
</button>
|
|
2624
|
+
}
|
|
2625
|
+
</nav>
|
|
2626
|
+
</div>
|
|
2627
|
+
|
|
2628
|
+
<!-- Tab Content -->
|
|
2629
|
+
<div class="mt-4">
|
|
2630
|
+
@switch (activeTab()) {
|
|
2631
|
+
@case ('preview') {
|
|
2632
|
+
<div class="p-6 bg-stone-50 rounded-lg border border-stone-200 dark:bg-cerca-primary-active dark:border-cerca-primary">
|
|
2633
|
+
<ng-content></ng-content>
|
|
2634
|
+
</div>
|
|
2635
|
+
}
|
|
2636
|
+
@case ('code') {
|
|
2637
|
+
<div class="relative group">
|
|
2638
|
+
<div class="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
2639
|
+
<button (click)="copyToClipboard(code()!)" class="p-1 rounded bg-stone-700 text-white hover:bg-stone-600 text-xs">Copy</button>
|
|
2640
|
+
</div>
|
|
2641
|
+
<pre class="p-4 bg-stone-900 text-stone-50 rounded-lg overflow-x-auto text-sm font-mono leading-relaxed"><code>{{ code() }}</code></pre>
|
|
2642
|
+
</div>
|
|
2643
|
+
}
|
|
2644
|
+
@case ('resource') {
|
|
2645
|
+
<div class="relative group">
|
|
2646
|
+
<div class="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
2647
|
+
<button (click)="copyToClipboard(componentResource()!)" class="p-1 rounded bg-stone-700 text-white hover:bg-stone-600 text-xs">Copy</button>
|
|
2648
|
+
</div>
|
|
2649
|
+
<pre class="p-4 bg-stone-900 text-stone-50 rounded-lg overflow-x-auto text-sm font-mono leading-relaxed"><code>{{ componentResource() }}</code></pre>
|
|
2650
|
+
</div>
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
</div>
|
|
2654
|
+
</div>
|
|
2655
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], encapsulation: i0.ViewEncapsulation.None });
|
|
755
2656
|
}
|
|
756
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
2657
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdDocumentationWrapperComponent, decorators: [{
|
|
757
2658
|
type: Component,
|
|
758
|
-
args: [{
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
2659
|
+
args: [{
|
|
2660
|
+
selector: 'ad-documentation-wrapper',
|
|
2661
|
+
standalone: true,
|
|
2662
|
+
imports: [CommonModule],
|
|
2663
|
+
template: `
|
|
2664
|
+
<div class="space-y-6">
|
|
2665
|
+
<!-- Header -->
|
|
2666
|
+
<div class="flex items-center justify-between border-b-2 border-stone-100 dark:border-cerca-primary-hover pb-2">
|
|
2667
|
+
<h2 class="text-2xl font-bold text-stone-800 dark:text-white">{{ title() }}</h2>
|
|
2668
|
+
@if (status() === 'new') {
|
|
2669
|
+
<span class="bg-emerald-100 text-emerald-800 text-xs font-medium px-2.5 py-0.5 rounded dark:bg-emerald-900 dark:text-emerald-300">New</span>
|
|
2670
|
+
} @else if (status() === 'updated') {
|
|
2671
|
+
<span class="bg-sky-100 text-sky-800 text-xs font-medium px-2.5 py-0.5 rounded dark:bg-sky-900 dark:text-sky-300">Updated</span>
|
|
2672
|
+
}
|
|
2673
|
+
</div>
|
|
2674
|
+
|
|
2675
|
+
<!-- Description -->
|
|
2676
|
+
<div class="p-4 bg-yellow-50 border-l-4 border-yellow-400 text-stone-700 dark:bg-yellow-900/10 dark:text-yellow-100 dark:border-yellow-600">
|
|
2677
|
+
<p>{{ description() }}</p>
|
|
2678
|
+
</div>
|
|
2679
|
+
|
|
2680
|
+
<!-- Tabs -->
|
|
2681
|
+
<div class="border-b border-stone-200 dark:border-cerca-primary">
|
|
2682
|
+
<nav class="-mb-px flex space-x-8" aria-label="Tabs">
|
|
2683
|
+
<button
|
|
2684
|
+
(click)="activeTab.set('preview')"
|
|
2685
|
+
[class.border-sky-500]="activeTab() === 'preview'"
|
|
2686
|
+
[class.text-sky-600]="activeTab() === 'preview'"
|
|
2687
|
+
[class.dark:text-sky-400]="activeTab() === 'preview'"
|
|
2688
|
+
[class.border-transparent]="activeTab() !== 'preview'"
|
|
2689
|
+
[class.text-stone-500]="activeTab() !== 'preview'"
|
|
2690
|
+
[class.hover:text-stone-700]="activeTab() !== 'preview'"
|
|
2691
|
+
[class.hover:border-stone-300]="activeTab() !== 'preview'"
|
|
2692
|
+
class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm transition-colors duration-200">
|
|
2693
|
+
Preview
|
|
2694
|
+
</button>
|
|
2695
|
+
|
|
2696
|
+
@if (code()) {
|
|
2697
|
+
<button
|
|
2698
|
+
(click)="activeTab.set('code')"
|
|
2699
|
+
[class.border-sky-500]="activeTab() === 'code'"
|
|
2700
|
+
[class.text-sky-600]="activeTab() === 'code'"
|
|
2701
|
+
[class.dark:text-sky-400]="activeTab() === 'code'"
|
|
2702
|
+
[class.border-transparent]="activeTab() !== 'code'"
|
|
2703
|
+
[class.text-stone-500]="activeTab() !== 'code'"
|
|
2704
|
+
[class.hover:text-stone-700]="activeTab() !== 'code'"
|
|
2705
|
+
[class.hover:border-stone-300]="activeTab() !== 'code'"
|
|
2706
|
+
class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm transition-colors duration-200">
|
|
2707
|
+
Code
|
|
2708
|
+
</button>
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
@if (componentResource()) {
|
|
2712
|
+
<button
|
|
2713
|
+
(click)="activeTab.set('resource')"
|
|
2714
|
+
[class.border-sky-500]="activeTab() === 'resource'"
|
|
2715
|
+
[class.text-sky-600]="activeTab() === 'resource'"
|
|
2716
|
+
[class.dark:text-sky-400]="activeTab() === 'resource'"
|
|
2717
|
+
[class.border-transparent]="activeTab() !== 'resource'"
|
|
2718
|
+
[class.text-stone-500]="activeTab() !== 'resource'"
|
|
2719
|
+
[class.hover:text-stone-700]="activeTab() !== 'resource'"
|
|
2720
|
+
[class.hover:border-stone-300]="activeTab() !== 'resource'"
|
|
2721
|
+
class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm transition-colors duration-200">
|
|
2722
|
+
Resource
|
|
2723
|
+
</button>
|
|
2724
|
+
}
|
|
2725
|
+
</nav>
|
|
2726
|
+
</div>
|
|
2727
|
+
|
|
2728
|
+
<!-- Tab Content -->
|
|
2729
|
+
<div class="mt-4">
|
|
2730
|
+
@switch (activeTab()) {
|
|
2731
|
+
@case ('preview') {
|
|
2732
|
+
<div class="p-6 bg-stone-50 rounded-lg border border-stone-200 dark:bg-cerca-primary-active dark:border-cerca-primary">
|
|
2733
|
+
<ng-content></ng-content>
|
|
2734
|
+
</div>
|
|
2735
|
+
}
|
|
2736
|
+
@case ('code') {
|
|
2737
|
+
<div class="relative group">
|
|
2738
|
+
<div class="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
2739
|
+
<button (click)="copyToClipboard(code()!)" class="p-1 rounded bg-stone-700 text-white hover:bg-stone-600 text-xs">Copy</button>
|
|
2740
|
+
</div>
|
|
2741
|
+
<pre class="p-4 bg-stone-900 text-stone-50 rounded-lg overflow-x-auto text-sm font-mono leading-relaxed"><code>{{ code() }}</code></pre>
|
|
2742
|
+
</div>
|
|
2743
|
+
}
|
|
2744
|
+
@case ('resource') {
|
|
2745
|
+
<div class="relative group">
|
|
2746
|
+
<div class="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
2747
|
+
<button (click)="copyToClipboard(componentResource()!)" class="p-1 rounded bg-stone-700 text-white hover:bg-stone-600 text-xs">Copy</button>
|
|
2748
|
+
</div>
|
|
2749
|
+
<pre class="p-4 bg-stone-900 text-stone-50 rounded-lg overflow-x-auto text-sm font-mono leading-relaxed"><code>{{ componentResource() }}</code></pre>
|
|
2750
|
+
</div>
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
</div>
|
|
2754
|
+
</div>
|
|
2755
|
+
`,
|
|
2756
|
+
encapsulation: ViewEncapsulation.None
|
|
2757
|
+
}]
|
|
2758
|
+
}], propDecorators: { wrapperResource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }] } });
|
|
762
2759
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
2760
|
+
const DocStatusSchema = z.enum(['new', 'updated', 'stable']);
|
|
2761
|
+
const DocumentationWrapperResourceSchema = z.object({
|
|
2762
|
+
title: z.string(),
|
|
2763
|
+
description: z.string(),
|
|
2764
|
+
code: z.string().optional(),
|
|
2765
|
+
componentResource: z.string().optional(),
|
|
2766
|
+
status: z.enum(['new', 'updated', 'stable']).default('stable').optional(),
|
|
2767
|
+
});
|
|
2768
|
+
|
|
2769
|
+
class AdFormLayoutComponent {
|
|
2770
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
2771
|
+
gap = computed(() => this.resource().gap ?? 'md', ...(ngDevMode ? [{ debugName: "gap" }] : []));
|
|
2772
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdFormLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2773
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.4", type: AdFormLayoutComponent, isStandalone: true, selector: "ad-form-layout", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
2774
|
+
<form class="grid grid-cols-1 md:grid-cols-12 gap-6 items-start">
|
|
2775
|
+
<ng-content></ng-content>
|
|
2776
|
+
|
|
2777
|
+
<!-- Footer Actions -->
|
|
2778
|
+
<div class="md:col-span-12 mt-6 flex justify-end gap-3 border-t border-stone-200 dark:border-cerca-primary pt-6">
|
|
2779
|
+
<ng-content select="[footer-actions]"></ng-content>
|
|
2780
|
+
</div>
|
|
2781
|
+
</form>
|
|
2782
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], encapsulation: i0.ViewEncapsulation.None });
|
|
769
2783
|
}
|
|
770
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
2784
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdFormLayoutComponent, decorators: [{
|
|
771
2785
|
type: Component,
|
|
772
|
-
args: [{
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
2786
|
+
args: [{
|
|
2787
|
+
selector: 'ad-form-layout',
|
|
2788
|
+
standalone: true,
|
|
2789
|
+
imports: [CommonModule],
|
|
2790
|
+
template: `
|
|
2791
|
+
<form class="grid grid-cols-1 md:grid-cols-12 gap-6 items-start">
|
|
2792
|
+
<ng-content></ng-content>
|
|
2793
|
+
|
|
2794
|
+
<!-- Footer Actions -->
|
|
2795
|
+
<div class="md:col-span-12 mt-6 flex justify-end gap-3 border-t border-stone-200 dark:border-cerca-primary pt-6">
|
|
2796
|
+
<ng-content select="[footer-actions]"></ng-content>
|
|
2797
|
+
</div>
|
|
2798
|
+
</form>
|
|
2799
|
+
`,
|
|
2800
|
+
encapsulation: ViewEncapsulation.None
|
|
2801
|
+
}]
|
|
2802
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }] } });
|
|
778
2803
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
2804
|
+
const FormLayoutResourceSchema = z.object({
|
|
2805
|
+
gap: z.enum(['sm', 'md', 'lg']).default('md').optional(),
|
|
2806
|
+
});
|
|
2807
|
+
|
|
2808
|
+
class AdFormPageTemplateComponent {
|
|
2809
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
2810
|
+
title = computed(() => this.resource().title ?? '', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
2811
|
+
backUrl = computed(() => this.resource().backUrl, ...(ngDevMode ? [{ debugName: "backUrl" }] : []));
|
|
2812
|
+
loading = computed(() => this.resource().loading ?? false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
2813
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdFormPageTemplateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2814
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdFormPageTemplateComponent, isStandalone: true, selector: "ad-form-page-template", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"ad-form-page\">\r\n <header class=\"ad-form-page-header\">\r\n <ad-stack [gap]=\"1\">\r\n <div class=\"ad-form-page-nav\">\r\n <ng-content select=\"[back-button]\"></ng-content>\r\n </div>\r\n <h1 class=\"ad-form-page-title\">{{ title() }}</h1>\r\n </ad-stack>\r\n <div class=\"ad-form-page-actions-header\">\r\n <ng-content select=\"[header-actions]\"></ng-content>\r\n </div>\r\n </header>\r\n\r\n <main class=\"ad-form-page-main\">\r\n <div class=\"ad-form-page-card\">\r\n <ng-content select=\"[form-content]\"></ng-content>\r\n </div>\r\n </main>\r\n\r\n <footer class=\"ad-form-page-footer\">\r\n <ng-content select=\"[form-actions]\"></ng-content>\r\n </footer>\r\n\r\n @if (loading()) {\r\n <div class=\"ad-form-page-loading-overlay\">\r\n <div class=\"ad-form-page-spinner\"></div>\r\n </div>\r\n }\r\n</div>", styles: [".ad-form-page{display:flex;flex-direction:column;gap:var(--space-6);position:relative;min-height:100%}.ad-form-page-header{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-4);margin-bottom:var(--space-2)}.ad-form-page-title{font-size:var(--font-size-2xl);font-weight:var(--font-weight-bold);color:var(--color-text-primary)}.ad-form-page-main{flex:1}.ad-form-page-card{background-color:var(--color-bg-primary);border:1px solid var(--color-border-subtle);border-radius:var(--radius-2xl);padding:var(--space-6);box-shadow:var(--shadow-sm)}@media(min-width:768px){.ad-form-page-card{padding:var(--space-8)}}.ad-form-page-footer{background-color:var(--color-bg-primary);border-top:1px solid var(--color-border-subtle);padding:var(--space-4) var(--space-6);margin:0 calc(var(--space-6) * -1);display:flex;justify-content:flex-end;gap:var(--space-4);border-bottom-left-radius:var(--radius-2xl);border-bottom-right-radius:var(--radius-2xl)}.ad-form-page-loading-overlay{position:absolute;inset:0;background-color:#ffffffbf;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);display:flex;align-items:center;justify-content:center;z-index:50;border-radius:var(--radius-2xl)}.ad-form-page-spinner{width:40px;height:40px;border:3px solid var(--color-border-subtle);border-top-color:var(--color-brand-600);border-radius:50%;animation:ad-spin .8s linear infinite}@keyframes ad-spin{to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AdStackComponent, selector: "ad-stack", inputs: ["gap", "align", "justify"] }] });
|
|
786
2815
|
}
|
|
787
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
2816
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdFormPageTemplateComponent, decorators: [{
|
|
788
2817
|
type: Component,
|
|
789
|
-
args: [{ selector: '
|
|
790
|
-
}], propDecorators: {
|
|
791
|
-
type: Input
|
|
792
|
-
}], description: [{
|
|
793
|
-
type: Input
|
|
794
|
-
}], hasFilters: [{
|
|
795
|
-
type: Input
|
|
796
|
-
}], filtersTemplate: [{
|
|
797
|
-
type: ContentChild,
|
|
798
|
-
args: ['filters']
|
|
799
|
-
}] } });
|
|
2818
|
+
args: [{ selector: 'ad-form-page-template', standalone: true, imports: [CommonModule, AdStackComponent], template: "<div class=\"ad-form-page\">\r\n <header class=\"ad-form-page-header\">\r\n <ad-stack [gap]=\"1\">\r\n <div class=\"ad-form-page-nav\">\r\n <ng-content select=\"[back-button]\"></ng-content>\r\n </div>\r\n <h1 class=\"ad-form-page-title\">{{ title() }}</h1>\r\n </ad-stack>\r\n <div class=\"ad-form-page-actions-header\">\r\n <ng-content select=\"[header-actions]\"></ng-content>\r\n </div>\r\n </header>\r\n\r\n <main class=\"ad-form-page-main\">\r\n <div class=\"ad-form-page-card\">\r\n <ng-content select=\"[form-content]\"></ng-content>\r\n </div>\r\n </main>\r\n\r\n <footer class=\"ad-form-page-footer\">\r\n <ng-content select=\"[form-actions]\"></ng-content>\r\n </footer>\r\n\r\n @if (loading()) {\r\n <div class=\"ad-form-page-loading-overlay\">\r\n <div class=\"ad-form-page-spinner\"></div>\r\n </div>\r\n }\r\n</div>", styles: [".ad-form-page{display:flex;flex-direction:column;gap:var(--space-6);position:relative;min-height:100%}.ad-form-page-header{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-4);margin-bottom:var(--space-2)}.ad-form-page-title{font-size:var(--font-size-2xl);font-weight:var(--font-weight-bold);color:var(--color-text-primary)}.ad-form-page-main{flex:1}.ad-form-page-card{background-color:var(--color-bg-primary);border:1px solid var(--color-border-subtle);border-radius:var(--radius-2xl);padding:var(--space-6);box-shadow:var(--shadow-sm)}@media(min-width:768px){.ad-form-page-card{padding:var(--space-8)}}.ad-form-page-footer{background-color:var(--color-bg-primary);border-top:1px solid var(--color-border-subtle);padding:var(--space-4) var(--space-6);margin:0 calc(var(--space-6) * -1);display:flex;justify-content:flex-end;gap:var(--space-4);border-bottom-left-radius:var(--radius-2xl);border-bottom-right-radius:var(--radius-2xl)}.ad-form-page-loading-overlay{position:absolute;inset:0;background-color:#ffffffbf;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);display:flex;align-items:center;justify-content:center;z-index:50;border-radius:var(--radius-2xl)}.ad-form-page-spinner{width:40px;height:40px;border:3px solid var(--color-border-subtle);border-top-color:var(--color-brand-600);border-radius:50%;animation:ad-spin .8s linear infinite}@keyframes ad-spin{to{transform:rotate(360deg)}}\n"] }]
|
|
2819
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }] } });
|
|
800
2820
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
2821
|
+
const FormPageTemplateResourceSchema = z.object({
|
|
2822
|
+
title: z.string().default(''),
|
|
2823
|
+
backUrl: z.string().optional(),
|
|
2824
|
+
loading: z.boolean().default(false).optional(),
|
|
2825
|
+
});
|
|
2826
|
+
|
|
2827
|
+
const FormSectionResourceSchema = z.object({
|
|
2828
|
+
title: z.string().optional(),
|
|
2829
|
+
cols: z.number().default(12).optional(),
|
|
2830
|
+
loading: z.boolean().default(false).optional(),
|
|
2831
|
+
});
|
|
2832
|
+
|
|
2833
|
+
class AdListPageTemplateComponent {
|
|
2834
|
+
resource = input.required(...(ngDevMode ? [{ debugName: "resource" }] : []));
|
|
2835
|
+
title = computed(() => this.resource().title ?? '', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
2836
|
+
description = computed(() => this.resource().description, ...(ngDevMode ? [{ debugName: "description" }] : []));
|
|
2837
|
+
hasFilters = computed(() => this.resource().hasFilters ?? true, ...(ngDevMode ? [{ debugName: "hasFilters" }] : []));
|
|
2838
|
+
filtersTemplate;
|
|
2839
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdListPageTemplateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2840
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AdListPageTemplateComponent, isStandalone: true, selector: "ad-list-page-template", inputs: { resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: true, transformFunction: null } }, queries: [{ propertyName: "filtersTemplate", first: true, predicate: ["filters"], descendants: true }], ngImport: i0, template: "<div class=\"ad-list-page\">\r\n <header class=\"ad-page-header\">\r\n <ad-stack [gap]=\"1\">\r\n <h1 class=\"ad-page-title\">{{ title() }}</h1>\r\n @if (description()) {\r\n <p class=\"ad-page-description\">{{ description() }}</p>\r\n }\r\n </ad-stack>\r\n <div class=\"ad-page-actions\">\r\n <ng-content select=\"[actions]\"></ng-content>\r\n </div>\r\n </header>\r\n\r\n @if (hasFilters()) {\r\n <section class=\"ad-page-filters\">\r\n <ng-content select=\"[filters]\"></ng-content>\r\n </section>\r\n }\r\n\r\n <main class=\"ad-page-main\">\r\n <ng-content select=\"[table]\"></ng-content>\r\n </main>\r\n\r\n <footer class=\"ad-page-footer\">\r\n <ng-content select=\"[pagination]\"></ng-content>\r\n </footer>\r\n</div>", styles: [".ad-list-page{display:flex;flex-direction:column;gap:var(--space-6)}.ad-page-header{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-4);margin-bottom:var(--space-2)}.ad-page-title{font-size:var(--font-size-2xl);font-weight:var(--font-weight-bold);color:var(--color-text-primary);line-height:1.2}.ad-page-description{color:var(--color-text-muted);font-size:var(--font-size-sm)}.ad-page-filters{background-color:var(--color-bg-primary);border:1px solid var(--color-border-subtle);border-radius:var(--radius-xl);padding:var(--space-4)}.ad-page-main{background-color:var(--color-bg-primary);border:1px solid var(--color-border-subtle);border-radius:var(--radius-xl);overflow:hidden;box-shadow:var(--shadow-sm)}.ad-page-footer{display:flex;justify-content:flex-end;margin-top:var(--space-2)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AdStackComponent, selector: "ad-stack", inputs: ["gap", "align", "justify"] }] });
|
|
808
2841
|
}
|
|
809
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type:
|
|
2842
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AdListPageTemplateComponent, decorators: [{
|
|
810
2843
|
type: Component,
|
|
811
|
-
args: [{ selector: '
|
|
812
|
-
}], propDecorators: {
|
|
813
|
-
type:
|
|
814
|
-
|
|
815
|
-
type: Input
|
|
816
|
-
}], loading: [{
|
|
817
|
-
type: Input
|
|
2844
|
+
args: [{ selector: 'ad-list-page-template', standalone: true, imports: [CommonModule, AdStackComponent], template: "<div class=\"ad-list-page\">\r\n <header class=\"ad-page-header\">\r\n <ad-stack [gap]=\"1\">\r\n <h1 class=\"ad-page-title\">{{ title() }}</h1>\r\n @if (description()) {\r\n <p class=\"ad-page-description\">{{ description() }}</p>\r\n }\r\n </ad-stack>\r\n <div class=\"ad-page-actions\">\r\n <ng-content select=\"[actions]\"></ng-content>\r\n </div>\r\n </header>\r\n\r\n @if (hasFilters()) {\r\n <section class=\"ad-page-filters\">\r\n <ng-content select=\"[filters]\"></ng-content>\r\n </section>\r\n }\r\n\r\n <main class=\"ad-page-main\">\r\n <ng-content select=\"[table]\"></ng-content>\r\n </main>\r\n\r\n <footer class=\"ad-page-footer\">\r\n <ng-content select=\"[pagination]\"></ng-content>\r\n </footer>\r\n</div>", styles: [".ad-list-page{display:flex;flex-direction:column;gap:var(--space-6)}.ad-page-header{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-4);margin-bottom:var(--space-2)}.ad-page-title{font-size:var(--font-size-2xl);font-weight:var(--font-weight-bold);color:var(--color-text-primary);line-height:1.2}.ad-page-description{color:var(--color-text-muted);font-size:var(--font-size-sm)}.ad-page-filters{background-color:var(--color-bg-primary);border:1px solid var(--color-border-subtle);border-radius:var(--radius-xl);padding:var(--space-4)}.ad-page-main{background-color:var(--color-bg-primary);border:1px solid var(--color-border-subtle);border-radius:var(--radius-xl);overflow:hidden;box-shadow:var(--shadow-sm)}.ad-page-footer{display:flex;justify-content:flex-end;margin-top:var(--space-2)}\n"] }]
|
|
2845
|
+
}], propDecorators: { resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: true }] }], filtersTemplate: [{
|
|
2846
|
+
type: ContentChild,
|
|
2847
|
+
args: ['filters']
|
|
818
2848
|
}] } });
|
|
819
2849
|
|
|
820
|
-
|
|
2850
|
+
const ListPageTemplateResourceSchema = z.object({
|
|
2851
|
+
title: z.string().default(''),
|
|
2852
|
+
description: z.string().optional(),
|
|
2853
|
+
hasFilters: z.boolean().default(true).optional(),
|
|
2854
|
+
});
|
|
821
2855
|
|
|
822
2856
|
/*
|
|
823
|
-
* Public API Surface of
|
|
2857
|
+
* Public API Surface of design-system
|
|
824
2858
|
*/
|
|
825
2859
|
|
|
826
2860
|
/**
|
|
827
2861
|
* Generated bundle index. Do not edit.
|
|
828
2862
|
*/
|
|
829
2863
|
|
|
830
|
-
export {
|
|
2864
|
+
export { AdAdminLayoutComponent, AdAuthLayoutComponent, AdBadgeComponent, AdButtonComponent, AdCardComponent, AdDashboardTemplateComponent, AdDataTableComponent, AdDescriptionHeaderComponent, AdDocViewerComponent, AdDocumentationWrapperComponent, AdFormFieldComponent, AdFormLayoutComponent, AdFormPageTemplateComponent, AdFormSectionComponent, AdHeaderComponent, AdIconComponent, AdInputComponent, AdLabelComponent, AdListPageTemplateComponent, AdLoadingComponent, AdLoginComponent, AdModalComponent, AdModalService, AdModalTriggerComponent, AdModalWrapperComponent, AdSearchBarComponent, AdSelectComponent, AdSidebarComponent, AdStatCardComponent, AdSwitchComponent, AdTableColumnSchema, AdTableComponent, AdminLayoutResourceSchema, AdminSectionCardActionSchema, AdminSectionCardComponent, AdminSectionCardResourceSchema, AuthLayoutResourceSchema, CardResourceSchema, ComponentApiInputSchema, ComponentApiOutputSchema, ComponentVariantSchema, DashboardTemplateResourceSchema, DataTableColumnSchema, DataTableResourceSchema, DescriptionHeaderButtonSchema, DescriptionHeaderResourceSchema, DesignSystem, DocStatusSchema, DocViewerResourceSchema, DocumentationWrapperResourceSchema, FieldRendererRegistry, FormEngineComponent, FormEngineService, FormFieldResourceSchema, FormLayoutResourceSchema, FormPageTemplateResourceSchema, FormSectionResourceSchema, HeaderResourceSchema, ListPageTemplateResourceSchema, LoginResourceSchema, ModalResourceSchema, ModalTriggerResourceSchema, NavItemSchema, STAT_CARD_COLOR_MAP, SearchBarResourceSchema, SidebarResourceSchema, StatCardColorSchema, StatCardResourceSchema, TableEngineComponent, TableResourceSchema, UserSchema, ValidatorRegistry };
|
|
831
2865
|
//# sourceMappingURL=cerca-design-system.mjs.map
|