@some-angular-utils/table 0.0.18 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,63 +1,37 @@
1
- # Table
1
+ # @some-angular-utils/table
2
2
 
3
- This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.3.0.
3
+ ![NPM Version](https://img.shields.io/npm/v/%40some-angular-utils%2Ftable)
4
+ ![NPM Downloads](https://img.shields.io/npm/dm/%40some-angular-utils%2Ftable)
4
5
 
5
- ## Code scaffolding
6
+ ![npm bundle size](https://img.shields.io/bundlephobia/min/%40some-angular-utils%2Ftable)
7
+ ![npm bundle size](https://img.shields.io/bundlephobia/minzip/%40some-angular-utils%2Ftable)
6
8
 
7
- Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
8
-
9
- ```bash
10
- ng generate component component-name
11
- ```
12
-
13
- For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
14
-
15
- ```bash
16
- ng generate --help
17
- ```
18
-
19
- ## Building
20
-
21
- To build the library, run:
22
-
23
- ```bash
24
- ng build table
25
- ```
26
-
27
- This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
28
-
29
- ### Publishing the Library
30
-
31
- Once the project is built, you can publish your library by following these steps:
32
-
33
- 1. Navigate to the `dist` directory:
34
- ```bash
35
- cd dist/table
36
- ```
37
-
38
- 2. Run the `npm publish` command to publish your library to the npm registry:
39
- ```bash
40
- npm publish
41
- ```
42
-
43
- ## Running unit tests
44
-
45
- To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
46
-
47
- ```bash
48
- ng test
9
+ ## IMPORT
10
+ ```ts
11
+ import { TableModule } from '@some-angular-utils/table';
49
12
  ```
50
13
 
51
- ## Running end-to-end tests
52
-
53
- For end-to-end (e2e) testing, run:
14
+ ## TYPESCRIPT
15
+ ```ts
16
+ public url = 'https://pokeapi.co/api/v2/pokemon';
54
17
 
55
- ```bash
56
- ng e2e
18
+ public headers = [
19
+ { name: 'NOMBRE', key: 'name' },
20
+ { name: 'URL', key: 'url', type: 'link', linkName: 'Ver' },
21
+ { name: 'IMG', key: 'name', type: 'image', url: 'https://img.pokemondb.net/artwork/{key}.jpg' }
22
+ ]
57
23
  ```
58
24
 
59
- Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
60
-
61
- ## Additional Resources
62
-
63
- For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
25
+ ## HTML
26
+ ```ts
27
+ <sau-table
28
+ [url]="url"
29
+ contentList="results"
30
+ contentTotal="count"
31
+ pageParamName="offset"
32
+ limitParamName="limit"
33
+ [sizeBetweenPages]="10"
34
+ [limit]="10"
35
+ [headers]="headers"
36
+ ></sau-table>
37
+ ```
@@ -1,22 +1,200 @@
1
+ import * as i3 from '@angular/common';
2
+ import { CommonModule, DatePipe } from '@angular/common';
1
3
  import * as i0 from '@angular/core';
2
- import { Component } from '@angular/core';
4
+ import { EventEmitter, Input, Output, Component } from '@angular/core';
5
+ import * as i2 from '@angular/router';
6
+ import { RouterModule } from '@angular/router';
7
+ import * as i1 from '@angular/common/http';
3
8
 
4
9
  class TableModule {
5
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TableModule, deps: [], target: i0.ɵɵFactoryTarget.Component });
6
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: TableModule, isStandalone: true, selector: "lib-table", ngImport: i0, template: `
7
- <p>
8
- table works!
9
- </p>
10
- `, isInline: true, styles: [""] });
10
+ http;
11
+ cdr;
12
+ url;
13
+ contentList;
14
+ contentTotal;
15
+ pageParamName = 'page';
16
+ limitParamName = 'limit';
17
+ sizeInitialPage = 0;
18
+ sizeBetweenPages = 1;
19
+ headers;
20
+ editEvent = new EventEmitter();
21
+ deleteEvent = new EventEmitter();
22
+ loading = false;
23
+ items = [];
24
+ total = [];
25
+ page = 1;
26
+ limit = 10;
27
+ // Getter para obtener las páginas visibles (3 antes y 3 después de la página actual)
28
+ get visiblePages() {
29
+ const totalPages = this.total.length;
30
+ if (totalPages <= 7) {
31
+ // Si hay 7 páginas o menos, mostrar todas
32
+ return this.total;
33
+ }
34
+ const currentPage = this.page;
35
+ const start = Math.max(1, currentPage - 3);
36
+ const end = Math.min(totalPages, currentPage + 3);
37
+ const pages = [];
38
+ for (let i = start; i <= end; i++) {
39
+ pages.push(i);
40
+ }
41
+ return pages;
42
+ }
43
+ constructor(http, cdr) {
44
+ this.http = http;
45
+ this.cdr = cdr;
46
+ }
47
+ ngOnInit() {
48
+ if (this.url) {
49
+ this.getItems();
50
+ }
51
+ }
52
+ // Método para obtener la página interna (0-based si sizeInitialPage es 0, 1-based si es 1)
53
+ getInternalPage() {
54
+ if (this.sizeInitialPage === 0) {
55
+ return (this.page - 1) * this.sizeBetweenPages;
56
+ }
57
+ return this.page * this.sizeBetweenPages;
58
+ }
59
+ getItems() {
60
+ this.loading = true;
61
+ this.cdr.detectChanges(); // Forzar detección antes de la petición
62
+ const internalPage = this.getInternalPage();
63
+ const filters = `?${this.pageParamName}=${internalPage}&${this.limitParamName}=${this.limit}`;
64
+ this.http.get(this.url + filters).subscribe({
65
+ next: (data) => {
66
+ if (this.contentList && data[this.contentList]) {
67
+ this.items = [...data[this.contentList]]; // Crear nueva referencia del array
68
+ }
69
+ else {
70
+ this.items = [...data]; // Crear nueva referencia del array
71
+ }
72
+ if (this.contentTotal) {
73
+ this.total = [];
74
+ for (let i = 0; i < data[this.contentTotal] / this.limit; i++) {
75
+ this.total.push(i + 1);
76
+ }
77
+ }
78
+ this.loading = false;
79
+ this.cdr.detectChanges(); // Forzar detección después de actualizar datos
80
+ },
81
+ error: (error) => {
82
+ console.error('ERROR obtener productos. ' + error);
83
+ this.loading = false;
84
+ this.cdr.detectChanges();
85
+ }
86
+ });
87
+ }
88
+ // Método simple para refrescar la tabla
89
+ refresh() {
90
+ if (this.url) {
91
+ this.items = []; // Limpiar array primero
92
+ this.cdr.detectChanges(); // Forzar actualización
93
+ this.getItems();
94
+ }
95
+ }
96
+ getLink(pattern = '{key}', item, value) {
97
+ const keyValue = this.getValue(item, value);
98
+ const url = pattern.replace('{key}', keyValue);
99
+ const isExternal = url.startsWith('http://') || url.startsWith('https://');
100
+ return {
101
+ url,
102
+ isExternal
103
+ };
104
+ }
105
+ getValue(item, key) {
106
+ let arrayKey = [];
107
+ if (!Array.isArray(key)) {
108
+ arrayKey.push(key);
109
+ }
110
+ else {
111
+ arrayKey = key.slice();
112
+ }
113
+ let result = '';
114
+ while (arrayKey.length > 0) {
115
+ let keys = arrayKey[0].split('.');
116
+ let value = item;
117
+ if (keys[0].includes('[]')) {
118
+ let arrayKey = keys[0].replace('[]', '');
119
+ value = value[arrayKey].map((element) => this.getValue(element, keys.slice(1).join('.'))).join(', ');
120
+ }
121
+ else {
122
+ let finalValue = item[String(key)];
123
+ let isArray = Array.isArray(finalValue);
124
+ let isBoolean = typeof finalValue === 'boolean';
125
+ if (isArray || isBoolean) {
126
+ return finalValue;
127
+ }
128
+ for (let i = 0; value && i < keys.length; i++) {
129
+ value = value[keys[i]];
130
+ }
131
+ }
132
+ arrayKey.shift();
133
+ result += (value ?? '') + (arrayKey.length > 0 ? ' ' : '');
134
+ }
135
+ return result;
136
+ }
137
+ isArray(array) {
138
+ return Array.isArray(array);
139
+ }
140
+ changePage(page) {
141
+ this.page = page;
142
+ this.getItems();
143
+ }
144
+ // Método para ir a la primera página
145
+ goToFirstPage() {
146
+ if (this.page !== 1) {
147
+ this.changePage(1);
148
+ }
149
+ }
150
+ // Método para ir a la última página
151
+ goToLastPage() {
152
+ const lastPage = this.total.length;
153
+ if (this.page !== lastPage && lastPage > 0) {
154
+ this.changePage(lastPage);
155
+ }
156
+ }
157
+ clickEditButton(id) {
158
+ this.editEvent.emit(id);
159
+ }
160
+ clickDeleteButton(id) {
161
+ this.deleteEvent.emit(id);
162
+ }
163
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TableModule, deps: [{ token: i1.HttpClient }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
164
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: TableModule, isStandalone: true, selector: "sau-table", inputs: { url: "url", contentList: "contentList", contentTotal: "contentTotal", pageParamName: "pageParamName", limitParamName: "limitParamName", sizeInitialPage: "sizeInitialPage", sizeBetweenPages: "sizeBetweenPages", headers: "headers", items: "items", limit: "limit" }, outputs: { editEvent: "editEvent", deleteEvent: "deleteEvent" }, ngImport: i0, template: "@if (loading) {\n<div>\n Loading\n</div>\n}\n\n<div class=\"overflow-auto rounded-2xl bg-white/90 backdrop-blur-lg shadow-xl border border-white/50\">\n\n <!----------------------------------- Table mobile ----------------------------------->\n <div class=\"md:hidden\">\n <!-- Mobile header -->\n <div class=\"bg-gradient-to-r from-purple-600 to-pink-600 text-white px-4 py-2 rounded-t-2xl\">\n <h3 class=\"text-base font-semibold leading-tight\">Lista de elementos</h3>\n <div class=\"w-8 h-0.5 bg-white/30 rounded-full mt-1\"></div>\n </div>\n\n <table class=\"w-full text-sm text-left rtl:text-right text-neutral-700\">\n <tbody>\n @for (item of items; track $index) {\n <tr class=\"border-b border-purple-100/50 last:border-b-0\">\n <td>\n <table class=\"w-full\">\n <tbody>\n @for (header of headers; track $index) {\n <tr [class]=\"$index%2==0?'bg-purple-50/30':''\">\n\n <th scope=\"col\"\n class=\"p-2 font-medium bg-gradient-to-r from-purple-600 to-pink-600 text-white max-w-min\">\n {{header.name}}\n </th>\n <td class=\"p-2 w-full text-neutral-800\">\n\n @if(header.type == 'table' && !isArray(header.key)){\n\n <!-- CSS-only toggle button -->\n <input type=\"checkbox\" [id]=\"'toggle-table-' + $index\" class=\"hidden peer\">\n <label [for]=\"'toggle-table-' + $index\"\n class=\"inline-flex items-center gap-2 px-3 py-2 bg-purple-100 text-purple-600 rounded-lg hover:bg-purple-200 transition-all duration-200 cursor-pointer select-none\">\n <!-- <fa-icon [icon]=\"['fas', 'chevron-down']\"\n class=\"text-xs transition-transform duration-200 peer-checked:rotate-180\"></fa-icon> -->\n <span class=\"text-sm font-medium\">\n <span class=\"peer-checked:hidden\">Mostrar</span>\n <span class=\"hidden peer-checked:inline\">Ocultar</span>\n </span>\n </label>\n\n <!-- Content that toggles -->\n <div\n class=\"mt-3 h-0 overflow-hidden opacity-0 peer-checked:h-auto peer-checked:opacity-100 peer-checked:overflow-visible transition-all duration-300 ease-in-out\">\n <sau-table [headers]=\"header.headers\"\n [items]=\"getValue(item, header.key)\"></sau-table>\n </div>\n\n }@else{\n <ng-container [ngTemplateOutlet]=\"DataTemplate\"\n [ngTemplateOutletContext]=\"{item:item, header:header}\"></ng-container>\n\n }\n\n </td>\n\n </tr>\n }\n\n @if(this.url){\n <tr\n class=\"border-b-8 border-transparent bg-gradient-to-r from-purple-600 to-purple-400 p-4\">\n <td colspan=\"2\">\n <div class=\"flex justify-center gap-4 p-4\">\n @if(editEvent.observers.length > 0){\n <button\n class=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-purple-600 bg-purple-50 hover:bg-purple-100 rounded-lg transition-all duration-200 border border-purple-200 hover:border-purple-300\"\n (click)=\"clickEditButton(item.id)\">\n <!-- <fa-icon [icon]=\"['fas', 'pen']\" class=\"text-xs\"></fa-icon> -->\n Editar\n </button>\n }\n\n @if(deleteEvent.observers.length > 0){\n <button\n class=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-rose-600 bg-rose-50 hover:bg-rose-100 rounded-lg transition-all duration-200 border border-rose-200 hover:border-rose-300\"\n (click)=\"clickDeleteButton(item.id)\">\n <!-- <fa-icon [icon]=\"['fas', 'trash-can']\" class=\"text-xs\"></fa-icon> -->\n Eliminar\n </button>\n }\n </div>\n </td>\n </tr>\n }\n\n </tbody>\n </table>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n <!--------------------------------- Table mobile end --------------------------------->\n\n <!----------------------------------- Table desktop ----------------------------------->\n <table class=\"w-full text-sm text-center rtl:text-right text-neutral-700 hidden md:table\">\n <thead class=\"text-xs font-semibold uppercase bg-gradient-to-r from-purple-600 to-pink-600 text-white\">\n <tr>\n @for (header of headers; track $index) {\n <th scope=\"col\" class=\"p-2\">\n {{header.name}}\n </th>\n }\n\n @if(this.url){\n <th scope=\"col\" class=\"p-2\">\n Opciones\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (item of items; track $index) {\n <tr\n [class]=\"'min-w-max hover:bg-purple-50/50 transition-colors duration-200 border-b border-purple-100/30 last:border-b-0 ' + ($index%2==0?'bg-purple-50/20':'')\">\n\n @for (header of headers; track $index) {\n <td class=\"p-2\">\n\n @if(header.type == 'table'){\n\n @if(!isArray(header.key)){\n <sau-table [headers]=\"header.headers\" [items]=\"getValue(item, header.key)\"></sau-table>\n }\n\n }@else{\n <ng-container [ngTemplateOutlet]=\"DataTemplate\"\n [ngTemplateOutletContext]=\"{item:item, header:header}\"></ng-container>\n }\n\n </td>\n }\n\n @if(this.url){\n <td class=\"px-6 py-4\">\n <div class=\"flex items-center gap-2\">\n @if(editEvent.observers.length > 0){\n <button\n class=\"inline-flex items-center justify-center w-8 h-8 text-purple-600 bg-purple-50 hover:bg-purple-100 rounded-lg transition-all duration-200 border border-purple-200 hover:border-purple-300\"\n (click)=\"clickEditButton(item.id)\" title=\"Editar\">\n <!-- <fa-icon [icon]=\"['fas', 'pen']\" class=\"text-xs\"></fa-icon> -->\n </button>\n }\n\n @if(deleteEvent.observers.length > 0){\n <button\n class=\"inline-flex items-center justify-center w-8 h-8 text-rose-600 bg-rose-50 hover:bg-rose-100 rounded-lg transition-all duration-200 border border-rose-200 hover:border-rose-300\"\n (click)=\"clickDeleteButton(item.id)\" title=\"Eliminar\">\n <!-- <fa-icon [icon]=\"['fas', 'trash-can']\" class=\"text-xs\"></fa-icon> -->\n </button>\n }\n </div>\n </td>\n }\n\n </tr>\n }\n </tbody>\n </table>\n <!--------------------------------- table desktop end --------------------------------->\n\n @if (items.length == 0) {\n <div class=\"flex flex-col items-center justify-center h-48 text-center\">\n <div class=\"w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mb-4\">\n <!-- <fa-icon [icon]=\"['fas', 'inbox']\" class=\"text-purple-400 text-2xl\"></fa-icon> -->\n </div>\n <p class=\"text-neutral-500 font-medium\">No hay elementos</p>\n <p class=\"text-neutral-400 text-sm\">Los elementos aparecer\u00E1n aqu\u00ED cuando est\u00E9n disponibles</p>\n </div>\n\n } @else if(total.length > 1) {\n\n <!----------------------------------- Pagination ----------------------------------->\n <div\n class=\"sticky left-0 flex flex-wrap gap-2 items-center justify-center md:justify-between p-6 bg-gradient-to-r from-purple-50/50 to-pink-50/50 border-t border-purple-200/50\">\n\n <!-- N\u00FAmeros de p\u00E1gina -->\n <div class=\"md:order-2 w-full md:w-max flex items-center justify-center gap-2\">\n @for (item of visiblePages; track $index) {\n <button (click)=\"changePage(item)\"\n [class]=\"'cursor-pointer w-10 h-10 rounded-lg font-medium text-sm transition-all duration-200 ' + (item == page ? 'bg-gradient-to-r from-purple-500 to-pink-500 text-white shadow-lg' : 'text-purple-600 hover:bg-purple-50 border border-purple-200 hover:border-purple-300')\"\n type=\"button\">\n {{item}}\n </button>\n }\n </div>\n\n <!-- Botones de navegaci\u00F3n izquierda -->\n <div class=\"md:order-1 flex items-center gap-2\">\n <!-- Bot\u00F3n ir al inicio -->\n <button type=\"button\" (click)=\"goToFirstPage()\"\n [class]=\"'cursor-pointer inline-flex items-center justify-center px-3 h-10 text-purple-600 bg-white border border-purple-200 rounded-lg hover:bg-purple-50 transition-all duration-200 text-sm font-medium ' + (page == 1?'opacity-50 pointer-events-none':'hover:border-purple-300')\"\n title=\"Ir al inicio\">\n \u2039\u2039\n </button>\n\n <!-- Bot\u00F3n p\u00E1gina anterior -->\n <button type=\"button\" (click)=\"changePage(page-1)\"\n [class]=\"'cursor-pointer inline-flex items-center justify-center w-10 h-10 text-purple-600 bg-white border border-purple-200 rounded-lg hover:bg-purple-50 transition-all duration-200 ' + (page == 1?'opacity-50 pointer-events-none':'hover:border-purple-300')\"\n title=\"P\u00E1gina anterior\">\n \u2039\n </button>\n </div>\n\n <!-- Botones de navegaci\u00F3n derecha -->\n <div class=\"md:order-3 flex items-center gap-2\">\n <!-- Bot\u00F3n p\u00E1gina siguiente -->\n <button type=\"button\" (click)=\"changePage(page+1)\"\n [class]=\"'cursor-pointer inline-flex items-center justify-center w-10 h-10 text-purple-600 bg-white border border-purple-200 rounded-lg hover:bg-purple-50 transition-all duration-200 ' + (page == total[total.length-1]?'opacity-50 pointer-events-none':'hover:border-purple-300')\"\n title=\"P\u00E1gina siguiente\">\n \u203A\n </button>\n\n <!-- Bot\u00F3n ir al final -->\n <button type=\"button\" (click)=\"goToLastPage()\"\n [class]=\"'cursor-pointer inline-flex items-center justify-center px-3 h-10 text-purple-600 bg-white border border-purple-200 rounded-lg hover:bg-purple-50 transition-all duration-200 text-sm font-medium ' + (page == total[total.length-1]?'opacity-50 pointer-events-none':'hover:border-purple-300')\"\n title=\"Ir al final\">\n \u203A\u203A\n </button>\n </div>\n </div>\n <!--------------------------------- pagination end --------------------------------->\n }\n\n</div>\n\n<!----------------------------------- Data template ----------------------------------->\n<ng-template #DataTemplate let-item=\"item\" let-header=\"header\">\n\n <section class=\"flex items-center gap-2\">\n\n @if(header.name == 'NOMBRE' && item.role == 'ROLE_ADMIN') {\n <div class=\"inline-flex items-center justify-center w-6 h-6 bg-orange-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-orange-600', 'text-xs']\" [icon]=\"['fas', 'crown']\"></fa-icon> -->\n </div>\n }\n\n <span>\n @if (header.innerHtml) {\n <span [innerHTML]=\"getValue(item, header.key)\"></span>\n } @else {\n <ng-container [ngTemplateOutlet]=\"DataTypeTemplate\"\n [ngTemplateOutletContext]=\"{item:item, header:header, value:header.key}\"></ng-container>\n }\n\n @if(header.subKey){\n <span class=\"block text-neutral-600 text-xs min-w-max\">\n (\n <ng-container [ngTemplateOutlet]=\"DataTypeTemplate\"\n [ngTemplateOutletContext]=\"{item:item, header:header, value:header.subKey}\"></ng-container>\n )\n </span>\n }\n </span>\n\n </section>\n\n</ng-template>\n<!--------------------------------- Data template end --------------------------------->\n\n<!----------------------------------- Data Type template ----------------------------------->\n<ng-template #DataTypeTemplate let-item=\"item\" let-header=\"header\" let-value=\"value\">\n\n <section class=\"inline-block min-w-max\">\n @switch (header.type) {\n\n @case ('boolean') {\n @if(getValue(item, value)){\n <div class=\"inline-flex items-center justify-center w-6 h-6 bg-emerald-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-emerald-600', 'text-xs']\" [icon]=\"['fas', 'check']\"></fa-icon> -->\n </div>\n } @else {\n <div class=\"inline-flex items-center justify-center w-6 h-6 bg-rose-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-rose-600', 'text-xs']\" [icon]=\"['fas', 'xmark']\"></fa-icon> -->\n </div>\n }\n }\n\n @case ('currency'){\n <!-- {{formatEuro(getValue(item, value))}} -->\n }\n\n @case ('dateTime') {\n <span class=\"text-neutral-600 text-sm\">\n {{getValue(item, value) | date: 'dd/MM/yyyy HH:mm'}}\n </span>\n }\n\n @case ('color'){\n <span class=\"inline-block w-8 h-4 rounded-full border border-neutral-200 shadow-sm\"\n [style.background-color]=\"getValue(item, value)\"></span>\n }\n\n @case ('link'){\n @let link = getLink(header.url, item, value);\n\n @if(link.isExternal){\n <a [href]=\"link.url\" class=\"text-purple-600 hover:underline\">\n {{header.linkName}}\n </a>\n }@else{\n <a [routerLink]=\"link.url\" class=\"text-purple-600 hover:underline\" target=\"_blank\">\n {{header.linkName}}\n </a>\n }\n\n }\n\n @case ('image'){\n @let link = getLink(header.url, item, value);\n\n <img [src]=\"link.url\" [alt]=\"getValue(item, value)\" loading=\"lazy\" class=\"w-10 h-10 object-cover\">\n }\n\n @case ('login'){\n @if(item.active){\n <span class=\"inline-flex items-center gap-1\">\n\n @if(item.email_verified_at){\n <div [title]=\"item.email\" class=\"inline-flex items-center justify-center w-6 h-6 bg-blue-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-blue-600', 'text-xs']\" [icon]=\"['fas', 'envelope']\"></fa-icon> -->\n </div>\n }\n\n @if(item.google_id){\n <div [title]=\"item.google_id\"\n class=\"inline-flex items-center justify-center w-6 h-6 bg-red-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-red-600', 'text-xs']\" [icon]=\"['fab', 'google']\"></fa-icon> -->\n </div>\n }\n\n </span>\n } @else {\n <div class=\"inline-flex items-center justify-center w-6 h-6 bg-rose-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-rose-600', 'text-xs']\" [icon]=\"['fas', 'xmark']\"></fa-icon> -->\n </div>\n }\n }\n\n @default {\n {{getValue(item, value)}}\n }\n }\n </section>\n\n</ng-template>\n<!--------------------------------- Data Type template end --------------------------------->", dependencies: [{ kind: "component", type: TableModule, selector: "sau-table", inputs: ["url", "contentList", "contentTotal", "pageParamName", "limitParamName", "sizeInitialPage", "sizeBetweenPages", "headers", "items", "limit"], outputs: ["editEvent", "deleteEvent"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: DatePipe, name: "date" }] });
11
165
  }
12
166
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TableModule, decorators: [{
13
167
  type: Component,
14
- args: [{ selector: 'lib-table', imports: [], template: `
15
- <p>
16
- table works!
17
- </p>
18
- ` }]
19
- }] });
168
+ args: [{ selector: 'sau-table', imports: [
169
+ RouterModule,
170
+ DatePipe,
171
+ CommonModule,
172
+ ], template: "@if (loading) {\n<div>\n Loading\n</div>\n}\n\n<div class=\"overflow-auto rounded-2xl bg-white/90 backdrop-blur-lg shadow-xl border border-white/50\">\n\n <!----------------------------------- Table mobile ----------------------------------->\n <div class=\"md:hidden\">\n <!-- Mobile header -->\n <div class=\"bg-gradient-to-r from-purple-600 to-pink-600 text-white px-4 py-2 rounded-t-2xl\">\n <h3 class=\"text-base font-semibold leading-tight\">Lista de elementos</h3>\n <div class=\"w-8 h-0.5 bg-white/30 rounded-full mt-1\"></div>\n </div>\n\n <table class=\"w-full text-sm text-left rtl:text-right text-neutral-700\">\n <tbody>\n @for (item of items; track $index) {\n <tr class=\"border-b border-purple-100/50 last:border-b-0\">\n <td>\n <table class=\"w-full\">\n <tbody>\n @for (header of headers; track $index) {\n <tr [class]=\"$index%2==0?'bg-purple-50/30':''\">\n\n <th scope=\"col\"\n class=\"p-2 font-medium bg-gradient-to-r from-purple-600 to-pink-600 text-white max-w-min\">\n {{header.name}}\n </th>\n <td class=\"p-2 w-full text-neutral-800\">\n\n @if(header.type == 'table' && !isArray(header.key)){\n\n <!-- CSS-only toggle button -->\n <input type=\"checkbox\" [id]=\"'toggle-table-' + $index\" class=\"hidden peer\">\n <label [for]=\"'toggle-table-' + $index\"\n class=\"inline-flex items-center gap-2 px-3 py-2 bg-purple-100 text-purple-600 rounded-lg hover:bg-purple-200 transition-all duration-200 cursor-pointer select-none\">\n <!-- <fa-icon [icon]=\"['fas', 'chevron-down']\"\n class=\"text-xs transition-transform duration-200 peer-checked:rotate-180\"></fa-icon> -->\n <span class=\"text-sm font-medium\">\n <span class=\"peer-checked:hidden\">Mostrar</span>\n <span class=\"hidden peer-checked:inline\">Ocultar</span>\n </span>\n </label>\n\n <!-- Content that toggles -->\n <div\n class=\"mt-3 h-0 overflow-hidden opacity-0 peer-checked:h-auto peer-checked:opacity-100 peer-checked:overflow-visible transition-all duration-300 ease-in-out\">\n <sau-table [headers]=\"header.headers\"\n [items]=\"getValue(item, header.key)\"></sau-table>\n </div>\n\n }@else{\n <ng-container [ngTemplateOutlet]=\"DataTemplate\"\n [ngTemplateOutletContext]=\"{item:item, header:header}\"></ng-container>\n\n }\n\n </td>\n\n </tr>\n }\n\n @if(this.url){\n <tr\n class=\"border-b-8 border-transparent bg-gradient-to-r from-purple-600 to-purple-400 p-4\">\n <td colspan=\"2\">\n <div class=\"flex justify-center gap-4 p-4\">\n @if(editEvent.observers.length > 0){\n <button\n class=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-purple-600 bg-purple-50 hover:bg-purple-100 rounded-lg transition-all duration-200 border border-purple-200 hover:border-purple-300\"\n (click)=\"clickEditButton(item.id)\">\n <!-- <fa-icon [icon]=\"['fas', 'pen']\" class=\"text-xs\"></fa-icon> -->\n Editar\n </button>\n }\n\n @if(deleteEvent.observers.length > 0){\n <button\n class=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-rose-600 bg-rose-50 hover:bg-rose-100 rounded-lg transition-all duration-200 border border-rose-200 hover:border-rose-300\"\n (click)=\"clickDeleteButton(item.id)\">\n <!-- <fa-icon [icon]=\"['fas', 'trash-can']\" class=\"text-xs\"></fa-icon> -->\n Eliminar\n </button>\n }\n </div>\n </td>\n </tr>\n }\n\n </tbody>\n </table>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n <!--------------------------------- Table mobile end --------------------------------->\n\n <!----------------------------------- Table desktop ----------------------------------->\n <table class=\"w-full text-sm text-center rtl:text-right text-neutral-700 hidden md:table\">\n <thead class=\"text-xs font-semibold uppercase bg-gradient-to-r from-purple-600 to-pink-600 text-white\">\n <tr>\n @for (header of headers; track $index) {\n <th scope=\"col\" class=\"p-2\">\n {{header.name}}\n </th>\n }\n\n @if(this.url){\n <th scope=\"col\" class=\"p-2\">\n Opciones\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (item of items; track $index) {\n <tr\n [class]=\"'min-w-max hover:bg-purple-50/50 transition-colors duration-200 border-b border-purple-100/30 last:border-b-0 ' + ($index%2==0?'bg-purple-50/20':'')\">\n\n @for (header of headers; track $index) {\n <td class=\"p-2\">\n\n @if(header.type == 'table'){\n\n @if(!isArray(header.key)){\n <sau-table [headers]=\"header.headers\" [items]=\"getValue(item, header.key)\"></sau-table>\n }\n\n }@else{\n <ng-container [ngTemplateOutlet]=\"DataTemplate\"\n [ngTemplateOutletContext]=\"{item:item, header:header}\"></ng-container>\n }\n\n </td>\n }\n\n @if(this.url){\n <td class=\"px-6 py-4\">\n <div class=\"flex items-center gap-2\">\n @if(editEvent.observers.length > 0){\n <button\n class=\"inline-flex items-center justify-center w-8 h-8 text-purple-600 bg-purple-50 hover:bg-purple-100 rounded-lg transition-all duration-200 border border-purple-200 hover:border-purple-300\"\n (click)=\"clickEditButton(item.id)\" title=\"Editar\">\n <!-- <fa-icon [icon]=\"['fas', 'pen']\" class=\"text-xs\"></fa-icon> -->\n </button>\n }\n\n @if(deleteEvent.observers.length > 0){\n <button\n class=\"inline-flex items-center justify-center w-8 h-8 text-rose-600 bg-rose-50 hover:bg-rose-100 rounded-lg transition-all duration-200 border border-rose-200 hover:border-rose-300\"\n (click)=\"clickDeleteButton(item.id)\" title=\"Eliminar\">\n <!-- <fa-icon [icon]=\"['fas', 'trash-can']\" class=\"text-xs\"></fa-icon> -->\n </button>\n }\n </div>\n </td>\n }\n\n </tr>\n }\n </tbody>\n </table>\n <!--------------------------------- table desktop end --------------------------------->\n\n @if (items.length == 0) {\n <div class=\"flex flex-col items-center justify-center h-48 text-center\">\n <div class=\"w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mb-4\">\n <!-- <fa-icon [icon]=\"['fas', 'inbox']\" class=\"text-purple-400 text-2xl\"></fa-icon> -->\n </div>\n <p class=\"text-neutral-500 font-medium\">No hay elementos</p>\n <p class=\"text-neutral-400 text-sm\">Los elementos aparecer\u00E1n aqu\u00ED cuando est\u00E9n disponibles</p>\n </div>\n\n } @else if(total.length > 1) {\n\n <!----------------------------------- Pagination ----------------------------------->\n <div\n class=\"sticky left-0 flex flex-wrap gap-2 items-center justify-center md:justify-between p-6 bg-gradient-to-r from-purple-50/50 to-pink-50/50 border-t border-purple-200/50\">\n\n <!-- N\u00FAmeros de p\u00E1gina -->\n <div class=\"md:order-2 w-full md:w-max flex items-center justify-center gap-2\">\n @for (item of visiblePages; track $index) {\n <button (click)=\"changePage(item)\"\n [class]=\"'cursor-pointer w-10 h-10 rounded-lg font-medium text-sm transition-all duration-200 ' + (item == page ? 'bg-gradient-to-r from-purple-500 to-pink-500 text-white shadow-lg' : 'text-purple-600 hover:bg-purple-50 border border-purple-200 hover:border-purple-300')\"\n type=\"button\">\n {{item}}\n </button>\n }\n </div>\n\n <!-- Botones de navegaci\u00F3n izquierda -->\n <div class=\"md:order-1 flex items-center gap-2\">\n <!-- Bot\u00F3n ir al inicio -->\n <button type=\"button\" (click)=\"goToFirstPage()\"\n [class]=\"'cursor-pointer inline-flex items-center justify-center px-3 h-10 text-purple-600 bg-white border border-purple-200 rounded-lg hover:bg-purple-50 transition-all duration-200 text-sm font-medium ' + (page == 1?'opacity-50 pointer-events-none':'hover:border-purple-300')\"\n title=\"Ir al inicio\">\n \u2039\u2039\n </button>\n\n <!-- Bot\u00F3n p\u00E1gina anterior -->\n <button type=\"button\" (click)=\"changePage(page-1)\"\n [class]=\"'cursor-pointer inline-flex items-center justify-center w-10 h-10 text-purple-600 bg-white border border-purple-200 rounded-lg hover:bg-purple-50 transition-all duration-200 ' + (page == 1?'opacity-50 pointer-events-none':'hover:border-purple-300')\"\n title=\"P\u00E1gina anterior\">\n \u2039\n </button>\n </div>\n\n <!-- Botones de navegaci\u00F3n derecha -->\n <div class=\"md:order-3 flex items-center gap-2\">\n <!-- Bot\u00F3n p\u00E1gina siguiente -->\n <button type=\"button\" (click)=\"changePage(page+1)\"\n [class]=\"'cursor-pointer inline-flex items-center justify-center w-10 h-10 text-purple-600 bg-white border border-purple-200 rounded-lg hover:bg-purple-50 transition-all duration-200 ' + (page == total[total.length-1]?'opacity-50 pointer-events-none':'hover:border-purple-300')\"\n title=\"P\u00E1gina siguiente\">\n \u203A\n </button>\n\n <!-- Bot\u00F3n ir al final -->\n <button type=\"button\" (click)=\"goToLastPage()\"\n [class]=\"'cursor-pointer inline-flex items-center justify-center px-3 h-10 text-purple-600 bg-white border border-purple-200 rounded-lg hover:bg-purple-50 transition-all duration-200 text-sm font-medium ' + (page == total[total.length-1]?'opacity-50 pointer-events-none':'hover:border-purple-300')\"\n title=\"Ir al final\">\n \u203A\u203A\n </button>\n </div>\n </div>\n <!--------------------------------- pagination end --------------------------------->\n }\n\n</div>\n\n<!----------------------------------- Data template ----------------------------------->\n<ng-template #DataTemplate let-item=\"item\" let-header=\"header\">\n\n <section class=\"flex items-center gap-2\">\n\n @if(header.name == 'NOMBRE' && item.role == 'ROLE_ADMIN') {\n <div class=\"inline-flex items-center justify-center w-6 h-6 bg-orange-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-orange-600', 'text-xs']\" [icon]=\"['fas', 'crown']\"></fa-icon> -->\n </div>\n }\n\n <span>\n @if (header.innerHtml) {\n <span [innerHTML]=\"getValue(item, header.key)\"></span>\n } @else {\n <ng-container [ngTemplateOutlet]=\"DataTypeTemplate\"\n [ngTemplateOutletContext]=\"{item:item, header:header, value:header.key}\"></ng-container>\n }\n\n @if(header.subKey){\n <span class=\"block text-neutral-600 text-xs min-w-max\">\n (\n <ng-container [ngTemplateOutlet]=\"DataTypeTemplate\"\n [ngTemplateOutletContext]=\"{item:item, header:header, value:header.subKey}\"></ng-container>\n )\n </span>\n }\n </span>\n\n </section>\n\n</ng-template>\n<!--------------------------------- Data template end --------------------------------->\n\n<!----------------------------------- Data Type template ----------------------------------->\n<ng-template #DataTypeTemplate let-item=\"item\" let-header=\"header\" let-value=\"value\">\n\n <section class=\"inline-block min-w-max\">\n @switch (header.type) {\n\n @case ('boolean') {\n @if(getValue(item, value)){\n <div class=\"inline-flex items-center justify-center w-6 h-6 bg-emerald-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-emerald-600', 'text-xs']\" [icon]=\"['fas', 'check']\"></fa-icon> -->\n </div>\n } @else {\n <div class=\"inline-flex items-center justify-center w-6 h-6 bg-rose-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-rose-600', 'text-xs']\" [icon]=\"['fas', 'xmark']\"></fa-icon> -->\n </div>\n }\n }\n\n @case ('currency'){\n <!-- {{formatEuro(getValue(item, value))}} -->\n }\n\n @case ('dateTime') {\n <span class=\"text-neutral-600 text-sm\">\n {{getValue(item, value) | date: 'dd/MM/yyyy HH:mm'}}\n </span>\n }\n\n @case ('color'){\n <span class=\"inline-block w-8 h-4 rounded-full border border-neutral-200 shadow-sm\"\n [style.background-color]=\"getValue(item, value)\"></span>\n }\n\n @case ('link'){\n @let link = getLink(header.url, item, value);\n\n @if(link.isExternal){\n <a [href]=\"link.url\" class=\"text-purple-600 hover:underline\">\n {{header.linkName}}\n </a>\n }@else{\n <a [routerLink]=\"link.url\" class=\"text-purple-600 hover:underline\" target=\"_blank\">\n {{header.linkName}}\n </a>\n }\n\n }\n\n @case ('image'){\n @let link = getLink(header.url, item, value);\n\n <img [src]=\"link.url\" [alt]=\"getValue(item, value)\" loading=\"lazy\" class=\"w-10 h-10 object-cover\">\n }\n\n @case ('login'){\n @if(item.active){\n <span class=\"inline-flex items-center gap-1\">\n\n @if(item.email_verified_at){\n <div [title]=\"item.email\" class=\"inline-flex items-center justify-center w-6 h-6 bg-blue-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-blue-600', 'text-xs']\" [icon]=\"['fas', 'envelope']\"></fa-icon> -->\n </div>\n }\n\n @if(item.google_id){\n <div [title]=\"item.google_id\"\n class=\"inline-flex items-center justify-center w-6 h-6 bg-red-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-red-600', 'text-xs']\" [icon]=\"['fab', 'google']\"></fa-icon> -->\n </div>\n }\n\n </span>\n } @else {\n <div class=\"inline-flex items-center justify-center w-6 h-6 bg-rose-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-rose-600', 'text-xs']\" [icon]=\"['fas', 'xmark']\"></fa-icon> -->\n </div>\n }\n }\n\n @default {\n {{getValue(item, value)}}\n }\n }\n </section>\n\n</ng-template>\n<!--------------------------------- Data Type template end --------------------------------->" }]
173
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i0.ChangeDetectorRef }], propDecorators: { url: [{
174
+ type: Input
175
+ }], contentList: [{
176
+ type: Input
177
+ }], contentTotal: [{
178
+ type: Input
179
+ }], pageParamName: [{
180
+ type: Input
181
+ }], limitParamName: [{
182
+ type: Input
183
+ }], sizeInitialPage: [{
184
+ type: Input
185
+ }], sizeBetweenPages: [{
186
+ type: Input
187
+ }], headers: [{
188
+ type: Input
189
+ }], editEvent: [{
190
+ type: Output
191
+ }], deleteEvent: [{
192
+ type: Output
193
+ }], items: [{
194
+ type: Input
195
+ }], limit: [{
196
+ type: Input
197
+ }] } });
20
198
 
21
199
  /*
22
200
  * Public API Surface of table
@@ -1 +1 @@
1
- {"version":3,"file":"some-angular-utils-table.mjs","sources":["../../../../projects/some-angular-utils/table/src/lib/table.ts","../../../../projects/some-angular-utils/table/src/public-api.ts","../../../../projects/some-angular-utils/table/src/some-angular-utils-table.ts"],"sourcesContent":["import { Component } from '@angular/core';\n\n@Component({\n selector: 'lib-table',\n imports: [],\n template: `\n <p>\n table works!\n </p>\n `,\n styles: ``\n})\nexport class TableModule {\n\n}\n","/*\n * Public API Surface of table\n */\n\nexport * from './lib/table';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;MAYa,WAAW,CAAA;uGAAX,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAX,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,WAAW,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,WAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAPZ;;;;AAIT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;2FAGU,WAAW,EAAA,UAAA,EAAA,CAAA;kBAVvB,SAAS;+BACE,WAAW,EAAA,OAAA,EACZ,EAAE,EAAA,QAAA,EACD;;;;AAIT,EAAA,CAAA,EAAA;;;ACTH;;AAEG;;ACFH;;AAEG;;;;"}
1
+ {"version":3,"file":"some-angular-utils-table.mjs","sources":["../../../../projects/some-angular-utils/table/src/lib/table.ts","../../../../projects/some-angular-utils/table/src/lib/table.html","../../../../projects/some-angular-utils/table/src/public-api.ts","../../../../projects/some-angular-utils/table/src/some-angular-utils-table.ts"],"sourcesContent":["import { CommonModule, DatePipe } from '@angular/common';\nimport { HttpClient } from '@angular/common/http';\nimport { ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core';\nimport { RouterModule } from '@angular/router';\n\n@Component({\n selector: 'sau-table',\n templateUrl: './table.html',\n imports: [\n RouterModule,\n DatePipe,\n CommonModule,\n ]\n})\nexport class TableModule {\n @Input() url?: string;\n @Input() contentList?: string;\n @Input() contentTotal?: string;\n @Input() pageParamName = 'page';\n @Input() limitParamName = 'limit'\n @Input() sizeInitialPage = 0\n @Input() sizeBetweenPages = 1\n @Input() headers?: { name: string, key: string | string[], subKey?: string, type?: string, innerHtml?: boolean, headers?: any }[];\n @Output() editEvent = new EventEmitter();\n @Output() deleteEvent = new EventEmitter();\n\n loading = false\n\n @Input() items: any = [];\n\n total: number[] = []\n\n page = 1\n\n @Input() limit = 10\n\n // Getter para obtener las páginas visibles (3 antes y 3 después de la página actual)\n get visiblePages(): number[] {\n const totalPages = this.total.length;\n if (totalPages <= 7) {\n // Si hay 7 páginas o menos, mostrar todas\n return this.total;\n }\n\n const currentPage = this.page;\n const start = Math.max(1, currentPage - 3);\n const end = Math.min(totalPages, currentPage + 3);\n\n const pages: number[] = [];\n for (let i = start; i <= end; i++) {\n pages.push(i);\n }\n\n return pages;\n }\n\n constructor(\n private http: HttpClient,\n private cdr: ChangeDetectorRef\n ) { }\n\n ngOnInit() {\n if (this.url) {\n this.getItems();\n }\n }\n\n // Método para obtener la página interna (0-based si sizeInitialPage es 0, 1-based si es 1)\n private getInternalPage(): number {\n if (this.sizeInitialPage === 0) {\n return (this.page - 1) * this.sizeBetweenPages;\n }\n return this.page * this.sizeBetweenPages;\n }\n\n getItems() {\n this.loading = true;\n this.cdr.detectChanges(); // Forzar detección antes de la petición\n\n const internalPage = this.getInternalPage();\n const filters = `?${this.pageParamName}=${internalPage}&${this.limitParamName}=${this.limit}`;\n\n this.http.get(this.url + filters).subscribe({\n next: (data: any) => {\n\n if (this.contentList && data[this.contentList]) {\n this.items = [...data[this.contentList]]; // Crear nueva referencia del array\n } else {\n this.items = [...data]; // Crear nueva referencia del array\n }\n\n if (this.contentTotal) {\n this.total = []\n for (let i = 0; i < data[this.contentTotal] / this.limit; i++) {\n this.total.push(i + 1)\n }\n }\n\n this.loading = false;\n this.cdr.detectChanges(); // Forzar detección después de actualizar datos\n },\n error: (error: any) => {\n console.error('ERROR obtener productos. ' + error);\n this.loading = false;\n this.cdr.detectChanges();\n }\n });\n }\n\n // Método simple para refrescar la tabla\n refresh() {\n if (this.url) {\n this.items = []; // Limpiar array primero\n this.cdr.detectChanges(); // Forzar actualización\n this.getItems();\n }\n }\n\n getLink(pattern: string = '{key}', item: any, value: string | string[]): { url: string, isExternal: boolean } {\n const keyValue = this.getValue(item, value);\n const url = pattern.replace('{key}', keyValue);\n const isExternal = url.startsWith('http://') || url.startsWith('https://')\n\n return {\n url,\n isExternal\n }\n }\n\n getValue(item: any, key: string | string[]) {\n\n let arrayKey = [];\n\n if (!Array.isArray(key)) {\n arrayKey.push(key);\n } else {\n arrayKey = key.slice();\n }\n\n let result = ''\n\n while (arrayKey.length > 0) {\n\n let keys = arrayKey[0].split('.');\n let value = item;\n\n if (keys[0].includes('[]')) {\n let arrayKey = keys[0].replace('[]', '');\n\n value = value[arrayKey].map((element: any) => this.getValue(element, keys.slice(1).join('.'))).join(', ');\n\n } else {\n let finalValue = item[String(key)]\n\n let isArray = Array.isArray(finalValue)\n let isBoolean = typeof finalValue === 'boolean'\n\n if (isArray || isBoolean) {\n return finalValue\n }\n\n for (let i = 0; value && i < keys.length; i++) {\n value = value[keys[i]];\n }\n }\n\n arrayKey.shift();\n\n result += (value ?? '') + (arrayKey.length > 0 ? ' ' : '');\n\n }\n\n return result;\n }\n\n isArray(array: any): boolean {\n return Array.isArray(array)\n }\n\n changePage(page: number) {\n this.page = page\n this.getItems()\n }\n\n // Método para ir a la primera página\n goToFirstPage() {\n if (this.page !== 1) {\n this.changePage(1);\n }\n }\n\n // Método para ir a la última página\n goToLastPage() {\n const lastPage = this.total.length;\n if (this.page !== lastPage && lastPage > 0) {\n this.changePage(lastPage);\n }\n }\n\n clickEditButton(id?: number) {\n this.editEvent.emit(id)\n }\n\n clickDeleteButton(id?: number) {\n this.deleteEvent.emit(id);\n }\n\n}\n","@if (loading) {\n<div>\n Loading\n</div>\n}\n\n<div class=\"overflow-auto rounded-2xl bg-white/90 backdrop-blur-lg shadow-xl border border-white/50\">\n\n <!----------------------------------- Table mobile ----------------------------------->\n <div class=\"md:hidden\">\n <!-- Mobile header -->\n <div class=\"bg-gradient-to-r from-purple-600 to-pink-600 text-white px-4 py-2 rounded-t-2xl\">\n <h3 class=\"text-base font-semibold leading-tight\">Lista de elementos</h3>\n <div class=\"w-8 h-0.5 bg-white/30 rounded-full mt-1\"></div>\n </div>\n\n <table class=\"w-full text-sm text-left rtl:text-right text-neutral-700\">\n <tbody>\n @for (item of items; track $index) {\n <tr class=\"border-b border-purple-100/50 last:border-b-0\">\n <td>\n <table class=\"w-full\">\n <tbody>\n @for (header of headers; track $index) {\n <tr [class]=\"$index%2==0?'bg-purple-50/30':''\">\n\n <th scope=\"col\"\n class=\"p-2 font-medium bg-gradient-to-r from-purple-600 to-pink-600 text-white max-w-min\">\n {{header.name}}\n </th>\n <td class=\"p-2 w-full text-neutral-800\">\n\n @if(header.type == 'table' && !isArray(header.key)){\n\n <!-- CSS-only toggle button -->\n <input type=\"checkbox\" [id]=\"'toggle-table-' + $index\" class=\"hidden peer\">\n <label [for]=\"'toggle-table-' + $index\"\n class=\"inline-flex items-center gap-2 px-3 py-2 bg-purple-100 text-purple-600 rounded-lg hover:bg-purple-200 transition-all duration-200 cursor-pointer select-none\">\n <!-- <fa-icon [icon]=\"['fas', 'chevron-down']\"\n class=\"text-xs transition-transform duration-200 peer-checked:rotate-180\"></fa-icon> -->\n <span class=\"text-sm font-medium\">\n <span class=\"peer-checked:hidden\">Mostrar</span>\n <span class=\"hidden peer-checked:inline\">Ocultar</span>\n </span>\n </label>\n\n <!-- Content that toggles -->\n <div\n class=\"mt-3 h-0 overflow-hidden opacity-0 peer-checked:h-auto peer-checked:opacity-100 peer-checked:overflow-visible transition-all duration-300 ease-in-out\">\n <sau-table [headers]=\"header.headers\"\n [items]=\"getValue(item, header.key)\"></sau-table>\n </div>\n\n }@else{\n <ng-container [ngTemplateOutlet]=\"DataTemplate\"\n [ngTemplateOutletContext]=\"{item:item, header:header}\"></ng-container>\n\n }\n\n </td>\n\n </tr>\n }\n\n @if(this.url){\n <tr\n class=\"border-b-8 border-transparent bg-gradient-to-r from-purple-600 to-purple-400 p-4\">\n <td colspan=\"2\">\n <div class=\"flex justify-center gap-4 p-4\">\n @if(editEvent.observers.length > 0){\n <button\n class=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-purple-600 bg-purple-50 hover:bg-purple-100 rounded-lg transition-all duration-200 border border-purple-200 hover:border-purple-300\"\n (click)=\"clickEditButton(item.id)\">\n <!-- <fa-icon [icon]=\"['fas', 'pen']\" class=\"text-xs\"></fa-icon> -->\n Editar\n </button>\n }\n\n @if(deleteEvent.observers.length > 0){\n <button\n class=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-rose-600 bg-rose-50 hover:bg-rose-100 rounded-lg transition-all duration-200 border border-rose-200 hover:border-rose-300\"\n (click)=\"clickDeleteButton(item.id)\">\n <!-- <fa-icon [icon]=\"['fas', 'trash-can']\" class=\"text-xs\"></fa-icon> -->\n Eliminar\n </button>\n }\n </div>\n </td>\n </tr>\n }\n\n </tbody>\n </table>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n <!--------------------------------- Table mobile end --------------------------------->\n\n <!----------------------------------- Table desktop ----------------------------------->\n <table class=\"w-full text-sm text-center rtl:text-right text-neutral-700 hidden md:table\">\n <thead class=\"text-xs font-semibold uppercase bg-gradient-to-r from-purple-600 to-pink-600 text-white\">\n <tr>\n @for (header of headers; track $index) {\n <th scope=\"col\" class=\"p-2\">\n {{header.name}}\n </th>\n }\n\n @if(this.url){\n <th scope=\"col\" class=\"p-2\">\n Opciones\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (item of items; track $index) {\n <tr\n [class]=\"'min-w-max hover:bg-purple-50/50 transition-colors duration-200 border-b border-purple-100/30 last:border-b-0 ' + ($index%2==0?'bg-purple-50/20':'')\">\n\n @for (header of headers; track $index) {\n <td class=\"p-2\">\n\n @if(header.type == 'table'){\n\n @if(!isArray(header.key)){\n <sau-table [headers]=\"header.headers\" [items]=\"getValue(item, header.key)\"></sau-table>\n }\n\n }@else{\n <ng-container [ngTemplateOutlet]=\"DataTemplate\"\n [ngTemplateOutletContext]=\"{item:item, header:header}\"></ng-container>\n }\n\n </td>\n }\n\n @if(this.url){\n <td class=\"px-6 py-4\">\n <div class=\"flex items-center gap-2\">\n @if(editEvent.observers.length > 0){\n <button\n class=\"inline-flex items-center justify-center w-8 h-8 text-purple-600 bg-purple-50 hover:bg-purple-100 rounded-lg transition-all duration-200 border border-purple-200 hover:border-purple-300\"\n (click)=\"clickEditButton(item.id)\" title=\"Editar\">\n <!-- <fa-icon [icon]=\"['fas', 'pen']\" class=\"text-xs\"></fa-icon> -->\n </button>\n }\n\n @if(deleteEvent.observers.length > 0){\n <button\n class=\"inline-flex items-center justify-center w-8 h-8 text-rose-600 bg-rose-50 hover:bg-rose-100 rounded-lg transition-all duration-200 border border-rose-200 hover:border-rose-300\"\n (click)=\"clickDeleteButton(item.id)\" title=\"Eliminar\">\n <!-- <fa-icon [icon]=\"['fas', 'trash-can']\" class=\"text-xs\"></fa-icon> -->\n </button>\n }\n </div>\n </td>\n }\n\n </tr>\n }\n </tbody>\n </table>\n <!--------------------------------- table desktop end --------------------------------->\n\n @if (items.length == 0) {\n <div class=\"flex flex-col items-center justify-center h-48 text-center\">\n <div class=\"w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mb-4\">\n <!-- <fa-icon [icon]=\"['fas', 'inbox']\" class=\"text-purple-400 text-2xl\"></fa-icon> -->\n </div>\n <p class=\"text-neutral-500 font-medium\">No hay elementos</p>\n <p class=\"text-neutral-400 text-sm\">Los elementos aparecerán aquí cuando estén disponibles</p>\n </div>\n\n } @else if(total.length > 1) {\n\n <!----------------------------------- Pagination ----------------------------------->\n <div\n class=\"sticky left-0 flex flex-wrap gap-2 items-center justify-center md:justify-between p-6 bg-gradient-to-r from-purple-50/50 to-pink-50/50 border-t border-purple-200/50\">\n\n <!-- Números de página -->\n <div class=\"md:order-2 w-full md:w-max flex items-center justify-center gap-2\">\n @for (item of visiblePages; track $index) {\n <button (click)=\"changePage(item)\"\n [class]=\"'cursor-pointer w-10 h-10 rounded-lg font-medium text-sm transition-all duration-200 ' + (item == page ? 'bg-gradient-to-r from-purple-500 to-pink-500 text-white shadow-lg' : 'text-purple-600 hover:bg-purple-50 border border-purple-200 hover:border-purple-300')\"\n type=\"button\">\n {{item}}\n </button>\n }\n </div>\n\n <!-- Botones de navegación izquierda -->\n <div class=\"md:order-1 flex items-center gap-2\">\n <!-- Botón ir al inicio -->\n <button type=\"button\" (click)=\"goToFirstPage()\"\n [class]=\"'cursor-pointer inline-flex items-center justify-center px-3 h-10 text-purple-600 bg-white border border-purple-200 rounded-lg hover:bg-purple-50 transition-all duration-200 text-sm font-medium ' + (page == 1?'opacity-50 pointer-events-none':'hover:border-purple-300')\"\n title=\"Ir al inicio\">\n ‹‹\n </button>\n\n <!-- Botón página anterior -->\n <button type=\"button\" (click)=\"changePage(page-1)\"\n [class]=\"'cursor-pointer inline-flex items-center justify-center w-10 h-10 text-purple-600 bg-white border border-purple-200 rounded-lg hover:bg-purple-50 transition-all duration-200 ' + (page == 1?'opacity-50 pointer-events-none':'hover:border-purple-300')\"\n title=\"Página anterior\">\n ‹\n </button>\n </div>\n\n <!-- Botones de navegación derecha -->\n <div class=\"md:order-3 flex items-center gap-2\">\n <!-- Botón página siguiente -->\n <button type=\"button\" (click)=\"changePage(page+1)\"\n [class]=\"'cursor-pointer inline-flex items-center justify-center w-10 h-10 text-purple-600 bg-white border border-purple-200 rounded-lg hover:bg-purple-50 transition-all duration-200 ' + (page == total[total.length-1]?'opacity-50 pointer-events-none':'hover:border-purple-300')\"\n title=\"Página siguiente\">\n ›\n </button>\n\n <!-- Botón ir al final -->\n <button type=\"button\" (click)=\"goToLastPage()\"\n [class]=\"'cursor-pointer inline-flex items-center justify-center px-3 h-10 text-purple-600 bg-white border border-purple-200 rounded-lg hover:bg-purple-50 transition-all duration-200 text-sm font-medium ' + (page == total[total.length-1]?'opacity-50 pointer-events-none':'hover:border-purple-300')\"\n title=\"Ir al final\">\n ››\n </button>\n </div>\n </div>\n <!--------------------------------- pagination end --------------------------------->\n }\n\n</div>\n\n<!----------------------------------- Data template ----------------------------------->\n<ng-template #DataTemplate let-item=\"item\" let-header=\"header\">\n\n <section class=\"flex items-center gap-2\">\n\n @if(header.name == 'NOMBRE' && item.role == 'ROLE_ADMIN') {\n <div class=\"inline-flex items-center justify-center w-6 h-6 bg-orange-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-orange-600', 'text-xs']\" [icon]=\"['fas', 'crown']\"></fa-icon> -->\n </div>\n }\n\n <span>\n @if (header.innerHtml) {\n <span [innerHTML]=\"getValue(item, header.key)\"></span>\n } @else {\n <ng-container [ngTemplateOutlet]=\"DataTypeTemplate\"\n [ngTemplateOutletContext]=\"{item:item, header:header, value:header.key}\"></ng-container>\n }\n\n @if(header.subKey){\n <span class=\"block text-neutral-600 text-xs min-w-max\">\n (\n <ng-container [ngTemplateOutlet]=\"DataTypeTemplate\"\n [ngTemplateOutletContext]=\"{item:item, header:header, value:header.subKey}\"></ng-container>\n )\n </span>\n }\n </span>\n\n </section>\n\n</ng-template>\n<!--------------------------------- Data template end --------------------------------->\n\n<!----------------------------------- Data Type template ----------------------------------->\n<ng-template #DataTypeTemplate let-item=\"item\" let-header=\"header\" let-value=\"value\">\n\n <section class=\"inline-block min-w-max\">\n @switch (header.type) {\n\n @case ('boolean') {\n @if(getValue(item, value)){\n <div class=\"inline-flex items-center justify-center w-6 h-6 bg-emerald-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-emerald-600', 'text-xs']\" [icon]=\"['fas', 'check']\"></fa-icon> -->\n </div>\n } @else {\n <div class=\"inline-flex items-center justify-center w-6 h-6 bg-rose-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-rose-600', 'text-xs']\" [icon]=\"['fas', 'xmark']\"></fa-icon> -->\n </div>\n }\n }\n\n @case ('currency'){\n <!-- {{formatEuro(getValue(item, value))}} -->\n }\n\n @case ('dateTime') {\n <span class=\"text-neutral-600 text-sm\">\n {{getValue(item, value) | date: 'dd/MM/yyyy HH:mm'}}\n </span>\n }\n\n @case ('color'){\n <span class=\"inline-block w-8 h-4 rounded-full border border-neutral-200 shadow-sm\"\n [style.background-color]=\"getValue(item, value)\"></span>\n }\n\n @case ('link'){\n @let link = getLink(header.url, item, value);\n\n @if(link.isExternal){\n <a [href]=\"link.url\" class=\"text-purple-600 hover:underline\">\n {{header.linkName}}\n </a>\n }@else{\n <a [routerLink]=\"link.url\" class=\"text-purple-600 hover:underline\" target=\"_blank\">\n {{header.linkName}}\n </a>\n }\n\n }\n\n @case ('image'){\n @let link = getLink(header.url, item, value);\n\n <img [src]=\"link.url\" [alt]=\"getValue(item, value)\" loading=\"lazy\" class=\"w-10 h-10 object-cover\">\n }\n\n @case ('login'){\n @if(item.active){\n <span class=\"inline-flex items-center gap-1\">\n\n @if(item.email_verified_at){\n <div [title]=\"item.email\" class=\"inline-flex items-center justify-center w-6 h-6 bg-blue-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-blue-600', 'text-xs']\" [icon]=\"['fas', 'envelope']\"></fa-icon> -->\n </div>\n }\n\n @if(item.google_id){\n <div [title]=\"item.google_id\"\n class=\"inline-flex items-center justify-center w-6 h-6 bg-red-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-red-600', 'text-xs']\" [icon]=\"['fab', 'google']\"></fa-icon> -->\n </div>\n }\n\n </span>\n } @else {\n <div class=\"inline-flex items-center justify-center w-6 h-6 bg-rose-100 rounded-full\">\n <!-- <fa-icon [ngClass]=\"['text-rose-600', 'text-xs']\" [icon]=\"['fas', 'xmark']\"></fa-icon> -->\n </div>\n }\n }\n\n @default {\n {{getValue(item, value)}}\n }\n }\n </section>\n\n</ng-template>\n<!--------------------------------- Data Type template end --------------------------------->","/*\n * Public API Surface of table\n */\n\nexport * from './lib/table';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/index.d.ts CHANGED
@@ -1,8 +1,51 @@
1
+ import { HttpClient } from '@angular/common/http';
1
2
  import * as i0 from '@angular/core';
3
+ import { EventEmitter, ChangeDetectorRef } from '@angular/core';
2
4
 
3
5
  declare class TableModule {
6
+ private http;
7
+ private cdr;
8
+ url?: string;
9
+ contentList?: string;
10
+ contentTotal?: string;
11
+ pageParamName: string;
12
+ limitParamName: string;
13
+ sizeInitialPage: number;
14
+ sizeBetweenPages: number;
15
+ headers?: {
16
+ name: string;
17
+ key: string | string[];
18
+ subKey?: string;
19
+ type?: string;
20
+ innerHtml?: boolean;
21
+ headers?: any;
22
+ }[];
23
+ editEvent: EventEmitter<any>;
24
+ deleteEvent: EventEmitter<any>;
25
+ loading: boolean;
26
+ items: any;
27
+ total: number[];
28
+ page: number;
29
+ limit: number;
30
+ get visiblePages(): number[];
31
+ constructor(http: HttpClient, cdr: ChangeDetectorRef);
32
+ ngOnInit(): void;
33
+ private getInternalPage;
34
+ getItems(): void;
35
+ refresh(): void;
36
+ getLink(pattern: string, item: any, value: string | string[]): {
37
+ url: string;
38
+ isExternal: boolean;
39
+ };
40
+ getValue(item: any, key: string | string[]): any;
41
+ isArray(array: any): boolean;
42
+ changePage(page: number): void;
43
+ goToFirstPage(): void;
44
+ goToLastPage(): void;
45
+ clickEditButton(id?: number): void;
46
+ clickDeleteButton(id?: number): void;
4
47
  static ɵfac: i0.ɵɵFactoryDeclaration<TableModule, never>;
5
- static ɵcmp: i0.ɵɵComponentDeclaration<TableModule, "lib-table", never, {}, {}, never, never, true, never>;
48
+ static ɵcmp: i0.ɵɵComponentDeclaration<TableModule, "sau-table", never, { "url": { "alias": "url"; "required": false; }; "contentList": { "alias": "contentList"; "required": false; }; "contentTotal": { "alias": "contentTotal"; "required": false; }; "pageParamName": { "alias": "pageParamName"; "required": false; }; "limitParamName": { "alias": "limitParamName"; "required": false; }; "sizeInitialPage": { "alias": "sizeInitialPage"; "required": false; }; "sizeBetweenPages": { "alias": "sizeBetweenPages"; "required": false; }; "headers": { "alias": "headers"; "required": false; }; "items": { "alias": "items"; "required": false; }; "limit": { "alias": "limit"; "required": false; }; }, { "editEvent": "editEvent"; "deleteEvent": "deleteEvent"; }, never, never, true, never>;
6
49
  }
7
50
 
8
51
  export { TableModule };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@some-angular-utils/table",
3
- "version": "0.0.18",
3
+ "version": "0.1.0",
4
4
  "description": "Angular table utility library",
5
5
  "repository": {
6
6
  "type": "git",