utn-cli 2.1.44 → 2.1.46
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/package.json +1 -1
- package/templates/backend/servicios/Nucleo/Miscelaneas.js +1 -1
- package/templates/frontend/src/app/Componentes/Nucleo/calendario-publico/calendario-publico.component.css +44 -4
- package/templates/frontend/src/app/Componentes/Nucleo/calendario-publico/calendario-publico.component.html +10 -8
- package/templates/frontend/src/app/Componentes/Nucleo/calendario-publico/calendario-publico.component.ts +2 -2
- package/templates/frontend/src/app/Componentes/Nucleo/estadisticas-del-modulo/estadisticas-del-modulo.component.css +49 -2
- package/templates/frontend/src/app/Componentes/Nucleo/estadisticas-del-modulo/estadisticas-del-modulo.component.html +9 -2
- package/templates/frontend/src/app/Componentes/Nucleo/estadisticas-del-modulo/estadisticas-del-modulo.component.ts +2 -2
- package/templates/frontend/src/app/Componentes/Nucleo/gestion-actividad/gestion-actividad.component.css +10 -2
- package/templates/frontend/src/app/Componentes/Nucleo/manual/manual.component.css +76 -7
- package/templates/frontend/src/app/Componentes/Nucleo/manual/manual.component.html +25 -7
- package/templates/frontend/src/app/Componentes/Nucleo/manual/manual.component.ts +93 -16
- package/templates/frontend/src/app/Componentes/Nucleo/mensaje-confirmacion/mensaje-confirmacion.component.css +71 -3
- package/templates/frontend/src/app/Componentes/Nucleo/mensaje-confirmacion/mensaje-confirmacion.component.html +11 -8
- package/templates/frontend/src/app/Componentes/Nucleo/mensaje-confirmacion/mensaje-confirmacion.ts +3 -3
- package/templates/frontend/src/app/Componentes/Nucleo/mensajes/mensajes.component.css +67 -0
- package/templates/frontend/src/app/Componentes/Nucleo/mensajes/mensajes.component.html +21 -9
- package/templates/frontend/src/app/Componentes/Nucleo/mensajes/mensajes.component.ts +1 -2
- package/templates/frontend/src/app/Componentes/Nucleo/panel-notificaciones/panel-notificaciones.component.css +209 -0
- package/templates/frontend/src/app/Componentes/Nucleo/panel-notificaciones/panel-notificaciones.component.html +45 -0
- package/templates/frontend/src/app/Componentes/Nucleo/panel-notificaciones/panel-notificaciones.component.ts +53 -0
- package/templates/frontend/src/app/Componentes/Nucleo/reporte-de-incidencias/reporte-de-incidencias.component.css +106 -13
- package/templates/frontend/src/app/Componentes/Nucleo/reporte-de-incidencias/reporte-de-incidencias.component.html +43 -32
- package/templates/frontend/src/app/Componentes/Nucleo/reporte-de-incidencias/reporte-de-incidencias.component.ts +4 -3
- package/templates/frontend/src/app/Componentes/Nucleo/reporte-de-sugerencias/reporte-de-sugerencias.component.css +76 -21
- package/templates/frontend/src/app/Componentes/Nucleo/reporte-de-sugerencias/reporte-de-sugerencias.component.html +23 -14
- package/templates/frontend/src/app/Componentes/Nucleo/reporte-de-sugerencias/reporte-de-sugerencias.component.ts +4 -3
- package/templates/frontend/src/app/Componentes/Nucleo/tarjeta-modulo/tarjeta-modulo.component.css +20 -10
- package/templates/frontend/src/app/Componentes/Nucleo/tarjeta-modulo/tarjeta-modulo.component.html +17 -8
- package/templates/frontend/src/app/Paginas/Nucleo/accesibilidad/accesibilidad.component.css +20 -1
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.css +143 -48
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.html +60 -38
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.ts +28 -6
- package/templates/frontend/src/app/Paginas/Nucleo/declaracion-ia/declaracion-ia.component.css +4 -4
- package/templates/frontend/src/index.html +7 -0
- package/templates/frontend/src/styles.css +14 -1
package/package.json
CHANGED
|
@@ -275,7 +275,7 @@ class Miscelaneo {
|
|
|
275
275
|
let datosFinales;
|
|
276
276
|
if (existentes.length > 0) {
|
|
277
277
|
const datosExistentes = typeof existentes[0].Datos === 'string' ? JSON.parse(existentes[0].Datos) : existentes[0].Datos;
|
|
278
|
-
datosFinales = {
|
|
278
|
+
datosFinales = { 'Archivo': archivo, ...tarjeta, ...datosExistentes };
|
|
279
279
|
await ejecutarConsultaSIGU(
|
|
280
280
|
`UPDATE \`SIGU\`.\`SIGU_ModulosV2Tarjetas\` SET \`Datos\` = ?, \`LastUser\` = 'Sistema' WHERE \`Modulo\` = ? AND JSON_VALUE(\`Datos\`, '$."Título"') = ?`,
|
|
281
281
|
[JSON.stringify(datosFinales), this.NombreCanonicoDelModulo, titulo]
|
|
@@ -1,15 +1,55 @@
|
|
|
1
|
-
|
|
1
|
+
/* Header */
|
|
2
|
+
.dialogo-header {
|
|
2
3
|
display: flex;
|
|
3
4
|
align-items: center;
|
|
4
|
-
gap:
|
|
5
|
+
gap: 10px;
|
|
6
|
+
background: linear-gradient(90deg, rgba(1, 33, 105, 1) 0%, rgba(63, 97, 171, 1) 100%);
|
|
7
|
+
color: white;
|
|
8
|
+
padding: 24px 20px 16px;
|
|
9
|
+
margin: -8px -8px 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.dialogo-icono {
|
|
13
|
+
font-size: 24px;
|
|
14
|
+
width: 24px;
|
|
15
|
+
height: 24px;
|
|
16
|
+
flex-shrink: 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.dialogo-titulo {
|
|
20
|
+
font-size: 1.1rem;
|
|
21
|
+
font-weight: 600;
|
|
22
|
+
font-family: 'Roboto', sans-serif;
|
|
23
|
+
letter-spacing: 0.2px;
|
|
5
24
|
}
|
|
6
25
|
|
|
7
|
-
.titulo
|
|
26
|
+
.dialogo-titulo small {
|
|
8
27
|
font-size: 0.65em;
|
|
9
|
-
opacity: 0.
|
|
28
|
+
opacity: 0.7;
|
|
10
29
|
font-weight: normal;
|
|
11
30
|
}
|
|
12
31
|
|
|
32
|
+
/* Botón cerrar */
|
|
33
|
+
mat-dialog-actions {
|
|
34
|
+
display: flex;
|
|
35
|
+
justify-content: flex-end;
|
|
36
|
+
padding: 8px 20px 16px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.btn-cancelar {
|
|
40
|
+
color: #012169;
|
|
41
|
+
border-color: #012169;
|
|
42
|
+
font-family: 'Roboto', sans-serif;
|
|
43
|
+
font-weight: 500;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Pie */
|
|
47
|
+
.dialogo-pie {
|
|
48
|
+
height: 20px;
|
|
49
|
+
background: linear-gradient(90deg, rgba(1, 33, 105, 1) 0%, rgba(63, 97, 171, 1) 100%);
|
|
50
|
+
margin: 0 -8px;
|
|
51
|
+
}
|
|
52
|
+
|
|
13
53
|
/* ── Buscador ── */
|
|
14
54
|
.buscador {
|
|
15
55
|
width: 100%;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
<
|
|
2
|
-
<mat-icon>calendar_month</mat-icon>
|
|
3
|
-
<span *ngIf="cargando">Cargando...</span>
|
|
4
|
-
<span *ngIf="!cargando && calendario">{{ calendario.Titulo }} <small>{{ calendario.Version }}</small></span>
|
|
5
|
-
<span *ngIf="!cargando && !calendario">Calendario institucional</span>
|
|
6
|
-
</
|
|
1
|
+
<div class="dialogo-header">
|
|
2
|
+
<mat-icon class="dialogo-icono">calendar_month</mat-icon>
|
|
3
|
+
<span class="dialogo-titulo" *ngIf="cargando">Cargando...</span>
|
|
4
|
+
<span class="dialogo-titulo" *ngIf="!cargando && calendario">{{ calendario.Titulo }} <small>{{ calendario.Version }}</small></span>
|
|
5
|
+
<span class="dialogo-titulo" *ngIf="!cargando && !calendario">Calendario institucional</span>
|
|
6
|
+
</div>
|
|
7
7
|
|
|
8
8
|
<mat-dialog-content>
|
|
9
9
|
|
|
@@ -167,6 +167,8 @@
|
|
|
167
167
|
</ng-container>
|
|
168
168
|
</mat-dialog-content>
|
|
169
169
|
|
|
170
|
-
<mat-dialog-actions
|
|
171
|
-
<button mat-button (click)="cerrar()">Cerrar</button>
|
|
170
|
+
<mat-dialog-actions>
|
|
171
|
+
<button mat-stroked-button class="btn-cancelar" (click)="cerrar()">Cerrar</button>
|
|
172
172
|
</mat-dialog-actions>
|
|
173
|
+
|
|
174
|
+
<div class="dialogo-pie"></div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Component, OnInit, inject } from '@angular/core';
|
|
2
2
|
import { HttpClient } from '@angular/common/http';
|
|
3
|
-
import { MatDialogActions, MatDialogContent, MatDialogRef
|
|
3
|
+
import { MatDialogActions, MatDialogContent, MatDialogRef } from '@angular/material/dialog';
|
|
4
4
|
import { MatButtonModule } from '@angular/material/button';
|
|
5
5
|
import { MatIconModule } from '@angular/material/icon';
|
|
6
6
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
@@ -16,7 +16,7 @@ import { DatosGlobalesService } from '../../../datos-globales.service';
|
|
|
16
16
|
styleUrl: './calendario-publico.component.css',
|
|
17
17
|
imports: [
|
|
18
18
|
CommonModule,
|
|
19
|
-
MatDialogContent, MatDialogActions,
|
|
19
|
+
MatDialogContent, MatDialogActions,
|
|
20
20
|
MatButtonModule, MatIconModule,
|
|
21
21
|
MatProgressBarModule, MatExpansionModule,
|
|
22
22
|
MatFormFieldModule, MatInputModule
|
|
@@ -1,8 +1,34 @@
|
|
|
1
|
+
/* Header */
|
|
2
|
+
.dialogo-header {
|
|
3
|
+
display: flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
gap: 10px;
|
|
6
|
+
background: linear-gradient(90deg, rgba(1, 33, 105, 1) 0%, rgba(63, 97, 171, 1) 100%);
|
|
7
|
+
color: white;
|
|
8
|
+
padding: 24px 20px 16px;
|
|
9
|
+
margin: -8px -8px 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.dialogo-icono {
|
|
13
|
+
font-size: 24px;
|
|
14
|
+
width: 24px;
|
|
15
|
+
height: 24px;
|
|
16
|
+
flex-shrink: 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.dialogo-titulo {
|
|
20
|
+
font-size: 1.1rem;
|
|
21
|
+
font-weight: 600;
|
|
22
|
+
font-family: 'Roboto', sans-serif;
|
|
23
|
+
letter-spacing: 0.2px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Contenido */
|
|
1
27
|
.contenedor {
|
|
2
28
|
display: flex;
|
|
3
29
|
flex-direction: column;
|
|
4
30
|
gap: 1rem;
|
|
5
|
-
padding: 0
|
|
31
|
+
padding: 16px 0 8px;
|
|
6
32
|
min-width: 260px;
|
|
7
33
|
}
|
|
8
34
|
|
|
@@ -39,6 +65,27 @@
|
|
|
39
65
|
.estadistica-valor {
|
|
40
66
|
font-size: 1.5rem;
|
|
41
67
|
font-weight: 700;
|
|
42
|
-
color: #
|
|
68
|
+
color: #012169;
|
|
43
69
|
line-height: 1.2;
|
|
44
70
|
}
|
|
71
|
+
|
|
72
|
+
/* Botones */
|
|
73
|
+
mat-dialog-actions {
|
|
74
|
+
display: flex;
|
|
75
|
+
justify-content: flex-end;
|
|
76
|
+
padding: 8px 20px 16px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.btn-cerrar {
|
|
80
|
+
color: #012169;
|
|
81
|
+
border-color: #012169;
|
|
82
|
+
font-family: 'Roboto', sans-serif;
|
|
83
|
+
font-weight: 500;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Pie */
|
|
87
|
+
.dialogo-pie {
|
|
88
|
+
height: 20px;
|
|
89
|
+
background: linear-gradient(90deg, rgba(1, 33, 105, 1) 0%, rgba(63, 97, 171, 1) 100%);
|
|
90
|
+
margin: 0 -8px;
|
|
91
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
<
|
|
1
|
+
<div class="dialogo-header">
|
|
2
|
+
<mat-icon class="dialogo-icono">bar_chart</mat-icon>
|
|
3
|
+
<span class="dialogo-titulo">Estadísticas del módulo</span>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
2
6
|
<mat-dialog-content>
|
|
3
7
|
<div class="contenedor">
|
|
4
8
|
<div class="estadistica">
|
|
@@ -17,6 +21,9 @@
|
|
|
17
21
|
</div>
|
|
18
22
|
</div>
|
|
19
23
|
</mat-dialog-content>
|
|
24
|
+
|
|
20
25
|
<mat-dialog-actions>
|
|
21
|
-
<button mat-button (click)="Cerrar()">Cerrar</button>
|
|
26
|
+
<button mat-stroked-button class="btn-cerrar" (click)="Cerrar()">Cerrar</button>
|
|
22
27
|
</mat-dialog-actions>
|
|
28
|
+
|
|
29
|
+
<div class="dialogo-pie"></div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Component, Inject, inject } from '@angular/core';
|
|
2
|
-
import { MAT_DIALOG_DATA, MatDialogActions, MatDialogContent, MatDialogRef
|
|
2
|
+
import { MAT_DIALOG_DATA, MatDialogActions, MatDialogContent, MatDialogRef } from '@angular/material/dialog';
|
|
3
3
|
import { MatButtonModule } from '@angular/material/button';
|
|
4
4
|
import { MatIconModule } from '@angular/material/icon';
|
|
5
5
|
import { CommonModule } from '@angular/common';
|
|
@@ -8,7 +8,7 @@ import { CommonModule } from '@angular/common';
|
|
|
8
8
|
selector: 'app-estadisticas-del-modulo',
|
|
9
9
|
templateUrl: './estadisticas-del-modulo.component.html',
|
|
10
10
|
styleUrl: './estadisticas-del-modulo.component.css',
|
|
11
|
-
imports: [MatDialogContent, MatDialogActions,
|
|
11
|
+
imports: [MatDialogContent, MatDialogActions, MatButtonModule, MatIconModule, CommonModule]
|
|
12
12
|
})
|
|
13
13
|
export class EstadisticasDelModuloComponent {
|
|
14
14
|
readonly dialogRef = inject(MatDialogRef<EstadisticasDelModuloComponent>);
|
|
@@ -211,14 +211,22 @@ mat-progress-bar {
|
|
|
211
211
|
flex-direction: column;
|
|
212
212
|
align-items: flex-start;
|
|
213
213
|
}
|
|
214
|
-
|
|
214
|
+
|
|
215
215
|
.item-icono {
|
|
216
216
|
margin-bottom: 12px;
|
|
217
217
|
}
|
|
218
|
-
|
|
218
|
+
|
|
219
219
|
.item-fecha {
|
|
220
220
|
margin-left: 0;
|
|
221
221
|
margin-top: 12px;
|
|
222
222
|
align-items: flex-start;
|
|
223
223
|
}
|
|
224
|
+
|
|
225
|
+
.item-detalles {
|
|
226
|
+
max-width: 100%;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.detalle-browser {
|
|
230
|
+
max-width: 55vw;
|
|
231
|
+
}
|
|
224
232
|
}
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
align-items: start;
|
|
14
14
|
min-height: 100%;
|
|
15
15
|
font-family: 'Roboto', 'Helvetica Neue', sans-serif;
|
|
16
|
+
margin-top: 24px;
|
|
17
|
+
max-width: 1100px;
|
|
18
|
+
margin-left: auto;
|
|
19
|
+
margin-right: auto;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
/* ═══════════════════════════════════════════════════════════
|
|
@@ -94,6 +98,19 @@
|
|
|
94
98
|
font-size: 0.78rem;
|
|
95
99
|
}
|
|
96
100
|
|
|
101
|
+
.toc-activo > .toc-enlace {
|
|
102
|
+
background: #dce9ff;
|
|
103
|
+
color: #002f6b;
|
|
104
|
+
font-weight: 700;
|
|
105
|
+
border-left: 3px solid #1976d2;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.toc-sublista {
|
|
109
|
+
list-style: none;
|
|
110
|
+
padding: 0;
|
|
111
|
+
margin: 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
97
114
|
.toc-descargar {
|
|
98
115
|
display: block;
|
|
99
116
|
width: calc(100% - 1rem);
|
|
@@ -119,10 +136,25 @@
|
|
|
119
136
|
Área principal del artículo
|
|
120
137
|
══════════════════════════════════════════════════════════ */
|
|
121
138
|
.manual-main {
|
|
122
|
-
padding: 1.5rem 2.5rem 4rem
|
|
139
|
+
padding: 1.5rem 2.5rem 4rem 5rem;
|
|
123
140
|
min-width: 0;
|
|
124
141
|
}
|
|
125
142
|
|
|
143
|
+
/* Título principal fijo */
|
|
144
|
+
.manual-titulo-principal {
|
|
145
|
+
font-size: 1.35rem;
|
|
146
|
+
font-weight: 700;
|
|
147
|
+
color: #012169;
|
|
148
|
+
margin: 0 0 1.5rem;
|
|
149
|
+
padding-bottom: 0.6rem;
|
|
150
|
+
border-bottom: 3px solid #2e6da4;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* En móvil se muestra el externo y se oculta el de dentro del main */
|
|
154
|
+
.manual-titulo-movil {
|
|
155
|
+
display: none;
|
|
156
|
+
}
|
|
157
|
+
|
|
126
158
|
/* ═══════════════════════════════════════════════════════════
|
|
127
159
|
Estados: cargando / error
|
|
128
160
|
══════════════════════════════════════════════════════════ */
|
|
@@ -161,11 +193,12 @@
|
|
|
161
193
|
scroll-margin-top: 1rem;
|
|
162
194
|
}
|
|
163
195
|
|
|
164
|
-
.manual-articulo h2
|
|
196
|
+
.manual-articulo h2,
|
|
197
|
+
:host ::ng-deep .manual-articulo h2 {
|
|
165
198
|
font-size: 1.25rem;
|
|
166
199
|
font-weight: 700;
|
|
167
200
|
color: #002f6b;
|
|
168
|
-
margin:
|
|
201
|
+
margin: 1rem 0 0.75rem;
|
|
169
202
|
padding: 0.4rem 0.9rem;
|
|
170
203
|
background: #e8f0fe;
|
|
171
204
|
border-left: 4px solid #1976d2;
|
|
@@ -173,11 +206,12 @@
|
|
|
173
206
|
scroll-margin-top: 1rem;
|
|
174
207
|
}
|
|
175
208
|
|
|
176
|
-
.manual-articulo h3
|
|
209
|
+
.manual-articulo h3,
|
|
210
|
+
:host ::ng-deep .manual-articulo h3 {
|
|
177
211
|
font-size: 1.05rem;
|
|
178
212
|
font-weight: 600;
|
|
179
213
|
color: #0b4fce;
|
|
180
|
-
margin:
|
|
214
|
+
margin: 3rem 0 0.5rem;
|
|
181
215
|
scroll-margin-top: 1rem;
|
|
182
216
|
}
|
|
183
217
|
|
|
@@ -190,8 +224,10 @@
|
|
|
190
224
|
}
|
|
191
225
|
|
|
192
226
|
/* Párrafos */
|
|
193
|
-
.manual-articulo p
|
|
194
|
-
|
|
227
|
+
.manual-articulo p,
|
|
228
|
+
:host ::ng-deep .manual-articulo p {
|
|
229
|
+
margin: 0 0 1.2rem;
|
|
230
|
+
text-align: justify;
|
|
195
231
|
}
|
|
196
232
|
|
|
197
233
|
/* Listas */
|
|
@@ -319,7 +355,40 @@
|
|
|
319
355
|
/* ═══════════════════════════════════════════════════════════
|
|
320
356
|
Responsivo — pantallas pequeñas
|
|
321
357
|
══════════════════════════════════════════════════════════ */
|
|
358
|
+
/* Botón volver arriba — solo móvil */
|
|
359
|
+
.btn-volver-arriba {
|
|
360
|
+
display: none;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
@media (max-width: 768px) {
|
|
364
|
+
.btn-volver-arriba {
|
|
365
|
+
display: flex;
|
|
366
|
+
align-items: center;
|
|
367
|
+
justify-content: center;
|
|
368
|
+
margin: 2rem auto 1rem;
|
|
369
|
+
padding: 0.6rem 1.4rem;
|
|
370
|
+
background: linear-gradient(90deg, rgba(1, 33, 105, 1) 0%, rgba(63, 97, 171, 1) 100%);
|
|
371
|
+
color: white;
|
|
372
|
+
border: none;
|
|
373
|
+
border-radius: 24px;
|
|
374
|
+
font-family: 'Roboto', sans-serif;
|
|
375
|
+
font-size: 0.9rem;
|
|
376
|
+
font-weight: 500;
|
|
377
|
+
cursor: pointer;
|
|
378
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
322
382
|
@media (max-width: 768px) {
|
|
383
|
+
.manual-titulo-movil {
|
|
384
|
+
display: block;
|
|
385
|
+
margin-top: 16px;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.manual-main .manual-titulo-principal:not(.manual-titulo-movil) {
|
|
389
|
+
display: none;
|
|
390
|
+
}
|
|
391
|
+
|
|
323
392
|
.manual-layout {
|
|
324
393
|
grid-template-columns: 1fr;
|
|
325
394
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
<h1 class="manual-titulo-principal manual-titulo-movil">Manual de usuario</h1>
|
|
2
|
+
|
|
1
3
|
<div class="manual-layout">
|
|
2
4
|
|
|
3
5
|
<!-- ── Índice lateral ─────────────────────────────────── -->
|
|
@@ -5,11 +7,22 @@
|
|
|
5
7
|
<p class="toc-titulo">Contenido</p>
|
|
6
8
|
<nav>
|
|
7
9
|
<ul class="toc-lista">
|
|
8
|
-
@for (
|
|
9
|
-
<li
|
|
10
|
-
<button class="toc-enlace" (click)="
|
|
11
|
-
{{
|
|
10
|
+
@for (seccion of secciones; track seccion.id) {
|
|
11
|
+
<li class="toc-nivel-2" [class.toc-activo]="seccionActiva?.id === seccion.id">
|
|
12
|
+
<button class="toc-enlace" (click)="seleccionarSeccion(seccion)" (focus)="seleccionarSeccion(seccion)" [title]="seccion.titulo">
|
|
13
|
+
{{ seccion.titulo }}
|
|
12
14
|
</button>
|
|
15
|
+
@if (seccionActiva?.id === seccion.id && seccion.subEntradas.length > 0) {
|
|
16
|
+
<ul class="toc-sublista">
|
|
17
|
+
@for (sub of seccion.subEntradas; track sub.id) {
|
|
18
|
+
<li class="toc-nivel-3">
|
|
19
|
+
<button class="toc-enlace" (click)="irA(sub.id)" [title]="sub.texto">
|
|
20
|
+
{{ sub.texto }}
|
|
21
|
+
</button>
|
|
22
|
+
</li>
|
|
23
|
+
}
|
|
24
|
+
</ul>
|
|
25
|
+
}
|
|
13
26
|
</li>
|
|
14
27
|
}
|
|
15
28
|
</ul>
|
|
@@ -23,6 +36,7 @@
|
|
|
23
36
|
|
|
24
37
|
<!-- ── Artículo principal ─────────────────────────────── -->
|
|
25
38
|
<main class="manual-main" role="main" aria-label="Manual de usuario">
|
|
39
|
+
<h1 class="manual-titulo-principal">Manual de usuario</h1>
|
|
26
40
|
|
|
27
41
|
@if (cargando) {
|
|
28
42
|
<div class="manual-estado" role="status" aria-live="polite" aria-busy="true">
|
|
@@ -39,11 +53,15 @@
|
|
|
39
53
|
</div>
|
|
40
54
|
}
|
|
41
55
|
|
|
42
|
-
@if (!cargando && !error) {
|
|
43
|
-
<article #contenidoManual class="manual-articulo" [innerHTML]="
|
|
56
|
+
@if (!cargando && !error && seccionActiva) {
|
|
57
|
+
<article #contenidoManual class="manual-articulo" [innerHTML]="seccionActiva.html"
|
|
58
|
+
(click)="manejarClicEnContenido($event)">
|
|
44
59
|
</article>
|
|
60
|
+
<button class="btn-volver-arriba" (click)="irAlInicio()" title="Volver arriba">
|
|
61
|
+
↑ Volver arriba
|
|
62
|
+
</button>
|
|
45
63
|
}
|
|
46
64
|
|
|
47
65
|
</main>
|
|
48
66
|
|
|
49
|
-
</div>
|
|
67
|
+
</div>
|
|
@@ -13,8 +13,25 @@ interface EntradaToc {
|
|
|
13
13
|
id: string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
interface Seccion {
|
|
17
|
+
id: string;
|
|
18
|
+
titulo: string;
|
|
19
|
+
html: SafeHtml;
|
|
20
|
+
subEntradas: EntradaToc[];
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
const DIACRITICOS = new RegExp('[̀-ͯ]', 'g');
|
|
17
24
|
|
|
25
|
+
function generarId(texto: string): string {
|
|
26
|
+
return texto
|
|
27
|
+
.toLowerCase()
|
|
28
|
+
.normalize('NFD')
|
|
29
|
+
.replace(DIACRITICOS, '')
|
|
30
|
+
.replace(/[^a-z0-9\s-]/g, '')
|
|
31
|
+
.trim()
|
|
32
|
+
.replace(/\s+/g, '-');
|
|
33
|
+
}
|
|
34
|
+
|
|
18
35
|
@Component({
|
|
19
36
|
selector: 'app-manual',
|
|
20
37
|
standalone: true,
|
|
@@ -23,18 +40,23 @@ const DIACRITICOS = new RegExp('[̀-ͯ]', 'g');
|
|
|
23
40
|
styleUrl: './manual.component.css'
|
|
24
41
|
})
|
|
25
42
|
export class ManualComponent implements OnInit, OnDestroy {
|
|
26
|
-
public
|
|
27
|
-
public
|
|
43
|
+
public secciones: Seccion[] = [];
|
|
44
|
+
public seccionActiva: Seccion | null = null;
|
|
28
45
|
public cargando: boolean = true;
|
|
29
46
|
public error: boolean = false;
|
|
30
47
|
private markdownRaw: string = '';
|
|
31
48
|
private _destroy$ = new Subject<void>();
|
|
32
49
|
@ViewChild('contenidoManual') contenidoManualRef!: ElementRef;
|
|
33
50
|
|
|
34
|
-
constructor(
|
|
51
|
+
constructor(
|
|
52
|
+
private http: HttpClient,
|
|
53
|
+
private sanitizer: DomSanitizer,
|
|
54
|
+
private datosGlobalesService: DatosGlobalesService
|
|
55
|
+
) {}
|
|
35
56
|
|
|
36
57
|
ngOnInit(): void {
|
|
37
|
-
this.http.get(`${this.datosGlobalesService.ObtenerURL()}misc/VistaDelManual`)
|
|
58
|
+
this.http.get(`${this.datosGlobalesService.ObtenerURL()}misc/VistaDelManual`)
|
|
59
|
+
.pipe(takeUntil(this._destroy$)).subscribe({ error: () => {} });
|
|
38
60
|
|
|
39
61
|
this.http.get('/Manual.md', { responseType: 'text' }).pipe(takeUntil(this._destroy$)).subscribe({
|
|
40
62
|
next: (markdown) => {
|
|
@@ -44,21 +66,54 @@ export class ManualComponent implements OnInit, OnDestroy {
|
|
|
44
66
|
const parser = new DOMParser();
|
|
45
67
|
const doc = parser.parseFromString(html, 'text/html');
|
|
46
68
|
|
|
69
|
+
// Asignar IDs a todos los headings
|
|
47
70
|
doc.querySelectorAll('h1, h2, h3').forEach((heading) => {
|
|
48
71
|
const texto = heading.textContent ?? '';
|
|
49
|
-
|
|
50
|
-
.toLowerCase()
|
|
51
|
-
.normalize('NFD')
|
|
52
|
-
.replace(DIACRITICOS, '')
|
|
53
|
-
.replace(/[^a-z0-9\s-]/g, '')
|
|
54
|
-
.trim()
|
|
55
|
-
.replace(/\s+/g, '-');
|
|
56
|
-
heading.id = id;
|
|
57
|
-
const nivel = parseInt(heading.tagName[1], 10);
|
|
58
|
-
this.toc.push({ nivel, texto, id });
|
|
72
|
+
heading.id = generarId(texto);
|
|
59
73
|
});
|
|
60
74
|
|
|
61
|
-
|
|
75
|
+
// Dividir en secciones por h2
|
|
76
|
+
const secciones: Seccion[] = [];
|
|
77
|
+
let nodos: Node[] = [];
|
|
78
|
+
let tituloActual = '';
|
|
79
|
+
let idActual = '';
|
|
80
|
+
let subEntradasActuales: EntradaToc[] = [];
|
|
81
|
+
|
|
82
|
+
const guardarSeccion = () => {
|
|
83
|
+
if (!idActual) return;
|
|
84
|
+
const div = document.createElement('div');
|
|
85
|
+
nodos.forEach(n => div.appendChild(n.cloneNode(true)));
|
|
86
|
+
secciones.push({
|
|
87
|
+
id: idActual,
|
|
88
|
+
titulo: tituloActual,
|
|
89
|
+
html: this.sanitizer.bypassSecurityTrustHtml(div.innerHTML),
|
|
90
|
+
subEntradas: [...subEntradasActuales]
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
Array.from(doc.body.childNodes).forEach(node => {
|
|
95
|
+
const el = node as Element;
|
|
96
|
+
if (el.tagName === 'H2') {
|
|
97
|
+
guardarSeccion();
|
|
98
|
+
tituloActual = el.textContent ?? '';
|
|
99
|
+
idActual = generarId(tituloActual);
|
|
100
|
+
el.id = idActual;
|
|
101
|
+
nodos = [node];
|
|
102
|
+
subEntradasActuales = [];
|
|
103
|
+
} else if (el.tagName === 'H3' && idActual) {
|
|
104
|
+
const texto = el.textContent ?? '';
|
|
105
|
+
const id = generarId(texto);
|
|
106
|
+
el.id = id;
|
|
107
|
+
subEntradasActuales.push({ nivel: 3, texto, id });
|
|
108
|
+
nodos.push(node);
|
|
109
|
+
} else {
|
|
110
|
+
if (idActual) nodos.push(node);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
guardarSeccion();
|
|
114
|
+
|
|
115
|
+
this.secciones = secciones;
|
|
116
|
+
this.seccionActiva = secciones[0] ?? null;
|
|
62
117
|
this.cargando = false;
|
|
63
118
|
},
|
|
64
119
|
error: () => {
|
|
@@ -73,8 +128,21 @@ export class ManualComponent implements OnInit, OnDestroy {
|
|
|
73
128
|
this._destroy$.complete();
|
|
74
129
|
}
|
|
75
130
|
|
|
131
|
+
seleccionarSeccion(seccion: Seccion): void {
|
|
132
|
+
this.seccionActiva = seccion;
|
|
133
|
+
}
|
|
134
|
+
|
|
76
135
|
irA(id: string): void {
|
|
77
|
-
|
|
136
|
+
// Buscar la sección que contiene ese id
|
|
137
|
+
const seccionContenedora = this.secciones.find(
|
|
138
|
+
s => s.id === id || s.subEntradas.some(e => e.id === id)
|
|
139
|
+
);
|
|
140
|
+
if (seccionContenedora) {
|
|
141
|
+
this.seccionActiva = seccionContenedora;
|
|
142
|
+
}
|
|
143
|
+
setTimeout(() => {
|
|
144
|
+
document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
145
|
+
}, 50);
|
|
78
146
|
}
|
|
79
147
|
|
|
80
148
|
descargar(): void {
|
|
@@ -87,6 +155,15 @@ export class ManualComponent implements OnInit, OnDestroy {
|
|
|
87
155
|
URL.revokeObjectURL(url);
|
|
88
156
|
}
|
|
89
157
|
|
|
158
|
+
irAlInicio(): void {
|
|
159
|
+
const contenedor = document.querySelector('.zona-scrollable');
|
|
160
|
+
if (contenedor) {
|
|
161
|
+
contenedor.scrollTo({ top: 0, behavior: 'smooth' });
|
|
162
|
+
} else {
|
|
163
|
+
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
90
167
|
manejarClicEnContenido(event: MouseEvent): void {
|
|
91
168
|
const anchor = (event.target as Element).closest('a');
|
|
92
169
|
if (!anchor) return;
|
|
@@ -1,5 +1,73 @@
|
|
|
1
|
+
/* Header */
|
|
2
|
+
.dialogo-header {
|
|
3
|
+
display: flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
gap: 10px;
|
|
6
|
+
background: linear-gradient(90deg, rgba(1, 33, 105, 1) 0%, rgba(63, 97, 171, 1) 100%);
|
|
7
|
+
color: white;
|
|
8
|
+
padding: 24px 20px 16px;
|
|
9
|
+
margin: -8px -8px 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.dialogo-icono {
|
|
13
|
+
font-size: 24px;
|
|
14
|
+
width: 24px;
|
|
15
|
+
height: 24px;
|
|
16
|
+
flex-shrink: 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.dialogo-titulo {
|
|
20
|
+
font-size: 1.1rem;
|
|
21
|
+
font-weight: 600;
|
|
22
|
+
font-family: 'Roboto', sans-serif;
|
|
23
|
+
letter-spacing: 0.2px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Mensaje */
|
|
27
|
+
.dialogo-mensaje {
|
|
28
|
+
margin: 20px 0 12px;
|
|
29
|
+
font-size: 0.95rem;
|
|
30
|
+
color: #333;
|
|
31
|
+
font-family: 'Roboto', sans-serif;
|
|
32
|
+
line-height: 1.5;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Campo de comentario */
|
|
1
36
|
.mensaje {
|
|
2
|
-
|
|
37
|
+
width: 100%;
|
|
38
|
+
margin-top: 4px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Botones */
|
|
42
|
+
mat-dialog-actions {
|
|
3
43
|
display: flex;
|
|
4
|
-
justify-content:
|
|
5
|
-
|
|
44
|
+
justify-content: flex-end;
|
|
45
|
+
gap: 10px;
|
|
46
|
+
padding: 8px 20px 16px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.btn-cancelar {
|
|
50
|
+
color: #012169;
|
|
51
|
+
border-color: #012169;
|
|
52
|
+
font-family: 'Roboto', sans-serif;
|
|
53
|
+
font-weight: 500;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.btn-aceptar {
|
|
57
|
+
background-color: #012169;
|
|
58
|
+
color: white;
|
|
59
|
+
font-family: 'Roboto', sans-serif;
|
|
60
|
+
font-weight: 500;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.btn-aceptar:disabled {
|
|
64
|
+
background-color: #a0b0c4;
|
|
65
|
+
color: white;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Pie */
|
|
69
|
+
.dialogo-pie {
|
|
70
|
+
height: 20px;
|
|
71
|
+
background: linear-gradient(90deg, rgba(1, 33, 105, 1) 0%, rgba(63, 97, 171, 1) 100%);
|
|
72
|
+
margin: 0 -8px;
|
|
73
|
+
}
|