enzostvs HF Staff commited on
Commit
c893e1d
·
verified ·
1 Parent(s): ac66996

the contact form is broken. improve it

Browse files
Files changed (3) hide show
  1. index.html +15 -12
  2. script.js +127 -9
  3. style.css +31 -10
index.html CHANGED
@@ -370,35 +370,38 @@
370
  </a>
371
  </div>
372
  </div>
373
-
374
  <form id="contact-form" class="glass-card rounded-2xl border border-white/10 bg-[color:rgb(var(--bg)_/_0.7)] p-6">
375
  <div class="grid grid-cols-2 gap-4">
376
  <div class="col-span-2 sm:col-span-1">
377
- <label class="label">Name</label>
378
- <input type="text" required placeholder="Jane Doe" />
 
379
  </div>
380
  <div class="col-span-2 sm:col-span-1">
381
- <label class="label">Email</label>
382
- <input type="email" required placeholder="jane@company.com" />
 
383
  </div>
384
  <div class="col-span-2">
385
- <label class="label">Subject</label>
386
- <input type="text" required placeholder="Let’s collaborate on a new project" />
 
387
  </div>
388
  <div class="col-span-2">
389
- <label class="label">Message</label>
390
- <textarea rows="5" required placeholder="Tell me about your goals and timeline..."></textarea>
 
391
  </div>
392
  </div>
393
  <div class="mt-6 flex items-center gap-3">
394
- <button type="submit" class="btn-primary">
395
  <i data-feather="send"></i>
396
- Send message
397
  </button>
398
  <span id="form-status" class="text-sm text-zinc-400"></span>
399
  </div>
400
  </form>
401
- </div>
402
  </div>
403
  </section>
404
  </main>
 
370
  </a>
371
  </div>
372
  </div>
 
373
  <form id="contact-form" class="glass-card rounded-2xl border border-white/10 bg-[color:rgb(var(--bg)_/_0.7)] p-6">
374
  <div class="grid grid-cols-2 gap-4">
375
  <div class="col-span-2 sm:col-span-1">
376
+ <label for="name" class="label">Name *</label>
377
+ <input type="text" id="name" name="name" required placeholder="Jane Doe" class="form-field-input" />
378
+ <div class="error-message hidden" id="name-error">Please enter your name</div>
379
  </div>
380
  <div class="col-span-2 sm:col-span-1">
381
+ <label for="email" class="label">Email *</label>
382
+ <input type="email" id="email" name="email" required placeholder="jane@company.com" class="form-field-input" />
383
+ <div class="error-message hidden" id="email-error">Please enter a valid email address</div>
384
  </div>
385
  <div class="col-span-2">
386
+ <label for="subject" class="label">Subject *</label>
387
+ <input type="text" id="subject" name="subject" required placeholder="Let’s collaborate on a new project" class="form-field-input" />
388
+ <div class="error-message hidden" id="subject-error">Please enter a subject</div>
389
  </div>
390
  <div class="col-span-2">
391
+ <label for="message" class="label">Message *</label>
392
+ <textarea id="message" name="message" rows="5" required placeholder="Tell me about your goals and timeline..." class="form-field-input"></textarea>
393
+ <div class="error-message hidden" id="message-error">Please enter your message</div>
394
  </div>
395
  </div>
396
  <div class="mt-6 flex items-center gap-3">
397
+ <button type="submit" id="submit-btn" class="btn-primary">
398
  <i data-feather="send"></i>
399
+ <span id="submit-text">Send message</span>
400
  </button>
401
  <span id="form-status" class="text-sm text-zinc-400"></span>
402
  </div>
403
  </form>
404
+ </div>
405
  </div>
406
  </section>
407
  </main>
script.js CHANGED
@@ -45,20 +45,138 @@ window.addEventListener('scroll', () => {
45
  backToTop?.classList.toggle('pointer-events-auto', scrolled > 400);
46
  });
47
  backToTop?.addEventListener('click', () => window.scrollTo({ top: 0, behavior: 'smooth' }));
48
-
49
- // Contact form (demo)
50
  const form = document.getElementById('contact-form');
51
  const status = document.getElementById('form-status');
52
- form?.addEventListener('submit', (e) => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  e.preventDefault();
54
- const data = Object.fromEntries(new FormData(form).entries());
55
- status.textContent = 'Sending...';
56
- setTimeout(() => {
57
- status.textContent = 'Thanks! I’ll get back to you soon.';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  form.reset();
59
- }, 800);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  });
61
-
62
  // Projects data
63
  const projects = [
64
  {
 
45
  backToTop?.classList.toggle('pointer-events-auto', scrolled > 400);
46
  });
47
  backToTop?.addEventListener('click', () => window.scrollTo({ top: 0, behavior: 'smooth' }));
48
+ // Contact form with validation
 
49
  const form = document.getElementById('contact-form');
50
  const status = document.getElementById('form-status');
51
+ const submitBtn = document.getElementById('submit-btn');
52
+ const submitText = document.getElementById('submit-text');
53
+
54
+ // Validation functions
55
+ function validateEmail(email) {
56
+ const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
57
+ return re.test(email);
58
+ }
59
+
60
+ function validateForm() {
61
+ let isValid = true;
62
+
63
+ // Clear previous errors
64
+ document.querySelectorAll('.error-message').forEach(error => {
65
+ error.classList.add('hidden');
66
+ });
67
+ document.querySelectorAll('.form-field-input').forEach(input => {
68
+ input.classList.remove('error');
69
+ });
70
+
71
+ // Get form data
72
+ const formData = new FormData(form);
73
+ const name = formData.get('name')?.trim();
74
+ const email = formData.get('email')?.trim();
75
+ const subject = formData.get('subject')?.trim();
76
+ const message = formData.get('message')?.trim();
77
+
78
+ // Validate name
79
+ if (!name) {
80
+ document.getElementById('name-error').classList.remove('hidden');
81
+ document.getElementById('name').classList.add('error');
82
+ isValid = false;
83
+ }
84
+
85
+ // Validate email
86
+ if (!email || !validateEmail(email)) {
87
+ document.getElementById('email-error').classList.remove('hidden');
88
+ document.getElementById('email').classList.add('error');
89
+ isValid = false;
90
+ }
91
+
92
+ // Validate subject
93
+ if (!subject) {
94
+ document.getElementById('subject-error').classList.remove('hidden');
95
+ document.getElementById('subject').classList.add('error');
96
+ isValid = false;
97
+ }
98
+
99
+ // Validate message
100
+ if (!message) {
101
+ document.getElementById('message-error').classList.remove('hidden');
102
+ document.getElementById('message').classList.add('error');
103
+ isValid = false;
104
+ } else if (message.length < 10) {
105
+ document.getElementById('message-error').textContent = 'Message must be at least 10 characters long';
106
+ document.getElementById('message-error').classList.remove('hidden');
107
+ document.getElementById('message').classList.add('error');
108
+ isValid = false;
109
+ }
110
+
111
+ return isValid;
112
+ }
113
+
114
+ // Clear errors on input
115
+ document.querySelectorAll('.form-field-input').forEach(input => {
116
+ input.addEventListener('input', () => {
117
+ const errorElement = document.getElementById(input.id + '-error');
118
+ if (errorElement) {
119
+ errorElement.classList.add('hidden');
120
+ }
121
+ input.classList.remove('error');
122
+ });
123
+ });
124
+
125
+ form?.addEventListener('submit', async (e) => {
126
  e.preventDefault();
127
+
128
+ if (!validateForm()) {
129
+ status.textContent = 'Please fix the errors above';
130
+ status.classList.add('text-red-400');
131
+ status.classList.remove('text-zinc-400');
132
+ return;
133
+ }
134
+
135
+ // Reset status
136
+ status.textContent = '';
137
+ status.classList.remove('text-red-400');
138
+ status.classList.add('text-zinc-400');
139
+
140
+ // Disable form and show loading state
141
+ submitBtn.disabled = true;
142
+ submitText.textContent = 'Sending...';
143
+ submitBtn.classList.add('opacity-75');
144
+
145
+ try {
146
+ // Simulate form submission (replace with actual endpoint)
147
+ const formData = new FormData(form);
148
+ const data = Object.fromEntries(formData.entries());
149
+
150
+ // Simulate API call delay
151
+ await new Promise(resolve => setTimeout(resolve, 1500));
152
+
153
+ // For demo purposes, just log the data
154
+ console.log('Form submitted:', data);
155
+
156
+ // Success
157
+ status.textContent = '✓ Message sent successfully! I\'ll get back to you soon.';
158
+ status.classList.remove('text-zinc-400');
159
+ status.classList.add('text-emerald-400');
160
+
161
  form.reset();
162
+
163
+ // Reset button state
164
+ submitBtn.disabled = false;
165
+ submitText.textContent = 'Send message';
166
+ submitBtn.classList.remove('opacity-75');
167
+
168
+ } catch (error) {
169
+ console.error('Form submission error:', error);
170
+ status.textContent = '✗ Something went wrong. Please try again or email me directly.';
171
+ status.classList.remove('text-zinc-400');
172
+ status.classList.add('text-red-400');
173
+
174
+ // Reset button state
175
+ submitBtn.disabled = false;
176
+ submitText.textContent = 'Send message';
177
+ submitBtn.classList.remove('opacity-75');
178
+ }
179
  });
 
180
  // Projects data
181
  const projects = [
182
  {
style.css CHANGED
@@ -84,35 +84,56 @@ html.light .chip {
84
  border-color: rgba(15, 23, 42, 0.1);
85
  color: rgb(71, 85, 105);
86
  }
87
-
88
- /* Form enhancements */
89
- .form-field {
90
  position: relative;
91
  }
92
 
93
- .form-input {
94
- @apply w-full rounded-lg border border-white/10 bg-white/5 text-zinc-200 placeholder:text-zinc-500 pl-4 pr-4 py-3 outline-none transition-all duration-200;
95
  }
96
 
97
- .form-input:focus {
98
- @apply border-[color:rgb(var(--color-primary-500)_/_0.6)] ring-2 ring-[color:rgb(var(--color-primary-500)_/_0.2)];
99
  }
100
 
101
- .form-input::placeholder {
102
  @apply text-zinc-500;
103
  }
104
 
 
 
 
 
 
105
  /* Light theme form inputs */
106
- html.light .form-input {
107
  background: rgba(255, 255, 255, 0.8);
108
  border-color: rgba(15, 23, 42, 0.15);
109
  color: rgb(15, 23, 42);
110
  }
111
 
112
- html.light .form-input::placeholder {
113
  color: rgb(100, 116, 139);
114
  }
115
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  * { -webkit-tap-highlight-color: transparent; }
117
 
118
  html, body {
 
84
  border-color: rgba(15, 23, 42, 0.1);
85
  color: rgb(71, 85, 105);
86
  }
87
+ /* Enhanced Form Styling */
88
+ .form-field-input {
89
+ @apply w-full rounded-lg border border-white/10 bg-white/5 text-zinc-200 placeholder:text-zinc-500 pl-4 pr-4 py-3 outline-none transition-all duration-200;
90
  position: relative;
91
  }
92
 
93
+ .form-field-input:focus {
94
+ @apply border-[color:rgb(var(--color-primary-500)_/_0.6)] ring-2 ring-[color:rgb(var(--color-primary-500)_/_0.2)];
95
  }
96
 
97
+ .form-field-input.error {
98
+ @apply border-red-500 ring-2 ring-red-500/20;
99
  }
100
 
101
+ .form-field-input::placeholder {
102
  @apply text-zinc-500;
103
  }
104
 
105
+ /* Error messages */
106
+ .error-message {
107
+ @apply text-red-400 text-xs mt-1 block;
108
+ }
109
+
110
  /* Light theme form inputs */
111
+ html.light .form-field-input {
112
  background: rgba(255, 255, 255, 0.8);
113
  border-color: rgba(15, 23, 42, 0.15);
114
  color: rgb(15, 23, 42);
115
  }
116
 
117
+ html.light .form-field-input::placeholder {
118
  color: rgb(100, 116, 139);
119
  }
120
 
121
+ html.light .form-field-input.error {
122
+ @apply border-red-500 ring-red-500/30;
123
+ }
124
+
125
+ html.light .error-message {
126
+ @apply text-red-600;
127
+ }
128
+
129
+ /* Button loading state */
130
+ .btn-primary:disabled {
131
+ @apply opacity-75 cursor-not-allowed;
132
+ }
133
+
134
+ .btn-primary:disabled:hover {
135
+ @apply scale-100;
136
+ }
137
  * { -webkit-tap-highlight-color: transparent; }
138
 
139
  html, body {