@avora-labs/meta-forge 1.0.5
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 +63 -0
- package/fesm2022/avora-labs-meta-forge-amf-auth-shell.component-BWSdjBUS.mjs +103 -0
- package/fesm2022/avora-labs-meta-forge-amf-auth-shell.component-BWSdjBUS.mjs.map +1 -0
- package/fesm2022/avora-labs-meta-forge-contact-support.page-BAUiKm3P.mjs +287 -0
- package/fesm2022/avora-labs-meta-forge-contact-support.page-BAUiKm3P.mjs.map +1 -0
- package/fesm2022/avora-labs-meta-forge-forgot-password.page-0XLiBrV1.mjs +467 -0
- package/fesm2022/avora-labs-meta-forge-forgot-password.page-0XLiBrV1.mjs.map +1 -0
- package/fesm2022/avora-labs-meta-forge-login.page-etTr5NqJ.mjs +181 -0
- package/fesm2022/avora-labs-meta-forge-login.page-etTr5NqJ.mjs.map +1 -0
- package/fesm2022/avora-labs-meta-forge.mjs +6544 -0
- package/fesm2022/avora-labs-meta-forge.mjs.map +1 -0
- package/package.json +37 -0
- package/styles/_palettes.scss +85 -0
- package/styles/_themes.scss +97 -0
- package/styles/_variables.scss +57 -0
- package/styles/styles.scss +296 -0
- package/types/avora-labs-meta-forge.d.ts +2528 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, signal, Component } from '@angular/core';
|
|
3
|
+
import * as i1$1 from '@angular/forms';
|
|
4
|
+
import { FormsModule } from '@angular/forms';
|
|
5
|
+
import * as i1 from '@angular/router';
|
|
6
|
+
import { RouterModule } from '@angular/router';
|
|
7
|
+
import { AuthService, ActionDispatcherService, APP_META_CONFIG_TOKEN, FormRendererComponent } from './avora-labs-meta-forge.mjs';
|
|
8
|
+
import { A as AmfAuthShellComponent } from './avora-labs-meta-forge-amf-auth-shell.component-BWSdjBUS.mjs';
|
|
9
|
+
|
|
10
|
+
class LoginComponent {
|
|
11
|
+
router;
|
|
12
|
+
auth = inject(AuthService);
|
|
13
|
+
dispatcher = inject(ActionDispatcherService);
|
|
14
|
+
meta = inject(APP_META_CONFIG_TOKEN, { optional: true }) || { app: { name: 'AvoraMetaForge' } };
|
|
15
|
+
loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
16
|
+
rememberMe = false;
|
|
17
|
+
// JSON Meta Definition replacing the hardcoded HTML fields
|
|
18
|
+
loginForm = {
|
|
19
|
+
id: 'loginForm',
|
|
20
|
+
hideSubmit: true, // We provide our own exact-match custom button below
|
|
21
|
+
fields: [
|
|
22
|
+
{
|
|
23
|
+
key: 'email',
|
|
24
|
+
type: 'email',
|
|
25
|
+
label: 'Email Address',
|
|
26
|
+
placeholder: 'name@company.com',
|
|
27
|
+
validators: [{ type: 'required' }]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
key: 'password',
|
|
31
|
+
type: 'password',
|
|
32
|
+
label: 'Password',
|
|
33
|
+
placeholder: '••••••••',
|
|
34
|
+
validators: [{ type: 'required' }]
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
};
|
|
38
|
+
constructor(router) {
|
|
39
|
+
this.router = router;
|
|
40
|
+
}
|
|
41
|
+
triggerSubmit() {
|
|
42
|
+
// Dispatches standard AMF action to submit the specific form
|
|
43
|
+
this.dispatcher.dispatch({
|
|
44
|
+
type: 'submit-form',
|
|
45
|
+
config: { formId: 'loginForm' }
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
onFormSubmit(values) {
|
|
49
|
+
if (!values.email || !values.password)
|
|
50
|
+
return;
|
|
51
|
+
this.loading.set(true);
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
this.loading.set(false);
|
|
54
|
+
this.dispatcher.dispatch({
|
|
55
|
+
type: 'open-modal',
|
|
56
|
+
config: {
|
|
57
|
+
title: 'Two-Step Verification',
|
|
58
|
+
size: 'sm',
|
|
59
|
+
content: {
|
|
60
|
+
type: 'form',
|
|
61
|
+
config: {
|
|
62
|
+
fields: [
|
|
63
|
+
{
|
|
64
|
+
name: 'otp',
|
|
65
|
+
label: 'Enter 6-digit PIN',
|
|
66
|
+
type: 'otp',
|
|
67
|
+
required: true,
|
|
68
|
+
otpLength: 6,
|
|
69
|
+
validation: { minLength: 6, maxLength: 6 }
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
submitLabel: 'Verify & Login',
|
|
73
|
+
loadingLabel: 'Verifying...',
|
|
74
|
+
onSubmit: {
|
|
75
|
+
type: 'api',
|
|
76
|
+
config: { endpointId: 'mock-login-otp', body: 'formValue' },
|
|
77
|
+
then: {
|
|
78
|
+
type: 'dispatch-multiple',
|
|
79
|
+
config: {
|
|
80
|
+
mode: 'parallel',
|
|
81
|
+
actions: [
|
|
82
|
+
{ type: 'notify', config: { type: 'success', message: 'OTP Verified! Redirecting...' } },
|
|
83
|
+
{ type: 'close-modal' },
|
|
84
|
+
{
|
|
85
|
+
type: 'delay',
|
|
86
|
+
config: { duration: 600 },
|
|
87
|
+
then: { type: 'navigate', config: { path: '/dashboard' } }
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
onError: { type: 'notify', config: { type: 'error', message: 'Invalid Verification Code' } }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}, 1200);
|
|
99
|
+
}
|
|
100
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: LoginComponent, deps: [{ token: i1.Router }], target: i0.ɵɵFactoryTarget.Component });
|
|
101
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: LoginComponent, isStandalone: true, selector: "amf-login", ngImport: i0, template: `
|
|
102
|
+
<amf-auth-shell
|
|
103
|
+
[brandName]="meta.auth?.builtInUI?.brandName || meta.app.name"
|
|
104
|
+
[brandTagline]="meta.auth?.builtInUI?.brandTagline || 'Sign in to your account'">
|
|
105
|
+
|
|
106
|
+
<div class="login-form-container">
|
|
107
|
+
<!-- AMF Data-Driven Form Definition -->
|
|
108
|
+
<amf-form-renderer
|
|
109
|
+
#renderer
|
|
110
|
+
[config]="loginForm"
|
|
111
|
+
(formSubmit)="onFormSubmit($event)">
|
|
112
|
+
</amf-form-renderer>
|
|
113
|
+
|
|
114
|
+
<!-- Custom Inline Options Row -->
|
|
115
|
+
<div class="form-options">
|
|
116
|
+
<label class="remember-me">
|
|
117
|
+
<input type="checkbox" name="remember" [(ngModel)]="rememberMe">
|
|
118
|
+
<span class="custom-check"></span>
|
|
119
|
+
<span>Remember me</span>
|
|
120
|
+
</label>
|
|
121
|
+
<a routerLink="/forgot-password" class="forgot-link">Forgot password?</a>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<button type="button" class="login-btn" (click)="triggerSubmit()" [disabled]="loading()">
|
|
125
|
+
@if (!loading()) {
|
|
126
|
+
<span>Sign In</span>
|
|
127
|
+
} @else {
|
|
128
|
+
<div class="loader"></div>
|
|
129
|
+
}
|
|
130
|
+
</button>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div class="auth-footer-note">
|
|
134
|
+
Don't have an account? <a routerLink="/contact-support">Contact Support</a>
|
|
135
|
+
</div>
|
|
136
|
+
</amf-auth-shell>
|
|
137
|
+
`, isInline: true, styles: [":host{display:block;height:100%}.login-form-container{display:flex;flex-direction:column;gap:24px}::ng-deep .login-form-container .amf-form{gap:24px}::ng-deep .login-form-container .amf-form-fields{gap:24px}::ng-deep .login-form-container .amf-field{display:flex;flex-direction:column;gap:8px}::ng-deep .login-form-container .field-label{font-size:.875rem!important;font-weight:600!important;color:#cbd5e1!important;margin-bottom:0!important}::ng-deep .login-form-container .field-input-wrapper{border-radius:12px!important;border:1px solid rgba(255,255,255,.08)!important;background:#ffffff0a!important;transition:all .3s!important;overflow:hidden;box-shadow:none!important}::ng-deep .login-form-container .field-input-wrapper:focus-within{border-color:var(--app-primary, #6366f1)!important;background:#ffffff0f!important;box-shadow:0 0 20px var(--app-glow, rgba(99,102,241,.3))!important}::ng-deep .login-form-container .field-input{padding:13px 16px!important;border:none!important;background:transparent!important;font-size:1rem!important;color:#f1f5f9!important}::ng-deep .login-form-container .field-input::placeholder{color:#64748b!important}::ng-deep .login-form-container .pwd-toggle-btn{color:#64748b!important}::ng-deep .login-form-container .pwd-toggle-btn:hover{color:var(--app-primary, #6366f1)!important}.form-options{display:flex;align-items:center;justify-content:space-between;font-size:.875rem}.remember-me{display:flex;align-items:center;gap:8px;cursor:pointer;color:#94a3b8}.remember-me input{display:none}.custom-check{width:16px;height:16px;border-radius:4px;border:1px solid rgba(255,255,255,.15);background:#ffffff0a;position:relative;transition:all .2s}.remember-me input:checked+.custom-check{background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));border-color:transparent}.remember-me input:checked+.custom-check:after{content:\"\";position:absolute;left:5px;top:2px;width:4px;height:7px;border:solid white;border-width:0 2px 2px 0;transform:rotate(45deg)}.forgot-link{color:var(--app-primary, #6366f1);font-weight:500;transition:all .2s;text-decoration:none}.forgot-link:hover{text-shadow:0 0 12px var(--app-glow, rgba(99,102,241,.3))}.login-btn{background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));color:#fff;padding:14px;border:none;border-radius:12px;font-size:1rem;font-weight:600;cursor:pointer;transition:all .3s;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden}.login-btn:hover{transform:translateY(-2px);box-shadow:0 10px 30px -5px var(--app-glow, rgba(99,102,241,.5))}.login-btn:disabled{opacity:.7;cursor:not-allowed;transform:none}.auth-footer-note{text-align:center;margin-top:32px;font-size:.875rem;color:#64748b}.auth-footer-note a{color:var(--app-primary, #6366f1);font-weight:600;text-decoration:none}.loader{width:20px;height:20px;border:3px solid rgba(255,255,255,.2);border-top:3px solid white;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: AmfAuthShellComponent, selector: "amf-auth-shell", inputs: ["brandName", "brandTagline", "maxWidth"] }, { kind: "component", type: FormRendererComponent, selector: "amf-form-renderer", inputs: ["config", "context"], outputs: ["formSubmit", "formCancel", "formChange"] }] });
|
|
138
|
+
}
|
|
139
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: LoginComponent, decorators: [{
|
|
140
|
+
type: Component,
|
|
141
|
+
args: [{ selector: 'amf-login', standalone: true, imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent], template: `
|
|
142
|
+
<amf-auth-shell
|
|
143
|
+
[brandName]="meta.auth?.builtInUI?.brandName || meta.app.name"
|
|
144
|
+
[brandTagline]="meta.auth?.builtInUI?.brandTagline || 'Sign in to your account'">
|
|
145
|
+
|
|
146
|
+
<div class="login-form-container">
|
|
147
|
+
<!-- AMF Data-Driven Form Definition -->
|
|
148
|
+
<amf-form-renderer
|
|
149
|
+
#renderer
|
|
150
|
+
[config]="loginForm"
|
|
151
|
+
(formSubmit)="onFormSubmit($event)">
|
|
152
|
+
</amf-form-renderer>
|
|
153
|
+
|
|
154
|
+
<!-- Custom Inline Options Row -->
|
|
155
|
+
<div class="form-options">
|
|
156
|
+
<label class="remember-me">
|
|
157
|
+
<input type="checkbox" name="remember" [(ngModel)]="rememberMe">
|
|
158
|
+
<span class="custom-check"></span>
|
|
159
|
+
<span>Remember me</span>
|
|
160
|
+
</label>
|
|
161
|
+
<a routerLink="/forgot-password" class="forgot-link">Forgot password?</a>
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
<button type="button" class="login-btn" (click)="triggerSubmit()" [disabled]="loading()">
|
|
165
|
+
@if (!loading()) {
|
|
166
|
+
<span>Sign In</span>
|
|
167
|
+
} @else {
|
|
168
|
+
<div class="loader"></div>
|
|
169
|
+
}
|
|
170
|
+
</button>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<div class="auth-footer-note">
|
|
174
|
+
Don't have an account? <a routerLink="/contact-support">Contact Support</a>
|
|
175
|
+
</div>
|
|
176
|
+
</amf-auth-shell>
|
|
177
|
+
`, styles: [":host{display:block;height:100%}.login-form-container{display:flex;flex-direction:column;gap:24px}::ng-deep .login-form-container .amf-form{gap:24px}::ng-deep .login-form-container .amf-form-fields{gap:24px}::ng-deep .login-form-container .amf-field{display:flex;flex-direction:column;gap:8px}::ng-deep .login-form-container .field-label{font-size:.875rem!important;font-weight:600!important;color:#cbd5e1!important;margin-bottom:0!important}::ng-deep .login-form-container .field-input-wrapper{border-radius:12px!important;border:1px solid rgba(255,255,255,.08)!important;background:#ffffff0a!important;transition:all .3s!important;overflow:hidden;box-shadow:none!important}::ng-deep .login-form-container .field-input-wrapper:focus-within{border-color:var(--app-primary, #6366f1)!important;background:#ffffff0f!important;box-shadow:0 0 20px var(--app-glow, rgba(99,102,241,.3))!important}::ng-deep .login-form-container .field-input{padding:13px 16px!important;border:none!important;background:transparent!important;font-size:1rem!important;color:#f1f5f9!important}::ng-deep .login-form-container .field-input::placeholder{color:#64748b!important}::ng-deep .login-form-container .pwd-toggle-btn{color:#64748b!important}::ng-deep .login-form-container .pwd-toggle-btn:hover{color:var(--app-primary, #6366f1)!important}.form-options{display:flex;align-items:center;justify-content:space-between;font-size:.875rem}.remember-me{display:flex;align-items:center;gap:8px;cursor:pointer;color:#94a3b8}.remember-me input{display:none}.custom-check{width:16px;height:16px;border-radius:4px;border:1px solid rgba(255,255,255,.15);background:#ffffff0a;position:relative;transition:all .2s}.remember-me input:checked+.custom-check{background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));border-color:transparent}.remember-me input:checked+.custom-check:after{content:\"\";position:absolute;left:5px;top:2px;width:4px;height:7px;border:solid white;border-width:0 2px 2px 0;transform:rotate(45deg)}.forgot-link{color:var(--app-primary, #6366f1);font-weight:500;transition:all .2s;text-decoration:none}.forgot-link:hover{text-shadow:0 0 12px var(--app-glow, rgba(99,102,241,.3))}.login-btn{background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));color:#fff;padding:14px;border:none;border-radius:12px;font-size:1rem;font-weight:600;cursor:pointer;transition:all .3s;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden}.login-btn:hover{transform:translateY(-2px);box-shadow:0 10px 30px -5px var(--app-glow, rgba(99,102,241,.5))}.login-btn:disabled{opacity:.7;cursor:not-allowed;transform:none}.auth-footer-note{text-align:center;margin-top:32px;font-size:.875rem;color:#64748b}.auth-footer-note a{color:var(--app-primary, #6366f1);font-weight:600;text-decoration:none}.loader{width:20px;height:20px;border:3px solid rgba(255,255,255,.2);border-top:3px solid white;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
|
|
178
|
+
}], ctorParameters: () => [{ type: i1.Router }] });
|
|
179
|
+
|
|
180
|
+
export { LoginComponent };
|
|
181
|
+
//# sourceMappingURL=avora-labs-meta-forge-login.page-etTr5NqJ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avora-labs-meta-forge-login.page-etTr5NqJ.mjs","sources":["../../../projects/avora-meta-forge/src/lib/avora-meta-forge/pages/auth/login.page.ts"],"sourcesContent":["import { Component, inject, signal } from '@angular/core';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { Router, RouterModule } from '@angular/router';\r\nimport { AuthService } from '../../../core/auth/auth.service';\r\nimport { ActionDispatcherService } from '../../core/action-dispatcher.service';\r\nimport { AmfAuthShellComponent } from '../../renderers/auth/amf-auth-shell.component';\r\nimport { FormRendererComponent } from '../../renderers/form/form-renderer.component';\r\nimport { FormMeta } from '../../models/meta.types';\r\nimport { APP_META_CONFIG_TOKEN } from '../../avora-meta-forge.provider';\r\n@Component({\r\n selector: 'amf-login',\r\n standalone: true,\r\n imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent],\r\n template: `\r\n <amf-auth-shell \r\n [brandName]=\"meta.auth?.builtInUI?.brandName || meta.app.name\" \r\n [brandTagline]=\"meta.auth?.builtInUI?.brandTagline || 'Sign in to your account'\">\r\n \r\n <div class=\"login-form-container\">\r\n <!-- AMF Data-Driven Form Definition -->\r\n <amf-form-renderer \r\n #renderer\r\n [config]=\"loginForm\" \r\n (formSubmit)=\"onFormSubmit($event)\">\r\n </amf-form-renderer>\r\n\r\n <!-- Custom Inline Options Row -->\r\n <div class=\"form-options\">\r\n <label class=\"remember-me\">\r\n <input type=\"checkbox\" name=\"remember\" [(ngModel)]=\"rememberMe\">\r\n <span class=\"custom-check\"></span>\r\n <span>Remember me</span>\r\n </label>\r\n <a routerLink=\"/forgot-password\" class=\"forgot-link\">Forgot password?</a>\r\n </div>\r\n\r\n <button type=\"button\" class=\"login-btn\" (click)=\"triggerSubmit()\" [disabled]=\"loading()\">\r\n @if (!loading()) {\r\n <span>Sign In</span>\r\n } @else {\r\n <div class=\"loader\"></div>\r\n }\r\n </button>\r\n </div>\r\n\r\n <div class=\"auth-footer-note\">\r\n Don't have an account? <a routerLink=\"/contact-support\">Contact Support</a>\r\n </div>\r\n </amf-auth-shell>\r\n `,\r\n styles: [`\r\n :host { display: block; height: 100%; }\r\n\r\n .login-form-container {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 24px;\r\n }\r\n\r\n /* ── Map AMF Form classes to exactly match input-glass style ── */\r\n ::ng-deep .login-form-container .amf-form {\r\n gap: 24px;\r\n }\r\n ::ng-deep .login-form-container .amf-form-fields {\r\n gap: 24px;\r\n }\r\n ::ng-deep .login-form-container .amf-field {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n }\r\n ::ng-deep .login-form-container .field-label {\r\n font-size: 0.875rem !important;\r\n font-weight: 600 !important;\r\n color: #cbd5e1 !important;\r\n margin-bottom: 0 !important;\r\n }\r\n ::ng-deep .login-form-container .field-input-wrapper {\r\n border-radius: 12px !important;\r\n border: 1px solid rgba(255, 255, 255, 0.08) !important;\r\n background: rgba(255, 255, 255, 0.04) !important;\r\n transition: all 0.3s !important;\r\n overflow: hidden;\r\n box-shadow: none !important;\r\n }\r\n ::ng-deep .login-form-container .field-input-wrapper:focus-within {\r\n border-color: var(--app-primary, #6366f1) !important;\r\n background: rgba(255, 255, 255, 0.06) !important;\r\n box-shadow: 0 0 20px var(--app-glow, rgba(99,102,241,0.3)) !important;\r\n }\r\n ::ng-deep .login-form-container .field-input {\r\n padding: 13px 16px !important;\r\n border: none !important;\r\n background: transparent !important;\r\n font-size: 1rem !important;\r\n color: #f1f5f9 !important;\r\n }\r\n ::ng-deep .login-form-container .field-input::placeholder {\r\n color: #64748b !important;\r\n }\r\n /* Adjust password eye toggle specifically for this glass look */\r\n ::ng-deep .login-form-container .pwd-toggle-btn {\r\n color: #64748b !important;\r\n }\r\n ::ng-deep .login-form-container .pwd-toggle-btn:hover {\r\n color: var(--app-primary, #6366f1) !important;\r\n }\r\n\r\n .form-options {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n font-size: 0.875rem;\r\n }\r\n\r\n .remember-me {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n cursor: pointer;\r\n color: #94a3b8;\r\n }\r\n\r\n .remember-me input { display: none; }\r\n\r\n .custom-check {\r\n width: 16px;\r\n height: 16px;\r\n border-radius: 4px;\r\n border: 1px solid rgba(255,255,255,0.15);\r\n background: rgba(255,255,255,0.04);\r\n position: relative;\r\n transition: all 0.2s;\r\n }\r\n\r\n .remember-me input:checked + .custom-check {\r\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\r\n border-color: transparent;\r\n }\r\n\r\n .remember-me input:checked + .custom-check::after {\r\n content: '';\r\n position: absolute;\r\n left: 5px; top: 2px;\r\n width: 4px; height: 7px;\r\n border: solid white;\r\n border-width: 0 2px 2px 0;\r\n transform: rotate(45deg);\r\n }\r\n\r\n .forgot-link {\r\n color: var(--app-primary, #6366f1);\r\n font-weight: 500;\r\n transition: all 0.2s;\r\n text-decoration: none;\r\n }\r\n\r\n .forgot-link:hover {\r\n text-shadow: 0 0 12px var(--app-glow, rgba(99,102,241,0.3));\r\n }\r\n\r\n .login-btn {\r\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\r\n color: white;\r\n padding: 14px;\r\n border: none;\r\n border-radius: 12px;\r\n font-size: 1rem;\r\n font-weight: 600;\r\n cursor: pointer;\r\n transition: all 0.3s;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n position: relative;\r\n overflow: hidden;\r\n }\r\n\r\n .login-btn:hover {\r\n transform: translateY(-2px);\r\n box-shadow: 0 10px 30px -5px var(--app-glow, rgba(99,102,241,0.5));\r\n }\r\n\r\n .login-btn:disabled {\r\n opacity: 0.7;\r\n cursor: not-allowed;\r\n transform: none;\r\n }\r\n\r\n .auth-footer-note {\r\n text-align: center;\r\n margin-top: 32px;\r\n font-size: 0.875rem;\r\n color: #64748b;\r\n }\r\n\r\n .auth-footer-note a {\r\n color: var(--app-primary, #6366f1);\r\n font-weight: 600;\r\n text-decoration: none;\r\n }\r\n\r\n .loader {\r\n width: 20px;\r\n height: 20px;\r\n border: 3px solid rgba(255,255,255,0.2);\r\n border-top: 3px solid white;\r\n border-radius: 50%;\r\n animation: spin 0.8s linear infinite;\r\n }\r\n\r\n @keyframes spin {\r\n 0% { transform: rotate(0deg); }\r\n 100% { transform: rotate(360deg); }\r\n }\r\n `]\r\n})\r\nexport class LoginComponent {\r\n private auth = inject(AuthService);\r\n private dispatcher = inject(ActionDispatcherService);\r\n protected meta: any = inject(APP_META_CONFIG_TOKEN, { optional: true }) || { app: { name: 'AvoraMetaForge' } };\r\n\r\n loading = signal(false);\r\n rememberMe = false;\r\n\r\n // JSON Meta Definition replacing the hardcoded HTML fields\r\n loginForm: FormMeta = {\r\n id: 'loginForm',\r\n hideSubmit: true, // We provide our own exact-match custom button below\r\n fields: [\r\n {\r\n key: 'email',\r\n type: 'email',\r\n label: 'Email Address',\r\n placeholder: 'name@company.com',\r\n validators: [{ type: 'required' }]\r\n },\r\n {\r\n key: 'password',\r\n type: 'password',\r\n label: 'Password',\r\n placeholder: '••••••••',\r\n validators: [{ type: 'required' }]\r\n }\r\n ]\r\n };\r\n\r\n constructor(private router: Router) { }\r\n\r\n triggerSubmit(): void {\r\n // Dispatches standard AMF action to submit the specific form\r\n this.dispatcher.dispatch({\r\n type: 'submit-form',\r\n config: { formId: 'loginForm' }\r\n });\r\n }\r\n\r\n onFormSubmit(values: any): void {\r\n if (!values.email || !values.password) return;\r\n\r\n this.loading.set(true);\r\n\r\n setTimeout(() => {\r\n this.loading.set(false);\r\n \r\n this.dispatcher.dispatch({\r\n type: 'open-modal',\r\n config: {\r\n title: 'Two-Step Verification',\r\n size: 'sm',\r\n content: {\r\n type: 'form',\r\n config: {\r\n fields: [\r\n {\r\n name: 'otp',\r\n label: 'Enter 6-digit PIN',\r\n type: 'otp',\r\n required: true,\r\n otpLength: 6,\r\n validation: { minLength: 6, maxLength: 6 }\r\n }\r\n ],\r\n submitLabel: 'Verify & Login',\r\n loadingLabel: 'Verifying...',\r\n onSubmit: {\r\n type: 'api',\r\n config: { endpointId: 'mock-login-otp', body: 'formValue' },\r\n then: {\r\n type: 'dispatch-multiple',\r\n config: {\r\n mode: 'parallel',\r\n actions: [\r\n { type: 'notify', config: { type: 'success', message: 'OTP Verified! Redirecting...' } },\r\n { type: 'close-modal' },\r\n { \r\n type: 'delay', \r\n config: { duration: 600 }, \r\n then: { type: 'navigate', config: { path: '/dashboard' } } \r\n }\r\n ]\r\n }\r\n },\r\n onError: { type: 'notify', config: { type: 'error', message: 'Invalid Verification Code' } }\r\n }\r\n }\r\n }\r\n }\r\n });\r\n }, 1200);\r\n }\r\n}\r\n"],"names":["i2"],"mappings":"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"}
|