tudu-components 0.2.1 → 0.2.3
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/karma.conf.js +44 -0
- package/ng-package.json +7 -0
- package/package.json +3 -22
- package/src/lib/components/card-layout/card-layout.component.css +166 -0
- package/src/lib/components/card-layout/card-layout.component.html +100 -0
- package/src/lib/components/card-layout/card-layout.component.spec.ts +23 -0
- package/src/lib/components/card-layout/card-layout.component.ts +78 -0
- package/src/lib/components/fallback-message/fallback-message.component.css +36 -0
- package/src/lib/components/fallback-message/fallback-message.component.html +95 -0
- package/src/lib/components/fallback-message/fallback-message.component.spec.ts +23 -0
- package/src/lib/components/fallback-message/fallback-message.component.ts +140 -0
- package/src/lib/components/nav/nav.component.css +40 -0
- package/src/lib/components/nav/nav.component.html +40 -0
- package/src/lib/components/nav/nav.component.spec.ts +23 -0
- package/src/lib/components/nav/nav.component.ts +84 -0
- package/src/lib/tudu-components.component.spec.ts +23 -0
- package/src/lib/tudu-components.component.ts +20 -0
- package/src/lib/tudu-components.module.ts +13 -0
- package/src/lib/tudu-components.service.spec.ts +16 -0
- package/src/lib/tudu-components.service.ts +9 -0
- package/src/public-api.ts +11 -0
- package/src/test.ts +27 -0
- package/tsconfig.lib.json +19 -0
- package/tsconfig.lib.prod.json +10 -0
- package/tsconfig.spec.json +17 -0
- package/esm2020/lib/components/card-layout/card-layout.component.mjs +0 -77
- package/esm2020/lib/components/nav/nav.component.mjs +0 -74
- package/esm2020/lib/tudu-components.component.mjs +0 -22
- package/esm2020/lib/tudu-components.module.mjs +0 -20
- package/esm2020/lib/tudu-components.service.mjs +0 -14
- package/esm2020/public-api.mjs +0 -10
- package/esm2020/tudu-components.mjs +0 -5
- package/fesm2015/tudu-components.mjs +0 -207
- package/fesm2015/tudu-components.mjs.map +0 -1
- package/fesm2020/tudu-components.mjs +0 -206
- package/fesm2020/tudu-components.mjs.map +0 -1
- package/index.d.ts +0 -5
- package/lib/components/card-layout/card-layout.component.d.ts +0 -31
- package/lib/components/nav/nav.component.d.ts +0 -25
- package/lib/tudu-components.component.d.ts +0 -8
- package/lib/tudu-components.module.d.ts +0 -10
- package/lib/tudu-components.service.d.ts +0 -6
- package/public-api.d.ts +0 -5
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
interface EmptyStateConfig {
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
icon: string;
|
|
7
|
+
iconColor: string;
|
|
8
|
+
bgColor: string;
|
|
9
|
+
primaryActionText?: string;
|
|
10
|
+
secondaryActionText?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@Component({
|
|
14
|
+
selector: 'lib-fallback-message',
|
|
15
|
+
templateUrl: './fallback-message.component.html',
|
|
16
|
+
styleUrls: ['./fallback-message.component.css'],
|
|
17
|
+
})
|
|
18
|
+
export class FallbackMessageComponent {
|
|
19
|
+
@Input() card: any[] = [];
|
|
20
|
+
@Input() statusPedido: string = '';
|
|
21
|
+
@Input() customTitle?: string;
|
|
22
|
+
@Input() customDescription?: string;
|
|
23
|
+
@Input() primaryActionText?: string;
|
|
24
|
+
@Input() secondaryActionText?: string;
|
|
25
|
+
|
|
26
|
+
@Output() primaryAction = new EventEmitter<void>();
|
|
27
|
+
@Output() secondaryAction = new EventEmitter<void>();
|
|
28
|
+
|
|
29
|
+
get emptyStateConfig(): EmptyStateConfig {
|
|
30
|
+
// Se não há propostas
|
|
31
|
+
// if (this.card.length === 0) {
|
|
32
|
+
// return {
|
|
33
|
+
// title: 'Nenhuma Proposta',
|
|
34
|
+
// description:
|
|
35
|
+
// 'Você ainda não possui negociações ou propostas recebidas.',
|
|
36
|
+
// icon: '📄',
|
|
37
|
+
// iconColor: 'text-gray-500',
|
|
38
|
+
// bgColor: 'bg-gray-100',
|
|
39
|
+
// primaryActionText: this.primaryActionText || 'Anúnciar Grátis',
|
|
40
|
+
// secondaryActionText: this.secondaryActionText,
|
|
41
|
+
// };
|
|
42
|
+
// }
|
|
43
|
+
|
|
44
|
+
// Se há status de pedido
|
|
45
|
+
if (this.statusPedido) {
|
|
46
|
+
switch (this.statusPedido.toLowerCase()) {
|
|
47
|
+
case 'finalizado':
|
|
48
|
+
return {
|
|
49
|
+
title: this.customTitle || 'Serviço Concluído! 🎉',
|
|
50
|
+
description:
|
|
51
|
+
this.customDescription ||
|
|
52
|
+
'O serviço foi finalizado com sucesso. Agradecemos pela confiança!',
|
|
53
|
+
icon: '✅',
|
|
54
|
+
iconColor: 'text-green-500',
|
|
55
|
+
bgColor: 'bg-green-100',
|
|
56
|
+
primaryActionText: this.primaryActionText || 'Ver Detalhes',
|
|
57
|
+
secondaryActionText: this.secondaryActionText || 'Avaliar Serviço',
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// case 'cancelado':
|
|
61
|
+
// return {
|
|
62
|
+
// title: this.customTitle || 'Serviço Cancelado',
|
|
63
|
+
// description:
|
|
64
|
+
// this.customDescription ||
|
|
65
|
+
// 'O serviço foi cancelado pelo prestador. Você pode buscar outros profissionais disponíveis.',
|
|
66
|
+
// icon: '❌',
|
|
67
|
+
// iconColor: 'text-red-500',
|
|
68
|
+
// bgColor: 'bg-red-100',
|
|
69
|
+
// primaryActionText: this.primaryActionText || 'Buscar Profissionais',
|
|
70
|
+
// secondaryActionText: this.secondaryActionText || 'Voltar ao Início',
|
|
71
|
+
// };
|
|
72
|
+
|
|
73
|
+
case 'sem servicos':
|
|
74
|
+
return {
|
|
75
|
+
title: this.customTitle || 'Sem serviço',
|
|
76
|
+
description:
|
|
77
|
+
this.customDescription ||
|
|
78
|
+
'Não há serviços disponíveis aqui.',
|
|
79
|
+
icon: '📄',
|
|
80
|
+
// iconColor: 'text-yellow-500',
|
|
81
|
+
// bgColor: 'bg-yellow-100',
|
|
82
|
+
iconColor: 'text-gray-500',
|
|
83
|
+
bgColor: 'bg-gray-100',
|
|
84
|
+
primaryActionText: this.primaryActionText || 'Procurar serviços',
|
|
85
|
+
// secondaryActionText: this.secondaryActionText || 'Meus Anúncios',
|
|
86
|
+
};
|
|
87
|
+
case 'indisponivel':
|
|
88
|
+
return {
|
|
89
|
+
title: this.customTitle || 'Proposta Indisponível',
|
|
90
|
+
description:
|
|
91
|
+
this.customDescription ||
|
|
92
|
+
'Esta proposta não está mais disponível para visualização.',
|
|
93
|
+
icon: '📄',
|
|
94
|
+
// iconColor: 'text-yellow-500',
|
|
95
|
+
// bgColor: 'bg-yellow-100',
|
|
96
|
+
iconColor: 'text-gray-500',
|
|
97
|
+
bgColor: 'bg-gray-100',
|
|
98
|
+
primaryActionText: this.primaryActionText || 'Ver Outras Propostas',
|
|
99
|
+
// secondaryActionText: this.secondaryActionText || 'Meus Anúncios',
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
default:
|
|
103
|
+
return this.getDefaultConfig();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return this.getDefaultConfig();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private getDefaultConfig(): EmptyStateConfig {
|
|
111
|
+
return {
|
|
112
|
+
title: this.customTitle || 'Nenhuma Proposta',
|
|
113
|
+
description:
|
|
114
|
+
this.customDescription || 'Você ainda não possui negociações.',
|
|
115
|
+
icon: '📄',
|
|
116
|
+
iconColor: 'text-gray-500',
|
|
117
|
+
bgColor: 'bg-gray-100',
|
|
118
|
+
primaryActionText: this.primaryActionText || 'Anúnciar Grátis',
|
|
119
|
+
secondaryActionText: this.secondaryActionText,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Método para determinar se deve mostrar o componente
|
|
124
|
+
shouldShowEmptyState(): boolean {
|
|
125
|
+
return (
|
|
126
|
+
this.card.length === 0 ||
|
|
127
|
+
['finalizado', 'cancelado', 'indisponível', 'indisponivel'].includes(
|
|
128
|
+
this.statusPedido?.toLowerCase()
|
|
129
|
+
)
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
onPrimaryAction() {
|
|
134
|
+
this.primaryAction.emit();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
onSecondaryAction() {
|
|
138
|
+
this.secondaryAction.emit();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
.navbar-ajust {
|
|
2
|
+
background-color: var(--medium);
|
|
3
|
+
padding: 1em;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.container-fluid {
|
|
7
|
+
display: flex;
|
|
8
|
+
justify-content: space-between;
|
|
9
|
+
align-items: center;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.navbar-left,
|
|
13
|
+
.navbar-right {
|
|
14
|
+
flex: 1; /* Ambos ocupam o mesmo espaço */
|
|
15
|
+
display: flex;
|
|
16
|
+
justify-content: flex-start; /* Alinha o da esquerda à esquerda */
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.navbar-right {
|
|
20
|
+
justify-content: flex-end; /* Alinha o da direita à direita */
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.navbar-center {
|
|
24
|
+
flex: 2; /* O dobro do espaço para centralizar corretamente */
|
|
25
|
+
display: flex;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
}
|
|
28
|
+
:host {
|
|
29
|
+
display: block;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.-translate-y-full {
|
|
33
|
+
transform: translateY(calc(-100% - 1px));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@media (max-width: 767px) {
|
|
37
|
+
.-translate-y-full {
|
|
38
|
+
transform: translateY(calc(-100% - 1px));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!-- Overlay -->
|
|
2
|
+
<div
|
|
3
|
+
*ngIf="openClose"
|
|
4
|
+
(click)="openClose = false"
|
|
5
|
+
class="fixed inset-0 bg-black bg-opacity-40 z-40 md:hidden"
|
|
6
|
+
></div>
|
|
7
|
+
|
|
8
|
+
<!-- Navbar Container -->
|
|
9
|
+
<div
|
|
10
|
+
class="fixed top-0 left-0 right-0 z-50 shadow-none transition-transform duration-300 ease-out "
|
|
11
|
+
[class.-translate-y-full]="!isHeaderVisible"
|
|
12
|
+
[style.backgroundColor]="
|
|
13
|
+
changeNavColor ? 'var(--primary)' : 'var(--primary)'
|
|
14
|
+
"
|
|
15
|
+
>
|
|
16
|
+
<!-- Main Navbar -->
|
|
17
|
+
<div class="w-full">
|
|
18
|
+
<div class="mx-auto px-2 h-16 flex items-center justify-between">
|
|
19
|
+
<!-- Left Content -->
|
|
20
|
+
<div class="flex-1 flex justify-start">
|
|
21
|
+
<ng-content select="[left-content]"></ng-content>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<!-- Center Content -->
|
|
25
|
+
<div class="flex-1 flex justify-center">
|
|
26
|
+
<ng-content select="[central-content]"></ng-content>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<!-- Right Content -->
|
|
30
|
+
<div class="flex-1" style="display: flex; justify-content: flex-end">
|
|
31
|
+
<ng-content select="[right-content]"></ng-content>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<!-- Header Menu (Submenu) -->
|
|
37
|
+
<div header-menu class="w-full hr-nav">
|
|
38
|
+
<ng-content select="[header-menu]"></ng-content>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { NavComponent } from './nav.component';
|
|
4
|
+
|
|
5
|
+
describe('NavComponent', () => {
|
|
6
|
+
let component: NavComponent;
|
|
7
|
+
let fixture: ComponentFixture<NavComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
await TestBed.configureTestingModule({
|
|
11
|
+
declarations: [ NavComponent ]
|
|
12
|
+
})
|
|
13
|
+
.compileComponents();
|
|
14
|
+
|
|
15
|
+
fixture = TestBed.createComponent(NavComponent);
|
|
16
|
+
component = fixture.componentInstance;
|
|
17
|
+
fixture.detectChanges();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should create', () => {
|
|
21
|
+
expect(component).toBeTruthy();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component,
|
|
3
|
+
ElementRef,
|
|
4
|
+
HostListener,
|
|
5
|
+
Input,
|
|
6
|
+
OnInit,
|
|
7
|
+
} from '@angular/core';
|
|
8
|
+
import { Router } from '@angular/router';
|
|
9
|
+
|
|
10
|
+
@Component({
|
|
11
|
+
selector: 'lib-nav',
|
|
12
|
+
templateUrl: './nav.component.html',
|
|
13
|
+
styleUrls: ['./nav.component.css'],
|
|
14
|
+
})
|
|
15
|
+
export class NavComponent implements OnInit {
|
|
16
|
+
@Input() changeNavColor: boolean = false;
|
|
17
|
+
|
|
18
|
+
openClose: boolean = false;
|
|
19
|
+
message: string = '';
|
|
20
|
+
|
|
21
|
+
lastScrollPosition = 0;
|
|
22
|
+
isHeaderVisible = true;
|
|
23
|
+
headerHeight = 0;
|
|
24
|
+
isMobile = false;
|
|
25
|
+
|
|
26
|
+
hasOffer: boolean = false;
|
|
27
|
+
|
|
28
|
+
constructor(private router: Router, private el: ElementRef) {}
|
|
29
|
+
|
|
30
|
+
ngAfterViewInit() {
|
|
31
|
+
this.checkMobile();
|
|
32
|
+
|
|
33
|
+
// Obtém a altura do header-menu após a view ser inicializada
|
|
34
|
+
const headerMenu = this.el.nativeElement.querySelector('[header-menu]');
|
|
35
|
+
if (headerMenu) {
|
|
36
|
+
this.headerHeight = headerMenu.offsetHeight;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
ngOnInit(): void {
|
|
41
|
+
this.hasOffer = this.router.url.includes('offer');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@HostListener('window:resize')
|
|
45
|
+
onResize() {
|
|
46
|
+
this.checkMobile();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private checkMobile() {
|
|
50
|
+
this.isMobile = window.innerWidth < 768; // 768px é o breakpoint padrão do Tailwind para md
|
|
51
|
+
if (!this.isMobile) {
|
|
52
|
+
this.isHeaderVisible = true; // Garante que fique visível em desktop
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
public menu() {
|
|
56
|
+
this.openClose = !this.openClose;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
receiveMessage(event: string) {
|
|
60
|
+
this.message = event;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@HostListener('window:scroll', [])
|
|
64
|
+
onWindowScroll() {
|
|
65
|
+
if (!this.isMobile) return;
|
|
66
|
+
|
|
67
|
+
const currentScrollPosition =
|
|
68
|
+
window.pageYOffset || document.documentElement.scrollTop;
|
|
69
|
+
|
|
70
|
+
// Scroll DOWN - esconde o header
|
|
71
|
+
if (
|
|
72
|
+
currentScrollPosition > this.lastScrollPosition &&
|
|
73
|
+
currentScrollPosition > 50
|
|
74
|
+
) {
|
|
75
|
+
this.isHeaderVisible = false;
|
|
76
|
+
}
|
|
77
|
+
// Scroll UP - mostra o header
|
|
78
|
+
else if (currentScrollPosition < this.lastScrollPosition) {
|
|
79
|
+
this.isHeaderVisible = true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.lastScrollPosition = currentScrollPosition;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { TuduComponentsComponent } from './tudu-components.component';
|
|
4
|
+
|
|
5
|
+
describe('TuduComponentsComponent', () => {
|
|
6
|
+
let component: TuduComponentsComponent;
|
|
7
|
+
let fixture: ComponentFixture<TuduComponentsComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
await TestBed.configureTestingModule({
|
|
11
|
+
declarations: [ TuduComponentsComponent ]
|
|
12
|
+
})
|
|
13
|
+
.compileComponents();
|
|
14
|
+
|
|
15
|
+
fixture = TestBed.createComponent(TuduComponentsComponent);
|
|
16
|
+
component = fixture.componentInstance;
|
|
17
|
+
fixture.detectChanges();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should create', () => {
|
|
21
|
+
expect(component).toBeTruthy();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Component, OnInit } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Component({
|
|
4
|
+
selector: 'lib-tudu-components',
|
|
5
|
+
template: `
|
|
6
|
+
<p>
|
|
7
|
+
tudu-components works!sss
|
|
8
|
+
</p>
|
|
9
|
+
`,
|
|
10
|
+
styles: [
|
|
11
|
+
]
|
|
12
|
+
})
|
|
13
|
+
export class TuduComponentsComponent implements OnInit {
|
|
14
|
+
|
|
15
|
+
constructor() { }
|
|
16
|
+
|
|
17
|
+
ngOnInit(): void {
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { TuduComponentsComponent } from './tudu-components.component';
|
|
3
|
+
import { CommonModule } from '@angular/common';
|
|
4
|
+
import { CardLayoutComponent } from '../lib/components/card-layout/card-layout.component';
|
|
5
|
+
import { NavComponent } from './components/nav/nav.component';
|
|
6
|
+
import { FallbackMessageComponent } from './components/fallback-message/fallback-message.component';
|
|
7
|
+
|
|
8
|
+
@NgModule({
|
|
9
|
+
declarations: [TuduComponentsComponent, CardLayoutComponent, NavComponent, FallbackMessageComponent],
|
|
10
|
+
imports: [CommonModule],
|
|
11
|
+
exports: [TuduComponentsComponent, CardLayoutComponent, NavComponent, FallbackMessageComponent],
|
|
12
|
+
})
|
|
13
|
+
export class TuduComponentsModule {}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { TuduComponentsService } from './tudu-components.service';
|
|
4
|
+
|
|
5
|
+
describe('TuduComponentsService', () => {
|
|
6
|
+
let service: TuduComponentsService;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
TestBed.configureTestingModule({});
|
|
10
|
+
service = TestBed.inject(TuduComponentsService);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should be created', () => {
|
|
14
|
+
expect(service).toBeTruthy();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Public API Surface of tudu-components
|
|
3
|
+
*/
|
|
4
|
+
export * from './lib/tudu-components.component';
|
|
5
|
+
export * from './lib/tudu-components.module'; // ← Se criou este módulo
|
|
6
|
+
|
|
7
|
+
export * from './lib/components/card-layout/card-layout.component';
|
|
8
|
+
export * from './lib/components/nav/nav.component';
|
|
9
|
+
export * from './lib/components/fallback-message/fallback-message.component';
|
|
10
|
+
export * from './lib/tudu-components.service';
|
|
11
|
+
// export * from './lib/card-layout.module'; // ← Ou se usou CardLayoutModule
|
package/src/test.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
|
2
|
+
|
|
3
|
+
import 'zone.js';
|
|
4
|
+
import 'zone.js/testing';
|
|
5
|
+
import { getTestBed } from '@angular/core/testing';
|
|
6
|
+
import {
|
|
7
|
+
BrowserDynamicTestingModule,
|
|
8
|
+
platformBrowserDynamicTesting
|
|
9
|
+
} from '@angular/platform-browser-dynamic/testing';
|
|
10
|
+
|
|
11
|
+
declare const require: {
|
|
12
|
+
context(path: string, deep?: boolean, filter?: RegExp): {
|
|
13
|
+
<T>(id: string): T;
|
|
14
|
+
keys(): string[];
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// First, initialize the Angular testing environment.
|
|
19
|
+
getTestBed().initTestEnvironment(
|
|
20
|
+
BrowserDynamicTestingModule,
|
|
21
|
+
platformBrowserDynamicTesting(),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
// Then we find all the tests.
|
|
25
|
+
const context = require.context('./', true, /\.spec\.ts$/);
|
|
26
|
+
// And load the modules.
|
|
27
|
+
context.keys().forEach(context);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../out-tsc/lib",
|
|
5
|
+
"target": "ES2020",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationMap": true,
|
|
8
|
+
"inlineSources": true,
|
|
9
|
+
"types": [],
|
|
10
|
+
"lib": ["dom", "es2020"]
|
|
11
|
+
},
|
|
12
|
+
"angularCompilerOptions": {
|
|
13
|
+
"skipTemplateCodegen": true,
|
|
14
|
+
"strictMetadataEmit": true,
|
|
15
|
+
"enableResourceInlining": true,
|
|
16
|
+
"compilationMode": "partial"
|
|
17
|
+
},
|
|
18
|
+
"exclude": ["src/test.ts", "**/*.spec.ts"]
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
|
2
|
+
{
|
|
3
|
+
"extends": "../../tsconfig.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"outDir": "../../out-tsc/spec",
|
|
6
|
+
"types": [
|
|
7
|
+
"jasmine"
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src/test.ts"
|
|
12
|
+
],
|
|
13
|
+
"include": [
|
|
14
|
+
"**/*.spec.ts",
|
|
15
|
+
"**/*.d.ts"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { Component, Input } from '@angular/core';
|
|
2
|
-
import * as i0 from "@angular/core";
|
|
3
|
-
import * as i1 from "@angular/router";
|
|
4
|
-
import * as i2 from "@angular/common";
|
|
5
|
-
export class CardLayoutComponent {
|
|
6
|
-
constructor(route) {
|
|
7
|
-
this.route = route;
|
|
8
|
-
this.statusPedido = '';
|
|
9
|
-
this.cardTemplateIndicator = 0; // 1 para serviço, 2 para candidatura
|
|
10
|
-
this.hideHeader = false; // 1 para serviço, 2 para candidatura
|
|
11
|
-
this.tags = ['Residencial', 'Urgente', 'Elétrica'];
|
|
12
|
-
this.statusOptions = [
|
|
13
|
-
{ class: 'status-active', text: 'Ativo', icon: 'fa-circle' },
|
|
14
|
-
{ class: 'status-pending', text: 'Em andamento', icon: 'fa-spinner' },
|
|
15
|
-
{ class: 'status-completed', text: 'Concluído', icon: 'fa-check' },
|
|
16
|
-
{ class: 'status-cancelled', text: 'Cancelado', icon: 'fa-times' },
|
|
17
|
-
];
|
|
18
|
-
this.currentStatus = this.statusOptions[0];
|
|
19
|
-
this.flowIndicator = '1';
|
|
20
|
-
this.route.events.subscribe(() => {
|
|
21
|
-
if (this.route.url.includes('budgets')) {
|
|
22
|
-
this.flowIndicator = 'budgets';
|
|
23
|
-
console.log('asdasdadsasda', this.flowIndicator);
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
ngOnInit() {
|
|
28
|
-
let index = 0;
|
|
29
|
-
this.statusInterval = setInterval(() => {
|
|
30
|
-
index = (index + 1) % this.statusOptions.length;
|
|
31
|
-
this.currentStatus = this.statusOptions[index];
|
|
32
|
-
}, 3000);
|
|
33
|
-
console.log('cardTemplateIndicator', this.cardTemplateIndicator);
|
|
34
|
-
}
|
|
35
|
-
get badgeStyles() {
|
|
36
|
-
const status = this.statusPedido?.toLowerCase();
|
|
37
|
-
switch (status) {
|
|
38
|
-
case 'finalizado':
|
|
39
|
-
return { backgroundColor: '#4caf5020', color: '#4caf50' }; // verde suave
|
|
40
|
-
case 'concluido':
|
|
41
|
-
return { backgroundColor: '#0096881c', color: '#009688' }; // teal
|
|
42
|
-
case 'cancelado':
|
|
43
|
-
return { backgroundColor: '#ff52521c', color: '#ff5252' }; // vermelho claro
|
|
44
|
-
case 'publicado':
|
|
45
|
-
return { backgroundColor: '#0096ff1c', color: '#25a5ff' }; // azul suave
|
|
46
|
-
case 'recusado':
|
|
47
|
-
return { backgroundColor: '#ff52521c', color: '#ff5252' }; // vermelho claro
|
|
48
|
-
case 'em negociacao':
|
|
49
|
-
return { backgroundColor: '#ffab251f', color: '#ff9800' }; // laranja suave
|
|
50
|
-
case 'pendente':
|
|
51
|
-
return { backgroundColor: '#9a1fad1c', color: '#7e57c2' }; // roxo claro
|
|
52
|
-
default:
|
|
53
|
-
return { backgroundColor: '#e0e0e01c', color: '#757575' }; // cinza padrão
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
ngOnDestroy() {
|
|
57
|
-
if (this.statusInterval) {
|
|
58
|
-
clearInterval(this.statusInterval);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
verDetalhes() {
|
|
62
|
-
alert('Abrir detalhes do serviço...');
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
CardLayoutComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CardLayoutComponent, deps: [{ token: i1.Router }], target: i0.ɵɵFactoryTarget.Component });
|
|
66
|
-
CardLayoutComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: CardLayoutComponent, selector: "lib-card-layout", inputs: { statusPedido: "statusPedido", cardTemplateIndicator: "cardTemplateIndicator", hideHeader: "hideHeader" }, ngImport: i0, template: "<div\n class=\"service-card rounded-xl shadow-md overflow-hidden bg-white hover:shadow-lg transition-all duration-300 relative mb-5\"\n>\n <!-- HEADER -->\n <div\n [class.force-show]=\"!hideHeader\"\n class=\"service-card-header flex items-center justify-between p-3 border-b border-gray-200\"\n >\n <div class=\"flex items-center gap-3\">\n <div class=\"icon-style\">\n <ng-content select=\"[service-icon]\"></ng-content>\n </div>\n <div class=\"flex flex-col\">\n <div class=\"flex items-center gap-3\">\n <div class=\"service-title truncate w-full\">\n <ng-content select=\"[service-title]\"></ng-content>\n </div>\n <div class=\"\">\n <ng-content select=\"[details-btn]\"></ng-content>\n </div>\n </div>\n <div\n class=\"whitespace-nowrap overflow-hidden text-ellipsis\"\n style=\"font-size: 12px; color: var(--tab-link)\"\n >\n <ng-content select=\"[service-address]\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n\n <!-- BODY -->\n <div class=\"service-card-body p-4 space-y-3\">\n <div>\n <div\n class=\"flex flex-col items-start gap-3 border-b border-gray-100 pb-3 mb-3\"\n *ngIf=\"cardTemplateIndicator === 1\"\n >\n <div class=\"flex justify-between w-full pb-2\">\n <div class=\"status-badge\" [ngStyle]=\"badgeStyles\">\n <ng-content select=\"[status-badge]\"></ng-content>\n </div>\n\n <div\n class=\"text-xs text-gray-50 font-semibold\"\n style=\"\n background-color: #d3d3d32c;\n color: grey;\n border-radius: 25px;\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 4px 10px;\n \"\n >\n <ng-content select=\"[order-number]\"></ng-content>\n </div>\n </div>\n\n <div class=\"flex flex-wrap gap-2 items-center\">\n <ng-content select=\"[filter-tag]\"></ng-content>\n </div>\n </div>\n\n <div class=\"fw-semibold\" *ngIf=\"statusPedido === 'finalizado'\">\n <ng-content select=\"[conclusion-date]\"></ng-content>\n </div>\n </div>\n <ng-content select=\"[info-row]\"></ng-content>\n\n <ng-content select=\"[description]\"></ng-content>\n </div>\n\n <!-- FOOTER -->\n\n <div\n class=\"service-card-footer flex justify-center items-center p-3 border-t border-gray-100 bg-gray-50 gap-1\"\n >\n <div class=\"col-6\">\n <ng-content select=\"[main-btn]\"></ng-content>\n </div>\n <div\n class=\"fw-semibold col-6\"\n style=\"display: flex; justify-content: flex-end\"\n >\n <ng-content select=\"[price]\"></ng-content>\n </div>\n </div>\n <!-- <div\n \n class=\"flex row justify-between items-center p-3 border-t border-gray-100 bg-gray-50\"\n >\n <div class=\"col-6\">\n <ng-content select=\"[main-btn]\"></ng-content>\n </div>\n <div class=\"col-6\">\n <ng-content select=\"[price]\"></ng-content>\n </div>\n </div> -->\n</div>\n", styles: [".service-card{background:var(--light, #fff);border-radius:1rem;transition:all .3s ease;.service-card-header i {color: var(--primary); font-size: 20px;} .order-badge {background-color: #d3d3d32c; color: grey; border-radius: 25px; padding: 5px;} .template-2-order {margin-top: -6em;} &[data-template=\"1\"] {} &[data-template=\"2\"] {} .status-badge {display: inline-flex; align-items: center; gap: 4px; font-weight: 600; font-size: 12px; padding: 4px 10px; border-radius: 25px; text-transform: capitalize; transition: all .3s ease; i {color: inherit !important;}} .filter-tag {background: var(--tag-bg, #f9fafb); border: 1px solid var(--primary); border-radius: 9999px; padding: .25rem .75rem; color: var(--primary); font-size: 12px;} .details-btn {cursor: pointer;} .price {font-weight: 600; font-size: 1rem; color: var(--primary);} .service-address {font-size: 13px; color: rgb(212,212,212) !important;} .icon-style {display: flex; justify-content: center; align-items: center; background-color: var(--primary) !important; width: 40px; height: 40px; font-size: 12px; font-size: 20px; border-radius: 10px;} .price {font-weight: 600; color: var(--background-color);} .service-title {font-weight: 600; font-size: 1.1rem;} .badge-finalizado {background-color: #e0f7fa; color: #00796b;} .badge-concluido {background-color: #e8f5e9; color: #2e7d32;} .badge-cancelado {background-color: #ffebee; color: #c62828;} .badge-publicado {background-color: #fff3e0; color: #25a5ff;} .badge-default {background-color: #eeeeee; color: #757575;}}.prestador-photo{width:100%;height:100%;object-fit:cover;border-radius:50%}.budget-card-footer button{width:100%;border-radius:8px;font-weight:600;transition:.2s}.status-badge i.notification-pulse{animation:pulse 2s infinite}:host-context(.has-notification) .status-badge i{animation:pulse 2s infinite}.service-card-header{display:none}@media (min-width: 768px){.service-card-header{display:block}}.service-card-header.force-show{display:block}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
|
|
67
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CardLayoutComponent, decorators: [{
|
|
68
|
-
type: Component,
|
|
69
|
-
args: [{ selector: 'lib-card-layout', template: "<div\n class=\"service-card rounded-xl shadow-md overflow-hidden bg-white hover:shadow-lg transition-all duration-300 relative mb-5\"\n>\n <!-- HEADER -->\n <div\n [class.force-show]=\"!hideHeader\"\n class=\"service-card-header flex items-center justify-between p-3 border-b border-gray-200\"\n >\n <div class=\"flex items-center gap-3\">\n <div class=\"icon-style\">\n <ng-content select=\"[service-icon]\"></ng-content>\n </div>\n <div class=\"flex flex-col\">\n <div class=\"flex items-center gap-3\">\n <div class=\"service-title truncate w-full\">\n <ng-content select=\"[service-title]\"></ng-content>\n </div>\n <div class=\"\">\n <ng-content select=\"[details-btn]\"></ng-content>\n </div>\n </div>\n <div\n class=\"whitespace-nowrap overflow-hidden text-ellipsis\"\n style=\"font-size: 12px; color: var(--tab-link)\"\n >\n <ng-content select=\"[service-address]\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n\n <!-- BODY -->\n <div class=\"service-card-body p-4 space-y-3\">\n <div>\n <div\n class=\"flex flex-col items-start gap-3 border-b border-gray-100 pb-3 mb-3\"\n *ngIf=\"cardTemplateIndicator === 1\"\n >\n <div class=\"flex justify-between w-full pb-2\">\n <div class=\"status-badge\" [ngStyle]=\"badgeStyles\">\n <ng-content select=\"[status-badge]\"></ng-content>\n </div>\n\n <div\n class=\"text-xs text-gray-50 font-semibold\"\n style=\"\n background-color: #d3d3d32c;\n color: grey;\n border-radius: 25px;\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 4px 10px;\n \"\n >\n <ng-content select=\"[order-number]\"></ng-content>\n </div>\n </div>\n\n <div class=\"flex flex-wrap gap-2 items-center\">\n <ng-content select=\"[filter-tag]\"></ng-content>\n </div>\n </div>\n\n <div class=\"fw-semibold\" *ngIf=\"statusPedido === 'finalizado'\">\n <ng-content select=\"[conclusion-date]\"></ng-content>\n </div>\n </div>\n <ng-content select=\"[info-row]\"></ng-content>\n\n <ng-content select=\"[description]\"></ng-content>\n </div>\n\n <!-- FOOTER -->\n\n <div\n class=\"service-card-footer flex justify-center items-center p-3 border-t border-gray-100 bg-gray-50 gap-1\"\n >\n <div class=\"col-6\">\n <ng-content select=\"[main-btn]\"></ng-content>\n </div>\n <div\n class=\"fw-semibold col-6\"\n style=\"display: flex; justify-content: flex-end\"\n >\n <ng-content select=\"[price]\"></ng-content>\n </div>\n </div>\n <!-- <div\n \n class=\"flex row justify-between items-center p-3 border-t border-gray-100 bg-gray-50\"\n >\n <div class=\"col-6\">\n <ng-content select=\"[main-btn]\"></ng-content>\n </div>\n <div class=\"col-6\">\n <ng-content select=\"[price]\"></ng-content>\n </div>\n </div> -->\n</div>\n", styles: [".service-card{background:var(--light, #fff);border-radius:1rem;transition:all .3s ease;.service-card-header i {color: var(--primary); font-size: 20px;} .order-badge {background-color: #d3d3d32c; color: grey; border-radius: 25px; padding: 5px;} .template-2-order {margin-top: -6em;} &[data-template=\"1\"] {} &[data-template=\"2\"] {} .status-badge {display: inline-flex; align-items: center; gap: 4px; font-weight: 600; font-size: 12px; padding: 4px 10px; border-radius: 25px; text-transform: capitalize; transition: all .3s ease; i {color: inherit !important;}} .filter-tag {background: var(--tag-bg, #f9fafb); border: 1px solid var(--primary); border-radius: 9999px; padding: .25rem .75rem; color: var(--primary); font-size: 12px;} .details-btn {cursor: pointer;} .price {font-weight: 600; font-size: 1rem; color: var(--primary);} .service-address {font-size: 13px; color: rgb(212,212,212) !important;} .icon-style {display: flex; justify-content: center; align-items: center; background-color: var(--primary) !important; width: 40px; height: 40px; font-size: 12px; font-size: 20px; border-radius: 10px;} .price {font-weight: 600; color: var(--background-color);} .service-title {font-weight: 600; font-size: 1.1rem;} .badge-finalizado {background-color: #e0f7fa; color: #00796b;} .badge-concluido {background-color: #e8f5e9; color: #2e7d32;} .badge-cancelado {background-color: #ffebee; color: #c62828;} .badge-publicado {background-color: #fff3e0; color: #25a5ff;} .badge-default {background-color: #eeeeee; color: #757575;}}.prestador-photo{width:100%;height:100%;object-fit:cover;border-radius:50%}.budget-card-footer button{width:100%;border-radius:8px;font-weight:600;transition:.2s}.status-badge i.notification-pulse{animation:pulse 2s infinite}:host-context(.has-notification) .status-badge i{animation:pulse 2s infinite}.service-card-header{display:none}@media (min-width: 768px){.service-card-header{display:block}}.service-card-header.force-show{display:block}\n"] }]
|
|
70
|
-
}], ctorParameters: function () { return [{ type: i1.Router }]; }, propDecorators: { statusPedido: [{
|
|
71
|
-
type: Input
|
|
72
|
-
}], cardTemplateIndicator: [{
|
|
73
|
-
type: Input
|
|
74
|
-
}], hideHeader: [{
|
|
75
|
-
type: Input
|
|
76
|
-
}] } });
|
|
77
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FyZC1sYXlvdXQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdHVkdS1jb21wb25lbnRzL3NyYy9saWIvY29tcG9uZW50cy9jYXJkLWxheW91dC9jYXJkLWxheW91dC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy90dWR1LWNvbXBvbmVudHMvc3JjL2xpYi9jb21wb25lbnRzL2NhcmQtbGF5b3V0L2NhcmQtbGF5b3V0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFVLE1BQU0sZUFBZSxDQUFDOzs7O0FBUXpELE1BQU0sT0FBTyxtQkFBbUI7SUFrQjlCLFlBQW9CLEtBQWE7UUFBYixVQUFLLEdBQUwsS0FBSyxDQUFRO1FBakJ4QixpQkFBWSxHQUFXLEVBQUUsQ0FBQztRQUMxQiwwQkFBcUIsR0FBVyxDQUFDLENBQUMsQ0FBQyxxQ0FBcUM7UUFDeEUsZUFBVSxHQUFZLEtBQUssQ0FBQyxDQUFDLHFDQUFxQztRQUUzRSxTQUFJLEdBQWEsQ0FBQyxhQUFhLEVBQUUsU0FBUyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBRXhELGtCQUFhLEdBQUc7WUFDZCxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFO1lBQzVELEVBQUUsS0FBSyxFQUFFLGdCQUFnQixFQUFFLElBQUksRUFBRSxjQUFjLEVBQUUsSUFBSSxFQUFFLFlBQVksRUFBRTtZQUNyRSxFQUFFLEtBQUssRUFBRSxrQkFBa0IsRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUU7WUFDbEUsRUFBRSxLQUFLLEVBQUUsa0JBQWtCLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFO1NBQ25FLENBQUM7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b25lbnQsIElucHV0LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2xpYi1jYXJkLWxheW91dCcsXG4gIHRlbXBsYXRlVXJsOiAnLi9jYXJkLWxheW91dC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2NhcmQtbGF5b3V0LmNvbXBvbmVudC5jc3MnXSxcbn0pXG5leHBvcnQgY2xhc3MgQ2FyZExheW91dENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIEBJbnB1dCgpIHN0YXR1c1BlZGlkbzogc3RyaW5nID0gJyc7XG4gIEBJbnB1dCgpIGNhcmRUZW1wbGF0ZUluZGljYXRvcjogbnVtYmVyID0gMDsgLy8gMSBwYXJhIHNlcnZpw6dvLCAyIHBhcmEgY2FuZGlkYXR1cmFcbiAgQElucHV0KCkgaGlkZUhlYWRlcjogYm9vbGVhbiA9IGZhbHNlOyAvLyAxIHBhcmEgc2VydmnDp28sIDIgcGFyYSBjYW5kaWRhdHVyYVxuXG4gIHRhZ3M6IHN0cmluZ1tdID0gWydSZXNpZGVuY2lhbCcsICdVcmdlbnRlJywgJ0Vsw6l0cmljYSddO1xuXG4gIHN0YXR1c09wdGlvbnMgPSBbXG4gICAgeyBjbGFzczogJ3N0YXR1cy1hY3RpdmUnLCB0ZXh0OiAnQXRpdm8nLCBpY29uOiAnZmEtY2lyY2xlJyB9LFxuICAgIHsgY2xhc3M6ICdzdGF0dXMtcGVuZGluZycsIHRleHQ6ICdFbSBhbmRhbWVudG8nLCBpY29uOiAnZmEtc3Bpbm5lcicgfSxcbiAgICB7IGNsYXNzOiAnc3RhdHVzLWNvbXBsZXRlZCcsIHRleHQ6ICdDb25jbHXDrWRvJywgaWNvbjogJ2ZhLWNoZWNrJyB9LFxuICAgIHsgY2xhc3M6ICdzdGF0dXMtY2FuY2VsbGVkJywgdGV4dDogJ0NhbmNlbGFkbycsIGljb246ICdmYS10aW1lcycgfSxcbiAgXTtcblxuICBjdXJyZW50U3RhdHVzID0gdGhpcy5zdGF0dXNPcHRpb25zWzBdO1xuICBwcml2YXRlIHN0YXR1c0ludGVydmFsOiBhbnk7XG4gIGZsb3dJbmRpY2F0b3I6IHN0cmluZyA9ICcxJztcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJvdXRlOiBSb3V0ZXIpIHtcbiAgICB0aGlzLnJvdXRlLmV2ZW50cy5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgaWYgKHRoaXMucm91dGUudXJsLmluY2x1ZGVzKCdidWRnZXRzJykpIHtcbiAgICAgICAgdGhpcy5mbG93SW5kaWNhdG9yID0gJ2J1ZGdldHMnO1xuICAgICAgICBjb25zb2xlLmxvZygnYXNkYXNkYWRzYXNkYScsIHRoaXMuZmxvd0luZGljYXRvcik7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBuZ09uSW5pdCgpIHtcbiAgICBsZXQgaW5kZXggPSAwO1xuICAgIHRoaXMuc3RhdHVzSW50ZXJ2YWwgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICBpbmRleCA9IChpbmRleCArIDEpICUgdGhpcy5zdGF0dXNPcHRpb25zLmxlbmd0aDtcbiAgICAgIHRoaXMuY3VycmVudFN0YXR1cyA9IHRoaXMuc3RhdHVzT3B0aW9uc1tpbmRleF07XG4gICAgfSwgMzAwMCk7XG5cbiAgICBjb25zb2xlLmxvZygnY2FyZFRlbXBsYXRlSW5kaWNhdG9yJywgdGhpcy5jYXJkVGVtcGxhdGVJbmRpY2F0b3IpO1xuICB9XG5cbiAgZ2V0IGJhZGdlU3R5bGVzKCk6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH0ge1xuICAgIGNvbnN0IHN0YXR1cyA9IHRoaXMuc3RhdHVzUGVkaWRvPy50b0xvd2VyQ2FzZSgpO1xuXG4gICAgc3dpdGNoIChzdGF0dXMpIHtcbiAgICAgIGNhc2UgJ2ZpbmFsaXphZG8nOlxuICAgICAgICByZXR1cm4geyBiYWNrZ3JvdW5kQ29sb3I6ICcjNGNhZjUwMjAnLCBjb2xvcjogJyM0Y2FmNTAnIH07IC8vIHZlcmRlIHN1YXZlXG4gICAgICBjYXNlICdjb25jbHVpZG8nOlxuICAgICAgICByZXR1cm4geyBiYWNrZ3JvdW5kQ29sb3I6ICcjMDA5Njg4MWMnLCBjb2xvcjogJyMwMDk2ODgnIH07IC8vIHRlYWxcbiAgICAgIGNhc2UgJ2NhbmNlbGFkbyc6XG4gICAgICAgIHJldHVybiB7IGJhY2tncm91bmRDb2xvcjogJyNmZjUyNTIxYycsIGNvbG9yOiAnI2ZmNTI1MicgfTsgLy8gdmVybWVsaG8gY2xhcm9cbiAgICAgIGNhc2UgJ3B1YmxpY2Fkbyc6XG4gICAgICAgIHJldHVybiB7IGJhY2tncm91bmRDb2xvcjogJyMwMDk2ZmYxYycsIGNvbG9yOiAnIzI1YTVmZicgfTsgLy8gYXp1bCBzdWF2ZVxuICAgICAgY2FzZSAncmVjdXNhZG8nOlxuICAgICAgICByZXR1cm4geyBiYWNrZ3JvdW5kQ29sb3I6ICcjZmY1MjUyMWMnLCBjb2xvcjogJyNmZjUyNTInIH07IC8vIHZlcm1lbGhvIGNsYXJvXG4gICAgICBjYXNlICdlbSBuZWdvY2lhY2FvJzpcbiAgICAgICAgcmV0dXJuIHsgYmFja2dyb3VuZENvbG9yOiAnI2ZmYWIyNTFmJywgY29sb3I6ICcjZmY5ODAwJyB9OyAvLyBsYXJhbmphIHN1YXZlXG4gICAgICBjYXNlICdwZW5kZW50ZSc6XG4gICAgICAgIHJldHVybiB7IGJhY2tncm91bmRDb2xvcjogJyM5YTFmYWQxYycsIGNvbG9yOiAnIzdlNTdjMicgfTsgLy8gcm94byBjbGFyb1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIHsgYmFja2dyb3VuZENvbG9yOiAnI2UwZTBlMDFjJywgY29sb3I6ICcjNzU3NTc1JyB9OyAvLyBjaW56YSBwYWRyw6NvXG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgaWYgKHRoaXMuc3RhdHVzSW50ZXJ2YWwpIHtcbiAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5zdGF0dXNJbnRlcnZhbCk7XG4gICAgfVxuICB9XG5cbiAgdmVyRGV0YWxoZXMoKSB7XG4gICAgYWxlcnQoJ0FicmlyIGRldGFsaGVzIGRvIHNlcnZpw6dvLi4uJyk7XG4gIH1cbn1cbiIsIjxkaXZcbiAgY2xhc3M9XCJzZXJ2aWNlLWNhcmQgcm91bmRlZC14bCBzaGFkb3ctbWQgb3ZlcmZsb3ctaGlkZGVuIGJnLXdoaXRlIGhvdmVyOnNoYWRvdy1sZyB0cmFuc2l0aW9uLWFsbCBkdXJhdGlvbi0zMDAgcmVsYXRpdmUgbWItNVwiXG4+XG4gIDwhLS0gSEVBREVSIC0tPlxuICA8ZGl2XG4gICAgW2NsYXNzLmZvcmNlLXNob3ddPVwiIWhpZGVIZWFkZXJcIlxuICAgIGNsYXNzPVwic2VydmljZS1jYXJkLWhlYWRlciBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWJldHdlZW4gcC0zIGJvcmRlci1iIGJvcmRlci1ncmF5LTIwMFwiXG4gID5cbiAgICA8ZGl2IGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTNcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJpY29uLXN0eWxlXCI+XG4gICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIltzZXJ2aWNlLWljb25dXCI+PC9uZy1jb250ZW50PlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwiZmxleCBmbGV4LWNvbFwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTNcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwic2VydmljZS10aXRsZSB0cnVuY2F0ZSB3LWZ1bGxcIj5cbiAgICAgICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIltzZXJ2aWNlLXRpdGxlXVwiPjwvbmctY29udGVudD5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiXCI+XG4gICAgICAgICAgICA8bmctY29udGVudCBzZWxlY3Q9XCJbZGV0YWlscy1idG5dXCI+PC9uZy1jb250ZW50PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdlxuICAgICAgICAgIGNsYXNzPVwid2hpdGVzcGFjZS1ub3dyYXAgb3ZlcmZsb3ctaGlkZGVuIHRleHQtZWxsaXBzaXNcIlxuICAgICAgICAgIHN0eWxlPVwiZm9udC1zaXplOiAxMnB4OyBjb2xvcjogdmFyKC0tdGFiLWxpbmspXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIltzZXJ2aWNlLWFkZHJlc3NdXCI+PC9uZy1jb250ZW50PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cblxuICA8IS0tIEJPRFkgLS0+XG4gIDxkaXYgY2xhc3M9XCJzZXJ2aWNlLWNhcmQtYm9keSBwLTQgc3BhY2UteS0zXCI+XG4gICAgPGRpdj5cbiAgICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJmbGV4IGZsZXgtY29sIGl0ZW1zLXN0YXJ0IGdhcC0zIGJvcmRlci1iIGJvcmRlci1ncmF5LTEwMCBwYi0zIG1iLTNcIlxuICAgICAgICAqbmdJZj1cImNhcmRUZW1wbGF0ZUluZGljYXRvciA9PT0gMVwiXG4gICAgICA+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJmbGV4IGp1c3RpZnktYmV0d2VlbiB3LWZ1bGwgcGItMlwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0dXMtYmFkZ2VcIiBbbmdTdHlsZV09XCJiYWRnZVN0eWxlc1wiPlxuICAgICAgICAgICAgPG5nLWNvbnRlbnQgc2VsZWN0PVwiW3N0YXR1cy1iYWRnZV1cIj48L25nLWNvbnRlbnQ+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICBjbGFzcz1cInRleHQteHMgdGV4dC1ncmF5LTUwIGZvbnQtc2VtaWJvbGRcIlxuICAgICAgICAgICAgc3R5bGU9XCJcbiAgICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogI2QzZDNkMzJjO1xuICAgICAgICAgICAgICBjb2xvcjogZ3JleTtcbiAgICAgICAgICAgICAgYm9yZGVyLXJhZGl1czogMjVweDtcbiAgICAgICAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAgICAgICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gICAgICAgICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICAgICAgICAgIHBhZGRpbmc6IDRweCAxMHB4O1xuICAgICAgICAgICAgXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8bmctY29udGVudCBzZWxlY3Q9XCJbb3JkZXItbnVtYmVyXVwiPjwvbmctY29udGVudD5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cImZsZXggZmxleC13cmFwIGdhcC0yIGl0ZW1zLWNlbnRlclwiPlxuICAgICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIltmaWx0ZXItdGFnXVwiPjwvbmctY29udGVudD5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPGRpdiBjbGFzcz1cImZ3LXNlbWlib2xkXCIgKm5nSWY9XCJzdGF0dXNQZWRpZG8gPT09ICdmaW5hbGl6YWRvJ1wiPlxuICAgICAgICA8bmctY29udGVudCBzZWxlY3Q9XCJbY29uY2x1c2lvbi1kYXRlXVwiPjwvbmctY29udGVudD5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIltpbmZvLXJvd11cIj48L25nLWNvbnRlbnQ+XG5cbiAgICA8bmctY29udGVudCBzZWxlY3Q9XCJbZGVzY3JpcHRpb25dXCI+PC9uZy1jb250ZW50PlxuICA8L2Rpdj5cblxuICA8IS0tIEZPT1RFUiAtLT5cblxuICA8ZGl2XG4gICAgY2xhc3M9XCJzZXJ2aWNlLWNhcmQtZm9vdGVyIGZsZXgganVzdGlmeS1jZW50ZXIgaXRlbXMtY2VudGVyIHAtMyBib3JkZXItdCBib3JkZXItZ3JheS0xMDAgYmctZ3JheS01MCBnYXAtMVwiXG4gID5cbiAgICA8ZGl2IGNsYXNzPVwiY29sLTZcIj5cbiAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIlttYWluLWJ0bl1cIj48L25nLWNvbnRlbnQ+XG4gICAgPC9kaXY+XG4gICAgPGRpdlxuICAgICAgY2xhc3M9XCJmdy1zZW1pYm9sZCBjb2wtNlwiXG4gICAgICBzdHlsZT1cImRpc3BsYXk6IGZsZXg7IGp1c3RpZnktY29udGVudDogZmxleC1lbmRcIlxuICAgID5cbiAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIltwcmljZV1cIj48L25nLWNvbnRlbnQ+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuICA8IS0tIDxkaXZcbiAgICBcbiAgICBjbGFzcz1cImZsZXggcm93IGp1c3RpZnktYmV0d2VlbiBpdGVtcy1jZW50ZXIgcC0zIGJvcmRlci10IGJvcmRlci1ncmF5LTEwMCBiZy1ncmF5LTUwXCJcbiAgPlxuICAgIDxkaXYgY2xhc3M9XCJjb2wtNlwiPlxuICAgICAgPG5nLWNvbnRlbnQgc2VsZWN0PVwiW21haW4tYnRuXVwiPjwvbmctY29udGVudD5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwiY29sLTZcIj5cbiAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIltwcmljZV1cIj48L25nLWNvbnRlbnQ+XG4gICAgPC9kaXY+XG4gIDwvZGl2PiAtLT5cbjwvZGl2PlxuIl19
|