tudu-components 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/karma.conf.js +44 -0
  2. package/ng-package.json +7 -0
  3. package/package.json +3 -22
  4. package/src/lib/components/card-layout/card-layout.component.css +166 -0
  5. package/src/lib/components/card-layout/card-layout.component.html +100 -0
  6. package/src/lib/components/card-layout/card-layout.component.spec.ts +23 -0
  7. package/src/lib/components/card-layout/card-layout.component.ts +78 -0
  8. package/src/lib/components/fallback-message/fallback-message.component.css +36 -0
  9. package/src/lib/components/fallback-message/fallback-message.component.html +95 -0
  10. package/src/lib/components/fallback-message/fallback-message.component.spec.ts +23 -0
  11. package/src/lib/components/fallback-message/fallback-message.component.ts +140 -0
  12. package/src/lib/components/nav/nav.component.css +40 -0
  13. package/src/lib/components/nav/nav.component.html +40 -0
  14. package/src/lib/components/nav/nav.component.spec.ts +23 -0
  15. package/src/lib/components/nav/nav.component.ts +84 -0
  16. package/src/lib/tudu-components.component.spec.ts +23 -0
  17. package/src/lib/tudu-components.component.ts +20 -0
  18. package/src/lib/tudu-components.module.ts +13 -0
  19. package/src/lib/tudu-components.service.spec.ts +16 -0
  20. package/src/lib/tudu-components.service.ts +9 -0
  21. package/src/public-api.ts +11 -0
  22. package/src/test.ts +27 -0
  23. package/tsconfig.lib.json +19 -0
  24. package/tsconfig.lib.prod.json +10 -0
  25. package/tsconfig.spec.json +17 -0
  26. package/esm2020/lib/components/card-layout/card-layout.component.mjs +0 -77
  27. package/esm2020/lib/components/nav/nav.component.mjs +0 -74
  28. package/esm2020/lib/tudu-components.component.mjs +0 -22
  29. package/esm2020/lib/tudu-components.module.mjs +0 -20
  30. package/esm2020/lib/tudu-components.service.mjs +0 -14
  31. package/esm2020/public-api.mjs +0 -10
  32. package/esm2020/tudu-components.mjs +0 -5
  33. package/fesm2015/tudu-components.mjs +0 -207
  34. package/fesm2015/tudu-components.mjs.map +0 -1
  35. package/fesm2020/tudu-components.mjs +0 -206
  36. package/fesm2020/tudu-components.mjs.map +0 -1
  37. package/index.d.ts +0 -5
  38. package/lib/components/card-layout/card-layout.component.d.ts +0 -31
  39. package/lib/components/nav/nav.component.d.ts +0 -25
  40. package/lib/tudu-components.component.d.ts +0 -8
  41. package/lib/tudu-components.module.d.ts +0 -10
  42. package/lib/tudu-components.service.d.ts +0 -6
  43. package/public-api.d.ts +0 -5
package/karma.conf.js ADDED
@@ -0,0 +1,44 @@
1
+ // Karma configuration file, see link for more information
2
+ // https://karma-runner.github.io/1.0/config/configuration-file.html
3
+
4
+ module.exports = function (config) {
5
+ config.set({
6
+ basePath: '',
7
+ frameworks: ['jasmine', '@angular-devkit/build-angular'],
8
+ plugins: [
9
+ require('karma-jasmine'),
10
+ require('karma-chrome-launcher'),
11
+ require('karma-jasmine-html-reporter'),
12
+ require('karma-coverage'),
13
+ require('@angular-devkit/build-angular/plugins/karma')
14
+ ],
15
+ client: {
16
+ jasmine: {
17
+ // you can add configuration options for Jasmine here
18
+ // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
19
+ // for example, you can disable the random execution with `random: false`
20
+ // or set a specific seed with `seed: 4321`
21
+ },
22
+ clearContext: false // leave Jasmine Spec Runner output visible in browser
23
+ },
24
+ jasmineHtmlReporter: {
25
+ suppressAll: true // removes the duplicated traces
26
+ },
27
+ coverageReporter: {
28
+ dir: require('path').join(__dirname, '../../coverage/tudu-components'),
29
+ subdir: '.',
30
+ reporters: [
31
+ { type: 'html' },
32
+ { type: 'text-summary' }
33
+ ]
34
+ },
35
+ reporters: ['progress', 'kjhtml'],
36
+ port: 9876,
37
+ colors: true,
38
+ logLevel: config.LOG_INFO,
39
+ autoWatch: true,
40
+ browsers: ['Chrome'],
41
+ singleRun: false,
42
+ restartOnFileChange: true
43
+ });
44
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3
+ "dest": "../../dist/tudu-components",
4
+ "lib": {
5
+ "entryFile": "src/public-api.ts"
6
+ }
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tudu-components",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^17.3.0",
6
6
  "@angular/core": "^17.3.0"
@@ -8,24 +8,5 @@
8
8
  "dependencies": {
9
9
  "tslib": "^2.3.0"
10
10
  },
11
- "sideEffects": false,
12
- "module": "fesm2015/tudu-components.mjs",
13
- "es2020": "fesm2020/tudu-components.mjs",
14
- "esm2020": "esm2020/tudu-components.mjs",
15
- "fesm2020": "fesm2020/tudu-components.mjs",
16
- "fesm2015": "fesm2015/tudu-components.mjs",
17
- "typings": "index.d.ts",
18
- "exports": {
19
- "./package.json": {
20
- "default": "./package.json"
21
- },
22
- ".": {
23
- "types": "./index.d.ts",
24
- "esm2020": "./esm2020/tudu-components.mjs",
25
- "es2020": "./fesm2020/tudu-components.mjs",
26
- "es2015": "./fesm2015/tudu-components.mjs",
27
- "node": "./fesm2015/tudu-components.mjs",
28
- "default": "./fesm2020/tudu-components.mjs"
29
- }
30
- }
31
- }
11
+ "sideEffects": false
12
+ }
@@ -0,0 +1,166 @@
1
+ .service-card {
2
+ background: var(--light, #fff);
3
+ border-radius: 1rem;
4
+ transition: all 0.3s ease;
5
+ .service-card-header i {
6
+ color: var(--primary);
7
+ font-size: 20px;
8
+ }
9
+
10
+ .order-badge {
11
+ background-color: #d3d3d32c;
12
+ color: grey;
13
+ border-radius: 25px;
14
+ padding: 5px;
15
+ }
16
+
17
+ .template-2-order {
18
+ margin-top: -6em;
19
+ }
20
+
21
+ /* Estilos específicos para cada template */
22
+ &[data-template="1"] {
23
+ /* Estilos específicos do template 1 */
24
+ }
25
+
26
+ &[data-template="2"] {
27
+ /* Estilos específicos do template 2 */
28
+ }
29
+
30
+ .status-badge {
31
+ display: inline-flex;
32
+ align-items: center;
33
+ gap: 4px;
34
+ font-weight: 600;
35
+ font-size: 12px;
36
+ padding: 4px 10px;
37
+ border-radius: 25px;
38
+ text-transform: capitalize;
39
+ transition: all 0.3s ease;
40
+
41
+ /* Faz o ícone herdar a cor da badge */
42
+ i {
43
+ color: inherit !important;
44
+ }
45
+ }
46
+
47
+ .filter-tag {
48
+ background: var(--tag-bg, #f9fafb);
49
+ border: 1px solid var(--primary);
50
+ border-radius: 9999px;
51
+ padding: 0.25rem 0.75rem;
52
+ color: var(--primary);
53
+ font-size: 12px;
54
+ }
55
+ /* .details-btn {
56
+ font-size: 17px;
57
+ font-weight: 600;
58
+ transition: background-color 0.8s ease-in-out;
59
+ background: var(--primary);
60
+ color: white;
61
+ padding: 8px 15px;
62
+ border: none;
63
+ border-radius: 10px;
64
+ cursor: pointer;
65
+ }
66
+ .details-btn:hover {
67
+ background: var(--primary-dark);
68
+ } */
69
+
70
+ .details-btn {
71
+ cursor: pointer;
72
+ }
73
+ .price {
74
+ font-weight: 600;
75
+ font-size: 1rem;
76
+ color: var(--primary);
77
+ }
78
+
79
+ .service-address {
80
+ font-size: 13px;
81
+ color: rgb(212, 212, 212) !important;
82
+ }
83
+
84
+ .icon-style {
85
+ display: flex;
86
+ justify-content: center;
87
+ align-items: center;
88
+ background-color: var(--primary) !important;
89
+ width: 40px;
90
+ height: 40px;
91
+ font-size: 12px;
92
+ font-size: 20px;
93
+ border-radius: 10px;
94
+ }
95
+ .price {
96
+ font-weight: 600;
97
+ color: var(--background-color);
98
+ }
99
+
100
+ .service-title {
101
+ font-weight: 600;
102
+
103
+ font-size: 1.1rem;
104
+ }
105
+
106
+ .badge-finalizado {
107
+ background-color: #e0f7fa;
108
+ color: #00796b;
109
+ }
110
+
111
+ .badge-concluido {
112
+ background-color: #e8f5e9;
113
+ color: #2e7d32;
114
+ }
115
+
116
+ .badge-cancelado {
117
+ background-color: #ffebee;
118
+ color: #c62828;
119
+ }
120
+
121
+ .badge-publicado {
122
+ background-color: #fff3e0;
123
+ color: #25a5ff;
124
+ }
125
+
126
+ .badge-default {
127
+ background-color: #eeeeee;
128
+ color: #757575;
129
+ }
130
+ }
131
+
132
+ .prestador-photo {
133
+ width: 100%;
134
+ height: 100%;
135
+ object-fit: cover;
136
+ border-radius: 50%;
137
+ }
138
+
139
+ .budget-card-footer button {
140
+ width: 100%;
141
+ border-radius: 8px;
142
+ font-weight: 600;
143
+ transition: 0.2s;
144
+ }
145
+
146
+ .status-badge i.notification-pulse {
147
+ animation: pulse 2s infinite;
148
+ }
149
+
150
+ :host-context(.has-notification) .status-badge i {
151
+ animation: pulse 2s infinite;
152
+ }
153
+
154
+ .service-card-header {
155
+ display: none; /* Escondido por padrão */
156
+ }
157
+
158
+ @media (min-width: 768px) {
159
+ .service-card-header {
160
+ display: block; /* Mostra apenas em telas grandes */
161
+ }
162
+ }
163
+
164
+ .service-card-header.force-show {
165
+ display: block; /* Força mostrar mesmo em mobile */
166
+ }
@@ -0,0 +1,100 @@
1
+ <div
2
+ class="service-card rounded-xl shadow-md overflow-hidden bg-white hover:shadow-lg transition-all duration-300 relative mb-5"
3
+ >
4
+ <!-- HEADER -->
5
+ <div
6
+ [class.force-show]="!hideHeader"
7
+ class="service-card-header flex items-center justify-between p-3 border-b border-gray-200"
8
+ >
9
+ <div class="flex items-center gap-3">
10
+ <div class="icon-style">
11
+ <ng-content select="[service-icon]"></ng-content>
12
+ </div>
13
+ <div class="flex flex-col">
14
+ <div class="flex items-center gap-3">
15
+ <div class="service-title truncate w-full">
16
+ <ng-content select="[service-title]"></ng-content>
17
+ </div>
18
+ <div class="">
19
+ <ng-content select="[details-btn]"></ng-content>
20
+ </div>
21
+ </div>
22
+ <div
23
+ class="whitespace-nowrap overflow-hidden text-ellipsis"
24
+ style="font-size: 12px; color: var(--tab-link)"
25
+ >
26
+ <ng-content select="[service-address]"></ng-content>
27
+ </div>
28
+ </div>
29
+ </div>
30
+ </div>
31
+
32
+ <!-- BODY -->
33
+ <div class="service-card-body p-4 space-y-3">
34
+ <div>
35
+ <div
36
+ class="flex flex-col items-start gap-3 border-b border-gray-100 pb-3 mb-3"
37
+ *ngIf="cardTemplateIndicator === 1"
38
+ >
39
+ <div class="flex justify-between w-full pb-2">
40
+ <div class="status-badge" [ngStyle]="badgeStyles">
41
+ <ng-content select="[status-badge]"></ng-content>
42
+ </div>
43
+
44
+ <div
45
+ class="text-xs text-gray-50 font-semibold"
46
+ style="
47
+ background-color: #d3d3d32c;
48
+ color: grey;
49
+ border-radius: 25px;
50
+ display: flex;
51
+ justify-content: center;
52
+ align-items: center;
53
+ padding: 4px 10px;
54
+ "
55
+ >
56
+ <ng-content select="[order-number]"></ng-content>
57
+ </div>
58
+ </div>
59
+
60
+ <div class="flex flex-wrap gap-2 items-center">
61
+ <ng-content select="[filter-tag]"></ng-content>
62
+ </div>
63
+ </div>
64
+
65
+ <div class="fw-semibold" *ngIf="statusPedido === 'finalizado'">
66
+ <ng-content select="[conclusion-date]"></ng-content>
67
+ </div>
68
+ </div>
69
+ <ng-content select="[info-row]"></ng-content>
70
+
71
+ <ng-content select="[description]"></ng-content>
72
+ </div>
73
+
74
+ <!-- FOOTER -->
75
+
76
+ <div
77
+ class="service-card-footer flex justify-center items-center p-3 border-t border-gray-100 bg-gray-50 gap-1"
78
+ >
79
+ <div class="col-6">
80
+ <ng-content select="[main-btn]"></ng-content>
81
+ </div>
82
+ <div
83
+ class="fw-semibold col-6"
84
+ style="display: flex; justify-content: flex-end"
85
+ >
86
+ <ng-content select="[price]"></ng-content>
87
+ </div>
88
+ </div>
89
+ <!-- <div
90
+
91
+ class="flex row justify-between items-center p-3 border-t border-gray-100 bg-gray-50"
92
+ >
93
+ <div class="col-6">
94
+ <ng-content select="[main-btn]"></ng-content>
95
+ </div>
96
+ <div class="col-6">
97
+ <ng-content select="[price]"></ng-content>
98
+ </div>
99
+ </div> -->
100
+ </div>
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { CardLayoutComponent } from './card-layout.component';
4
+
5
+ describe('CardLayoutComponent', () => {
6
+ let component: CardLayoutComponent;
7
+ let fixture: ComponentFixture<CardLayoutComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ declarations: [ CardLayoutComponent ]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(CardLayoutComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,78 @@
1
+ import { Component, Input, OnInit } from '@angular/core';
2
+ import { Router } from '@angular/router';
3
+
4
+ @Component({
5
+ selector: 'lib-card-layout',
6
+ templateUrl: './card-layout.component.html',
7
+ styleUrls: ['./card-layout.component.css'],
8
+ })
9
+ export class CardLayoutComponent implements OnInit {
10
+ @Input() statusPedido: string = '';
11
+ @Input() cardTemplateIndicator: number = 0; // 1 para serviço, 2 para candidatura
12
+ @Input() hideHeader: boolean = false; // 1 para serviço, 2 para candidatura
13
+
14
+ tags: string[] = ['Residencial', 'Urgente', 'Elétrica'];
15
+
16
+ statusOptions = [
17
+ { class: 'status-active', text: 'Ativo', icon: 'fa-circle' },
18
+ { class: 'status-pending', text: 'Em andamento', icon: 'fa-spinner' },
19
+ { class: 'status-completed', text: 'Concluído', icon: 'fa-check' },
20
+ { class: 'status-cancelled', text: 'Cancelado', icon: 'fa-times' },
21
+ ];
22
+
23
+ currentStatus = this.statusOptions[0];
24
+ private statusInterval: any;
25
+ flowIndicator: string = '1';
26
+
27
+ constructor(private route: Router) {
28
+ this.route.events.subscribe(() => {
29
+ if (this.route.url.includes('budgets')) {
30
+ this.flowIndicator = 'budgets';
31
+ console.log('asdasdadsasda', this.flowIndicator);
32
+ }
33
+ });
34
+ }
35
+
36
+ ngOnInit() {
37
+ let index = 0;
38
+ this.statusInterval = setInterval(() => {
39
+ index = (index + 1) % this.statusOptions.length;
40
+ this.currentStatus = this.statusOptions[index];
41
+ }, 3000);
42
+
43
+ console.log('cardTemplateIndicator', this.cardTemplateIndicator);
44
+ }
45
+
46
+ get badgeStyles(): { [key: string]: string } {
47
+ const status = this.statusPedido?.toLowerCase();
48
+
49
+ switch (status) {
50
+ case 'finalizado':
51
+ return { backgroundColor: '#4caf5020', color: '#4caf50' }; // verde suave
52
+ case 'concluido':
53
+ return { backgroundColor: '#0096881c', color: '#009688' }; // teal
54
+ case 'cancelado':
55
+ return { backgroundColor: '#ff52521c', color: '#ff5252' }; // vermelho claro
56
+ case 'publicado':
57
+ return { backgroundColor: '#0096ff1c', color: '#25a5ff' }; // azul suave
58
+ case 'recusado':
59
+ return { backgroundColor: '#ff52521c', color: '#ff5252' }; // vermelho claro
60
+ case 'em negociacao':
61
+ return { backgroundColor: '#ffab251f', color: '#ff9800' }; // laranja suave
62
+ case 'pendente':
63
+ return { backgroundColor: '#9a1fad1c', color: '#7e57c2' }; // roxo claro
64
+ default:
65
+ return { backgroundColor: '#e0e0e01c', color: '#757575' }; // cinza padrão
66
+ }
67
+ }
68
+
69
+ ngOnDestroy() {
70
+ if (this.statusInterval) {
71
+ clearInterval(this.statusInterval);
72
+ }
73
+ }
74
+
75
+ verDetalhes() {
76
+ alert('Abrir detalhes do serviço...');
77
+ }
78
+ }
@@ -0,0 +1,36 @@
1
+ .empty-state-card {
2
+ animation: fadeInUp 0.5s ease-out;
3
+ }
4
+
5
+ @keyframes fadeInUp {
6
+ from {
7
+ opacity: 0;
8
+ transform: translateY(20px);
9
+ }
10
+ to {
11
+ opacity: 1;
12
+ transform: translateY(0);
13
+ }
14
+ }
15
+
16
+ /* Animação para o ícone */
17
+ .empty-state-icon {
18
+ animation: bounceIn 0.6s ease-out;
19
+ }
20
+
21
+ @keyframes bounceIn {
22
+ 0% {
23
+ opacity: 0;
24
+ transform: scale(0.3);
25
+ }
26
+ 50% {
27
+ opacity: 1;
28
+ transform: scale(1.05);
29
+ }
30
+ 70% {
31
+ transform: scale(0.9);
32
+ }
33
+ 100% {
34
+ transform: scale(1);
35
+ }
36
+ }
@@ -0,0 +1,95 @@
1
+ <div *ngIf="shouldShowEmptyState()" class="empty-state-container">
2
+ <div
3
+ class="empty-state-card max-w-md mx-auto bg-white shadow-xl rounded-3xl p-8 border border-gray-100"
4
+ >
5
+ <!-- Ícone dinâmico -->
6
+ <div class="empty-state-icon mb-6 flex justify-center">
7
+ <div class="relative">
8
+ <!-- Ícone principal -->
9
+ <div [class]="emptyStateConfig.iconColor">
10
+ <div class="text-6xl">
11
+ {{ emptyStateConfig.icon }}
12
+ </div>
13
+ </div>
14
+
15
+ <!-- Background decorativo -->
16
+ <div class="absolute -z-10 inset-0 flex items-center justify-center">
17
+ <div
18
+ [class]="emptyStateConfig.bgColor"
19
+ class="w-32 h-32 rounded-full opacity-50"
20
+ ></div>
21
+ </div>
22
+ </div>
23
+ </div>
24
+
25
+ <!-- Conteúdo da mensagem -->
26
+ <div class="empty-state-content text-center space-y-4">
27
+ <!-- Título -->
28
+ <h3 class="text-2xl font-bold text-gray-900 mb-2">
29
+ {{ emptyStateConfig.title }}
30
+ </h3>
31
+
32
+ <!-- Descrição -->
33
+ <p class="text-gray-600 text-lg leading-relaxed px-4">
34
+ {{ emptyStateConfig.description }}
35
+ </p>
36
+
37
+ <!-- Informações adicionais baseadas no status -->
38
+ <div *ngIf="statusPedido === 'finalizado'" class="mt-4">
39
+ <div
40
+ class="inline-flex items-center gap-2 bg-green-50 text-green-700 px-4 py-2 rounded-full"
41
+ >
42
+ <i class="fas fa-check-circle"></i>
43
+ <span class="font-medium">Serviço avaliado e finalizado</span>
44
+ </div>
45
+ </div>
46
+
47
+ <div *ngIf="statusPedido === 'cancelado'" class="mt-4">
48
+ <div
49
+ class="inline-flex items-center gap-2 bg-red-50 text-red-700 px-4 py-2 rounded-full"
50
+ >
51
+ <i class="fas fa-exclamation-circle"></i>
52
+ <span class="font-medium">Cancelado pelo prestador do serviço</span>
53
+ </div>
54
+ </div>
55
+ </div>
56
+
57
+ <!-- Ações -->
58
+ <div class="mt-8 flex flex-col sm:flex-row gap-4 justify-center">
59
+ <!-- Ação Primária -->
60
+ <button
61
+ (click)="onPrimaryAction()"
62
+ [ngClass]="{
63
+ 'bg-green-600 hover:bg-green-700': statusPedido === 'finalizado',
64
+ 'bg-red-600 hover:bg-red-700': statusPedido === 'cancelado',
65
+ 'bg-blue-600 ':
66
+ statusPedido === 'indisponível' || statusPedido === 'indisponivel',
67
+ 'bg-primary-600 hover:bg-primary-700': card.length === 0
68
+ }"
69
+ class="col-12 btn btn-primary"
70
+ >
71
+ {{ emptyStateConfig.primaryActionText }}
72
+ </button>
73
+
74
+ <!-- Ação Secundária -->
75
+ <button
76
+ *ngIf="emptyStateConfig.secondaryActionText"
77
+ (click)="onSecondaryAction()"
78
+ class="col-12 btn btn-outline-primary"
79
+ >
80
+ {{ emptyStateConfig.secondaryActionText }}
81
+ </button>
82
+ </div>
83
+
84
+ <!-- Link de ajuda (opcional) -->
85
+ <div *ngIf="statusPedido === 'cancelado'" class="mt-6 text-center">
86
+ <a
87
+ href="#"
88
+ class="text-sm text-blue-600 hover:text-blue-800 hover:underline"
89
+ >
90
+ <i class="fas fa-question-circle mr-2"></i>
91
+ Precisa de ajuda? Entre em contato com o suporte
92
+ </a>
93
+ </div>
94
+ </div>
95
+ </div>
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { FallbackMessageComponent } from './fallback-message.component';
4
+
5
+ describe('FallbackMessageComponent', () => {
6
+ let component: FallbackMessageComponent;
7
+ let fixture: ComponentFixture<FallbackMessageComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ declarations: [ FallbackMessageComponent ]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(FallbackMessageComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });