@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,169 @@
1
+ import { createSignal, createEffect, onMount } from "solid-js";
2
+ import Particles, { initParticlesEngine } from "@tsparticles/solid";
3
+ import { loadSlim } from "@tsparticles/slim";
4
+ import type { ISourceOptions } from "@tsparticles/engine";
5
+
6
+ export default function App() {
7
+ const [isLogin, setIsLogin] = createSignal(true);
8
+ const [theme, setTheme] = createSignal(localStorage.getItem("theme") || "dark");
9
+ const [email, setEmail] = createSignal("");
10
+ const [password, setPassword] = createSignal("");
11
+ const [confirm, setConfirm] = createSignal("");
12
+ const [emailError, setEmailError] = createSignal("");
13
+ const [passwordError, setPasswordError] = createSignal("");
14
+ const [confirmError, setConfirmError] = createSignal("");
15
+
16
+ createEffect(() => {
17
+ document.documentElement.setAttribute("data-theme", theme());
18
+ });
19
+
20
+ onMount(() => {
21
+ void initParticlesEngine(async (engine) => {
22
+ await loadSlim(engine);
23
+ });
24
+ });
25
+
26
+ const options: ISourceOptions = {
27
+ background: { color: { value: "transparent" } },
28
+ fpsLimit: 60,
29
+ particles: {
30
+ number: { value: 60, density: { enable: true } },
31
+ color: { value: ["#6c5ce7", "#a29bfe", "#fd79a8", "#00cec9"] },
32
+ shape: { type: "circle" },
33
+ opacity: { value: 0.5, random: true },
34
+ size: { value: { min: 1, max: 3 }, random: true },
35
+ move: {
36
+ enable: true,
37
+ speed: 1,
38
+ direction: "none",
39
+ random: true,
40
+ straight: false,
41
+ outModes: { default: "out" },
42
+ },
43
+ },
44
+ interactivity: {
45
+ events: {
46
+ onHover: { enable: true, mode: "bubble" },
47
+ },
48
+ modes: {
49
+ bubble: { distance: 200, size: 6, duration: 2, opacity: 0.8 },
50
+ },
51
+ },
52
+ detectRetina: true,
53
+ };
54
+
55
+ function validateEmail(value: string): boolean {
56
+ return /^[^\s@]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+$/.test(value);
57
+ }
58
+
59
+ function handleSubmit(e: Event) {
60
+ e.preventDefault();
61
+ let valid = true;
62
+
63
+ if (!email() || !validateEmail(email())) {
64
+ setEmailError("Please enter a valid email address");
65
+ valid = false;
66
+ } else {
67
+ setEmailError("");
68
+ }
69
+
70
+ if (!password() || password().length < 6) {
71
+ setPasswordError("Password must be at least 6 characters");
72
+ valid = false;
73
+ } else {
74
+ setPasswordError("");
75
+ }
76
+
77
+ if (!isLogin() && password() !== confirm()) {
78
+ setConfirmError("Passwords do not match");
79
+ valid = false;
80
+ } else {
81
+ setConfirmError("");
82
+ }
83
+
84
+ if (!valid) return;
85
+
86
+ if (isLogin()) {
87
+ alert("Logged in successfully! (demo)");
88
+ } else {
89
+ alert("Account created successfully! (demo)");
90
+ setIsLogin(true);
91
+ }
92
+
93
+ setEmail("");
94
+ setPassword("");
95
+ setConfirm("");
96
+ }
97
+
98
+ function toggleMode() {
99
+ setIsLogin(!isLogin());
100
+ setEmailError("");
101
+ setPasswordError("");
102
+ setConfirmError("");
103
+ }
104
+
105
+ function toggleTheme() {
106
+ setTheme(theme() === "dark" ? "light" : "dark");
107
+ localStorage.setItem("theme", theme());
108
+ }
109
+
110
+ return (
111
+ <>
112
+ <div class="auth-container">
113
+ <div class="auth-card">
114
+ <div class="auth-header">
115
+ <h1>{isLogin() ? "Login" : "Register"}</h1>
116
+ <button class="theme-btn" onClick={toggleTheme} aria-label="Toggle theme">
117
+ {theme() === "dark" ? "🌙" : "☀️"}
118
+ </button>
119
+ </div>
120
+ <form onSubmit={handleSubmit} novalidate>
121
+ <div class="form-group">
122
+ <label for="email">Email</label>
123
+ <input
124
+ type="email"
125
+ id="email"
126
+ placeholder="you@example.com"
127
+ value={email()}
128
+ onInput={(e) => setEmail(e.currentTarget.value)}
129
+ required
130
+ />
131
+ <span class="error">{emailError()}</span>
132
+ </div>
133
+ <div class="form-group">
134
+ <label for="password">Password</label>
135
+ <input
136
+ type="password"
137
+ id="password"
138
+ placeholder="Enter password"
139
+ value={password()}
140
+ onInput={(e) => setPassword(e.currentTarget.value)}
141
+ required
142
+ />
143
+ <span class="error">{passwordError()}</span>
144
+ </div>
145
+ <div class="form-group" style={{ display: isLogin() ? "none" : "block" }}>
146
+ <label for="confirmPassword">Confirm Password</label>
147
+ <input
148
+ type="password"
149
+ id="confirmPassword"
150
+ placeholder="Confirm password"
151
+ value={confirm()}
152
+ onInput={(e) => setConfirm(e.currentTarget.value)}
153
+ />
154
+ <span class="error">{confirmError()}</span>
155
+ </div>
156
+ <button type="submit">{isLogin() ? "Sign In" : "Create Account"}</button>
157
+ </form>
158
+ <p class="toggle-text">
159
+ <span>{isLogin() ? "Don't have an account?" : "Already have an account?"}</span>
160
+ <a href="#" onClick={(e) => { e.preventDefault(); toggleMode(); }}>
161
+ {isLogin() ? "Register" : "Login"}
162
+ </a>
163
+ </p>
164
+ </div>
165
+ </div>
166
+ <Particles id="tsparticles" options={options} />
167
+ </>
168
+ );
169
+ }
@@ -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,9 @@
1
+ import "./index.css";
2
+ import { render } from "solid-js/web";
3
+ import App from "./App";
4
+
5
+ const root = document.getElementById("root");
6
+
7
+ if (root) {
8
+ render(() => <App />, root);
9
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "{{packageName}}",
3
+ "private": true,
4
+ "version": "1.0.0",
5
+ "scripts": {
6
+ "dev": "stencil build --dev --watch --serve",
7
+ "build": "stencil build",
8
+ "preview": "stencil build --serve"
9
+ },
10
+ "dependencies": {
11
+ "@stencil/core": "^4.43.5",
12
+ "@tsparticles/stencil": "^4.1.3",
13
+ "@tsparticles/slim": "^4.1.3",
14
+ "@tsparticles/configs": "^4.1.3",
15
+ "@tsparticles/engine": "^4.1.3"
16
+ },
17
+ "devDependencies": {
18
+ "typescript": "^6.0.3"
19
+ }
20
+ }
@@ -0,0 +1,164 @@
1
+ import { Component, State, h, type JSX } from "@stencil/core";
2
+ import { loadSlim } from "@tsparticles/slim";
3
+ import type { Engine, ISourceOptions } from "@tsparticles/engine";
4
+
5
+ const options: ISourceOptions = {
6
+ background: { color: { value: "transparent" } },
7
+ fpsLimit: 60,
8
+ particles: {
9
+ number: { value: 60, density: { enable: true } },
10
+ color: { value: ["#6c5ce7", "#a29bfe", "#fd79a8", "#00cec9"] },
11
+ shape: { type: "circle" },
12
+ opacity: { value: 0.5, random: true },
13
+ size: { value: { min: 1, max: 3 }, random: true },
14
+ move: { enable: true, speed: 1, direction: "none", random: true, straight: false, outModes: { default: "out" } },
15
+ },
16
+ interactivity: {
17
+ events: { onHover: { enable: true, mode: "bubble" } },
18
+ modes: { bubble: { distance: 200, size: 6, duration: 2, opacity: 0.8 } },
19
+ },
20
+ detectRetina: true,
21
+ };
22
+
23
+ function validateEmail(val: string): boolean {
24
+ return /^[^\s@]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+$/.test(val);
25
+ }
26
+
27
+ @Component({
28
+ tag: "app-home",
29
+ styleUrl: "app-home.css",
30
+ shadow: true,
31
+ })
32
+ export class AppHome {
33
+ @State() isLogin = true;
34
+ @State() theme = localStorage.getItem("theme") || "dark";
35
+ @State() email = "";
36
+ @State() password = "";
37
+ @State() confirm = "";
38
+ @State() emailErr = "";
39
+ @State() passErr = "";
40
+ @State() confirmErr = "";
41
+
42
+ componentDidLoad(): void {
43
+ document.documentElement.setAttribute("data-theme", this.theme);
44
+ }
45
+
46
+ private async particlesInit(engine: Engine): Promise<void> {
47
+ await loadSlim(engine);
48
+ }
49
+
50
+ private setTheme(t: string): void {
51
+ this.theme = t;
52
+ document.documentElement.setAttribute("data-theme", t);
53
+ localStorage.setItem("theme", t);
54
+ }
55
+
56
+ private toggleTheme = (): void => {
57
+ this.setTheme(this.theme === "dark" ? "light" : "dark");
58
+ };
59
+
60
+ private handleSubmit = (e: Event): void => {
61
+ e.preventDefault();
62
+ let valid = true;
63
+
64
+ if (!this.email || !validateEmail(this.email)) {
65
+ this.emailErr = "Please enter a valid email address";
66
+ valid = false;
67
+ } else {
68
+ this.emailErr = "";
69
+ }
70
+
71
+ if (!this.password || this.password.length < 6) {
72
+ this.passErr = "Password must be at least 6 characters";
73
+ valid = false;
74
+ } else {
75
+ this.passErr = "";
76
+ }
77
+
78
+ if (!this.isLogin) {
79
+ if (this.password !== this.confirm) {
80
+ this.confirmErr = "Passwords do not match";
81
+ valid = false;
82
+ } else {
83
+ this.confirmErr = "";
84
+ }
85
+ }
86
+
87
+ if (!valid) return;
88
+
89
+ if (this.isLogin) {
90
+ alert("Logged in successfully! (demo)");
91
+ } else {
92
+ alert("Account created successfully! (demo)");
93
+ this.isLogin = true;
94
+ }
95
+
96
+ this.email = "";
97
+ this.password = "";
98
+ this.confirm = "";
99
+ };
100
+
101
+ private toggleMode = (e: Event): void => {
102
+ e.preventDefault();
103
+ this.isLogin = !this.isLogin;
104
+ this.emailErr = "";
105
+ this.passErr = "";
106
+ this.confirmErr = "";
107
+ };
108
+
109
+ private handleEmailInput = (e: InputEvent): void => {
110
+ this.email = (e.target as HTMLInputElement).value;
111
+ };
112
+
113
+ private handlePasswordInput = (e: InputEvent): void => {
114
+ this.password = (e.target as HTMLInputElement).value;
115
+ };
116
+
117
+ private handleConfirmInput = (e: InputEvent): void => {
118
+ this.confirm = (e.target as HTMLInputElement).value;
119
+ };
120
+
121
+ render(): JSX.Element {
122
+ return (
123
+ <div>
124
+ <div class="auth-container">
125
+ <div class="auth-card">
126
+ <div class="auth-header">
127
+ <h1>{this.isLogin ? "Login" : "Register"}</h1>
128
+ <button class="theme-btn" onClick={this.toggleTheme} aria-label="Toggle theme">{this.theme === "dark" ? "🌙" : "☀️"}</button>
129
+ </div>
130
+ <form onSubmit={this.handleSubmit} noValidate>
131
+ <div class="form-group">
132
+ <label htmlFor="email">Email</label>
133
+ <input id="email" type="email" placeholder="you@example.com" value={this.email} onInput={this.handleEmailInput} required />
134
+ <span class="error">{this.emailErr}</span>
135
+ </div>
136
+ <div class="form-group">
137
+ <label htmlFor="password">Password</label>
138
+ <input id="password" type="password" placeholder="Enter password" value={this.password} onInput={this.handlePasswordInput} required />
139
+ <span class="error">{this.passErr}</span>
140
+ </div>
141
+ {!this.isLogin && (
142
+ <div class="form-group">
143
+ <label htmlFor="confirmPassword">Confirm Password</label>
144
+ <input id="confirmPassword" type="password" placeholder="Confirm password" value={this.confirm} onInput={this.handleConfirmInput} />
145
+ <span class="error">{this.confirmErr}</span>
146
+ </div>
147
+ )}
148
+ <button type="submit">{this.isLogin ? "Sign In" : "Create Account"}</button>
149
+ </form>
150
+ <p class="toggle-text">
151
+ <span>{this.isLogin ? "Don't have an account?" : "Already have an account?"}</span>
152
+ <a href="#" onClick={this.toggleMode}>{this.isLogin ? "Register" : "Login"}</a>
153
+ </p>
154
+ </div>
155
+ </div>
156
+ <stencil-particles
157
+ container-id="tsparticles"
158
+ init={this.particlesInit.bind(this)}
159
+ options={options}
160
+ />
161
+ </div>
162
+ );
163
+ }
164
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "{{packageName}}",
3
+ "private": true,
4
+ "version": "1.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "@tsparticles/svelte": "^4.1.3"
13
+ },
14
+ "devDependencies": {
15
+ "@sveltejs/vite-plugin-svelte": "^5.0.3",
16
+ "svelte": "^5.55.7",
17
+ "svelte-check": "^3.7.1",
18
+ "tslib": "^2.8.1"
19
+ }
20
+ }