@dataclouder/ngx-lessons 0.0.30 → 0.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/dataclouder-ngx-lessons.mjs +1169 -449
- package/fesm2022/dataclouder-ngx-lessons.mjs.map +1 -1
- package/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.d.ts +2 -2
- package/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.d.ts +11 -0
- package/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.d.ts +39 -38
- package/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.d.ts +22 -0
- package/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.d.ts +32 -37
- package/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.d.ts +2 -4
- package/lib/components/lesson-mini-components/components/ComponentBuilder.d.ts +7 -2
- package/lib/components/lesson-mini-components/components/lessons.clases.d.ts +17 -42
- package/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.d.ts +13 -0
- package/lib/components/lesson-mini-components/components/speaker/speaker.component.d.ts +12 -0
- package/lib/services/lesson-ai.service.d.ts +18 -0
- package/lib/services/lesson-notion.service.d.ts +35 -0
- package/lib/services/lesson-utils.service.d.ts +34 -0
- package/package.json +3 -2
- package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.html +0 -35
- package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.scss +0 -107
- package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.ts +0 -82
- package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.css +0 -90
- package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.html +0 -105
- package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.scss +0 -0
- package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.ts +0 -318
- package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.html +0 -27
- package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.scss +0 -3
- package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.ts +0 -271
- package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.html +0 -5
- package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.scss +0 -3
- package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.ts +0 -14
- package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.html +0 -30
- package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.scss +0 -17
- package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.ts +0 -170
- package/src/lib/components/dc-lessons/lessons.component.ts +0 -10
- package/src/lib/components/lesson-mini-components/components/ComponentBuilder.ts +0 -74
- package/src/lib/components/lesson-mini-components/components/ComponentWithForm.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/lesson-dynamic.component.ts +0 -13
- package/src/lib/components/lesson-mini-components/components/lessons.clases.ts +0 -254
- package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.html +0 -58
- package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.scss +0 -15
- package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.ts +0 -70
- package/src/lib/components/lesson-mini-components/components/selector/selector.component.html +0 -2
- package/src/lib/components/lesson-mini-components/components/selector/selector.component.scss +0 -12
- package/src/lib/components/lesson-mini-components/components/selector/selector.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/selector/selector.component.ts +0 -47
- package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.html +0 -35
- package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.scss +0 -0
- package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.ts +0 -27
- package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.html +0 -7
- package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.scss +0 -3
- package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.ts +0 -29
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.html +0 -24
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.scss +0 -15
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.ts +0 -29
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.html +0 -4
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.scss +0 -8
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.ts +0 -61
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.css +0 -3
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.html +0 -9
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.ts +0 -32
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.css +0 -3
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.html +0 -28
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.ts +0 -30
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.html +0 -18
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.scss +0 -3
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.html +0 -15
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.scss +0 -27
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.ts +0 -46
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.html +0 -19
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.scss +0 -0
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.ts +0 -27
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.html +0 -14
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.scss +0 -22
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.ts +0 -51
- package/src/lib/models/lessons.pipes.ts +0 -38
- package/src/lib/models/models.ts +0 -92
- package/src/lib/models/notion.models.ts +0 -43
- package/src/public-api.ts +0 -25
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
.card-container {
|
|
2
|
-
position: relative;
|
|
3
|
-
margin-bottom: 20px;
|
|
4
|
-
margin-left: 10px;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
.dial-button {
|
|
8
|
-
position: absolute;
|
|
9
|
-
top: 10px;
|
|
10
|
-
right: 20px;
|
|
11
|
-
z-index: 10;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.lesson-card {
|
|
15
|
-
// position: relative;
|
|
16
|
-
border-radius: 0.5rem;
|
|
17
|
-
height: 100%;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.lesson-card .photo {
|
|
21
|
-
position: absolute;
|
|
22
|
-
top: 0;
|
|
23
|
-
left: 0;
|
|
24
|
-
right: 0;
|
|
25
|
-
bottom: 0;
|
|
26
|
-
z-index: 1;
|
|
27
|
-
|
|
28
|
-
img {
|
|
29
|
-
width: 100%;
|
|
30
|
-
height: 100%;
|
|
31
|
-
object-fit: cover;
|
|
32
|
-
object-position: center;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.description {
|
|
37
|
-
position: relative;
|
|
38
|
-
z-index: 2;
|
|
39
|
-
padding: 1.5rem;
|
|
40
|
-
color: white;
|
|
41
|
-
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0.8) 100%);
|
|
42
|
-
height: 100%;
|
|
43
|
-
display: flex;
|
|
44
|
-
flex-direction: column;
|
|
45
|
-
|
|
46
|
-
h1 {
|
|
47
|
-
margin-top: 0;
|
|
48
|
-
margin-bottom: 0.5rem;
|
|
49
|
-
font-size: 1.5rem;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
p {
|
|
53
|
-
margin-bottom: 1rem;
|
|
54
|
-
flex-grow: 1;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.date {
|
|
59
|
-
position: absolute;
|
|
60
|
-
top: 1rem;
|
|
61
|
-
left: 1rem;
|
|
62
|
-
z-index: 3;
|
|
63
|
-
background-color: rgba(0, 0, 0, 0.7);
|
|
64
|
-
color: white;
|
|
65
|
-
padding: 0.3rem 0.6rem;
|
|
66
|
-
border-radius: 0.25rem;
|
|
67
|
-
font-size: 0.8rem;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.card-footer {
|
|
71
|
-
display: flex;
|
|
72
|
-
justify-content: space-between;
|
|
73
|
-
align-items: center;
|
|
74
|
-
margin-top: auto;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.status-tags {
|
|
78
|
-
display: flex;
|
|
79
|
-
gap: 0.5rem;
|
|
80
|
-
|
|
81
|
-
.level-tag,
|
|
82
|
-
.status-tag {
|
|
83
|
-
padding: 0.3rem 0.6rem;
|
|
84
|
-
border-radius: 0.25rem;
|
|
85
|
-
font-size: 0.8rem;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.level-tag {
|
|
89
|
-
background-color: rgba(255, 255, 255, 0.2);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.status-tag {
|
|
93
|
-
&.success {
|
|
94
|
-
background-color: rgba(40, 167, 69, 0.7);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
&.danger {
|
|
98
|
-
background-color: rgba(220, 53, 69, 0.7);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
.actions {
|
|
104
|
-
::ng-deep .p-button {
|
|
105
|
-
font-size: 0.9rem;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
|
2
|
-
import { NgFor, NgIf, DatePipe } from '@angular/common';
|
|
3
|
-
|
|
4
|
-
import { ButtonModule } from 'primeng/button';
|
|
5
|
-
import { PopoverModule } from 'primeng/popover';
|
|
6
|
-
|
|
7
|
-
import { SpeedDialModule } from 'primeng/speeddial';
|
|
8
|
-
import { MenuItem } from 'primeng/api';
|
|
9
|
-
import { CardModule } from 'primeng/card';
|
|
10
|
-
|
|
11
|
-
import { ILesson, ILessonWithTaken } from '../../lesson-mini-components/components/lessons.clases';
|
|
12
|
-
import { OnActionEvent } from '@dataclouder/ngx-core';
|
|
13
|
-
|
|
14
|
-
enum EventCard {
|
|
15
|
-
Edit = 'edit',
|
|
16
|
-
Delete = 'delete',
|
|
17
|
-
Select = 'select',
|
|
18
|
-
Qr = 'qr',
|
|
19
|
-
}
|
|
20
|
-
@Component({
|
|
21
|
-
selector: 'dc-lesson-card',
|
|
22
|
-
templateUrl: './dc-lesson-card.component.html',
|
|
23
|
-
styleUrls: ['./dc-lesson-card.component.scss'],
|
|
24
|
-
standalone: true,
|
|
25
|
-
imports: [NgFor, NgIf, DatePipe, ButtonModule, PopoverModule, SpeedDialModule, CardModule],
|
|
26
|
-
})
|
|
27
|
-
export class DcLessonCardComponent implements OnInit {
|
|
28
|
-
@Input() lesson: ILessonWithTaken | ILesson | any;
|
|
29
|
-
@Input() isAdmin: boolean = true;
|
|
30
|
-
|
|
31
|
-
@Output() onAction: EventEmitter<OnActionEvent> = new EventEmitter();
|
|
32
|
-
|
|
33
|
-
public coverUrl: string = 'assets/background/default-background.webp';
|
|
34
|
-
public eventType = EventCard;
|
|
35
|
-
|
|
36
|
-
public items: MenuItem[] = [
|
|
37
|
-
{
|
|
38
|
-
label: 'Editar',
|
|
39
|
-
icon: 'pi pi-pencil',
|
|
40
|
-
command: () => {
|
|
41
|
-
this.eventCard(EventCard.Edit);
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
label: 'Eliminar',
|
|
46
|
-
icon: 'pi pi-trash',
|
|
47
|
-
command: () => {
|
|
48
|
-
this.eventCard(EventCard.Delete);
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
label: 'Tomar lección',
|
|
53
|
-
icon: 'pi pi-play',
|
|
54
|
-
command: () => {
|
|
55
|
-
this.eventCard(EventCard.Select);
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
ngOnInit() {
|
|
61
|
-
if (this.lesson?.media?.images![0]?.url) {
|
|
62
|
-
this.coverUrl = this.lesson.media.images[0].url;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
public eventCard(eventType: EventCard) {
|
|
67
|
-
switch (eventType) {
|
|
68
|
-
case EventCard.Edit:
|
|
69
|
-
this.onAction.emit({ action: 'edit', item: this.lesson });
|
|
70
|
-
break;
|
|
71
|
-
case EventCard.Delete:
|
|
72
|
-
this.onAction.emit({ action: 'delete', item: this.lesson });
|
|
73
|
-
break;
|
|
74
|
-
case EventCard.Select:
|
|
75
|
-
this.onAction.emit({ action: 'select', item: this.lesson });
|
|
76
|
-
break;
|
|
77
|
-
case EventCard.Qr:
|
|
78
|
-
this.onAction.emit({ action: 'qr', item: this.lesson });
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
.btn {
|
|
2
|
-
padding: 0.5rem 1rem;
|
|
3
|
-
border-radius: 4px;
|
|
4
|
-
border: 1px solid transparent;
|
|
5
|
-
cursor: pointer;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.btn-primary {
|
|
9
|
-
background-color: #007bff;
|
|
10
|
-
color: white;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.btn-outline-primary {
|
|
14
|
-
border-color: #007bff;
|
|
15
|
-
color: #007bff;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.btn-secondary {
|
|
19
|
-
background-color: #6c757d;
|
|
20
|
-
color: white;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.btn-outline-secondary {
|
|
24
|
-
border-color: #6c757d;
|
|
25
|
-
color: #6c757d;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.btn-rounded {
|
|
29
|
-
border-radius: 50%;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.form-control {
|
|
33
|
-
padding: 0.375rem 0.75rem;
|
|
34
|
-
border: 1px solid #ced4da;
|
|
35
|
-
border-radius: 0.25rem;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.splitter {
|
|
39
|
-
display: flex;
|
|
40
|
-
gap: 1rem;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.splitter-panel {
|
|
44
|
-
flex: 1;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.checkbox-container {
|
|
48
|
-
display: inline-flex;
|
|
49
|
-
align-items: center;
|
|
50
|
-
gap: 0.5rem;
|
|
51
|
-
cursor: pointer;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.mr-2 {
|
|
55
|
-
margin-right: 0.5rem;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.header-cover {
|
|
59
|
-
width: 100%;
|
|
60
|
-
height: 250px;
|
|
61
|
-
background-position: center;
|
|
62
|
-
background-repeat: no-repeat;
|
|
63
|
-
background-size: cover;
|
|
64
|
-
position: relative;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.float-button {
|
|
68
|
-
position: fixed;
|
|
69
|
-
bottom: 3.5rem;
|
|
70
|
-
right: 2rem;
|
|
71
|
-
z-index: 1000;
|
|
72
|
-
display: flex;
|
|
73
|
-
gap: 1px;
|
|
74
|
-
:host ::ng-deep .p-button {
|
|
75
|
-
width: 4rem;
|
|
76
|
-
height: 4rem;
|
|
77
|
-
border-radius: 50%;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.text-editor {
|
|
82
|
-
width: -webkit-fill-available;
|
|
83
|
-
overflow-y: auto;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
:host ::ng-deep .p-inputtext{
|
|
88
|
-
background: rgba(255, 255, 255, 0.2);
|
|
89
|
-
|
|
90
|
-
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
<div style="position: relative; margin-bottom: 20px">
|
|
2
|
-
<div class="header-cover" [style.background-image]="cover"></div>
|
|
3
|
-
|
|
4
|
-
<dc-cropper-modal
|
|
5
|
-
style="position: absolute; top: 10px; left: 20px"
|
|
6
|
-
[buttonLabel]="'Carga una portada'"
|
|
7
|
-
[imgStorageSettings]="coverStorageSettings"
|
|
8
|
-
(imageUploaded)="onImageUploaded($event)"></dc-cropper-modal>
|
|
9
|
-
</div>
|
|
10
|
-
|
|
11
|
-
<br />
|
|
12
|
-
|
|
13
|
-
<div>
|
|
14
|
-
<div>
|
|
15
|
-
<div>
|
|
16
|
-
<div style="display: flex; gap: 10px; padding: 10px">
|
|
17
|
-
<p-button label="Guardar" severity="primary" (click)="saveLesson()" />
|
|
18
|
-
|
|
19
|
-
<p-button label="Previsualizar" severity="secondary" (click)="togleRender()" />
|
|
20
|
-
<p-button label="Importar de Notion" severity="help" (click)="importFromNotion()" />
|
|
21
|
-
<p-button label="Mejorar Notion con AI" severity="help" (click)="improveNotionWithAI()" />
|
|
22
|
-
</div>
|
|
23
|
-
|
|
24
|
-
<div>
|
|
25
|
-
<input pInputText style="width: 100%" [(ngModel)]="lesson.title" type="text" placeholder="Agrega un título" />
|
|
26
|
-
</div>
|
|
27
|
-
<div style="margin-top: 4px">
|
|
28
|
-
<input pInputText style="width: 100%" [(ngModel)]="lesson.description" type="text" placeholder="Agrega una descripción" />
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<div style="display: flex; align-items: center">
|
|
32
|
-
<br />
|
|
33
|
-
<br />
|
|
34
|
-
<input pInputText style="flex: auto" [(ngModel)]="lesson.prompt" type="text" placeholder="Prompt" />
|
|
35
|
-
<p-button severity="primary" [disabled]="isLoadingLesson" (click)="generateByAI()"> Generar </p-button>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
<div>
|
|
39
|
-
<label class="checkbox-container">
|
|
40
|
-
<input type="checkbox" [(ngModel)]="lesson.isPublished" title="Cuando termines la edición marca esta casilla" />
|
|
41
|
-
<span class="checkmark"></span>
|
|
42
|
-
Lección publicada
|
|
43
|
-
</label>
|
|
44
|
-
<br />
|
|
45
|
-
|
|
46
|
-
<input pInputText [(ngModel)]="lesson.level" type="number" placeholder="Level" />
|
|
47
|
-
</div>
|
|
48
|
-
|
|
49
|
-
<div>
|
|
50
|
-
{{ lesson.baseLang | flagEmoji }} -> {{ lesson.targetLang | flagEmoji }} Lección para hablantes de {{ lesson.baseLang | langDesc : 'es' }} que aprenden
|
|
51
|
-
{{ lesson.targetLang | langDesc : 'es' }}
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
|
|
56
|
-
<hr />
|
|
57
|
-
<span>Componentes: </span>
|
|
58
|
-
<div style="display: flex; gap: 10px">
|
|
59
|
-
<p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.Selector)" pTooltip="Agrega un selector con multiples opciones">
|
|
60
|
-
Selector
|
|
61
|
-
</p-button>
|
|
62
|
-
<p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.Speaker)" pTooltip="Para que una palabra o frase sea reproducible">
|
|
63
|
-
Speaker
|
|
64
|
-
</p-button>
|
|
65
|
-
<p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.TextWriter)" pTooltip="Escribe una respuesta en un cuadro de texto">
|
|
66
|
-
Text
|
|
67
|
-
</p-button>
|
|
68
|
-
<p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.VerbSummary)" pTooltip="Muestra la información de un verbo"> Text </p-button>
|
|
69
|
-
<p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.VerbSummary)" pTooltip="Muestra la información de un verbo"> Verb </p-button>
|
|
70
|
-
<p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.WordSummary)" pTooltip="Muestra la información de una palabra">
|
|
71
|
-
Palabra
|
|
72
|
-
</p-button>
|
|
73
|
-
<p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.TranslationSwitcher)" pTooltip="Muestra el texto pero al pica cambia de idioma">
|
|
74
|
-
Traducción
|
|
75
|
-
</p-button>
|
|
76
|
-
</div>
|
|
77
|
-
|
|
78
|
-
<hr />
|
|
79
|
-
|
|
80
|
-
<p-splitter [style]="{ height: '80vh' }" styleClass="mb-8">
|
|
81
|
-
<ng-template pTemplate>
|
|
82
|
-
<ckeditor
|
|
83
|
-
(keydown.control.s)="saveLesson($event)"
|
|
84
|
-
(keydown.control.space)="togleRender($event)"
|
|
85
|
-
class="text-editor"
|
|
86
|
-
[editor]="editor"
|
|
87
|
-
[(ngModel)]="lesson.textCoded">
|
|
88
|
-
</ckeditor>
|
|
89
|
-
</ng-template>
|
|
90
|
-
|
|
91
|
-
<ng-template pTemplate>
|
|
92
|
-
@if (isRendered) {
|
|
93
|
-
<dc-lesson-renderer class="text-editor" [lesson]="lesson" [test]="true"></dc-lesson-renderer>
|
|
94
|
-
}
|
|
95
|
-
</ng-template>
|
|
96
|
-
</p-splitter>
|
|
97
|
-
|
|
98
|
-
<div class="float-button">
|
|
99
|
-
<p-speeddial [model]="items" [radius]="120" type="quarter-circle" direction="up-left" />
|
|
100
|
-
|
|
101
|
-
<p-button icon="pi pi-save" (click)="saveLesson()" severity="primary" [rounded]="true" [raised]="true" pTooltip="Guardar (Ctrl + S)"> </p-button>
|
|
102
|
-
</div>
|
|
103
|
-
|
|
104
|
-
<hr />
|
|
105
|
-
</div>
|
|
File without changes
|
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
import { ChangeDetectorRef, Component, ComponentRef, ElementRef, Inject, OnInit, TemplateRef, ViewChild, ViewContainerRef } from '@angular/core';
|
|
2
|
-
import { ActivatedRoute, Router } from '@angular/router';
|
|
3
|
-
import { FormsModule } from '@angular/forms';
|
|
4
|
-
import { Observable } from 'rxjs';
|
|
5
|
-
|
|
6
|
-
import BalloonEditor from '@ckeditor/ckeditor5-build-balloon-block';
|
|
7
|
-
import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
|
|
8
|
-
// PrimeNG
|
|
9
|
-
import { DialogService } from 'primeng/dynamicdialog';
|
|
10
|
-
import { SpeedDialModule } from 'primeng/speeddial';
|
|
11
|
-
import { ButtonModule } from 'primeng/button';
|
|
12
|
-
import { InputTextModule } from 'primeng/inputtext';
|
|
13
|
-
import { SplitterModule } from 'primeng/splitter';
|
|
14
|
-
import { TooltipModule } from 'primeng/tooltip';
|
|
15
|
-
// Dataclouder
|
|
16
|
-
import { AspectType, CropImageSettings, CropperComponentModal, ResolutionType, StorageImageSettings } from '@dataclouder/ngx-cloud-storage';
|
|
17
|
-
import { TOAST_ALERTS_TOKEN, ToastAlertsAbstractService } from '@dataclouder/ngx-core';
|
|
18
|
-
|
|
19
|
-
import { DCLessonRendererComponent } from '../dc-lesson-renderer/dc-lesson-renderer.component';
|
|
20
|
-
import {
|
|
21
|
-
LessonComponentEnum,
|
|
22
|
-
LessonImage,
|
|
23
|
-
ILesson,
|
|
24
|
-
LessonComponentInterface,
|
|
25
|
-
LESSONS_TOKEN,
|
|
26
|
-
LessonsAbstractService,
|
|
27
|
-
} from '../../lesson-mini-components/components/lessons.clases';
|
|
28
|
-
import { LessonComponentBuilders } from '../../lesson-mini-components/components/lessons.clases';
|
|
29
|
-
import { FlagLanguagePipe, LangDescTranslationPipe } from '../../../models/lessons.pipes';
|
|
30
|
-
import { NOTION_SERVICE_TOKEN, NotionAbstractService, NotionExportType } from '../../../models/notion.models';
|
|
31
|
-
import { MenuItem } from 'primeng/api';
|
|
32
|
-
|
|
33
|
-
const GradientCss = 'linear-gradient(to bottom,var(--primary-color), rgba(213, 238, 239, 0.31))';
|
|
34
|
-
|
|
35
|
-
@Component({
|
|
36
|
-
selector: 'dc-lesson-editor',
|
|
37
|
-
templateUrl: './dc-lesson-editor.component.html',
|
|
38
|
-
styleUrls: ['./dc-lesson-editor.component.css'],
|
|
39
|
-
standalone: true,
|
|
40
|
-
imports: [
|
|
41
|
-
FormsModule,
|
|
42
|
-
CKEditorModule,
|
|
43
|
-
CropperComponentModal,
|
|
44
|
-
ButtonModule,
|
|
45
|
-
InputTextModule,
|
|
46
|
-
SplitterModule,
|
|
47
|
-
DCLessonRendererComponent,
|
|
48
|
-
LangDescTranslationPipe,
|
|
49
|
-
FlagLanguagePipe,
|
|
50
|
-
TooltipModule,
|
|
51
|
-
SpeedDialModule,
|
|
52
|
-
],
|
|
53
|
-
})
|
|
54
|
-
export class DCLessonEditorComponent implements OnInit {
|
|
55
|
-
// public get activatedRoute(): ActivatedRoute {
|
|
56
|
-
// return this._activatedRoute;
|
|
57
|
-
// }
|
|
58
|
-
// public set activatedRoute(value: ActivatedRoute) {
|
|
59
|
-
// this._activatedRoute = value;
|
|
60
|
-
// }
|
|
61
|
-
@ViewChild('target', { read: ViewContainerRef }) target: ViewContainerRef;
|
|
62
|
-
@ViewChild('dhtml', { static: true }) dhtml: ElementRef;
|
|
63
|
-
|
|
64
|
-
public editor = BalloonEditor;
|
|
65
|
-
public coverStorageSettings: StorageImageSettings = {
|
|
66
|
-
path: 'lessons/covers',
|
|
67
|
-
fileName: 'cover',
|
|
68
|
-
cropSettings: { resizeToWidth: 850, aspectRatio: AspectType.RectangleLarge, resolutions: [ResolutionType.Medium] },
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
public lessonComponentEnum = LessonComponentEnum;
|
|
72
|
-
public lessonId: string = this._activatedRoute.snapshot.paramMap.get('id');
|
|
73
|
-
public lesson: any = { textCoded: `<h1>Nueva lección </h1> <p> Texto aquí</p>`, tags: [] };
|
|
74
|
-
public components: { [key: string]: ComponentRef<LessonComponentInterface> } = {};
|
|
75
|
-
public isRendered: boolean = false;
|
|
76
|
-
public cover: string = '';
|
|
77
|
-
public isCropperVisible = false;
|
|
78
|
-
public items: MenuItem[];
|
|
79
|
-
|
|
80
|
-
constructor(
|
|
81
|
-
@Inject(LESSONS_TOKEN) private lessonService: LessonsAbstractService,
|
|
82
|
-
@Inject(TOAST_ALERTS_TOKEN) private toastService: ToastAlertsAbstractService,
|
|
83
|
-
@Inject(NOTION_SERVICE_TOKEN) private notionService: NotionAbstractService,
|
|
84
|
-
private _activatedRoute: ActivatedRoute,
|
|
85
|
-
private router: Router,
|
|
86
|
-
private cdr: ChangeDetectorRef,
|
|
87
|
-
private dialogService: DialogService,
|
|
88
|
-
) {}
|
|
89
|
-
|
|
90
|
-
ngOnInit(): void {
|
|
91
|
-
this.getLessonIfId();
|
|
92
|
-
|
|
93
|
-
this.items = [
|
|
94
|
-
{
|
|
95
|
-
tooltipOptions: { tooltipLabel: 'Reparar con IA: Repara la lección con IA', tooltipPosition: 'bottom' },
|
|
96
|
-
icon: 'pi pi-magic',
|
|
97
|
-
command: () => this.generateByAI(),
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
tooltipOptions: { tooltipLabel: 'Selector: Agrega un selector con multiples opciones', tooltipPosition: 'bottom' },
|
|
101
|
-
icon: 'pi pi-caret-down',
|
|
102
|
-
command: () => this.openComponentBuilder('selector'),
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
tooltipOptions: { tooltipLabel: 'Hablar: Para que una palabra o frase sea reproducible', tooltipPosition: 'bottom' },
|
|
106
|
-
icon: 'pi pi-megaphone',
|
|
107
|
-
command: () => this.openComponentBuilder('speaker'),
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
tooltipOptions: {
|
|
111
|
-
tooltipLabel: 'Entrada de texto: Escribe una respuesta en un cuadro de texto',
|
|
112
|
-
tooltipPosition: 'bottom',
|
|
113
|
-
},
|
|
114
|
-
icon: 'pi pi-pencil',
|
|
115
|
-
command: () => this.openComponentBuilder('textWriter'),
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
tooltipOptions: { tooltipLabel: 'Verbo: Para ver datos de un verbo', tooltipPosition: 'bottom' },
|
|
119
|
-
icon: 'pi pi-eye',
|
|
120
|
-
command: () => this.openComponentBuilder('verbSummary'),
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
tooltipOptions: { tooltipLabel: 'Palabra: Para ver datos de una palabra', tooltipPosition: 'bottom' },
|
|
124
|
-
icon: 'pi pi-file-word',
|
|
125
|
-
command: () => this.openComponentBuilder('wordSummary'),
|
|
126
|
-
},
|
|
127
|
-
];
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
public async getLessonIfId(): Promise<void> {
|
|
131
|
-
if (!this.lessonId) {
|
|
132
|
-
this.cover = `${GradientCss}, url("/assets/images/default_banner.webp")`;
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
this.lesson = await this.lessonService.getLesson(this.lessonId);
|
|
136
|
-
console.log('lesson', this.lesson);
|
|
137
|
-
if (!this.lesson) {
|
|
138
|
-
this.toastService.warn({ title: 'No se encontró la lección', subtitle: 'Quiza el id es incorrecto' });
|
|
139
|
-
}
|
|
140
|
-
this.togleRender();
|
|
141
|
-
this.updateCover();
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
public updateCover(): void {
|
|
145
|
-
const cover: LessonImage = this.lesson.media?.images?.find((img) => img.type === 'cover');
|
|
146
|
-
if (cover) {
|
|
147
|
-
this.cover = `${GradientCss}, url('${cover.url}')`;
|
|
148
|
-
} else {
|
|
149
|
-
this.cover = `${GradientCss}, url("/assets/images/default_banner.webp")`;
|
|
150
|
-
}
|
|
151
|
-
this.cdr.detectChanges();
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
public onTagRemove(tag: any): void {
|
|
155
|
-
this.lesson.tags = this.lesson.tags.filter((text) => text !== tag.text);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
public onTagAdd(tag: { value: string; input: any }): void {
|
|
159
|
-
if (tag.value) {
|
|
160
|
-
this.lesson.tags.push(tag.value);
|
|
161
|
-
}
|
|
162
|
-
tag.input.nativeElement.value = '';
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
public async saveLesson(event: Event = null): Promise<ILesson> {
|
|
166
|
-
if (event) {
|
|
167
|
-
event.preventDefault();
|
|
168
|
-
}
|
|
169
|
-
// TODO: Optimización importante, guardar una lección guarda todos los datos de nuevo, y no solo los que se modificaron, encontrar una forma de optimizar.
|
|
170
|
-
const lesson = await this.lessonService.postLesson(this.lesson);
|
|
171
|
-
if (!this.lessonId) {
|
|
172
|
-
this.toastService.success({ title: 'Se creó la lección', subtitle: 'Éxito' });
|
|
173
|
-
this.router.navigate([lesson.id], { relativeTo: this._activatedRoute });
|
|
174
|
-
} else {
|
|
175
|
-
this.toastService.info({ title: 'Se guadarón los cambios en la lección', subtitle: 'Guardado' });
|
|
176
|
-
this.lesson = lesson;
|
|
177
|
-
this.validateAudios();
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
this.togleRender();
|
|
181
|
-
return lesson;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
public async validateAudios() {
|
|
185
|
-
if (!this.lesson.components) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
// al menos un audio sin generar.
|
|
189
|
-
// agregar más condigciones después
|
|
190
|
-
// this.lesson.components.forEach((component: SpeakerCompConfiguration) => {
|
|
191
|
-
// if (component.component === 'speaker') {
|
|
192
|
-
// if (component.settings.voice && !component.audio) {
|
|
193
|
-
// // this.toastrService.warn('Se encontraron audios por generar', 'Será rápido');
|
|
194
|
-
// // TODO call backend.
|
|
195
|
-
// this.lessonService.generateAudiosForLesson(this.lesson.id).then((res) => {
|
|
196
|
-
// // this.toastrService.success('Se generaron los audios', 'Listo');
|
|
197
|
-
// console.log(res);
|
|
198
|
-
// });
|
|
199
|
-
// return;
|
|
200
|
-
// }
|
|
201
|
-
// }
|
|
202
|
-
// });
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
public togleRender(_event: any = null): void {
|
|
206
|
-
this.isRendered = false;
|
|
207
|
-
setTimeout(() => {
|
|
208
|
-
this.isRendered = true;
|
|
209
|
-
this.cdr.detectChanges();
|
|
210
|
-
}, 400);
|
|
211
|
-
this.cdr.detectChanges();
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
public openComponentBuilder(type: string): Observable<any> {
|
|
215
|
-
return this.dialogService.open(LessonComponentBuilders[type], { width: '550px', header: 'Agregar componente', closable: true }).onClose.pipe();
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
public uploadCover(imageUploaded: any) {
|
|
219
|
-
const image = { type: 'cover', ...imageUploaded };
|
|
220
|
-
|
|
221
|
-
if (!this.lesson.media) {
|
|
222
|
-
// puede que no exista media
|
|
223
|
-
this.lesson.media = {};
|
|
224
|
-
this.lesson.media.images = [image];
|
|
225
|
-
} else {
|
|
226
|
-
// solo sustituir el cover si ya existe, como siempre utilizo el mismo nombre, no tengo que eliminar la anterior si actualizo.
|
|
227
|
-
// const currentCover = this.lesson.media.images.find((img) => img.type === 'cover');
|
|
228
|
-
|
|
229
|
-
this.lesson.media.images = this.lesson.media.images.filter((img) => img.type !== 'cover');
|
|
230
|
-
this.lesson.media.images.push(image);
|
|
231
|
-
}
|
|
232
|
-
this.updateCover();
|
|
233
|
-
this.saveLesson();
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
openCropper() {
|
|
237
|
-
this.isCropperVisible = true;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
isLoadingLesson = false;
|
|
241
|
-
public async generateByAI() {
|
|
242
|
-
this.isLoadingLesson = true;
|
|
243
|
-
try {
|
|
244
|
-
await this.saveLesson();
|
|
245
|
-
await this.lessonService.postGenerateByAI(this.lesson.id);
|
|
246
|
-
await this.getLessonIfId();
|
|
247
|
-
} finally {
|
|
248
|
-
this.isLoadingLesson = false;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
public onImageSelected(event: any) {
|
|
253
|
-
console.log(event);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
public async onImageUploaded(event: any) {
|
|
257
|
-
this.uploadCover(event);
|
|
258
|
-
this.cdr.detectChanges();
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
public async importFromNotion() {
|
|
262
|
-
let notionPageId: string;
|
|
263
|
-
if (this.lesson?.extras?.notionPageId) {
|
|
264
|
-
const response = confirm(`Ya tenemos el id ${this.lesson.extras?.notionPageId} ¿Quieres usar este id?`);
|
|
265
|
-
if (!response) {
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
notionPageId = this.lesson.extras?.notionPageId;
|
|
269
|
-
} else {
|
|
270
|
-
const response = prompt('Ingresa el url de notion para importar la lección, se guardará este id');
|
|
271
|
-
if (!response) {
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
notionPageId = this.extractNotionPageId(response);
|
|
275
|
-
if (!notionPageId) return;
|
|
276
|
-
this.linkWithNotion(notionPageId);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
this.toastService.info({ title: 'Importando lección...', subtitle: 'Espera unos segundos' });
|
|
280
|
-
|
|
281
|
-
const md = await this.notionService.getPageInSpecificFormat(notionPageId, NotionExportType.HTML);
|
|
282
|
-
console.log(md);
|
|
283
|
-
this.lesson.textCoded = md.content;
|
|
284
|
-
this.togleRender();
|
|
285
|
-
this.toastService.success({ title: 'Listo', subtitle: 'La lección se importó correctamente' });
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
extractNotionPageId(url: string) {
|
|
289
|
-
const notionIdRegex = /[a-f0-9]{32}(?=\?|$)/;
|
|
290
|
-
const match = url.match(notionIdRegex);
|
|
291
|
-
const notionId = match ? match[0] : null;
|
|
292
|
-
if (!notionId) {
|
|
293
|
-
this.toastService.error({
|
|
294
|
-
title: 'URL inválido',
|
|
295
|
-
subtitle: 'Por favor ingresa una URL válida de Notion',
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
return notionId;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
public async linkWithNotion(notionPageId: string) {
|
|
302
|
-
const extra = this.lesson.extras || {};
|
|
303
|
-
extra.notionPageId = notionPageId;
|
|
304
|
-
|
|
305
|
-
await this.lessonService.postLesson({ ...this.lesson, extras: extra });
|
|
306
|
-
this.toastService.success({ title: 'Listo', subtitle: 'Se enlazó la lección con Notion' });
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
public async improveNotionWithAI() {
|
|
310
|
-
const md = await this.notionService.getPageInSpecificFormat(this.lesson.extras.notionPageId, NotionExportType.HTML);
|
|
311
|
-
console.log(md);
|
|
312
|
-
|
|
313
|
-
// this.lesson.textCoded = md.content;
|
|
314
|
-
|
|
315
|
-
// this.togleRender();
|
|
316
|
-
// this.toastService.success({ title: 'Listo', subtitle: 'La lección se mejoró con AI' });
|
|
317
|
-
}
|
|
318
|
-
}
|