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,110 @@
1
+ import { div, h1, h2, p, input, label, button, form, span, h3 } from 'elit/el';
2
+ import { createState, reactive } from 'elit/state';
3
+ import type { Router } from 'elit';
4
+
5
+ export function ForgotPasswordPage(router: Router) {
6
+ const email = createState('');
7
+ const error = createState('');
8
+ const success = createState(false);
9
+ const isLoading = createState(false);
10
+
11
+ const handleSubmit = async (e: Event) => {
12
+ e.preventDefault();
13
+
14
+ if (!email.value) {
15
+ error.value = 'Please enter your email address';
16
+ return;
17
+ }
18
+
19
+ if (!email.value.includes('@')) {
20
+ error.value = 'Please enter a valid email address';
21
+ return;
22
+ }
23
+
24
+ isLoading.value = true;
25
+ error.value = '';
26
+
27
+ // Simulate API call
28
+ setTimeout(() => {
29
+ isLoading.value = false;
30
+ success.value = true;
31
+ console.log('Password reset requested for:', email.value);
32
+ }, 1000);
33
+ };
34
+
35
+ return div({ className: 'auth-page' },
36
+ div({ className: 'auth-container auth-container-single' },
37
+ // Form side
38
+ div({ className: 'auth-form-wrapper auth-form-wrapper-full' },
39
+ div({ className: 'auth-form-card' },
40
+ div({ className: 'auth-header' },
41
+ button({
42
+ className: 'back-button',
43
+ onclick: () => router.push('/login')
44
+ }, '←'),
45
+ h2({ className: 'auth-title' }, 'Forgot Password?'),
46
+ p({ className: 'auth-subtitle' }, 'Enter your email address and we\'ll send you a link to reset your password')
47
+ ),
48
+
49
+ reactive(error, (err) => err ? div({ className: 'auth-error' }, err) : null),
50
+
51
+ reactive(success, (succ) => {
52
+ if (succ) {
53
+ return div({ className: 'success-message' },
54
+ div({ className: 'success-icon' }, '✓'),
55
+ h3({ className: 'success-title' }, 'Check your email'),
56
+ p({ className: 'success-text' },
57
+ 'We\'ve sent a password reset link to ',
58
+ span({ className: 'success-email' }, email.value)
59
+ ),
60
+ p({ className: 'success-description' },
61
+ 'Didn\'t receive the email? Check your spam folder or try again.'
62
+ ),
63
+ button({
64
+ className: 'btn btn-primary btn-block btn-lg',
65
+ onclick: () => router.push('/login')
66
+ }, 'Back to Login')
67
+ );
68
+ }
69
+
70
+ return form({ onsubmit: handleSubmit },
71
+ div({ className: 'form-group' },
72
+ label({ htmlFor: 'email', className: 'form-label' }, 'Email Address'),
73
+ div({ className: 'input-wrapper' },
74
+ span({ className: 'input-icon' }, '📧'),
75
+ input({
76
+ type: 'email',
77
+ id: 'email',
78
+ className: 'form-input',
79
+ placeholder: 'your@email.com',
80
+ value: email.value,
81
+ oninput: (e: Event) => {
82
+ email.value = (e.target as HTMLInputElement).value;
83
+ error.value = '';
84
+ }
85
+ })
86
+ )
87
+ ),
88
+
89
+ button({
90
+ type: 'submit',
91
+ className: 'btn btn-primary btn-block btn-lg',
92
+ disabled: isLoading.value
93
+ }, isLoading.value ? 'Sending...' : 'Send Reset Link'),
94
+
95
+ div({ className: 'auth-footer' },
96
+ p({ className: 'footer-text' },
97
+ 'Remember your password? ',
98
+ button({
99
+ className: 'link-button-inline',
100
+ onclick: () => router.push('/login')
101
+ }, 'Sign in')
102
+ )
103
+ )
104
+ );
105
+ })
106
+ )
107
+ )
108
+ )
109
+ );
110
+ }
@@ -0,0 +1,166 @@
1
+ import { div, h1, h2, h3, p, button, span, img } from 'elit/el';
2
+ import { createState, reactive } from 'elit/state';
3
+ import type { Router } from 'elit';
4
+
5
+ export function HomePage(router: Router) {
6
+ // Check if user is logged in
7
+ const isLoggedIn = createState(!!localStorage.getItem('token'));
8
+ const user = createState(() => {
9
+ const userStr = localStorage.getItem('user');
10
+ return userStr ? JSON.parse(userStr) : null;
11
+ });
12
+
13
+ // Listen for storage changes
14
+ const handleStorageChange = () => {
15
+ isLoggedIn.value = !!localStorage.getItem('token');
16
+ const userStr = localStorage.getItem('user');
17
+ user.value = userStr ? JSON.parse(userStr) : null;
18
+ };
19
+
20
+ window.addEventListener('storage', handleStorageChange);
21
+ window.addEventListener('elit:storage', handleStorageChange);
22
+
23
+ return div({ className: 'home-page' },
24
+ // Hero Section
25
+ div({ className: 'hero-section' },
26
+ div({ className: 'hero-content' },
27
+ div({ className: 'hero-badge' }, '✨ New Features Available'),
28
+ reactive(isLoggedIn, (loggedIn) => {
29
+ if (loggedIn) {
30
+ return [
31
+ h1({ className: 'hero-title' },
32
+ 'Welcome back, ',
33
+ span({ className: 'hero-highlight' }, user.value?.name || 'User')
34
+ ),
35
+ p({ className: 'hero-description' },
36
+ 'Continue building amazing applications with your team.'
37
+ ),
38
+ div({ className: 'hero-buttons' },
39
+ button({
40
+ className: 'btn btn-primary btn-lg',
41
+ onclick: () => router.push('/chat/list')
42
+ }, 'Go to Messages'),
43
+ button({
44
+ className: 'btn btn-outline btn-lg',
45
+ onclick: () => router.push('/profile')
46
+ }, 'View Profile')
47
+ )
48
+ ];
49
+ }
50
+ return [
51
+ h1({ className: 'hero-title' },
52
+ 'Build Amazing Apps ',
53
+ span({ className: 'hero-highlight' }, 'Faster')
54
+ ),
55
+ p({ className: 'hero-description' },
56
+ 'A modern full-stack TypeScript framework designed for developers who love beautiful code and stunning interfaces.'
57
+ ),
58
+ div({ className: 'hero-buttons' },
59
+ button({
60
+ className: 'btn btn-primary btn-lg',
61
+ onclick: () => router.push('/register')
62
+ }, 'Get Started'),
63
+ button({
64
+ className: 'btn btn-outline btn-lg',
65
+ onclick: () => router.push('/login')
66
+ }, 'Sign In')
67
+ )
68
+ ];
69
+ }),
70
+ div({ className: 'hero-stats' },
71
+ div({ className: 'hero-stat' },
72
+ span({ className: 'hero-stat-number' }, '10K+'),
73
+ span({ className: 'hero-stat-label' }, 'Developers')
74
+ ),
75
+ div({ className: 'hero-stat' }),
76
+ div({ className: 'hero-stat' },
77
+ span({ className: 'hero-stat-number' }, '50K+'),
78
+ span({ className: 'hero-stat-label' }, 'Projects')
79
+ ),
80
+ div({ className: 'hero-stat' }),
81
+ div({ className: 'hero-stat' },
82
+ span({ className: 'hero-stat-number' }, '99.9%'),
83
+ span({ className: 'hero-stat-label' }, 'Uptime')
84
+ )
85
+ )
86
+ ),
87
+ div({ className: 'hero-visual' },
88
+ div({ className: 'hero-card-preview' },
89
+ div({ className: 'preview-header' },
90
+ div({ className: 'preview-dots' },
91
+ span({ className: 'preview-dot preview-dot-red' }),
92
+ span({ className: 'preview-dot preview-dot-yellow' }),
93
+ span({ className: 'preview-dot preview-dot-green' })
94
+ )
95
+ ),
96
+ div({ className: 'preview-body' },
97
+ div({ className: 'preview-line preview-line-long' }),
98
+ div({ className: 'preview-line preview-line-medium' }),
99
+ div({ className: 'preview-line preview-line-short' }),
100
+ div({ className: 'preview-grid' },
101
+ div({ className: 'preview-grid-item' }),
102
+ div({ className: 'preview-grid-item' }),
103
+ div({ className: 'preview-grid-item' }),
104
+ div({ className: 'preview-grid-item' })
105
+ )
106
+ )
107
+ )
108
+ )
109
+ ),
110
+
111
+ // Features Section
112
+ div({ className: 'features-section' },
113
+ h2({ className: 'section-title' }, 'Everything You Need'),
114
+ p({ className: 'section-subtitle' }, 'Powerful features to help you build better applications'),
115
+ div({ className: 'features-grid' },
116
+ div({ className: 'feature-item' },
117
+ div({ className: 'feature-icon' }, '⚡'),
118
+ h3({ className: 'feature-title' }, 'Lightning Fast'),
119
+ p({ className: 'feature-description' }, 'Optimized performance with cutting-edge rendering technology')
120
+ ),
121
+ div({ className: 'feature-item' },
122
+ div({ className: 'feature-icon' }, '🔒'),
123
+ h3({ className: 'feature-title' }, 'Secure'),
124
+ p({ className: 'feature-description' }, 'Built-in security features to protect your applications')
125
+ ),
126
+ div({ className: 'feature-item' },
127
+ div({ className: 'feature-icon' }, '📱'),
128
+ h3({ className: 'feature-title' }, 'Responsive'),
129
+ p({ className: 'feature-description' }, 'Beautiful interfaces that work perfectly on any device')
130
+ ),
131
+ div({ className: 'feature-item' },
132
+ div({ className: 'feature-icon' }, '🎨'),
133
+ h3({ className: 'feature-title' }, 'Customizable'),
134
+ p({ className: 'feature-description' }, 'Flexible theming system for unlimited design possibilities')
135
+ ),
136
+ div({ className: 'feature-item' },
137
+ div({ className: 'feature-icon' }, '🔧'),
138
+ h3({ className: 'feature-title' }, 'Developer Friendly'),
139
+ p({ className: 'feature-description' }, 'TypeScript-first with excellent tooling and DX')
140
+ ),
141
+ div({ className: 'feature-item' },
142
+ div({ className: 'feature-icon' }, '🚀'),
143
+ h3({ className: 'feature-title' }, 'Easy Deployment'),
144
+ p({ className: 'feature-description' }, 'Deploy anywhere with minimal configuration required')
145
+ )
146
+ )
147
+ ),
148
+
149
+ // CTA Section
150
+ reactive(isLoggedIn, (loggedIn) => {
151
+ if (loggedIn) {
152
+ return null; // Don't show CTA for logged in users
153
+ }
154
+ return div({ className: 'cta-section' },
155
+ div({ className: 'cta-content' },
156
+ h2({ className: 'cta-title' }, 'Ready to Get Started?'),
157
+ p({ className: 'cta-description' }, 'Join thousands of developers building amazing applications'),
158
+ button({
159
+ className: 'btn btn-primary btn-lg cta-button',
160
+ onclick: () => router.push('/register')
161
+ }, 'Start Building Now')
162
+ )
163
+ );
164
+ })
165
+ );
166
+ }
@@ -0,0 +1,182 @@
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 LoginPage(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 email = createState('');
13
+ const password = createState('');
14
+ const error = createState('');
15
+ const isLoading = createState(false);
16
+
17
+ const handleLogin = async (e: Event) => {
18
+ e.preventDefault();
19
+
20
+ if (!email.value || !password.value) {
21
+ error.value = 'Please fill in all fields';
22
+ return;
23
+ }
24
+
25
+ if (!email.value.includes('@')) {
26
+ error.value = 'Please enter a valid email';
27
+ return;
28
+ }
29
+
30
+ isLoading.value = true;
31
+ error.value = '';
32
+
33
+ try {
34
+ const response = await fetch('/api/auth/login', {
35
+ method: 'POST',
36
+ headers: {
37
+ 'Content-Type': 'application/json'
38
+ },
39
+ body: JSON.stringify({
40
+ email: email.value,
41
+ password: password.value
42
+ })
43
+ });
44
+
45
+ const data = await response.json();
46
+
47
+ if (!response.ok) {
48
+ error.value = data.error || 'Login failed';
49
+ isLoading.value = false;
50
+ return;
51
+ }
52
+
53
+ // Store token and user data
54
+ localStorage.setItem('token', data.token);
55
+ localStorage.setItem('user', JSON.stringify(data.user));
56
+
57
+ // Dispatch custom event to notify other components (like Header)
58
+ window.dispatchEvent(new Event('elit:storage'));
59
+
60
+ isLoading.value = false;
61
+ router.push('/profile');
62
+ } catch (err) {
63
+ isLoading.value = false;
64
+ error.value = 'Network error. Please try again.';
65
+ }
66
+ };
67
+
68
+ return div({ className: 'auth-page' },
69
+ div({ className: 'auth-container' },
70
+ // Left side - branding
71
+ div({ className: 'auth-branding' },
72
+ div({ className: 'branding-content' },
73
+ h1({ className: 'branding-title' }, 'Welcome Back'),
74
+ p({ className: 'branding-description' },
75
+ 'Sign in to continue to your account and access all features.'
76
+ ),
77
+ div({ className: 'branding-features' },
78
+ div({ className: 'branding-feature' },
79
+ span({ className: 'feature-icon' }, '✓'),
80
+ span({ className: 'feature-text' }, 'Lightning fast performance')
81
+ ),
82
+ div({ className: 'branding-feature' },
83
+ span({ className: 'feature-icon' }, '✓'),
84
+ span({ className: 'feature-text' }, 'Secure and reliable')
85
+ ),
86
+ div({ className: 'branding-feature' },
87
+ span({ className: 'feature-icon' }, '✓'),
88
+ span({ className: 'feature-text' }, '24/7 support available')
89
+ )
90
+ )
91
+ )
92
+ ),
93
+
94
+ // Right side - form
95
+ div({ className: 'auth-form-wrapper' },
96
+ div({ className: 'auth-form-card' },
97
+ div({ className: 'auth-header' },
98
+ h2({ className: 'auth-title' }, 'Sign In'),
99
+ p({ className: 'auth-subtitle' }, 'Enter your credentials to access your account')
100
+ ),
101
+
102
+ reactive(error, (err) => err ? div({ className: 'auth-error' }, err) : null),
103
+
104
+ form({ onsubmit: handleLogin },
105
+ div({ className: 'form-group' },
106
+ label({ htmlFor: 'email', className: 'form-label' }, 'Email Address'),
107
+ div({ className: 'input-wrapper' },
108
+ span({ className: 'input-icon' }, '📧'),
109
+ input({
110
+ type: 'email',
111
+ id: 'email',
112
+ className: 'form-input',
113
+ placeholder: 'your@email.com',
114
+ value: email.value,
115
+ oninput: (e: Event) => {
116
+ email.value = (e.target as HTMLInputElement).value;
117
+ error.value = '';
118
+ }
119
+ })
120
+ )
121
+ ),
122
+
123
+ div({ className: 'form-group' },
124
+ label({ htmlFor: 'password', className: 'form-label' }, 'Password'),
125
+ div({ className: 'input-wrapper' },
126
+ span({ className: 'input-icon' }, '🔒'),
127
+ input({
128
+ type: 'password',
129
+ id: 'password',
130
+ className: 'form-input',
131
+ placeholder: '••••••••',
132
+ value: password.value,
133
+ oninput: (e: Event) => {
134
+ password.value = (e.target as HTMLInputElement).value;
135
+ error.value = '';
136
+ }
137
+ })
138
+ )
139
+ ),
140
+
141
+ div({ className: 'form-options' },
142
+ label({ className: 'checkbox-label' },
143
+ input({ type: 'checkbox', className: 'checkbox' }),
144
+ span({ className: 'checkbox-text' }, 'Remember me')
145
+ ),
146
+ button({ type: 'button', className: 'link-button', onclick: () => router.push('/forgot-password') }, 'Forgot password?')
147
+ ),
148
+
149
+ button({
150
+ type: 'submit',
151
+ className: 'btn btn-primary btn-block btn-lg',
152
+ disabled: isLoading.value
153
+ }, isLoading.value ? 'Signing in...' : 'Sign In')
154
+ ),
155
+
156
+ div({ className: 'auth-divider' }, 'OR'),
157
+
158
+ div({ className: 'social-login' },
159
+ button({ className: 'social-button' },
160
+ span({ className: 'social-icon' }, 'G'),
161
+ 'Continue with Google'
162
+ ),
163
+ button({ className: 'social-button' },
164
+ span({ className: 'social-icon' }, 'Gh'),
165
+ 'Continue with GitHub'
166
+ )
167
+ ),
168
+
169
+ div({ className: 'auth-footer' },
170
+ p({ className: 'footer-text' },
171
+ "Don't have an account? ",
172
+ button({
173
+ className: 'link-button-inline',
174
+ onclick: () => router.push('/register')
175
+ }, 'Sign up')
176
+ )
177
+ )
178
+ )
179
+ )
180
+ )
181
+ );
182
+ }