PageSourceSearch

https://kezen.ai/signup

html kezen.ai collected 2026-10-05 12:16:20 UTC 15,177 bytes, 309 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <!-- Google tag (gtag.js) -->
vendor: 68 bytes, lines 4-5
4
5    <script async src="https://www.googletagmanager.com/gtag/js?id=
5G-0CQSNRPTVZ
vendor: 16 bytes, lines 5-6
5"></script>
6    
6<script>
7      
vendor: 146 bytes, lines 7-11
7window.dataLayer = window.dataLayer || [];
8      function gtag(){dataLayer.push(arguments);}
9      gtag('js', new Date());
10
11      gtag('config', '
11G-0CQSNRPTVZ
vendor: 8 bytes, lines 11-12
11');
12    
12</script>
12
13    <meta charset="UTF-8">
14    <meta name="viewport" content="width=device-width, initial-scale=1.0">
15    <title>Sign Up - KEZEN</title>
16    
17    <!-- Favicon -->
18    <link rel="icon" type="image/x-icon" href="/favicon.ico">
19    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
20    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
21    <link rel="icon" type="image/png" sizes="64x64" href="/favicon-64x64.png">
22    <link rel="apple-touch-icon" sizes="128x128" href="/favicon-128x128.png">
23    <link rel="apple-touch-icon" sizes="256x256" href="/favicon-256x256.png">
24    
25    <!-- Tailwind CSS -->
26    
26<script src="https://cdn.tailwindcss.com"></script>
26
27    
28    <!-- Alpine.js -->
29    
29<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>
29
30    
31    <!-- Font Awesome -->
32    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
33    
34    <style>
35        .emerald-gradient {
36            background: linear-gradient(to right, #10b981, #059669);
37        }
38        
39        .emerald-gradient:hover {
40            background: linear-gradient(to right, #059669, #047857);
41        }
42    </style>
43
44    <!-- Meta Pixel Code -->
45    
45<script>
vendor: 435 bytes, lines 45-54
45
46    !function(f,b,e,v,n,t,s)
47    {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
48    n.callMethod.apply(n,arguments):n.queue.push(arguments)};
49    if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
50    n.queue=[];t=b.createElement(e);t.async=!0;
51    t.src=v;s=b.getElementsByTagName(e)[0];
52    s.parentNode.insertBefore(t,s)}(window, document,'script',
53    'https://connect.facebook.net/en_US/fbevents.js');
54    fbq('init', '
541763902164190191
vendor: 38 bytes, lines 54-56
54');
55    fbq('track', 'PageView');
56    
56</script>
56
57    <noscript><img height="1" width="1" style="display:none"
58    src="https://www.facebook.com/tr?id=1763902164190191&ev=PageView&noscript=1"
59    /></noscript>
60    <!-- End Meta Pixel Code -->
61</head>
62<body class="bg-gray-50" x-data="signupApp()">
63    <div class="min-h-screen flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
64        <div class="max-w-md w-full space-y-8">
65            <!-- Logo and Header -->
66            <div class="text-center">
67                <a href="/" class="inline-flex items-center space-x-2 mb-6">
68                    <i class="fas fa-paint-brush text-3xl text-emerald-600"></i>
69                    <span class="text-2xl font-bold text-gray-900">KEZEN</span>
70                </a>
71                
72                <h2 class="text-3xl font-bold text-gray-900" x-text="inviteToken ? 'Accept Invitation' : 'Create Account'"></h2>
73                <p class="mt-2 text-sm text-gray-600">
74                    Already have an account? 
75                    <a href="/" class="font-medium text-emerald-600 hover:text-emerald-500">Sign in</a>
76                </p>
77                
78                <!-- Invite Info -->
79                <div x-show="inviteToken" x-cloak class="mt-4 p-4 bg-emerald-50 rounded-lg">
80                    <i class="fas fa-gift text-emerald-600 mb-2"></i>
81                    <p class="text-sm text-emerald-800">You've been invited to join KEZEN!</p>
82                </div>
83            </div>
84            
85            <!-- Registration Form -->
86            <form class="mt-8 space-y-6" @submit.prevent="register()">
87                <!-- Error Display -->
88                <div x-show="error" x-cloak class="bg-red-50 border-l-4 border-red-500 p-4 rounded">
89                    <div class="flex">
90                        <i class="fas fa-exclamation-circle text-red-500 mt-0.5 mr-3"></i>
91                        <p class="text-red-700" x-text="error"></p>
92                    </div>
93                </div>
94                
95                <!-- Success Display -->
96                <div x-show="success" x-cloak class="bg-green-50 border-l-4 border-green-500 p-4 rounded">
97                    <div class="flex">
98                        <i class="fas fa-check-circle text-green-500 mt-0.5 mr-3"></i>
99                        <p class="text-green-700" x-text="success"></p>
100                    </div>
101                </div>
102                
103                <div class="space-y-4">
104                    <!-- Username -->
105                    <div>
106                        <label for="username" class="block text-sm font-medium text-gray-700">Username</label>
107                        <input 
108                            id="username" 
109                            name="username" 
110                            type="text" 
111                            x-model="username"
112                            required 
113                            class="mt-1 block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:ring-emerald-500 focus:border-emerald-500"
114                            placeholder="johndoe">
115                    </div>
116                    
117                    <!-- Email -->
118                    <div>
119                        <label for="email" class="block text-sm font-medium text-gray-700">Email Address</label>
120                        <input 
121                            id="email" 
122                            name="email" 
123                            type="email" 
124                            x-model="email"
125                            required 
126                            class="mt-1 block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:ring-emerald-500 focus:border-emerald-500"
127                            placeholder="[email protected]">
128                    </div>
129                    
130                    <!-- Password -->
131                    <div>
132                        <label for="password" class="block text-sm font-medium text-gray-700">Password</label>
133                        <input 
134                            id="password" 
135                            name="password" 
136                            type="password" 
137                            x-model="password"
138                            required 
139                            minlength="8"
140                            class="mt-1 block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:ring-emerald-500 focus:border-emerald-500"
141                            placeholder="At least 8 characters">
142                        <p class="mt-1 text-xs text-gray-500">Must be at least 8 characters</p>
143                    </div>
144                    
145                    <!-- Confirm Password -->
146                    <div>
147                        <label for="confirmPassword" class="block text-sm font-medium text-gray-700">Confirm Password</label>
148                        <input 
149                            id="confirmPassword" 
150                            name="confirmPassword" 
151                            type="password" 
152                            x-model="confirmPassword"
153                            required 
154                            class="mt-1 block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:ring-emerald-500 focus:border-emerald-500"
155                            placeholder="Confirm your password">
156                    </div>
157                </div>
158                
159                <!-- Submit Button -->
160                <button 
161                    type="submit"
162                    :disabled="loading"
163                    class="w-full flex justify-center py-3 px-4 border border-transparent roun
163ded-lg shadow-sm text-sm font-medium text-white emerald-gradient hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-emerald-500 disabled:opacity-50 disabled:cursor-not-allowed"
164                >
165                    <span x-show="!loading">Create Account</span>
166                    <span x-show="loading" class="flex items-center">
167                        <div class="animate-spin rounded-full h-5 w-5 border-b-2 border-white mr-2"></div>
168                        Creating Account...
169                    </span>
170                </button>
171                
172                <!-- Terms -->
173                <p class="text-center text-xs text-gray-500">
174                    By signing up, you agree to our 
175                    <a href="/terms-of-service" class="text-emerald-600 hover:text-emerald-500">Terms of Service</a> and 
176                    <a href="/privacy-policy" class="text-emerald-600 hover:text-emerald-500">Privacy Policy</a>
177                </p>
178            </form>
179        </div>
180    </div>
181    
182    
182<script>
183        function signupApp() {
184            return {
185                username: '',
186                email: '',
187                password: '',
188                confirmPassword: '',
189                inviteToken: null,
190                loading: false,
191                error: '',
192                success: '',
193                
194                init() {
195                    // Check for invite token in URL
196                    const urlParams = new URLSearchParams(window.location.search);
197                    this.inviteToken = urlParams.get('invite');
198                    
199                    if (this.inviteToken) {
200                        // Pre-fill email if provided
201                        const email = urlParams.get('email');
202                        if (email) {
203                            this.email = decodeURIComponent(email);
204                        }
205                    }
206                },
207                
208                async register() {
209                    // Reset messages
210                    this.error = '';
211                    this.success = '';
212                    
213                    // Validate passwords match
214                    if (this.password !== this.confirmPassword) {
215                        this.error = 'Passwords do not match';
216                        return;
217                    }
218                    
219                    // Validate password length
220                    if (this.password.length < 8) {
221                        this.error = 'Password must be at least 8 characters';
222                        return;
223                    }
224                    
225                    this.loading = true;
226                    
227                    try {
228                        const response = await fetch('/api/auth/register', {
229                            method: 'POST',
230                            headers: {
231                                'Content-Type': 'application/json'
232                            },
233                            body: JSON.stringify({
234                                username: this.username,
235                                email: this.email,
236                                password: this.password,
237                                inviteToken: this.inviteToken
238                            })
239                        });
240                        
241                        const data = await response.json();
242
243                        if (response.ok) {
244                            // Track Facebook CompleteRegistration conversion
245                            if (typeof fbq !== 'undefined') {
246                                fbq('track', 'CompleteRegistration', {
247                                    content_name: 'Account Registration',
248                                    value: 0.00,
249                                    currency: 'USD',
250                                    status: true
251                                });
252                            }
253
254                            // Check if email verification is required
255                            if (data.requiresVerification) {
256                                // Email verification required
257                                this.success = data.message || 'Account created! Please check your email to verify your account before logging in.';
258                                
259                                // If email failed to send and we have a verification link, show it
260                                if (data.verifyLink) {
261                                    this.error = '';
262                                    this.success = `
263                                        <div style="text-align: left;">
264                                            <p style="margin-bottom: 10px;">Account created! We couldn't send the verification email automatically.</p>
265                                            <p style="margin-bottom: 15px;">Please copy this link and open it in your browser to verify your email:</p>
266                                            <div style="background: #f5f5f5; padding: 10px; border-radius: 5px; word-break: break-all; margin-bottom: 15px;">
267                                                <code style="font-size: 12px;">${data.verifyLink}</code>
268                                            </div>
269                                            <button onclick="navigator.clipboard.writeText('${data.verifyLink}').then(() => alert('Link copied to clipboard!'))" 
270                                                    style="background: #4CAF50; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer;">
271                                                Copy Link
272                                            </button>
273                                        </div>
274                                    `;
275                                }
276                                
277                                // Don't redirect - let user see the message
278                            } else {
279                                // No verification required (shouldn't happen normally)
280                                this.success = 'Account created successfully! Redirecting to login...';
281                                
282                                // Store token if provided
283                                if (data.token) {
284                                    localStorage.setItem('authToken', data.token);
285                                    if (data.refreshToken) {
286                                        localStorage.setItem('refreshToken', data.refreshToken);
287                                    }
288                                }
289                                
290                                // Redirect after a short delay
291                                setTimeout(() => {
292                                    window.location.href = '/';
293                                }, 2000);
294                            }
295                        } else {
296                            this.error = data.error || data.message || 'Registration failed. Please try again.';
297                        }
298                    } catch (err) {
299                        console.error('Registration error:', err);
300                        this.error = 'Network error. Please check your connection and try again.';
301                    } finally {
302                        this.loading = false;
303                    }
304                }
305            }
306        }
307    </script>
307
308</body>
309</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.