create-elit 3.2.7 → 3.2.9

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.
@@ -0,0 +1,230 @@
1
+ import { div, h1, h2, p, input, label, button, form, span } from 'elit/el';
2
+ import { createState, reactive } from 'elit/state';
3
+ import type { Router } from 'elit';
4
+
5
+ export function RegisterPage(router: Router) {
6
+ // Check if already logged in
7
+ const token = localStorage.getItem('token');
8
+ if (token) {
9
+ router.push('/profile');
10
+ }
11
+
12
+ const name = createState('');
13
+ const email = createState('');
14
+ const password = createState('');
15
+ const confirmPassword = createState('');
16
+ const error = createState('');
17
+ const isLoading = createState(false);
18
+
19
+ const handleRegister = async (e: Event) => {
20
+ e.preventDefault();
21
+
22
+ if (!name.value || !email.value || !password.value || !confirmPassword.value) {
23
+ error.value = 'Please fill in all fields';
24
+ return;
25
+ }
26
+
27
+ if (!email.value.includes('@')) {
28
+ error.value = 'Please enter a valid email';
29
+ return;
30
+ }
31
+
32
+ if (password.value.length < 6) {
33
+ error.value = 'Password must be at least 6 characters';
34
+ return;
35
+ }
36
+
37
+ if (password.value !== confirmPassword.value) {
38
+ error.value = 'Passwords do not match';
39
+ return;
40
+ }
41
+
42
+ isLoading.value = true;
43
+ error.value = '';
44
+
45
+ try {
46
+ const response = await fetch('/api/auth/register', {
47
+ method: 'POST',
48
+ headers: {
49
+ 'Content-Type': 'application/json'
50
+ },
51
+ body: JSON.stringify({
52
+ name: name.value,
53
+ email: email.value,
54
+ password: password.value
55
+ })
56
+ });
57
+
58
+ const data = await response.json();
59
+
60
+ if (!response.ok) {
61
+ error.value = data.error || 'Registration failed';
62
+ isLoading.value = false;
63
+ return;
64
+ }
65
+
66
+ // Store token and user data
67
+ localStorage.setItem('token', data.token);
68
+ localStorage.setItem('user', JSON.stringify(data.user));
69
+
70
+ // Dispatch custom event to notify other components (like Header)
71
+ window.dispatchEvent(new Event('elit:storage'));
72
+
73
+ isLoading.value = false;
74
+ router.push('/profile');
75
+ } catch (err) {
76
+ isLoading.value = false;
77
+ error.value = 'Network error. Please try again.';
78
+ }
79
+ };
80
+
81
+ return div({ className: 'auth-page' },
82
+ div({ className: 'auth-container' },
83
+ // Left side - branding
84
+ div({ className: 'auth-branding' },
85
+ div({ className: 'branding-content' },
86
+ h1({ className: 'branding-title' }, 'Join Us Today'),
87
+ p({ className: 'branding-description' },
88
+ 'Create your account and start building amazing applications in minutes.'
89
+ ),
90
+ div({ className: 'branding-features' },
91
+ div({ className: 'branding-feature' },
92
+ span({ className: 'feature-icon' }, '✓'),
93
+ span({ className: 'feature-text' }, 'Free forever for personal projects')
94
+ ),
95
+ div({ className: 'branding-feature' },
96
+ span({ className: 'feature-icon' }, '✓'),
97
+ span({ className: 'feature-text' }, 'No credit card required')
98
+ ),
99
+ div({ className: 'branding-feature' },
100
+ span({ className: 'feature-icon' }, '✓'),
101
+ span({ className: 'feature-text' }, 'Instant setup & deployment')
102
+ )
103
+ )
104
+ )
105
+ ),
106
+
107
+ // Right side - form
108
+ div({ className: 'auth-form-wrapper' },
109
+ div({ className: 'auth-form-card' },
110
+ div({ className: 'auth-header' },
111
+ h2({ className: 'auth-title' }, 'Create Account'),
112
+ p({ className: 'auth-subtitle' }, 'Sign up to get started with your free account')
113
+ ),
114
+
115
+ reactive(error, (err) => err ? div({ className: 'auth-error' }, err) : null),
116
+
117
+ form({ onsubmit: handleRegister },
118
+ div({ className: 'form-group' },
119
+ label({ htmlFor: 'name', className: 'form-label' }, 'Full Name'),
120
+ div({ className: 'input-wrapper' },
121
+ span({ className: 'input-icon' }, '👤'),
122
+ input({
123
+ type: 'text',
124
+ id: 'name',
125
+ className: 'form-input',
126
+ placeholder: 'John Doe',
127
+ value: name.value,
128
+ oninput: (e: Event) => {
129
+ name.value = (e.target as HTMLInputElement).value;
130
+ error.value = '';
131
+ }
132
+ })
133
+ )
134
+ ),
135
+
136
+ div({ className: 'form-group' },
137
+ label({ htmlFor: 'email', className: 'form-label' }, 'Email Address'),
138
+ div({ className: 'input-wrapper' },
139
+ span({ className: 'input-icon' }, '📧'),
140
+ input({
141
+ type: 'email',
142
+ id: 'email',
143
+ className: 'form-input',
144
+ placeholder: 'your@email.com',
145
+ value: email.value,
146
+ oninput: (e: Event) => {
147
+ email.value = (e.target as HTMLInputElement).value;
148
+ error.value = '';
149
+ }
150
+ })
151
+ )
152
+ ),
153
+
154
+ div({ className: 'form-group' },
155
+ label({ htmlFor: 'password', className: 'form-label' }, 'Password'),
156
+ div({ className: 'input-wrapper' },
157
+ span({ className: 'input-icon' }, '🔒'),
158
+ input({
159
+ type: 'password',
160
+ id: 'password',
161
+ className: 'form-input',
162
+ placeholder: '••••••••',
163
+ value: password.value,
164
+ oninput: (e: Event) => {
165
+ password.value = (e.target as HTMLInputElement).value;
166
+ error.value = '';
167
+ }
168
+ })
169
+ )
170
+ ),
171
+
172
+ div({ className: 'form-group' },
173
+ label({ htmlFor: 'confirmPassword', className: 'form-label' }, 'Confirm Password'),
174
+ div({ className: 'input-wrapper' },
175
+ span({ className: 'input-icon' }, '🔒'),
176
+ input({
177
+ type: 'password',
178
+ id: 'confirmPassword',
179
+ className: 'form-input',
180
+ placeholder: '••••••••',
181
+ value: confirmPassword.value,
182
+ oninput: (e: Event) => {
183
+ confirmPassword.value = (e.target as HTMLInputElement).value;
184
+ error.value = '';
185
+ }
186
+ })
187
+ )
188
+ ),
189
+
190
+ div({ className: 'form-options' },
191
+ label({ className: 'checkbox-label' },
192
+ input({ type: 'checkbox', className: 'checkbox' }),
193
+ span({ className: 'checkbox-text' }, 'I agree to the Terms of Service and Privacy Policy')
194
+ )
195
+ ),
196
+
197
+ button({
198
+ type: 'submit',
199
+ className: 'btn btn-primary btn-block btn-lg',
200
+ disabled: isLoading.value
201
+ }, isLoading.value ? 'Creating account...' : 'Create Account')
202
+ ),
203
+
204
+ div({ className: 'auth-divider' }, 'OR'),
205
+
206
+ div({ className: 'social-login' },
207
+ button({ className: 'social-button' },
208
+ span({ className: 'social-icon' }, 'G'),
209
+ 'Sign up with Google'
210
+ ),
211
+ button({ className: 'social-button' },
212
+ span({ className: 'social-icon' }, 'Gh'),
213
+ 'Sign up with GitHub'
214
+ )
215
+ ),
216
+
217
+ div({ className: 'auth-footer' },
218
+ p({ className: 'footer-text' },
219
+ 'Already have an account? ',
220
+ button({
221
+ className: 'link-button-inline',
222
+ onclick: () => router.push('/login')
223
+ }, 'Sign in')
224
+ )
225
+ )
226
+ )
227
+ )
228
+ )
229
+ );
230
+ }
@@ -0,0 +1,30 @@
1
+ import { createRouter, createRouterView, type RouteParams, type Router } from 'elit';
2
+ import { HomePage } from './pages/HomePage';
3
+ import { LoginPage } from './pages/LoginPage';
4
+ import { RegisterPage } from './pages/RegisterPage';
5
+ import { ProfilePage } from './pages/ProfilePage';
6
+ import { ForgotPasswordPage } from './pages/ForgotPasswordPage';
7
+ import { ChatPage } from './pages/ChatPage';
8
+ import { ChatListPage } from './pages/ChatListPage';
9
+ import { PrivateChatPage } from './pages/PrivateChatPage';
10
+
11
+ // Initialize router
12
+ export const router = createRouter({
13
+ mode: 'hash',
14
+ base: '/',
15
+ routes: []
16
+ });
17
+
18
+ // Define routes
19
+ const routes = [
20
+ { path: '/', component: () => HomePage(router) },
21
+ { path: '/login', component: () => LoginPage(router) },
22
+ { path: '/register', component: () => RegisterPage(router) },
23
+ { path: '/profile', component: () => ProfilePage(router) },
24
+ { path: '/forgot-password', component: () => ForgotPasswordPage(router) },
25
+ { path: '/chat', component: () => ChatPage(router) },
26
+ { path: '/chat/list', component: () => ChatListPage(router) },
27
+ { path: '/chat/dm/:userId', component: (params: RouteParams) => PrivateChatPage(router, params.userId as string) }
28
+ ];
29
+
30
+ export const RouterView = createRouterView(router, { mode: 'hash', routes });