@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
@@ -0,0 +1,303 @@
1
+ <template>
2
+ <div>
3
+ <Particles id="tsparticles" :options="options" />
4
+ <div class="auth-container">
5
+ <div class="auth-card">
6
+ <div class="auth-header">
7
+ <h1>{{ isLogin ? 'Login' : 'Register' }}</h1>
8
+ <button class="theme-btn" @click="toggleTheme" aria-label="Toggle theme">{{ theme === 'dark' ? '🌙' : '☀️' }}</button>
9
+ </div>
10
+ <form @submit="handleSubmit" novalidate>
11
+ <div class="form-group">
12
+ <label for="email">Email</label>
13
+ <input id="email" v-model="email" type="email" placeholder="you@example.com" required />
14
+ <span class="error">{{ emailErr }}</span>
15
+ </div>
16
+ <div class="form-group">
17
+ <label for="password">Password</label>
18
+ <input id="password" v-model="password" type="password" placeholder="Enter password" required />
19
+ <span class="error">{{ passErr }}</span>
20
+ </div>
21
+ <div v-if="!isLogin" class="form-group">
22
+ <label for="confirmPassword">Confirm Password</label>
23
+ <input id="confirmPassword" v-model="confirm" type="password" placeholder="Confirm password" />
24
+ <span class="error">{{ confirmErr }}</span>
25
+ </div>
26
+ <button type="submit">{{ isLogin ? 'Sign In' : 'Create Account' }}</button>
27
+ </form>
28
+ <p class="toggle-text">
29
+ <span>{{ isLogin ? "Don't have an account?" : 'Already have an account?' }}</span>
30
+ <a href="#" @click="toggleMode">{{ isLogin ? 'Register' : 'Login' }}</a>
31
+ </p>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </template>
36
+
37
+ <script>
38
+ import { loadSlim } from "@tsparticles/slim";
39
+
40
+ function validateEmail(val) {
41
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val);
42
+ }
43
+
44
+ export default {
45
+ name: "HomePage",
46
+ data() {
47
+ return {
48
+ isLogin: true,
49
+ theme: (typeof localStorage !== "undefined" ? localStorage.getItem("theme") : null) || "dark",
50
+ email: "",
51
+ password: "",
52
+ confirm: "",
53
+ emailErr: "",
54
+ passErr: "",
55
+ confirmErr: "",
56
+ options: {
57
+ background: { color: { value: "transparent" } },
58
+ fpsLimit: 60,
59
+ particles: {
60
+ number: { value: 60, density: { enable: true } },
61
+ color: { value: ["#6c5ce7", "#a29bfe", "#fd79a8", "#00cec9"] },
62
+ shape: { type: "circle" },
63
+ opacity: { value: 0.5, random: true },
64
+ size: { value: { min: 1, max: 3 }, random: true },
65
+ move: { enable: true, speed: 1, direction: "none", random: true, straight: false, outModes: { default: "out" } },
66
+ },
67
+ interactivity: {
68
+ events: { onHover: { enable: true, mode: "bubble" } },
69
+ modes: { bubble: { distance: 200, size: 6, duration: 2, opacity: 0.8 } },
70
+ },
71
+ detectRetina: true,
72
+ },
73
+ };
74
+ },
75
+ mounted() {
76
+ document.documentElement.setAttribute("data-theme", this.theme);
77
+ },
78
+ methods: {
79
+ toggleTheme() {
80
+ this.theme = this.theme === "dark" ? "light" : "dark";
81
+ document.documentElement.setAttribute("data-theme", this.theme);
82
+ localStorage.setItem("theme", this.theme);
83
+ },
84
+ handleSubmit(e) {
85
+ e.preventDefault();
86
+ let valid = true;
87
+
88
+ if (!this.email || !validateEmail(this.email)) {
89
+ this.emailErr = "Please enter a valid email address";
90
+ valid = false;
91
+ } else {
92
+ this.emailErr = "";
93
+ }
94
+
95
+ if (!this.password || this.password.length < 6) {
96
+ this.passErr = "Password must be at least 6 characters";
97
+ valid = false;
98
+ } else {
99
+ this.passErr = "";
100
+ }
101
+
102
+ if (!this.isLogin) {
103
+ if (this.password !== this.confirm) {
104
+ this.confirmErr = "Passwords do not match";
105
+ valid = false;
106
+ } else {
107
+ this.confirmErr = "";
108
+ }
109
+ }
110
+
111
+ if (!valid) return;
112
+
113
+ if (this.isLogin) {
114
+ alert("Logged in successfully! (demo)");
115
+ } else {
116
+ alert("Account created successfully! (demo)");
117
+ this.isLogin = true;
118
+ }
119
+
120
+ this.email = "";
121
+ this.password = "";
122
+ this.confirm = "";
123
+ },
124
+ toggleMode(e) {
125
+ e.preventDefault();
126
+ this.isLogin = !this.isLogin;
127
+ this.emailErr = "";
128
+ this.passErr = "";
129
+ this.confirmErr = "";
130
+ },
131
+ },
132
+ head() {
133
+ return {
134
+ script: [
135
+ {
136
+ innerHTML: `
137
+ (async function() {
138
+ const { loadSlim } = await import("@tsparticles/slim");
139
+ const { tsParticles } = await import("@tsparticles/engine");
140
+ await loadSlim(tsParticles);
141
+ })();
142
+ `,
143
+ },
144
+ ],
145
+ __dangerouslyDisableSanitizers: ["script"],
146
+ };
147
+ },
148
+ };
149
+ </script>
150
+
151
+ <style>
152
+ :root {
153
+ --bg: #0f0f1a;
154
+ --card-bg: rgba(255, 255, 255, 0.05);
155
+ --text: #fff;
156
+ --border: rgba(255, 255, 255, 0.1);
157
+ --input-bg: rgba(255, 255, 255, 0.08);
158
+ --accent: #6c5ce7;
159
+ --accent-hover: #a29bfe;
160
+ --error: #e74c3c;
161
+ }
162
+
163
+ [data-theme="light"] {
164
+ --bg: #f0f0f5;
165
+ --card-bg: rgba(255, 255, 255, 0.8);
166
+ --text: #1a1a2e;
167
+ --border: rgba(0, 0, 0, 0.1);
168
+ --input-bg: rgba(0, 0, 0, 0.05);
169
+ }
170
+
171
+ * {
172
+ box-sizing: border-box;
173
+ }
174
+
175
+ body {
176
+ margin: 0;
177
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
178
+ background: var(--bg);
179
+ color: var(--text);
180
+ transition: background 0.3s, color 0.3s;
181
+ }
182
+
183
+ .auth-container {
184
+ position: absolute;
185
+ top: 50%;
186
+ left: 50%;
187
+ transform: translate(-50%, -50%);
188
+ z-index: 10;
189
+ width: 100%;
190
+ max-width: 400px;
191
+ padding: 1rem;
192
+ }
193
+
194
+ .auth-card {
195
+ background: var(--card-bg);
196
+ backdrop-filter: blur(10px);
197
+ border: 1px solid var(--border);
198
+ border-radius: 16px;
199
+ padding: 2rem;
200
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
201
+ }
202
+
203
+ .auth-header {
204
+ display: flex;
205
+ justify-content: space-between;
206
+ align-items: center;
207
+ margin-bottom: 1.5rem;
208
+ }
209
+
210
+ .auth-header h1 {
211
+ margin: 0;
212
+ font-size: 1.8em;
213
+ }
214
+
215
+ .theme-btn {
216
+ background: none;
217
+ border: 1px solid var(--border);
218
+ border-radius: 8px;
219
+ padding: 0.4em 0.6em;
220
+ font-size: 1.2em;
221
+ cursor: pointer;
222
+ transition: background 0.2s;
223
+ }
224
+
225
+ .theme-btn:hover {
226
+ background: var(--input-bg);
227
+ }
228
+
229
+ .form-group {
230
+ margin-bottom: 1rem;
231
+ }
232
+
233
+ label {
234
+ display: block;
235
+ margin-bottom: 0.3em;
236
+ font-size: 0.9em;
237
+ opacity: 0.8;
238
+ }
239
+
240
+ input {
241
+ width: 100%;
242
+ padding: 0.7em 1em;
243
+ font-size: 1em;
244
+ border: 1px solid var(--border);
245
+ border-radius: 8px;
246
+ background: var(--input-bg);
247
+ color: var(--text);
248
+ outline: none;
249
+ transition: border-color 0.2s;
250
+ }
251
+
252
+ input:focus {
253
+ border-color: var(--accent);
254
+ }
255
+
256
+ input::placeholder {
257
+ color: var(--text);
258
+ opacity: 0.4;
259
+ }
260
+
261
+ .error {
262
+ display: block;
263
+ margin-top: 0.3em;
264
+ font-size: 0.8em;
265
+ color: var(--error);
266
+ min-height: 1em;
267
+ }
268
+
269
+ button[type="submit"] {
270
+ width: 100%;
271
+ padding: 0.8em;
272
+ font-size: 1em;
273
+ font-weight: 600;
274
+ border: none;
275
+ border-radius: 8px;
276
+ background: var(--accent);
277
+ color: #fff;
278
+ cursor: pointer;
279
+ transition: background 0.2s;
280
+ margin-top: 0.5rem;
281
+ }
282
+
283
+ button[type="submit"]:hover {
284
+ background: var(--accent-hover);
285
+ }
286
+
287
+ .toggle-text {
288
+ text-align: center;
289
+ margin-top: 1.5rem;
290
+ font-size: 0.9em;
291
+ opacity: 0.7;
292
+ }
293
+
294
+ .toggle-text a {
295
+ color: var(--accent);
296
+ text-decoration: none;
297
+ margin-left: 0.3em;
298
+ }
299
+
300
+ .toggle-text a:hover {
301
+ text-decoration: underline;
302
+ }
303
+ </style>
@@ -0,0 +1,288 @@
1
+ <template>
2
+ <div>
3
+ <Particles id="tsparticles" :options="options" />
4
+ <div class="auth-container">
5
+ <div class="auth-card">
6
+ <div class="auth-header">
7
+ <h1>{{ isLogin ? 'Login' : 'Register' }}</h1>
8
+ <button class="theme-btn" @click="toggleTheme" aria-label="Toggle theme">{{ theme === 'dark' ? '🌙' : '☀️' }}</button>
9
+ </div>
10
+ <form @submit="handleSubmit" novalidate>
11
+ <div class="form-group">
12
+ <label for="email">Email</label>
13
+ <input id="email" v-model="email" type="email" placeholder="you@example.com" required />
14
+ <span class="error">{{ emailErr }}</span>
15
+ </div>
16
+ <div class="form-group">
17
+ <label for="password">Password</label>
18
+ <input id="password" v-model="password" type="password" placeholder="Enter password" required />
19
+ <span class="error">{{ passErr }}</span>
20
+ </div>
21
+ <div v-if="!isLogin" class="form-group">
22
+ <label for="confirmPassword">Confirm Password</label>
23
+ <input id="confirmPassword" v-model="confirm" type="password" placeholder="Confirm password" />
24
+ <span class="error">{{ confirmErr }}</span>
25
+ </div>
26
+ <button type="submit">{{ isLogin ? 'Sign In' : 'Create Account' }}</button>
27
+ </form>
28
+ <p class="toggle-text">
29
+ <span>{{ isLogin ? "Don't have an account?" : 'Already have an account?' }}</span>
30
+ <a href="#" @click="toggleMode">{{ isLogin ? 'Register' : 'Login' }}</a>
31
+ </p>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </template>
36
+
37
+ <script setup lang="ts">
38
+ import { ref, onMounted } from "vue";
39
+ import { loadSlim } from "@tsparticles/slim";
40
+ import type { ISourceOptions } from "@tsparticles/engine";
41
+
42
+ const isLogin = ref(true);
43
+ const theme = ref("dark");
44
+ const email = ref("");
45
+ const password = ref("");
46
+ const confirm = ref("");
47
+ const emailErr = ref("");
48
+ const passErr = ref("");
49
+ const confirmErr = ref("");
50
+
51
+ const options: ISourceOptions = {
52
+ background: { color: { value: "transparent" } },
53
+ fpsLimit: 60,
54
+ particles: {
55
+ number: { value: 60, density: { enable: true } },
56
+ color: { value: ["#6c5ce7", "#a29bfe", "#fd79a8", "#00cec9"] },
57
+ shape: { type: "circle" },
58
+ opacity: { value: 0.5, random: true },
59
+ size: { value: { min: 1, max: 3 }, random: true },
60
+ move: { enable: true, speed: 1, direction: "none", random: true, straight: false, outModes: { default: "out" } },
61
+ },
62
+ interactivity: {
63
+ events: { onHover: { enable: true, mode: "bubble" } },
64
+ modes: { bubble: { distance: 200, size: 6, duration: 2, opacity: 0.8 } },
65
+ },
66
+ detectRetina: true,
67
+ };
68
+
69
+ onMounted(() => {
70
+ const saved = localStorage.getItem("theme") || "dark";
71
+ theme.value = saved;
72
+ document.documentElement.setAttribute("data-theme", saved);
73
+ });
74
+
75
+ function toggleTheme(): void {
76
+ const t = theme.value === "dark" ? "light" : "dark";
77
+ theme.value = t;
78
+ document.documentElement.setAttribute("data-theme", t);
79
+ localStorage.setItem("theme", t);
80
+ }
81
+
82
+ function validateEmail(val: string): boolean {
83
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val);
84
+ }
85
+
86
+ function handleSubmit(e: Event): void {
87
+ e.preventDefault();
88
+ let valid = true;
89
+
90
+ if (!email.value || !validateEmail(email.value)) {
91
+ emailErr.value = "Please enter a valid email address";
92
+ valid = false;
93
+ } else {
94
+ emailErr.value = "";
95
+ }
96
+
97
+ if (!password.value || password.value.length < 6) {
98
+ passErr.value = "Password must be at least 6 characters";
99
+ valid = false;
100
+ } else {
101
+ passErr.value = "";
102
+ }
103
+
104
+ if (!isLogin.value) {
105
+ if (password.value !== confirm.value) {
106
+ confirmErr.value = "Passwords do not match";
107
+ valid = false;
108
+ } else {
109
+ confirmErr.value = "";
110
+ }
111
+ }
112
+
113
+ if (!valid) return;
114
+
115
+ if (isLogin.value) {
116
+ alert("Logged in successfully! (demo)");
117
+ } else {
118
+ alert("Account created successfully! (demo)");
119
+ isLogin.value = true;
120
+ }
121
+
122
+ email.value = "";
123
+ password.value = "";
124
+ confirm.value = "";
125
+ }
126
+
127
+ function toggleMode(e: Event): void {
128
+ e.preventDefault();
129
+ isLogin.value = !isLogin.value;
130
+ emailErr.value = "";
131
+ passErr.value = "";
132
+ confirmErr.value = "";
133
+ }
134
+ </script>
135
+
136
+ <style>
137
+ :root {
138
+ --bg: #0f0f1a;
139
+ --card-bg: rgba(255, 255, 255, 0.05);
140
+ --text: #fff;
141
+ --border: rgba(255, 255, 255, 0.1);
142
+ --input-bg: rgba(255, 255, 255, 0.08);
143
+ --accent: #6c5ce7;
144
+ --accent-hover: #a29bfe;
145
+ --error: #e74c3c;
146
+ }
147
+
148
+ [data-theme="light"] {
149
+ --bg: #f0f0f5;
150
+ --card-bg: rgba(255, 255, 255, 0.8);
151
+ --text: #1a1a2e;
152
+ --border: rgba(0, 0, 0, 0.1);
153
+ --input-bg: rgba(0, 0, 0, 0.05);
154
+ }
155
+
156
+ * {
157
+ box-sizing: border-box;
158
+ }
159
+
160
+ body {
161
+ margin: 0;
162
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
163
+ background: var(--bg);
164
+ color: var(--text);
165
+ transition: background 0.3s, color 0.3s;
166
+ }
167
+
168
+ .auth-container {
169
+ position: absolute;
170
+ top: 50%;
171
+ left: 50%;
172
+ transform: translate(-50%, -50%);
173
+ z-index: 10;
174
+ width: 100%;
175
+ max-width: 400px;
176
+ padding: 1rem;
177
+ }
178
+
179
+ .auth-card {
180
+ background: var(--card-bg);
181
+ backdrop-filter: blur(10px);
182
+ border: 1px solid var(--border);
183
+ border-radius: 16px;
184
+ padding: 2rem;
185
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
186
+ }
187
+
188
+ .auth-header {
189
+ display: flex;
190
+ justify-content: space-between;
191
+ align-items: center;
192
+ margin-bottom: 1.5rem;
193
+ }
194
+
195
+ .auth-header h1 {
196
+ margin: 0;
197
+ font-size: 1.8em;
198
+ }
199
+
200
+ .theme-btn {
201
+ background: none;
202
+ border: 1px solid var(--border);
203
+ border-radius: 8px;
204
+ padding: 0.4em 0.6em;
205
+ font-size: 1.2em;
206
+ cursor: pointer;
207
+ transition: background 0.2s;
208
+ }
209
+
210
+ .theme-btn:hover {
211
+ background: var(--input-bg);
212
+ }
213
+
214
+ .form-group {
215
+ margin-bottom: 1rem;
216
+ }
217
+
218
+ label {
219
+ display: block;
220
+ margin-bottom: 0.3em;
221
+ font-size: 0.9em;
222
+ opacity: 0.8;
223
+ }
224
+
225
+ input {
226
+ width: 100%;
227
+ padding: 0.7em 1em;
228
+ font-size: 1em;
229
+ border: 1px solid var(--border);
230
+ border-radius: 8px;
231
+ background: var(--input-bg);
232
+ color: var(--text);
233
+ outline: none;
234
+ transition: border-color 0.2s;
235
+ }
236
+
237
+ input:focus {
238
+ border-color: var(--accent);
239
+ }
240
+
241
+ input::placeholder {
242
+ color: var(--text);
243
+ opacity: 0.4;
244
+ }
245
+
246
+ .error {
247
+ display: block;
248
+ margin-top: 0.3em;
249
+ font-size: 0.8em;
250
+ color: var(--error);
251
+ min-height: 1em;
252
+ }
253
+
254
+ button[type="submit"] {
255
+ width: 100%;
256
+ padding: 0.8em;
257
+ font-size: 1em;
258
+ font-weight: 600;
259
+ border: none;
260
+ border-radius: 8px;
261
+ background: var(--accent);
262
+ color: #fff;
263
+ cursor: pointer;
264
+ transition: background 0.2s;
265
+ margin-top: 0.5rem;
266
+ }
267
+
268
+ button[type="submit"]:hover {
269
+ background: var(--accent-hover);
270
+ }
271
+
272
+ .toggle-text {
273
+ text-align: center;
274
+ margin-top: 1.5rem;
275
+ font-size: 0.9em;
276
+ opacity: 0.7;
277
+ }
278
+
279
+ .toggle-text a {
280
+ color: var(--accent);
281
+ text-decoration: none;
282
+ margin-left: 0.3em;
283
+ }
284
+
285
+ .toggle-text a:hover {
286
+ text-decoration: underline;
287
+ }
288
+ </style>
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "{{packageName}}",
3
+ "private": true,
4
+ "version": "1.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "nuxt dev",
8
+ "build": "nuxt build",
9
+ "preview": "nuxt preview"
10
+ },
11
+ "dependencies": {
12
+ "nuxt": "^3.17.3",
13
+ "@tsparticles/nuxt3": "^4.1.3",
14
+ "@tsparticles/slim": "^4.1.3",
15
+ "@tsparticles/configs": "^4.1.3",
16
+ "@tsparticles/engine": "^4.1.3"
17
+ },
18
+ "devDependencies": {
19
+ "typescript": "^6.0.3"
20
+ }
21
+ }