@tsparticles/template-login 4.1.3 → 4.2.1

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 (69) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +3 -0
  3. package/package.json +4 -3
  4. package/template/angular/package.json +34 -0
  5. package/template/angular/src/app/app.component.css +151 -0
  6. package/template/angular/src/app/app.component.html +32 -0
  7. package/template/angular/src/app/app.component.ts +105 -0
  8. package/template/angular/src/app/app.module.ts +13 -0
  9. package/template/angular-confetti/package.json +36 -0
  10. package/template/angular-confetti/src/app/app.component.css +151 -0
  11. package/template/angular-confetti/src/app/app.component.html +32 -0
  12. package/template/angular-confetti/src/app/app.component.ts +105 -0
  13. package/template/angular-confetti/src/app/app.module.ts +13 -0
  14. package/template/angular-fireworks/package.json +36 -0
  15. package/template/angular-fireworks/src/app/app.component.css +151 -0
  16. package/template/angular-fireworks/src/app/app.component.html +32 -0
  17. package/template/angular-fireworks/src/app/app.component.ts +105 -0
  18. package/template/angular-fireworks/src/app/app.module.ts +13 -0
  19. package/template/astro/package.json +22 -0
  20. package/template/astro/src/pages/index.astro +173 -0
  21. package/template/ember/app/templates/application.hbs +61 -0
  22. package/template/ember/package.json +42 -0
  23. package/template/inferno/package.json +24 -0
  24. package/template/inferno/src/App.css +151 -0
  25. package/template/inferno/src/App.tsx +158 -0
  26. package/template/jquery/package.json +22 -0
  27. package/template/jquery/src/main.ts +110 -0
  28. package/template/jquery/src/style.css +151 -0
  29. package/template/lit/package.json +22 -0
  30. package/template/lit/src/my-app.ts +143 -0
  31. package/template/nextjs/package.json +25 -0
  32. package/template/nextjs/src/app/page.tsx +168 -0
  33. package/template/nextjs/src/app/providers.tsx +13 -0
  34. package/template/nuxt2/package.json +17 -0
  35. package/template/nuxt2/pages/index.vue +303 -0
  36. package/template/nuxt3/app.vue +288 -0
  37. package/template/nuxt3/package.json +21 -0
  38. package/template/nuxt4/app.vue +288 -0
  39. package/template/nuxt4/package.json +21 -0
  40. package/template/preact/package.json +23 -0
  41. package/template/preact/src/App.css +151 -0
  42. package/template/preact/src/App.tsx +140 -0
  43. package/template/qwik/package.json +22 -0
  44. package/template/qwik/src/App.tsx +139 -0
  45. package/template/react/package.json +19 -0
  46. package/template/react/src/App.css +151 -0
  47. package/template/react/src/App.tsx +140 -0
  48. package/template/riot/package.json +24 -0
  49. package/template/riot/src/app.riot +156 -0
  50. package/template/solid/package.json +18 -0
  51. package/template/solid/src/App.tsx +169 -0
  52. package/template/solid/src/index.css +151 -0
  53. package/template/solid/src/main.tsx +9 -0
  54. package/template/stencil/package.json +20 -0
  55. package/template/stencil/src/components/app-home/app-home.tsx +164 -0
  56. package/template/svelte/package.json +20 -0
  57. package/template/svelte/src/App.svelte +325 -0
  58. package/template/svelte/src/main.ts +12 -0
  59. package/template/vanilla/LICENSE +21 -0
  60. package/template/vanilla/package.json +1 -1
  61. package/template/vanilla/src/main.ts +1 -1
  62. package/template/vue2/package.json +24 -0
  63. package/template/vue2/src/App.vue +287 -0
  64. package/template/vue3/package.json +19 -0
  65. package/template/vue3/src/App.vue +286 -0
  66. package/template/vue3/src/main.ts +14 -0
  67. package/template/webcomponents/package.json +21 -0
  68. package/template/webcomponents/src/main.ts +125 -0
  69. package/template/webcomponents/src/style.css +151 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18)
7
+
8
+ ### Bug Fixes
9
+
10
+ - fixed some various issues ([8534979](https://github.com/tsparticles/tsparticles/commit/85349791a4978f80f98f141a94a403a7e15785c0))
11
+
12
+ # [4.2.0](https://github.com/tsparticles/tsparticles/compare/v4.1.3...v4.2.0) (2026-06-17)
13
+
14
+ ### Features
15
+
16
+ - adding templates to cli create ([bc118ef](https://github.com/tsparticles/tsparticles/commit/bc118efa3f40497f9fa84186ac6102411a19fda7))
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @tsparticles/template-login
2
+
3
+ tsParticles login page template. Use with `create-tsparticles-app` to scaffold a new login page project with animated particle background.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsparticles/template-login",
3
- "version": "4.1.3",
3
+ "version": "4.2.1",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -8,7 +8,8 @@
8
8
  "scripts": {
9
9
  "prebuild": "node scripts/prebuild.js",
10
10
  "build": "pnpm run prebuild",
11
- "build:ci": "pnpm run prebuild"
11
+ "build:ci": "pnpm run prebuild",
12
+ "version": "pnpm run build && git add template.json"
12
13
  },
13
- "gitHead": "0551736c55ae8eec3855a693af8a99b1b4420350"
14
+ "gitHead": "e2a7699c1f4212bbda4e6933970c062e6fc000dc"
14
15
  }
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "{{packageName}}",
3
+ "private": true,
4
+ "version": "1.0.0",
5
+ "scripts": {
6
+ "ng": "ng",
7
+ "start": "ng serve",
8
+ "dev": "ng serve",
9
+ "build": "ng build",
10
+ "preview": "ng serve",
11
+ "watch": "ng build --watch --configuration development"
12
+ },
13
+ "dependencies": {
14
+ "@angular/animations": "~22.0.0",
15
+ "@angular/common": "~22.0.0",
16
+ "@angular/compiler": "~22.0.0",
17
+ "@angular/core": "~22.0.0",
18
+ "@angular/forms": "~22.0.0",
19
+ "@angular/platform-browser": "~22.0.0",
20
+ "@angular/platform-browser-dynamic": "~22.0.0",
21
+ "@angular/router": "~22.0.0",
22
+ "@tsparticles/angular": "^4.1.3",
23
+ "@tsparticles/slim": "^4.0.0",
24
+ "rxjs": "~7.8.2",
25
+ "tslib": "^2.8.1",
26
+ "zone.js": "~0.16.2"
27
+ },
28
+ "devDependencies": {
29
+ "@angular-devkit/build-angular": "~22.0.0",
30
+ "@angular/cli": "~22.0.0",
31
+ "@angular/compiler-cli": "~22.0.0",
32
+ "typescript": "~6.0.3"
33
+ }
34
+ }
@@ -0,0 +1,151 @@
1
+ :root {
2
+ --bg: #0f0f1a;
3
+ --card-bg: rgba(255, 255, 255, 0.05);
4
+ --text: #fff;
5
+ --border: rgba(255, 255, 255, 0.1);
6
+ --input-bg: rgba(255, 255, 255, 0.08);
7
+ --accent: #6c5ce7;
8
+ --accent-hover: #a29bfe;
9
+ --error: #e74c3c;
10
+ }
11
+
12
+ [data-theme="light"] {
13
+ --bg: #f0f0f5;
14
+ --card-bg: rgba(255, 255, 255, 0.8);
15
+ --text: #1a1a2e;
16
+ --border: rgba(0, 0, 0, 0.1);
17
+ --input-bg: rgba(0, 0, 0, 0.05);
18
+ }
19
+
20
+ * {
21
+ box-sizing: border-box;
22
+ }
23
+
24
+ body {
25
+ margin: 0;
26
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
27
+ background: var(--bg);
28
+ color: var(--text);
29
+ transition: background 0.3s, color 0.3s;
30
+ }
31
+
32
+ .auth-container {
33
+ position: absolute;
34
+ top: 50%;
35
+ left: 50%;
36
+ transform: translate(-50%, -50%);
37
+ z-index: 10;
38
+ width: 100%;
39
+ max-width: 400px;
40
+ padding: 1rem;
41
+ }
42
+
43
+ .auth-card {
44
+ background: var(--card-bg);
45
+ backdrop-filter: blur(10px);
46
+ border: 1px solid var(--border);
47
+ border-radius: 16px;
48
+ padding: 2rem;
49
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
50
+ }
51
+
52
+ .auth-header {
53
+ display: flex;
54
+ justify-content: space-between;
55
+ align-items: center;
56
+ margin-bottom: 1.5rem;
57
+ }
58
+
59
+ .auth-header h1 {
60
+ margin: 0;
61
+ font-size: 1.8em;
62
+ }
63
+
64
+ .theme-btn {
65
+ background: none;
66
+ border: 1px solid var(--border);
67
+ border-radius: 8px;
68
+ padding: 0.4em 0.6em;
69
+ font-size: 1.2em;
70
+ cursor: pointer;
71
+ transition: background 0.2s;
72
+ }
73
+
74
+ .theme-btn:hover {
75
+ background: var(--input-bg);
76
+ }
77
+
78
+ .form-group {
79
+ margin-bottom: 1rem;
80
+ }
81
+
82
+ label {
83
+ display: block;
84
+ margin-bottom: 0.3em;
85
+ font-size: 0.9em;
86
+ opacity: 0.8;
87
+ }
88
+
89
+ input {
90
+ width: 100%;
91
+ padding: 0.7em 1em;
92
+ font-size: 1em;
93
+ border: 1px solid var(--border);
94
+ border-radius: 8px;
95
+ background: var(--input-bg);
96
+ color: var(--text);
97
+ outline: none;
98
+ transition: border-color 0.2s;
99
+ }
100
+
101
+ input:focus {
102
+ border-color: var(--accent);
103
+ }
104
+
105
+ input::placeholder {
106
+ color: var(--text);
107
+ opacity: 0.4;
108
+ }
109
+
110
+ .error {
111
+ display: block;
112
+ margin-top: 0.3em;
113
+ font-size: 0.8em;
114
+ color: var(--error);
115
+ min-height: 1em;
116
+ }
117
+
118
+ button[type="submit"] {
119
+ width: 100%;
120
+ padding: 0.8em;
121
+ font-size: 1em;
122
+ font-weight: 600;
123
+ border: none;
124
+ border-radius: 8px;
125
+ background: var(--accent);
126
+ color: #fff;
127
+ cursor: pointer;
128
+ transition: background 0.2s;
129
+ margin-top: 0.5rem;
130
+ }
131
+
132
+ button[type="submit"]:hover {
133
+ background: var(--accent-hover);
134
+ }
135
+
136
+ .toggle-text {
137
+ text-align: center;
138
+ margin-top: 1.5rem;
139
+ font-size: 0.9em;
140
+ opacity: 0.7;
141
+ }
142
+
143
+ .toggle-text a {
144
+ color: var(--accent);
145
+ text-decoration: none;
146
+ margin-left: 0.3em;
147
+ }
148
+
149
+ .toggle-text a:hover {
150
+ text-decoration: underline;
151
+ }
@@ -0,0 +1,32 @@
1
+ <ngx-particles id="tsparticles" [options]="options" />
2
+
3
+ <div class="auth-container">
4
+ <div class="auth-card">
5
+ <div class="auth-header">
6
+ <h1>{{ isLogin ? 'Login' : 'Register' }}</h1>
7
+ <button class="theme-btn" (click)="toggleTheme()" aria-label="Toggle theme">{{ theme === 'dark' ? '🌙' : '☀️' }}</button>
8
+ </div>
9
+ <form (ngSubmit)="onSubmit()" novalidate>
10
+ <div class="form-group">
11
+ <label for="email">Email</label>
12
+ <input id="email" type="email" [(ngModel)]="email" name="email" placeholder="you@example.com" required />
13
+ <span class="error">{{ emailErr }}</span>
14
+ </div>
15
+ <div class="form-group">
16
+ <label for="password">Password</label>
17
+ <input id="password" type="password" [(ngModel)]="password" name="password" placeholder="Enter password" required />
18
+ <span class="error">{{ passErr }}</span>
19
+ </div>
20
+ <div class="form-group" *ngIf="!isLogin">
21
+ <label for="confirmPassword">Confirm Password</label>
22
+ <input id="confirmPassword" type="password" [(ngModel)]="confirm" name="confirmPassword" placeholder="Confirm password" />
23
+ <span class="error">{{ confirmErr }}</span>
24
+ </div>
25
+ <button type="submit">{{ isLogin ? 'Sign In' : 'Create Account' }}</button>
26
+ </form>
27
+ <p class="toggle-text">
28
+ <span>{{ isLogin ? "Don't have an account?" : 'Already have an account?' }}</span>
29
+ <a href="#" (click)="toggleMode($event)">{{ isLogin ? 'Register' : 'Login' }}</a>
30
+ </p>
31
+ </div>
32
+ </div>
@@ -0,0 +1,105 @@
1
+ import { Component, OnInit } from "@angular/core";
2
+ import { NgParticlesService } from "@tsparticles/angular";
3
+ import { loadSlim } from "@tsparticles/slim";
4
+ import type { ISourceOptions } from "@tsparticles/engine";
5
+
6
+ @Component({
7
+ selector: "app-root",
8
+ templateUrl: "./app.component.html",
9
+ styleUrls: ["./app.component.css"],
10
+ })
11
+ export class AppComponent implements OnInit {
12
+ isLogin = true;
13
+ theme = localStorage.getItem("theme") || "dark";
14
+ email = "";
15
+ password = "";
16
+ confirm = "";
17
+ emailErr = "";
18
+ passErr = "";
19
+ confirmErr = "";
20
+
21
+ constructor(private readonly ngParticlesService: NgParticlesService) {}
22
+
23
+ options: ISourceOptions = {
24
+ background: { color: { value: "transparent" } },
25
+ fpsLimit: 60,
26
+ particles: {
27
+ number: { value: 60, density: { enable: true } },
28
+ color: { value: ["#6c5ce7", "#a29bfe", "#fd79a8", "#00cec9"] },
29
+ shape: { type: "circle" },
30
+ opacity: { value: 0.5, random: true },
31
+ size: { value: { min: 1, max: 3 }, random: true },
32
+ move: { enable: true, speed: 1, direction: "none", random: true, straight: false, outModes: { default: "out" } },
33
+ },
34
+ interactivity: {
35
+ events: { onHover: { enable: true, mode: "bubble" } },
36
+ modes: { bubble: { distance: 200, size: 6, duration: 2, opacity: 0.8 } },
37
+ },
38
+ detectRetina: true,
39
+ };
40
+
41
+ ngOnInit(): void {
42
+ document.documentElement.setAttribute("data-theme", this.theme);
43
+ void this.ngParticlesService.init(async (engine) => {
44
+ await loadSlim(engine);
45
+ });
46
+ }
47
+
48
+ toggleTheme(): void {
49
+ this.theme = this.theme === "dark" ? "light" : "dark";
50
+ document.documentElement.setAttribute("data-theme", this.theme);
51
+ localStorage.setItem("theme", this.theme);
52
+ }
53
+
54
+ private validateEmail(val: string): boolean {
55
+ return /^[^\s@]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+$/.test(val);
56
+ }
57
+
58
+ onSubmit(): void {
59
+ let valid = true;
60
+
61
+ if (!this.email || !this.validateEmail(this.email)) {
62
+ this.emailErr = "Please enter a valid email address";
63
+ valid = false;
64
+ } else {
65
+ this.emailErr = "";
66
+ }
67
+
68
+ if (!this.password || this.password.length < 6) {
69
+ this.passErr = "Password must be at least 6 characters";
70
+ valid = false;
71
+ } else {
72
+ this.passErr = "";
73
+ }
74
+
75
+ if (!this.isLogin) {
76
+ if (this.password !== this.confirm) {
77
+ this.confirmErr = "Passwords do not match";
78
+ valid = false;
79
+ } else {
80
+ this.confirmErr = "";
81
+ }
82
+ }
83
+
84
+ if (!valid) return;
85
+
86
+ if (this.isLogin) {
87
+ alert("Logged in successfully! (demo)");
88
+ } else {
89
+ alert("Account created successfully! (demo)");
90
+ this.isLogin = true;
91
+ }
92
+
93
+ this.email = "";
94
+ this.password = "";
95
+ this.confirm = "";
96
+ }
97
+
98
+ toggleMode(event: Event): void {
99
+ event.preventDefault();
100
+ this.isLogin = !this.isLogin;
101
+ this.emailErr = "";
102
+ this.passErr = "";
103
+ this.confirmErr = "";
104
+ }
105
+ }
@@ -0,0 +1,13 @@
1
+ import { NgModule } from "@angular/core";
2
+ import { BrowserModule } from "@angular/platform-browser";
3
+ import { FormsModule } from "@angular/forms";
4
+ import { NgxParticlesModule } from "@tsparticles/angular";
5
+ import { AppComponent } from "./app.component";
6
+
7
+ @NgModule({
8
+ declarations: [AppComponent],
9
+ imports: [BrowserModule, FormsModule, NgxParticlesModule],
10
+ providers: [],
11
+ bootstrap: [AppComponent],
12
+ })
13
+ export class AppModule {}
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "{{packageName}}",
3
+ "private": true,
4
+ "version": "1.0.0",
5
+ "scripts": {
6
+ "ng": "ng",
7
+ "start": "ng serve",
8
+ "dev": "ng serve",
9
+ "build": "ng build",
10
+ "preview": "ng serve",
11
+ "watch": "ng build --watch --configuration development"
12
+ },
13
+ "dependencies": {
14
+ "@angular/animations": "~22.0.0",
15
+ "@angular/common": "~22.0.0",
16
+ "@angular/compiler": "~22.0.0",
17
+ "@angular/core": "~22.0.0",
18
+ "@angular/forms": "~22.0.0",
19
+ "@angular/platform-browser": "~22.0.0",
20
+ "@angular/platform-browser-dynamic": "~22.0.0",
21
+ "@angular/router": "~22.0.0",
22
+ "angular-confetti": "^4.1.3",
23
+ "@tsparticles/slim": "^4.1.3",
24
+ "@tsparticles/configs": "^4.1.3",
25
+ "@tsparticles/engine": "^4.1.3",
26
+ "rxjs": "~7.8.2",
27
+ "tslib": "^2.8.1",
28
+ "zone.js": "~0.16.2"
29
+ },
30
+ "devDependencies": {
31
+ "@angular-devkit/build-angular": "~22.0.0",
32
+ "@angular/cli": "~22.0.0",
33
+ "@angular/compiler-cli": "~22.0.0",
34
+ "typescript": "~6.0.3"
35
+ }
36
+ }
@@ -0,0 +1,151 @@
1
+ :root {
2
+ --bg: #0f0f1a;
3
+ --card-bg: rgba(255, 255, 255, 0.05);
4
+ --text: #fff;
5
+ --border: rgba(255, 255, 255, 0.1);
6
+ --input-bg: rgba(255, 255, 255, 0.08);
7
+ --accent: #6c5ce7;
8
+ --accent-hover: #a29bfe;
9
+ --error: #e74c3c;
10
+ }
11
+
12
+ [data-theme="light"] {
13
+ --bg: #f0f0f5;
14
+ --card-bg: rgba(255, 255, 255, 0.8);
15
+ --text: #1a1a2e;
16
+ --border: rgba(0, 0, 0, 0.1);
17
+ --input-bg: rgba(0, 0, 0, 0.05);
18
+ }
19
+
20
+ * {
21
+ box-sizing: border-box;
22
+ }
23
+
24
+ body {
25
+ margin: 0;
26
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
27
+ background: var(--bg);
28
+ color: var(--text);
29
+ transition: background 0.3s, color 0.3s;
30
+ }
31
+
32
+ .auth-container {
33
+ position: absolute;
34
+ top: 50%;
35
+ left: 50%;
36
+ transform: translate(-50%, -50%);
37
+ z-index: 10;
38
+ width: 100%;
39
+ max-width: 400px;
40
+ padding: 1rem;
41
+ }
42
+
43
+ .auth-card {
44
+ background: var(--card-bg);
45
+ backdrop-filter: blur(10px);
46
+ border: 1px solid var(--border);
47
+ border-radius: 16px;
48
+ padding: 2rem;
49
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
50
+ }
51
+
52
+ .auth-header {
53
+ display: flex;
54
+ justify-content: space-between;
55
+ align-items: center;
56
+ margin-bottom: 1.5rem;
57
+ }
58
+
59
+ .auth-header h1 {
60
+ margin: 0;
61
+ font-size: 1.8em;
62
+ }
63
+
64
+ .theme-btn {
65
+ background: none;
66
+ border: 1px solid var(--border);
67
+ border-radius: 8px;
68
+ padding: 0.4em 0.6em;
69
+ font-size: 1.2em;
70
+ cursor: pointer;
71
+ transition: background 0.2s;
72
+ }
73
+
74
+ .theme-btn:hover {
75
+ background: var(--input-bg);
76
+ }
77
+
78
+ .form-group {
79
+ margin-bottom: 1rem;
80
+ }
81
+
82
+ label {
83
+ display: block;
84
+ margin-bottom: 0.3em;
85
+ font-size: 0.9em;
86
+ opacity: 0.8;
87
+ }
88
+
89
+ input {
90
+ width: 100%;
91
+ padding: 0.7em 1em;
92
+ font-size: 1em;
93
+ border: 1px solid var(--border);
94
+ border-radius: 8px;
95
+ background: var(--input-bg);
96
+ color: var(--text);
97
+ outline: none;
98
+ transition: border-color 0.2s;
99
+ }
100
+
101
+ input:focus {
102
+ border-color: var(--accent);
103
+ }
104
+
105
+ input::placeholder {
106
+ color: var(--text);
107
+ opacity: 0.4;
108
+ }
109
+
110
+ .error {
111
+ display: block;
112
+ margin-top: 0.3em;
113
+ font-size: 0.8em;
114
+ color: var(--error);
115
+ min-height: 1em;
116
+ }
117
+
118
+ button[type="submit"] {
119
+ width: 100%;
120
+ padding: 0.8em;
121
+ font-size: 1em;
122
+ font-weight: 600;
123
+ border: none;
124
+ border-radius: 8px;
125
+ background: var(--accent);
126
+ color: #fff;
127
+ cursor: pointer;
128
+ transition: background 0.2s;
129
+ margin-top: 0.5rem;
130
+ }
131
+
132
+ button[type="submit"]:hover {
133
+ background: var(--accent-hover);
134
+ }
135
+
136
+ .toggle-text {
137
+ text-align: center;
138
+ margin-top: 1.5rem;
139
+ font-size: 0.9em;
140
+ opacity: 0.7;
141
+ }
142
+
143
+ .toggle-text a {
144
+ color: var(--accent);
145
+ text-decoration: none;
146
+ margin-left: 0.3em;
147
+ }
148
+
149
+ .toggle-text a:hover {
150
+ text-decoration: underline;
151
+ }
@@ -0,0 +1,32 @@
1
+ <ngx-confetti id="tsparticles" [options]="options" />
2
+
3
+ <div class="auth-container">
4
+ <div class="auth-card">
5
+ <div class="auth-header">
6
+ <h1>{{ isLogin ? 'Login' : 'Register' }}</h1>
7
+ <button class="theme-btn" (click)="toggleTheme()" aria-label="Toggle theme">{{ theme === 'dark' ? '🌙' : '☀️' }}</button>
8
+ </div>
9
+ <form (ngSubmit)="onSubmit()" novalidate>
10
+ <div class="form-group">
11
+ <label for="email">Email</label>
12
+ <input id="email" type="email" [(ngModel)]="email" name="email" placeholder="you@example.com" required />
13
+ <span class="error">{{ emailErr }}</span>
14
+ </div>
15
+ <div class="form-group">
16
+ <label for="password">Password</label>
17
+ <input id="password" type="password" [(ngModel)]="password" name="password" placeholder="Enter password" required />
18
+ <span class="error">{{ passErr }}</span>
19
+ </div>
20
+ <div class="form-group" *ngIf="!isLogin">
21
+ <label for="confirmPassword">Confirm Password</label>
22
+ <input id="confirmPassword" type="password" [(ngModel)]="confirm" name="confirmPassword" placeholder="Confirm password" />
23
+ <span class="error">{{ confirmErr }}</span>
24
+ </div>
25
+ <button type="submit">{{ isLogin ? 'Sign In' : 'Create Account' }}</button>
26
+ </form>
27
+ <p class="toggle-text">
28
+ <span>{{ isLogin ? "Don't have an account?" : 'Already have an account?' }}</span>
29
+ <a href="#" (click)="toggleMode($event)">{{ isLogin ? 'Register' : 'Login' }}</a>
30
+ </p>
31
+ </div>
32
+ </div>