@devstroupe/devkit-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/dist/boilerplates/angular-template/.dockerignore +4 -0
- package/dist/boilerplates/angular-template/.postcssrc.json +5 -0
- package/dist/boilerplates/angular-template/Dockerfile +14 -0
- package/dist/boilerplates/angular-template/angular.json +85 -0
- package/dist/boilerplates/angular-template/components.json +5 -0
- package/dist/boilerplates/angular-template/framework.code-workspace +7 -0
- package/dist/boilerplates/angular-template/nginx.conf +23 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/browserslist +21 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/jiti +21 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/lessc +21 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/ng +21 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/ng-xi18n +21 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/ngc +21 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/sass +21 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/terser +21 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/tsc +21 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/tsserver +21 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/vite +21 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/vitest +21 -0
- package/dist/boilerplates/angular-template/node_modules/.bin/yaml +21 -0
- package/dist/boilerplates/angular-template/package.json +47 -0
- package/dist/boilerplates/angular-template/postcss.config.js +5 -0
- package/dist/boilerplates/angular-template/proxy.conf.json +7 -0
- package/dist/boilerplates/angular-template/src/app/app.component.html +3 -0
- package/dist/boilerplates/angular-template/src/app/app.component.ts +12 -0
- package/dist/boilerplates/angular-template/src/app/app.config.ts +59 -0
- package/dist/boilerplates/angular-template/src/app/app.entity-routes.ts +4 -0
- package/dist/boilerplates/angular-template/src/app/app.routes.ts +25 -0
- package/dist/boilerplates/angular-template/src/app/core/guards/auth.guard.ts +16 -0
- package/dist/boilerplates/angular-template/src/app/core/services/auth.service.ts +98 -0
- package/dist/boilerplates/angular-template/src/app/modules/auth/login/login.component.html +51 -0
- package/dist/boilerplates/angular-template/src/app/modules/auth/login/login.component.ts +47 -0
- package/dist/boilerplates/angular-template/src/app/modules/auth/register/register.component.html +59 -0
- package/dist/boilerplates/angular-template/src/app/modules/auth/register/register.component.ts +47 -0
- package/dist/boilerplates/angular-template/src/app/modules/dashboard/dashboard.component.html +14 -0
- package/dist/boilerplates/angular-template/src/app/modules/dashboard/dashboard.component.ts +23 -0
- package/dist/boilerplates/angular-template/src/app/shared/interceptors/tenant.interceptor.ts +25 -0
- package/dist/boilerplates/angular-template/src/index.html +64 -0
- package/dist/boilerplates/angular-template/src/main.ts +6 -0
- package/dist/boilerplates/angular-template/src/styles.css +9 -0
- package/dist/boilerplates/angular-template/tsconfig.json +36 -0
- package/dist/boilerplates/nest-template/Dockerfile +16 -0
- package/dist/boilerplates/nest-template/node_modules/.bin/acorn +21 -0
- package/dist/boilerplates/nest-template/node_modules/.bin/nest +21 -0
- package/dist/boilerplates/nest-template/node_modules/.bin/prettier +21 -0
- package/dist/boilerplates/nest-template/node_modules/.bin/tsc +21 -0
- package/dist/boilerplates/nest-template/node_modules/.bin/tsserver +21 -0
- package/dist/boilerplates/nest-template/node_modules/.bin/typeorm +21 -0
- package/dist/boilerplates/nest-template/node_modules/.bin/typeorm-ts-node-commonjs +21 -0
- package/dist/boilerplates/nest-template/node_modules/.bin/typeorm-ts-node-esm +21 -0
- package/dist/boilerplates/nest-template/node_modules/.bin/webpack +21 -0
- package/dist/boilerplates/nest-template/package.json +43 -0
- package/dist/boilerplates/nest-template/src/app.module.ts +24 -0
- package/dist/boilerplates/nest-template/src/database/data-source.ts +16 -0
- package/dist/boilerplates/nest-template/src/database/migrations/1700000000000-create-users.ts +26 -0
- package/dist/boilerplates/nest-template/src/main.ts +46 -0
- package/dist/boilerplates/nest-template/src/modules/auth/auth.controller.ts +34 -0
- package/dist/boilerplates/nest-template/src/modules/auth/auth.module.ts +22 -0
- package/dist/boilerplates/nest-template/src/modules/auth/auth.service.ts +57 -0
- package/dist/boilerplates/nest-template/src/modules/auth/current-user.decorator.ts +8 -0
- package/dist/boilerplates/nest-template/src/modules/auth/jwt-auth.guard.ts +31 -0
- package/dist/boilerplates/nest-template/src/modules/auth/roles.decorator.ts +4 -0
- package/dist/boilerplates/nest-template/src/modules/auth/roles.guard.ts +24 -0
- package/dist/boilerplates/nest-template/src/modules/user/database-seed.service.ts +47 -0
- package/dist/boilerplates/nest-template/src/modules/user/domain/user.repository.ts +9 -0
- package/dist/boilerplates/nest-template/src/modules/user/domain/user.ts +9 -0
- package/dist/boilerplates/nest-template/src/modules/user/infra/database/user.orm-entity.ts +31 -0
- package/dist/boilerplates/nest-template/src/modules/user/infra/database/user.repository.adapter.ts +53 -0
- package/dist/boilerplates/nest-template/src/modules/user/service/user.service.ts +44 -0
- package/dist/boilerplates/nest-template/src/modules/user/user.module.ts +20 -0
- package/dist/boilerplates/nest-template/tsconfig.build.json +4 -0
- package/dist/boilerplates/nest-template/tsconfig.json +21 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1967 -0
- package/dist/migrations/sort-entities.d.ts +2 -0
- package/dist/migrations/sort-entities.js +30 -0
- package/dist/rules/linter-rules.d.ts +12 -0
- package/dist/rules/linter-rules.js +338 -0
- package/dist/rules/linter-rules.test.d.ts +1 -0
- package/dist/rules/linter-rules.test.js +214 -0
- package/dist/templates/angular/dialog-handler.template.d.ts +2 -0
- package/dist/templates/angular/dialog-handler.template.js +49 -0
- package/dist/templates/angular/form.template.d.ts +3 -0
- package/dist/templates/angular/form.template.js +453 -0
- package/dist/templates/angular/index.d.ts +4 -0
- package/dist/templates/angular/index.js +20 -0
- package/dist/templates/angular/list.template.d.ts +3 -0
- package/dist/templates/angular/list.template.js +213 -0
- package/dist/templates/angular/service.template.d.ts +1 -0
- package/dist/templates/angular/service.template.js +20 -0
- package/dist/templates/cli-templates.d.ts +2 -0
- package/dist/templates/cli-templates.js +18 -0
- package/dist/templates/nest/crud.templates.d.ts +9 -0
- package/dist/templates/nest/crud.templates.js +362 -0
- package/dist/templates/nest/index.d.ts +3 -0
- package/dist/templates/nest/index.js +19 -0
- package/dist/templates/nest/microservice.templates.d.ts +4 -0
- package/dist/templates/nest/microservice.templates.js +157 -0
- package/dist/templates/nest/migration.template.d.ts +3 -0
- package/dist/templates/nest/migration.template.js +127 -0
- package/dist/templates/relationship-templates.test.d.ts +1 -0
- package/dist/templates/relationship-templates.test.js +181 -0
- package/dist/templates/shared/names.d.ts +3 -0
- package/dist/templates/shared/names.js +14 -0
- package/dist/templates/shared/relationships.d.ts +27 -0
- package/dist/templates/shared/relationships.js +96 -0
- package/dist/templates/ui/components/avatar.template.d.ts +3 -0
- package/dist/templates/ui/components/avatar.template.js +66 -0
- package/dist/templates/ui/components/badge.template.d.ts +3 -0
- package/dist/templates/ui/components/badge.template.js +27 -0
- package/dist/templates/ui/components/button.template.d.ts +5 -0
- package/dist/templates/ui/components/button.template.js +64 -0
- package/dist/templates/ui/components/card-list.template.d.ts +5 -0
- package/dist/templates/ui/components/card-list.template.js +79 -0
- package/dist/templates/ui/components/dialog.template.d.ts +5 -0
- package/dist/templates/ui/components/dialog.template.js +51 -0
- package/dist/templates/ui/components/filter.template.d.ts +4 -0
- package/dist/templates/ui/components/filter.template.js +218 -0
- package/dist/templates/ui/components/index.d.ts +10 -0
- package/dist/templates/ui/components/index.js +26 -0
- package/dist/templates/ui/components/input.template.d.ts +4 -0
- package/dist/templates/ui/components/input.template.js +76 -0
- package/dist/templates/ui/components/select.template.d.ts +4 -0
- package/dist/templates/ui/components/select.template.js +176 -0
- package/dist/templates/ui/components/simple-list.template.d.ts +5 -0
- package/dist/templates/ui/components/simple-list.template.js +89 -0
- package/dist/templates/ui/components/table.template.d.ts +5 -0
- package/dist/templates/ui/components/table.template.js +112 -0
- package/dist/templates/ui/index.d.ts +9 -0
- package/dist/templates/ui/index.js +25 -0
- package/dist/templates/ui/layout/header.template.d.ts +5 -0
- package/dist/templates/ui/layout/header.template.js +236 -0
- package/dist/templates/ui/layout/index.d.ts +4 -0
- package/dist/templates/ui/layout/index.js +20 -0
- package/dist/templates/ui/layout/main-layout.template.d.ts +5 -0
- package/dist/templates/ui/layout/main-layout.template.js +126 -0
- package/dist/templates/ui/layout/shell.template.d.ts +5 -0
- package/dist/templates/ui/layout/shell.template.js +76 -0
- package/dist/templates/ui/layout/sidebar.template.d.ts +5 -0
- package/dist/templates/ui/layout/sidebar.template.js +412 -0
- package/dist/templates/ui/playground.template.d.ts +5 -0
- package/dist/templates/ui/playground.template.js +570 -0
- package/dist/templates/ui/readme.template.d.ts +1 -0
- package/dist/templates/ui/readme.template.js +23 -0
- package/dist/templates/ui/shared/colors.d.ts +1 -0
- package/dist/templates/ui/shared/colors.js +31 -0
- package/dist/templates/ui/shared/profile-component.template.d.ts +5 -0
- package/dist/templates/ui/shared/profile-component.template.js +403 -0
- package/dist/templates/ui/shared/profile-service.template.d.ts +1 -0
- package/dist/templates/ui/shared/profile-service.template.js +44 -0
- package/dist/templates/ui/shared/theme-service.template.d.ts +1 -0
- package/dist/templates/ui/shared/theme-service.template.js +47 -0
- package/dist/templates/ui/spartan/badge-directive.template.d.ts +3 -0
- package/dist/templates/ui/spartan/badge-directive.template.js +50 -0
- package/dist/templates/ui/spartan/button-directive.template.d.ts +3 -0
- package/dist/templates/ui/spartan/button-directive.template.js +82 -0
- package/dist/templates/ui/spartan/button-token.template.d.ts +3 -0
- package/dist/templates/ui/spartan/button-token.template.js +31 -0
- package/dist/templates/ui/spartan/hlm-core.template.d.ts +3 -0
- package/dist/templates/ui/spartan/hlm-core.template.js +322 -0
- package/dist/templates/ui/spartan/index.d.ts +5 -0
- package/dist/templates/ui/spartan/index.js +21 -0
- package/dist/templates/ui/spartan/input-directive.template.d.ts +3 -0
- package/dist/templates/ui/spartan/input-directive.template.js +31 -0
- package/dist/templates/ui/theme-css.template.d.ts +7 -0
- package/dist/templates/ui/theme-css.template.js +210 -0
- package/dist/templates/ui-templates.d.ts +1 -0
- package/dist/templates/ui-templates.js +17 -0
- package/package.json +50 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.devkitProfileComponentTemplate = devkitProfileComponentTemplate;
|
|
4
|
+
function devkitProfileComponentTemplate() {
|
|
5
|
+
return {
|
|
6
|
+
ts: `import { Component, OnInit, inject } from '@angular/core';
|
|
7
|
+
import { CommonModule } from '@angular/common';
|
|
8
|
+
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
9
|
+
import { Router } from '@angular/router';
|
|
10
|
+
import { NgIconComponent } from '@ng-icons/core';
|
|
11
|
+
import { HlmButton } from '@spartan-ng/helm/button';
|
|
12
|
+
import { HlmInput } from '@spartan-ng/helm/input';
|
|
13
|
+
import { AuthService } from '../../../core/services/auth.service';
|
|
14
|
+
import { ProfileService } from '../../../core/services/profile.service';
|
|
15
|
+
|
|
16
|
+
@Component({
|
|
17
|
+
selector: 'app-profile',
|
|
18
|
+
standalone: true,
|
|
19
|
+
imports: [CommonModule, ReactiveFormsModule, NgIconComponent, HlmButton, HlmInput],
|
|
20
|
+
templateUrl: './profile.component.html',
|
|
21
|
+
styleUrl: './profile.component.css'
|
|
22
|
+
})
|
|
23
|
+
export class ProfileComponent implements OnInit {
|
|
24
|
+
private fb = inject(FormBuilder);
|
|
25
|
+
private authService = inject(AuthService);
|
|
26
|
+
private profileService = inject(ProfileService);
|
|
27
|
+
private router = inject(Router);
|
|
28
|
+
|
|
29
|
+
profileForm!: FormGroup;
|
|
30
|
+
isLoading = false;
|
|
31
|
+
isSaving = false;
|
|
32
|
+
successMessage = '';
|
|
33
|
+
errorMessage = '';
|
|
34
|
+
avatarPreview = '';
|
|
35
|
+
|
|
36
|
+
currentUser$ = this.authService.currentUser$;
|
|
37
|
+
|
|
38
|
+
ngOnInit(): void {
|
|
39
|
+
const user = this.authService.currentUser;
|
|
40
|
+
this.profileForm = this.fb.group({
|
|
41
|
+
name: [user?.name || '', [Validators.required, Validators.minLength(2)]],
|
|
42
|
+
email: [user?.email || '', [Validators.required, Validators.email]],
|
|
43
|
+
avatar: [user?.avatar || '']
|
|
44
|
+
});
|
|
45
|
+
this.avatarPreview = user?.avatar || '';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
onAvatarChange(): void {
|
|
49
|
+
const url = this.profileForm.get('avatar')?.value;
|
|
50
|
+
this.avatarPreview = url || '';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
onSave(): void {
|
|
54
|
+
if (this.profileForm.invalid) {
|
|
55
|
+
this.profileForm.markAllAsTouched();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.isSaving = true;
|
|
60
|
+
this.successMessage = '';
|
|
61
|
+
this.errorMessage = '';
|
|
62
|
+
|
|
63
|
+
const data = this.profileForm.value;
|
|
64
|
+
|
|
65
|
+
this.profileService.updateProfile(data).subscribe({
|
|
66
|
+
next: () => {
|
|
67
|
+
this.isSaving = false;
|
|
68
|
+
this.successMessage = 'Perfil atualizado com sucesso!';
|
|
69
|
+
setTimeout(() => (this.successMessage = ''), 4000);
|
|
70
|
+
},
|
|
71
|
+
error: (err) => {
|
|
72
|
+
this.isSaving = false;
|
|
73
|
+
this.errorMessage = err?.error?.message || 'Erro ao salvar o perfil. Tente novamente.';
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
onCancel(): void {
|
|
79
|
+
this.router.navigate(['/dashboard']);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get nameControl() { return this.profileForm.get('name'); }
|
|
83
|
+
get emailControl() { return this.profileForm.get('email'); }
|
|
84
|
+
}
|
|
85
|
+
`,
|
|
86
|
+
html: `<div class="dt-profile-page">
|
|
87
|
+
<div class="dt-profile-container">
|
|
88
|
+
|
|
89
|
+
<!-- Header da Página -->
|
|
90
|
+
<div class="dt-profile-header">
|
|
91
|
+
<button hlmBtn variant="ghost" size="icon" (click)="onCancel()" class="dt-profile-back" title="Voltar">
|
|
92
|
+
<ng-icon name="lucideArrowLeft" class="size-5"></ng-icon>
|
|
93
|
+
</button>
|
|
94
|
+
<div>
|
|
95
|
+
<h1 class="dt-profile-title">Editar Perfil</h1>
|
|
96
|
+
<p class="dt-profile-subtitle">Atualize suas informações pessoais</p>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div class="dt-profile-content" *ngIf="currentUser$ | async as user">
|
|
101
|
+
|
|
102
|
+
<!-- Card do Avatar -->
|
|
103
|
+
<div class="dt-profile-avatar-card">
|
|
104
|
+
<div class="dt-profile-avatar-wrapper">
|
|
105
|
+
<img
|
|
106
|
+
*ngIf="avatarPreview; else avatarInitials"
|
|
107
|
+
[src]="avatarPreview"
|
|
108
|
+
[alt]="user.name"
|
|
109
|
+
class="dt-profile-avatar-img"
|
|
110
|
+
(error)="avatarPreview = ''"
|
|
111
|
+
/>
|
|
112
|
+
<ng-template #avatarInitials>
|
|
113
|
+
<div class="dt-profile-avatar-initials">
|
|
114
|
+
{{ user.name.slice(0, 2).toUpperCase() }}
|
|
115
|
+
</div>
|
|
116
|
+
</ng-template>
|
|
117
|
+
</div>
|
|
118
|
+
<div class="dt-profile-avatar-info">
|
|
119
|
+
<p class="dt-profile-avatar-name">{{ user.name }}</p>
|
|
120
|
+
<p class="dt-profile-avatar-role" *ngIf="user.role">{{ user.role }}</p>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<!-- Formulário -->
|
|
125
|
+
<form [formGroup]="profileForm" (ngSubmit)="onSave()" class="dt-profile-form" novalidate>
|
|
126
|
+
|
|
127
|
+
<!-- Campo: Nome -->
|
|
128
|
+
<div class="dt-profile-field">
|
|
129
|
+
<label class="dt-profile-label" for="profile-name">
|
|
130
|
+
<ng-icon name="lucideUser" class="size-4"></ng-icon>
|
|
131
|
+
Nome Completo
|
|
132
|
+
</label>
|
|
133
|
+
<input
|
|
134
|
+
hlmInput
|
|
135
|
+
id="profile-name"
|
|
136
|
+
type="text"
|
|
137
|
+
formControlName="name"
|
|
138
|
+
placeholder="Seu nome completo"
|
|
139
|
+
class="dt-profile-input"
|
|
140
|
+
[class.dt-profile-input--error]="nameControl?.invalid && nameControl?.touched"
|
|
141
|
+
/>
|
|
142
|
+
<span *ngIf="nameControl?.invalid && nameControl?.touched" class="dt-profile-error">
|
|
143
|
+
{{ nameControl?.errors?.['required'] ? 'Nome é obrigatório.' : 'Nome deve ter no mínimo 2 caracteres.' }}
|
|
144
|
+
</span>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<!-- Campo: E-mail -->
|
|
148
|
+
<div class="dt-profile-field">
|
|
149
|
+
<label class="dt-profile-label" for="profile-email">
|
|
150
|
+
<ng-icon name="lucideMail" class="size-4"></ng-icon>
|
|
151
|
+
E-mail
|
|
152
|
+
</label>
|
|
153
|
+
<input
|
|
154
|
+
hlmInput
|
|
155
|
+
id="profile-email"
|
|
156
|
+
type="email"
|
|
157
|
+
formControlName="email"
|
|
158
|
+
placeholder="seu@email.com"
|
|
159
|
+
class="dt-profile-input"
|
|
160
|
+
[class.dt-profile-input--error]="emailControl?.invalid && emailControl?.touched"
|
|
161
|
+
/>
|
|
162
|
+
<span *ngIf="emailControl?.invalid && emailControl?.touched" class="dt-profile-error">
|
|
163
|
+
{{ emailControl?.errors?.['required'] ? 'E-mail é obrigatório.' : 'Informe um e-mail válido.' }}
|
|
164
|
+
</span>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<!-- Campo: Avatar URL -->
|
|
168
|
+
<div class="dt-profile-field">
|
|
169
|
+
<label class="dt-profile-label" for="profile-avatar">
|
|
170
|
+
<ng-icon name="lucideImage" class="size-4"></ng-icon>
|
|
171
|
+
URL do Avatar (opcional)
|
|
172
|
+
</label>
|
|
173
|
+
<input
|
|
174
|
+
hlmInput
|
|
175
|
+
id="profile-avatar"
|
|
176
|
+
type="url"
|
|
177
|
+
formControlName="avatar"
|
|
178
|
+
placeholder="https://exemplo.com/sua-foto.jpg"
|
|
179
|
+
class="dt-profile-input"
|
|
180
|
+
(input)="onAvatarChange()"
|
|
181
|
+
/>
|
|
182
|
+
<span class="dt-profile-hint">Cole a URL de uma imagem para usar como foto de perfil.</span>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
<!-- Feedbacks -->
|
|
186
|
+
<div *ngIf="successMessage" class="dt-profile-alert dt-profile-alert--success">
|
|
187
|
+
<ng-icon name="lucideCircleCheck" class="size-4"></ng-icon>
|
|
188
|
+
{{ successMessage }}
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
<div *ngIf="errorMessage" class="dt-profile-alert dt-profile-alert--error">
|
|
192
|
+
<ng-icon name="lucideCircleAlert" class="size-4"></ng-icon>
|
|
193
|
+
{{ errorMessage }}
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<!-- Ações -->
|
|
197
|
+
<div class="dt-profile-actions">
|
|
198
|
+
<button hlmBtn type="button" variant="outline" (click)="onCancel()" [disabled]="isSaving">
|
|
199
|
+
Cancelar
|
|
200
|
+
</button>
|
|
201
|
+
<button hlmBtn type="submit" variant="default" [disabled]="isSaving || profileForm.invalid">
|
|
202
|
+
<ng-icon *ngIf="isSaving" name="lucideLoader" class="size-4 mr-2 dt-spin"></ng-icon>
|
|
203
|
+
{{ isSaving ? 'Salvando...' : 'Salvar Alterações' }}
|
|
204
|
+
</button>
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
</form>
|
|
208
|
+
</div>
|
|
209
|
+
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
`,
|
|
213
|
+
css: `.dt-profile-page {
|
|
214
|
+
min-height: 100%;
|
|
215
|
+
padding: 32px 16px;
|
|
216
|
+
background-color: var(--background);
|
|
217
|
+
font-family: var(--font-family);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.dt-profile-container {
|
|
221
|
+
max-width: 640px;
|
|
222
|
+
margin: 0 auto;
|
|
223
|
+
display: flex;
|
|
224
|
+
flex-direction: column;
|
|
225
|
+
gap: 28px;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* Header */
|
|
229
|
+
.dt-profile-header {
|
|
230
|
+
display: flex;
|
|
231
|
+
align-items: center;
|
|
232
|
+
gap: 12px;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.dt-profile-back {
|
|
236
|
+
flex-shrink: 0;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.dt-profile-title {
|
|
240
|
+
font-size: 22px;
|
|
241
|
+
font-weight: 700;
|
|
242
|
+
color: var(--foreground);
|
|
243
|
+
margin: 0;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.dt-profile-subtitle {
|
|
247
|
+
font-size: 13px;
|
|
248
|
+
color: var(--muted-foreground);
|
|
249
|
+
margin: 2px 0 0;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* Card Avatar */
|
|
253
|
+
.dt-profile-avatar-card {
|
|
254
|
+
display: flex;
|
|
255
|
+
align-items: center;
|
|
256
|
+
gap: 20px;
|
|
257
|
+
padding: 24px;
|
|
258
|
+
background-color: var(--card);
|
|
259
|
+
border: 1px solid var(--border);
|
|
260
|
+
border-radius: var(--radius);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.dt-profile-avatar-wrapper {
|
|
264
|
+
flex-shrink: 0;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.dt-profile-avatar-img {
|
|
268
|
+
width: 80px;
|
|
269
|
+
height: 80px;
|
|
270
|
+
border-radius: 50%;
|
|
271
|
+
object-fit: cover;
|
|
272
|
+
border: 3px solid var(--border);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.dt-profile-avatar-initials {
|
|
276
|
+
width: 80px;
|
|
277
|
+
height: 80px;
|
|
278
|
+
border-radius: 50%;
|
|
279
|
+
display: flex;
|
|
280
|
+
align-items: center;
|
|
281
|
+
justify-content: center;
|
|
282
|
+
font-size: 24px;
|
|
283
|
+
font-weight: 700;
|
|
284
|
+
background-color: var(--primary);
|
|
285
|
+
color: var(--primary-foreground);
|
|
286
|
+
border: 3px solid color-mix(in srgb, var(--primary) 30%, transparent);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.dt-profile-avatar-name {
|
|
290
|
+
font-size: 18px;
|
|
291
|
+
font-weight: 600;
|
|
292
|
+
color: var(--foreground);
|
|
293
|
+
margin: 0;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.dt-profile-avatar-role {
|
|
297
|
+
font-size: 13px;
|
|
298
|
+
color: var(--muted-foreground);
|
|
299
|
+
margin: 4px 0 0;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* Formulário */
|
|
303
|
+
.dt-profile-form {
|
|
304
|
+
display: flex;
|
|
305
|
+
flex-direction: column;
|
|
306
|
+
gap: 20px;
|
|
307
|
+
padding: 24px;
|
|
308
|
+
background-color: var(--card);
|
|
309
|
+
border: 1px solid var(--border);
|
|
310
|
+
border-radius: var(--radius);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.dt-profile-field {
|
|
314
|
+
display: flex;
|
|
315
|
+
flex-direction: column;
|
|
316
|
+
gap: 6px;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.dt-profile-label {
|
|
320
|
+
font-size: 13px;
|
|
321
|
+
font-weight: 600;
|
|
322
|
+
color: var(--foreground);
|
|
323
|
+
display: flex;
|
|
324
|
+
align-items: center;
|
|
325
|
+
gap: 6px;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.dt-profile-input {
|
|
329
|
+
width: 100%;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.dt-profile-input--error {
|
|
333
|
+
border-color: var(--destructive) !important;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.dt-profile-error {
|
|
337
|
+
font-size: 12px;
|
|
338
|
+
color: var(--destructive);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.dt-profile-hint {
|
|
342
|
+
font-size: 12px;
|
|
343
|
+
color: var(--muted-foreground);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/* Feedbacks */
|
|
347
|
+
.dt-profile-alert {
|
|
348
|
+
display: flex;
|
|
349
|
+
align-items: center;
|
|
350
|
+
gap: 8px;
|
|
351
|
+
padding: 12px 16px;
|
|
352
|
+
border-radius: var(--radius);
|
|
353
|
+
font-size: 13px;
|
|
354
|
+
font-weight: 500;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.dt-profile-alert--success {
|
|
358
|
+
background-color: color-mix(in srgb, var(--primary) 10%, transparent);
|
|
359
|
+
color: var(--primary);
|
|
360
|
+
border: 1px solid color-mix(in srgb, var(--primary) 30%, transparent);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.dt-profile-alert--error {
|
|
364
|
+
background-color: color-mix(in srgb, var(--destructive) 10%, transparent);
|
|
365
|
+
color: var(--destructive);
|
|
366
|
+
border: 1px solid color-mix(in srgb, var(--destructive) 30%, transparent);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/* Ações */
|
|
370
|
+
.dt-profile-actions {
|
|
371
|
+
display: flex;
|
|
372
|
+
justify-content: flex-end;
|
|
373
|
+
gap: 12px;
|
|
374
|
+
padding-top: 8px;
|
|
375
|
+
border-top: 1px solid var(--border);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/* Spinner */
|
|
379
|
+
@keyframes dt-spin {
|
|
380
|
+
from { transform: rotate(0deg); }
|
|
381
|
+
to { transform: rotate(360deg); }
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.dt-spin {
|
|
385
|
+
animation: dt-spin 1s linear infinite;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
@media (max-width: 640px) {
|
|
389
|
+
.dt-profile-page {
|
|
390
|
+
padding: 16px 12px;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.dt-profile-actions {
|
|
394
|
+
flex-direction: column-reverse;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.dt-profile-actions button {
|
|
398
|
+
width: 100%;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
`
|
|
402
|
+
};
|
|
403
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function devkitProfileServiceTemplate(): string;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.devkitProfileServiceTemplate = devkitProfileServiceTemplate;
|
|
4
|
+
function devkitProfileServiceTemplate() {
|
|
5
|
+
return `import { Injectable, inject } from '@angular/core';
|
|
6
|
+
import { HttpClient } from '@angular/common/http';
|
|
7
|
+
import { Observable, tap } from 'rxjs';
|
|
8
|
+
import { AuthService } from './auth.service';
|
|
9
|
+
|
|
10
|
+
export interface UpdateProfileDto {
|
|
11
|
+
name?: string;
|
|
12
|
+
email?: string;
|
|
13
|
+
avatar?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@Injectable({
|
|
17
|
+
providedIn: 'root'
|
|
18
|
+
})
|
|
19
|
+
export class ProfileService {
|
|
20
|
+
private http = inject(HttpClient);
|
|
21
|
+
private authService = inject(AuthService);
|
|
22
|
+
private apiUrl = '/api/auth/profile';
|
|
23
|
+
|
|
24
|
+
updateProfile(data: UpdateProfileDto): Observable<any> {
|
|
25
|
+
return this.http.patch<any>(this.apiUrl, data).pipe(
|
|
26
|
+
tap((updatedUser) => {
|
|
27
|
+
const current = this.authService.currentUser;
|
|
28
|
+
if (current) {
|
|
29
|
+
const merged = { ...current, ...updatedUser };
|
|
30
|
+
localStorage.setItem('user', JSON.stringify(merged));
|
|
31
|
+
this.authService.setCurrentUser(merged);
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
uploadAvatar(file: File): Observable<{ url: string }> {
|
|
38
|
+
const formData = new FormData();
|
|
39
|
+
formData.append('file', file);
|
|
40
|
+
return this.http.post<{ url: string }>(\`\${this.apiUrl}/avatar\`, formData);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function devkitThemeServiceTemplate(): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.devkitThemeServiceTemplate = devkitThemeServiceTemplate;
|
|
4
|
+
function devkitThemeServiceTemplate() {
|
|
5
|
+
return `import { Injectable } from '@angular/core';
|
|
6
|
+
import { BehaviorSubject } from 'rxjs';
|
|
7
|
+
|
|
8
|
+
const THEME_KEY = 'devkit-theme';
|
|
9
|
+
|
|
10
|
+
@Injectable({
|
|
11
|
+
providedIn: 'root'
|
|
12
|
+
})
|
|
13
|
+
export class ThemeService {
|
|
14
|
+
private isDarkSubject = new BehaviorSubject<boolean>(false);
|
|
15
|
+
isDark$ = this.isDarkSubject.asObservable();
|
|
16
|
+
|
|
17
|
+
get isDark(): boolean {
|
|
18
|
+
return this.isDarkSubject.getValue();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
constructor() {
|
|
22
|
+
this.loadTheme();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
toggle(): void {
|
|
26
|
+
this.setDark(!this.isDark);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
setDark(dark: boolean): void {
|
|
30
|
+
this.isDarkSubject.next(dark);
|
|
31
|
+
localStorage.setItem(THEME_KEY, dark ? 'dark' : 'light');
|
|
32
|
+
if (dark) {
|
|
33
|
+
document.documentElement.classList.add('dark');
|
|
34
|
+
} else {
|
|
35
|
+
document.documentElement.classList.remove('dark');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private loadTheme(): void {
|
|
40
|
+
const saved = localStorage.getItem(THEME_KEY);
|
|
41
|
+
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
42
|
+
const dark = saved ? saved === 'dark' : prefersDark;
|
|
43
|
+
this.setDark(dark);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.devkitHlmBadgeDirectiveTemplate = devkitHlmBadgeDirectiveTemplate;
|
|
4
|
+
function devkitHlmBadgeDirectiveTemplate() {
|
|
5
|
+
return {
|
|
6
|
+
ts: `import { Directive, input } from '@angular/core';
|
|
7
|
+
import { classes } from '@spartan-ng/helm/utils';
|
|
8
|
+
import { type VariantProps, cva } from 'class-variance-authority';
|
|
9
|
+
|
|
10
|
+
const badgeVariants = cva(
|
|
11
|
+
'h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&>ng-icon]:text-[length:--spacing(3)] group/badge focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 inline-flex w-fit shrink-0 items-center justify-center overflow-hidden whitespace-nowrap focus-visible:ring-[3px] [&>ng-icon]:pointer-events-none',
|
|
12
|
+
{
|
|
13
|
+
variants: {
|
|
14
|
+
variant: {
|
|
15
|
+
default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',
|
|
16
|
+
secondary: 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80',
|
|
17
|
+
destructive:
|
|
18
|
+
'bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20',
|
|
19
|
+
outline: 'border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground',
|
|
20
|
+
ghost: 'hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50',
|
|
21
|
+
link: 'text-primary underline-offset-4 hover:underline',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: {
|
|
25
|
+
variant: 'default',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export type BadgeVariants = VariantProps<typeof badgeVariants>;
|
|
31
|
+
|
|
32
|
+
@Directive({
|
|
33
|
+
selector: '[hlmBadge],hlm-badge',
|
|
34
|
+
host: {
|
|
35
|
+
'data-slot': 'badge',
|
|
36
|
+
'[attr.data-variant]': 'variant()',
|
|
37
|
+
},
|
|
38
|
+
standalone: true,
|
|
39
|
+
})
|
|
40
|
+
export class HlmBadge {
|
|
41
|
+
public readonly variant = input<BadgeVariants['variant']>('default');
|
|
42
|
+
|
|
43
|
+
constructor() {
|
|
44
|
+
classes(() => badgeVariants({ variant: this.variant() }));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// 19. Template do devkit-badge (adaptado para importar HlmBadge oficial)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.devkitHlmButtonDirectiveTemplate = devkitHlmButtonDirectiveTemplate;
|
|
4
|
+
function devkitHlmButtonDirectiveTemplate() {
|
|
5
|
+
return {
|
|
6
|
+
ts: `import { Directive, input, signal } from '@angular/core';
|
|
7
|
+
import { BrnButton } from '@spartan-ng/brain/button';
|
|
8
|
+
import { classes } from '@spartan-ng/helm/utils';
|
|
9
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
10
|
+
import type { ClassValue } from 'clsx';
|
|
11
|
+
import { injectBrnButtonConfig } from './hlm-button.token';
|
|
12
|
+
|
|
13
|
+
export const buttonVariants = cva(
|
|
14
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 data-[matches-spartan-invalid=true]:ring-destructive/20 dark:data-[matches-spartan-invalid=true]:ring-destructive/40 data-[matches-spartan-invalid=true]:border-destructive dark:data-[matches-spartan-invalid=true]:border-destructive/50 rounded-lg border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 active:not-aria-[haspopup]:translate-y-px data-[matches-spartan-invalid=true]:ring-3 [&_ng-icon:not([class*='text-'])]:text-[length:--spacing(4)] group/button inline-flex shrink-0 items-center justify-center whitespace-nowrap transition-all outline-none select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_ng-icon]:pointer-events-none [&_ng-icon]:shrink-0",
|
|
15
|
+
{
|
|
16
|
+
variants: {
|
|
17
|
+
variant: {
|
|
18
|
+
default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',
|
|
19
|
+
outline:
|
|
20
|
+
'border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground',
|
|
21
|
+
secondary:
|
|
22
|
+
'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',
|
|
23
|
+
ghost:
|
|
24
|
+
'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',
|
|
25
|
+
destructive:
|
|
26
|
+
'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',
|
|
27
|
+
link: 'text-primary underline-offset-4 hover:underline',
|
|
28
|
+
},
|
|
29
|
+
size: {
|
|
30
|
+
default:
|
|
31
|
+
'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2',
|
|
32
|
+
xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_ng-icon:not([class*='text-'])]:text-[length:--spacing(3)]",
|
|
33
|
+
sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_ng-icon:not([class*='text-'])]:text-[length:--spacing(3.5)]",
|
|
34
|
+
lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pe-3 has-data-[icon=inline-start]:ps-3',
|
|
35
|
+
icon: 'size-8',
|
|
36
|
+
'icon-xs':
|
|
37
|
+
"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_ng-icon:not([class*='text-'])]:text-[length:--spacing(3)]",
|
|
38
|
+
'icon-sm':
|
|
39
|
+
'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg',
|
|
40
|
+
'icon-lg': 'size-9',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
defaultVariants: {
|
|
44
|
+
variant: 'default',
|
|
45
|
+
size: 'default',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
export type ButtonVariants = VariantProps<typeof buttonVariants>;
|
|
51
|
+
|
|
52
|
+
@Directive({
|
|
53
|
+
selector: 'button[hlmBtn], a[hlmBtn]',
|
|
54
|
+
exportAs: 'hlmBtn',
|
|
55
|
+
hostDirectives: [{ directive: BrnButton, inputs: ['disabled'] }],
|
|
56
|
+
host: { 'data-slot': 'button' },
|
|
57
|
+
standalone: true,
|
|
58
|
+
})
|
|
59
|
+
export class HlmButton {
|
|
60
|
+
private readonly _config = injectBrnButtonConfig();
|
|
61
|
+
|
|
62
|
+
private readonly _additionalClasses = signal<ClassValue>('');
|
|
63
|
+
|
|
64
|
+
public readonly variant = input<ButtonVariants['variant']>(this._config.variant);
|
|
65
|
+
|
|
66
|
+
public readonly size = input<ButtonVariants['size']>(this._config.size);
|
|
67
|
+
|
|
68
|
+
constructor() {
|
|
69
|
+
classes(() => [
|
|
70
|
+
buttonVariants({ variant: this.variant(), size: this.size() }),
|
|
71
|
+
this._additionalClasses(),
|
|
72
|
+
]);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
setClass(classes: string): void {
|
|
76
|
+
this._additionalClasses.set(classes);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
`
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
// Template do hlm-button.token.ts oficial
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.devkitHlmButtonTokenTemplate = devkitHlmButtonTokenTemplate;
|
|
4
|
+
function devkitHlmButtonTokenTemplate() {
|
|
5
|
+
return {
|
|
6
|
+
ts: `import { InjectionToken, type ValueProvider, inject } from '@angular/core';
|
|
7
|
+
import type { ButtonVariants } from './hlm-button';
|
|
8
|
+
|
|
9
|
+
export interface BrnButtonConfig {
|
|
10
|
+
variant: ButtonVariants['variant'];
|
|
11
|
+
size: ButtonVariants['size'];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const defaultConfig: BrnButtonConfig = {
|
|
15
|
+
variant: 'default',
|
|
16
|
+
size: 'default',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const BrnButtonConfigToken = new InjectionToken<BrnButtonConfig>('BrnButtonConfig');
|
|
20
|
+
|
|
21
|
+
export function provideBrnButtonConfig(config: Partial<BrnButtonConfig>): ValueProvider {
|
|
22
|
+
return { provide: BrnButtonConfigToken, useValue: { ...defaultConfig, ...config } };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function injectBrnButtonConfig(): BrnButtonConfig {
|
|
26
|
+
return inject(BrnButtonConfigToken, { optional: true }) ?? defaultConfig;
|
|
27
|
+
}
|
|
28
|
+
`
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// 17. Template da diretiva hlmInput do Spartan local (hlm-input.ts oficial)
|