feat(frontend): update pages, components and branding
Refresh Astro frontend implementation including new pages (Portfolio, Teams, Services), components, and styling updates.
This commit is contained in:
@@ -1,85 +1,625 @@
|
||||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
/**
|
||||
* Contact Page - 聯絡我們頁面
|
||||
* Pixel-perfect implementation based on Webflow design
|
||||
* Includes form validation, submission handling, and responsive layout
|
||||
*/
|
||||
import Layout from '../layouts/Layout.astro'
|
||||
|
||||
// Metadata for SEO
|
||||
const title = '聯絡我們 | 恩群數位行銷'
|
||||
const description = '有任何問題嗎?歡迎聯絡恩群數位行銷,我們的專業團隊將竭誠為您服務。電話: 02 5570 0527,Email: enchuntaiwan@gmail.com'
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<section class="contact-section">
|
||||
<div class="container">
|
||||
<h1>聯絡我們</h1>
|
||||
<form id="contact-form">
|
||||
<div class="form-group">
|
||||
<label for="name">姓名</label>
|
||||
<input type="text" id="name" name="name" required />
|
||||
<Layout title={title} description={description}>
|
||||
<section class="contact-section" id="contact">
|
||||
<div class="contactus_wrapper">
|
||||
<!-- Contact Form Side -->
|
||||
<div class="contact_form_wrapper">
|
||||
<h1 class="contact_head">聯絡我們</h1>
|
||||
<p class="contact_parafraph">
|
||||
有任何問題嗎?歡迎聯絡我們,我們將竭誠為您服務。
|
||||
</p>
|
||||
<p class="contact_reminder">
|
||||
* 標註欄位為必填
|
||||
</p>
|
||||
|
||||
<!-- Contact Form -->
|
||||
<form id="contact-form" class="contact_form" novalidate>
|
||||
<!-- Success Message -->
|
||||
<div id="form-success" class="w-form-done" style="display: none;">
|
||||
感謝您的留言!我們會盡快回覆您。
|
||||
</div>
|
||||
|
||||
<!-- Error Message -->
|
||||
<div id="form-error" class="w-form-fail" style="display: none;">
|
||||
送出失敗,請稍後再試或直接來電。
|
||||
</div>
|
||||
|
||||
<!-- Form Fields -->
|
||||
<div class="contact-form-grid">
|
||||
<!-- Name Field -->
|
||||
<div class="contact_field_wrapper">
|
||||
<label for="Name" class="contact_field_name">
|
||||
姓名 <span>*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="Name"
|
||||
name="Name"
|
||||
class="input_field"
|
||||
required
|
||||
minlength="2"
|
||||
maxlength="256"
|
||||
placeholder="請輸入您的姓名"
|
||||
/>
|
||||
<span class="error-message" id="Name-error"></span>
|
||||
</div>
|
||||
|
||||
<!-- Phone Field -->
|
||||
<div class="contact_field_wrapper">
|
||||
<label for="Phone" class="contact_field_name">
|
||||
聯絡電話 <span>*</span>
|
||||
</label>
|
||||
<input
|
||||
type="tel"
|
||||
id="Phone"
|
||||
name="Phone"
|
||||
class="input_field"
|
||||
required
|
||||
placeholder="請輸入您的電話號碼"
|
||||
/>
|
||||
<span class="error-message" id="Phone-error"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Email Field -->
|
||||
<div class="contact_field_wrapper">
|
||||
<label for="Email" class="contact_field_name">
|
||||
Email <span>*</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="Email"
|
||||
name="Email"
|
||||
class="input_field"
|
||||
required
|
||||
placeholder="請輸入您的 Email"
|
||||
/>
|
||||
<span class="error-message" id="Email-error"></span>
|
||||
</div>
|
||||
|
||||
<!-- Message Field -->
|
||||
<div class="contact_field_wrapper">
|
||||
<label for="Message" class="contact_field_name">
|
||||
聯絡訊息 <span>*</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="Message"
|
||||
name="Message"
|
||||
class="input_field"
|
||||
minlength="10"
|
||||
maxlength="5000"
|
||||
required
|
||||
placeholder="請輸入您的訊息(至少 10 個字元)"
|
||||
></textarea>
|
||||
<span class="error-message" id="Message-error"></span>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<button type="submit" class="submit-button" id="submit-btn">
|
||||
<span class="button-text">送出訊息</span>
|
||||
<span class="button-loading" style="display: none;">送出中...</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Contact Image Side -->
|
||||
<div class="contact-image">
|
||||
<div class="image-wrapper">
|
||||
<img
|
||||
src="/placeholder-contact.jpg"
|
||||
alt="聯絡恩群數位"
|
||||
width="600"
|
||||
height="400"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">電子郵件</label>
|
||||
<input type="email" id="email" name="email" required />
|
||||
|
||||
<!-- Contact Info Card -->
|
||||
<div class="contact-info-card">
|
||||
<h3>聯絡資訊</h3>
|
||||
<div class="info-item">
|
||||
<svg class="info-icon" viewBox="0 0 24 24"><path fill="currentColor" d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1.45-.17 2.53-.5.36-.11.74-.47 1.02-.75l2.2-2.2c.27-.27.36-.67.24-1.02-.37-1.12-.57-2.33-.57-3.57 0-.55.17-1.45.5-2.53.36-.11.74.47-1.14.75-1.02zM2.05 21.05c.15.35.48.59.84.59l2.2.73c.36.12.74.12 1.06-.05.13-.07.22-.17.28-.28l2.2-2.2c.27-.27.36-.67.24-1.02-.37-1.12-.57-2.33-.57-3.57 0-.55.17-1.45.5-2.53.36-.11.74.47 1.14.75 1.02L2.05 21.05zM19.95 2.95c-.15-.35-.48-.59-.84-.59l-2.2-.73c-.36-.12-.74-.12-1.06.05-.13.07-.22.17-.28.28l-2.2 2.2c-.27.27-.36.67-.24 1.02.37 1.12.57 2.33.57 3.57 0 .55-.17 1.45-.5 2.53-.36.11-.74-.47-1.14-.75l1.02-1.02 2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1.45-.17 2.53-.5.36-.11.74-.47 1.02-.75l2.2-2.2c.27-.27.36-.67.24-1.02-.37-1.12-.57-2.33-.57-3.57 0-.55.17-1.45.5-2.53z"/></svg>
|
||||
<span>諮詢電話: 02 5570 0527</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<svg class="info-icon" viewBox="0 0 24 24"><path fill="currentColor" d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg>
|
||||
<span>Email: <a href="mailto:enchuntaiwan@gmail.com">enchuntaiwan@gmail.com</a></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="message">訊息</label>
|
||||
<textarea id="message" name="message" required></textarea>
|
||||
</div>
|
||||
<button type="submit">送出</button>
|
||||
</form>
|
||||
<div class="contact-info">
|
||||
<p>諮詢電話: 02 5570 0527</p>
|
||||
<p>電子郵件: <a href="mailto:enchuntaiwan@gmail.com">enchuntaiwan@gmail.com</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
// Basic form handler - would integrate with Cloudflare Worker
|
||||
document.getElementById('contact-form')?.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
// Submit to Cloudflare Worker
|
||||
alert('Form submitted (placeholder)');
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Contact Section Styles - Pixel-perfect from Webflow */
|
||||
.contact-section {
|
||||
padding: 40px 0;
|
||||
padding: 4rem 0;
|
||||
background: var(--color-background);
|
||||
scroll-margin-top: 80px;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
|
||||
.contactus_wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3rem;
|
||||
align-items: center;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
input, textarea {
|
||||
|
||||
/* Form Side */
|
||||
.contact_form_wrapper {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
textarea {
|
||||
height: 150px;
|
||||
|
||||
/* Headings */
|
||||
.contact_head {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
color: var(--color-text-primary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
button {
|
||||
background: #007bff;
|
||||
|
||||
.contact_parafraph {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.6;
|
||||
color: var(--color-gray-600);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.contact_reminder {
|
||||
font-size: 0.875rem;
|
||||
font-style: italic;
|
||||
color: var(--color-text-muted);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
/* Form Container */
|
||||
.contact_form {
|
||||
padding: 2rem;
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
/* Form Grid */
|
||||
.contact-form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
/* Field Wrapper */
|
||||
.contact_field_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.contact_field_wrapper:last-child {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
/* Field Label */
|
||||
.contact_field_name {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.contact_field_name span {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
/* Input Fields */
|
||||
.input_field {
|
||||
width: 100%;
|
||||
padding: 0.75rem 1rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius);
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
background: var(--color-background);
|
||||
transition: all var(--transition-fast);
|
||||
font-family: inherit;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.input_field:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 0 0 3px rgba(56, 152, 236, 0.1);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.input_field::placeholder {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.input_field.error {
|
||||
border-color: #dc3545 !important;
|
||||
background-color: #fff5f5;
|
||||
}
|
||||
|
||||
#Message {
|
||||
min-height: 120px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
/* Error Message */
|
||||
.error-message {
|
||||
color: #dc3545;
|
||||
font-size: 0.875rem;
|
||||
margin-top: 0.25rem;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.error-message:not(:empty) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Submit Button */
|
||||
.submit-button {
|
||||
background: var(--color-primary);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 4px;
|
||||
border-radius: var(--radius);
|
||||
padding: 0.875rem 2rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
.contact-info {
|
||||
margin-top: 40px;
|
||||
transition: all var(--transition-fast);
|
||||
text-align: center;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 200px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
.submit-button:hover:not(:disabled) {
|
||||
background: var(--color-primary-hover);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.submit-button:active:not(:disabled) {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.submit-button:disabled {
|
||||
background: var(--color-gray-500);
|
||||
cursor: not-allowed;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* Form Success/Error Messages */
|
||||
.w-form-done,
|
||||
.w-form-fail {
|
||||
padding: 1rem 1.5rem;
|
||||
border-radius: var(--radius);
|
||||
margin-top: 1rem;
|
||||
text-align: center;
|
||||
font-weight: 500;
|
||||
animation: slideUp 0.3s ease-out;
|
||||
}
|
||||
|
||||
.w-form-done {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.w-form-fail {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(1rem);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Image Side */
|
||||
.contact-image {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.image-wrapper {
|
||||
width: 100%;
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow-md);
|
||||
background: var(--color-gray-100);
|
||||
aspect-ratio: 3/2;
|
||||
}
|
||||
|
||||
.image-wrapper img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
/* Contact Info Card */
|
||||
.contact-info-card {
|
||||
width: 100%;
|
||||
padding: 1.5rem;
|
||||
background: white;
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.contact-info-card h3 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.info-item a {
|
||||
color: var(--color-primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.info-item a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Responsive Adjustments */
|
||||
@media (max-width: 991px) {
|
||||
.contactus_wrapper {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.contact_head {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.contact-section {
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.contact_form {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.contact-form-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
min-width: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 479px) {
|
||||
.contact_form {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.contact_head {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// Form validation and submission handler
|
||||
function initContactForm() {
|
||||
const form = document.getElementById('contact-form') as HTMLFormElement
|
||||
const submitBtn = document.getElementById('submit-btn') as HTMLButtonElement
|
||||
const successMsg = document.getElementById('form-success') as HTMLElement
|
||||
const errorMsg = document.getElementById('form-error') as HTMLElement
|
||||
|
||||
if (!form) return
|
||||
|
||||
// Validation patterns
|
||||
const patterns = {
|
||||
Name: /^[\u4e00-\u9fa5a-zA-Z\s]{2,256}$/,
|
||||
Phone: /^[0-9\-\s\+]{6,20}$/,
|
||||
Email: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
|
||||
Message: /^.{10,5000}$/
|
||||
}
|
||||
|
||||
// Validation function
|
||||
function validateField(input: HTMLInputElement | HTMLTextAreaElement): boolean {
|
||||
const name = input.name
|
||||
const value = input.value.trim()
|
||||
const errorSpan = document.getElementById(`${name}-error`) as HTMLElement
|
||||
|
||||
if (!input.hasAttribute('required') && !value) {
|
||||
clearError(input, errorSpan)
|
||||
return true
|
||||
}
|
||||
|
||||
let isValid = true
|
||||
let errorMessage = ''
|
||||
|
||||
// Required check
|
||||
if (input.hasAttribute('required') && !value) {
|
||||
isValid = false
|
||||
errorMessage = '此欄位為必填'
|
||||
}
|
||||
// Pattern validation
|
||||
else if (patterns[name as keyof typeof patterns] && !patterns[name as keyof typeof patterns].test(value)) {
|
||||
isValid = false
|
||||
switch (name) {
|
||||
case 'Name':
|
||||
errorMessage = '請輸入有效的姓名(至少 2 個字元)'
|
||||
break
|
||||
case 'Phone':
|
||||
errorMessage = '請輸入有效的電話號碼'
|
||||
break
|
||||
case 'Email':
|
||||
errorMessage = '請輸入有效的 Email 格式'
|
||||
break
|
||||
case 'Message':
|
||||
errorMessage = '訊息至少需要 10 個字元'
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Show/hide error
|
||||
if (!isValid) {
|
||||
input.classList.add('error')
|
||||
if (errorSpan) {
|
||||
errorSpan.textContent = errorMessage
|
||||
errorSpan.style.display = 'block'
|
||||
}
|
||||
} else {
|
||||
clearError(input, errorSpan)
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
|
||||
function clearError(input: HTMLInputElement | HTMLTextAreaElement, errorSpan: HTMLElement) {
|
||||
input.classList.remove('error')
|
||||
if (errorSpan) {
|
||||
errorSpan.textContent = ''
|
||||
errorSpan.style.display = 'none'
|
||||
}
|
||||
}
|
||||
|
||||
// Real-time validation on blur
|
||||
form.querySelectorAll('input, textarea').forEach((field) => {
|
||||
field.addEventListener('blur', () => {
|
||||
validateField(field as HTMLInputElement | HTMLTextAreaElement)
|
||||
})
|
||||
|
||||
field.addEventListener('input', () => {
|
||||
const input = field as HTMLInputElement | HTMLTextAreaElement
|
||||
if (input.classList.contains('error')) {
|
||||
validateField(input)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Form submission
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
// Validate all fields
|
||||
const inputs = form.querySelectorAll('input, textarea') as NodeListOf<HTMLInputElement | HTMLTextAreaElement>
|
||||
let isFormValid = true
|
||||
|
||||
inputs.forEach((input) => {
|
||||
if (!validateField(input)) {
|
||||
isFormValid = false
|
||||
}
|
||||
})
|
||||
|
||||
if (!isFormValid) {
|
||||
// Scroll to first error
|
||||
const firstError = form.querySelector('.input_field.error') as HTMLElement
|
||||
if (firstError) {
|
||||
firstError.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Show loading state
|
||||
submitBtn.disabled = true
|
||||
const buttonText = submitBtn.querySelector('.button-text') as HTMLElement
|
||||
const buttonLoading = submitBtn.querySelector('.button-loading') as HTMLElement
|
||||
if (buttonText) buttonText.style.display = 'none'
|
||||
if (buttonLoading) buttonLoading.style.display = 'inline'
|
||||
|
||||
// Hide previous messages
|
||||
successMsg.style.display = 'none'
|
||||
errorMsg.style.display = 'none'
|
||||
|
||||
// Collect form data
|
||||
const formData = new FormData(form)
|
||||
const data = {
|
||||
name: formData.get('Name'),
|
||||
phone: formData.get('Phone'),
|
||||
email: formData.get('Email'),
|
||||
message: formData.get('Message')
|
||||
}
|
||||
|
||||
try {
|
||||
// Submit to backend (via API proxy)
|
||||
const response = await fetch('/api/contact', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
|
||||
if (response.ok) {
|
||||
// Success
|
||||
successMsg.style.display = 'block'
|
||||
form.reset()
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' })
|
||||
} else {
|
||||
throw new Error('Submission failed')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Form submission error:', error)
|
||||
errorMsg.style.display = 'block'
|
||||
} finally {
|
||||
// Reset button state
|
||||
submitBtn.disabled = false
|
||||
if (buttonText) buttonText.style.display = 'inline'
|
||||
if (buttonLoading) buttonLoading.style.display = 'none'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Initialize when DOM is ready
|
||||
document.addEventListener('DOMContentLoaded', initContactForm)
|
||||
if (document.readyState !== 'loading') {
|
||||
initContactForm()
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user