- Add Go modules with required dependencies (Gin, UUID, JWT, etc.) - Implement main web server with landing page endpoint - Add comprehensive API endpoints for health and status - Include proper error handling and request validation - Set up CORS middleware and security headers
1592 lines
61 KiB
HTML
1592 lines
61 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en" dir="ltr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="description" content="Launch your sovereign hosting business with automated domain registration, VPS provisioning, and Cloudron installation. Complete business automation for $250/month.">
|
||
<meta name="keywords" content="hosting business, sovereign hosting, domain registration, VPS, Cloudron, automation, SaaS">
|
||
<meta name="author" content="YourDreamNameHere">
|
||
|
||
<!-- Open Graph for social sharing -->
|
||
<meta property="og:title" content="YourDreamNameHere - Launch Your Sovereign Hosting Business">
|
||
<meta property="og:description" content="Transform your vision into a fully automated hosting empire. Domain registration, VPS provisioning, Cloudron installation - all automated.">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://yourdreamnamehere.com">
|
||
|
||
<!-- Twitter Card -->
|
||
<meta name="twitter:card" content="summary_large_image">
|
||
<meta name="twitter:title" content="YourDreamNameHere - Launch Your Sovereign Hosting Business">
|
||
<meta name="twitter:description" content="Automated hosting business platform with domain registration, VPS provisioning, and Cloudron installation.">
|
||
|
||
<!-- Favicon and app icons -->
|
||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🚀</text></svg>">
|
||
|
||
<title>YourDreamNameHere - Launch Your Sovereign Hosting Business</title>
|
||
|
||
<!-- Preconnect to external domains -->
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
|
||
<style>
|
||
/* CSS Reset and Base Styles */
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
:root {
|
||
/* Color system - high contrast ratios for accessibility */
|
||
--primary-50: #eff6ff;
|
||
--primary-100: #dbeafe;
|
||
--primary-200: #bfdbfe;
|
||
--primary-300: #93c5fd;
|
||
--primary-400: #60a5fa;
|
||
--primary-500: #3b82f6;
|
||
--primary-600: #2563eb;
|
||
--primary-700: #1d4ed8;
|
||
--primary-800: #1e40af;
|
||
--primary-900: #1e3a8a;
|
||
|
||
--secondary-50: #ecfdf5;
|
||
--secondary-100: #d1fae5;
|
||
--secondary-200: #a7f3d0;
|
||
--secondary-300: #6ee7b7;
|
||
--secondary-400: #34d399;
|
||
--secondary-500: #10b981;
|
||
--secondary-600: #059669;
|
||
--secondary-700: #047857;
|
||
--secondary-800: #065f46;
|
||
--secondary-900: #064e3b;
|
||
|
||
--gray-50: #f9fafb;
|
||
--gray-100: #f3f4f6;
|
||
--gray-200: #e5e7eb;
|
||
--gray-300: #d1d5db;
|
||
--gray-400: #9ca3af;
|
||
--gray-500: #6b7280;
|
||
--gray-600: #4b5563;
|
||
--gray-700: #374151;
|
||
--gray-800: #1f2937;
|
||
--gray-900: #111827;
|
||
|
||
--error-50: #fef2f2;
|
||
--error-500: #ef4444;
|
||
--error-600: #dc2626;
|
||
|
||
--warning-50: #fffbeb;
|
||
--warning-500: #f59e0b;
|
||
--warning-600: #d97706;
|
||
|
||
--success-50: #ecfdf5;
|
||
--success-500: #10b981;
|
||
--success-600: #059669;
|
||
|
||
/* Typography scale */
|
||
--font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||
--font-mono: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
|
||
|
||
/* Spacing scale (based on 8px grid) */
|
||
--space-1: 0.25rem; /* 4px */
|
||
--space-2: 0.5rem; /* 8px */
|
||
--space-3: 0.75rem; /* 12px */
|
||
--space-4: 1rem; /* 16px */
|
||
--space-5: 1.25rem; /* 20px */
|
||
--space-6: 1.5rem; /* 24px */
|
||
--space-8: 2rem; /* 32px */
|
||
--space-10: 2.5rem; /* 40px */
|
||
--space-12: 3rem; /* 48px */
|
||
--space-16: 4rem; /* 64px */
|
||
--space-20: 5rem; /* 80px */
|
||
--space-24: 6rem; /* 96px */
|
||
--space-32: 8rem; /* 128px */
|
||
|
||
/* Border radius */
|
||
--radius-sm: 0.125rem;
|
||
--radius-base: 0.25rem;
|
||
--radius-md: 0.375rem;
|
||
--radius-lg: 0.5rem;
|
||
--radius-xl: 0.75rem;
|
||
--radius-2xl: 1rem;
|
||
--radius-full: 9999px;
|
||
|
||
/* Shadows */
|
||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||
--shadow-base: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
||
|
||
/* Focus ring */
|
||
--focus-ring: 0 0 0 3px rgb(59 130 246 / 0.5);
|
||
}
|
||
|
||
/* Base HTML element styles */
|
||
html {
|
||
font-size: 16px; /* Base font size for rem calculations */
|
||
scroll-behavior: smooth;
|
||
}
|
||
|
||
body {
|
||
font-family: var(--font-sans);
|
||
line-height: 1.6;
|
||
color: var(--gray-900);
|
||
background: linear-gradient(135deg, var(--primary-600) 0%, var(--primary-800) 100%);
|
||
min-height: 100vh;
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
}
|
||
|
||
/* Skip link for keyboard navigation */
|
||
.skip-link {
|
||
position: absolute;
|
||
top: -40px;
|
||
left: 6px;
|
||
background: var(--primary-600);
|
||
color: white;
|
||
padding: 8px;
|
||
text-decoration: none;
|
||
border-radius: var(--radius-base);
|
||
z-index: 10000;
|
||
transition: top 0.3s;
|
||
}
|
||
|
||
.skip-link:focus {
|
||
top: 6px;
|
||
}
|
||
|
||
/* Container */
|
||
.container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 0 var(--space-4);
|
||
width: 100%;
|
||
}
|
||
|
||
@media (min-width: 640px) {
|
||
.container {
|
||
padding: 0 var(--space-6);
|
||
}
|
||
}
|
||
|
||
@media (min-width: 1024px) {
|
||
.container {
|
||
padding: 0 var(--space-8);
|
||
}
|
||
}
|
||
|
||
/* Header */
|
||
.header {
|
||
padding: var(--space-4) 0;
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(10px);
|
||
position: fixed;
|
||
width: 100%;
|
||
top: 0;
|
||
z-index: 1000;
|
||
box-shadow: var(--shadow-base);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.nav {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
gap: var(--space-4);
|
||
}
|
||
|
||
.logo {
|
||
font-size: 1.5rem;
|
||
font-weight: 700;
|
||
color: var(--primary-600);
|
||
text-decoration: none;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-2);
|
||
transition: color 0.3s ease;
|
||
}
|
||
|
||
.logo:hover,
|
||
.logo:focus {
|
||
color: var(--primary-700);
|
||
outline: none;
|
||
}
|
||
|
||
.logo:focus-visible {
|
||
outline: 2px solid var(--primary-500);
|
||
outline-offset: 2px;
|
||
border-radius: var(--radius-base);
|
||
}
|
||
|
||
.nav-links {
|
||
display: flex;
|
||
gap: var(--space-6);
|
||
align-items: center;
|
||
}
|
||
|
||
.nav-link {
|
||
color: var(--gray-700);
|
||
text-decoration: none;
|
||
font-weight: 500;
|
||
padding: var(--space-2) var(--space-3);
|
||
border-radius: var(--radius-base);
|
||
transition: all 0.3s ease;
|
||
position: relative;
|
||
}
|
||
|
||
.nav-link:hover,
|
||
.nav-link:focus {
|
||
color: var(--primary-600);
|
||
background-color: var(--primary-50);
|
||
outline: none;
|
||
}
|
||
|
||
.nav-link:focus-visible {
|
||
outline: 2px solid var(--primary-500);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
/* Language selector */
|
||
.language-selector {
|
||
position: relative;
|
||
}
|
||
|
||
.language-button {
|
||
background: var(--gray-100);
|
||
border: 2px solid var(--gray-200);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-2) var(--space-3);
|
||
font-size: 0.875rem;
|
||
font-weight: 500;
|
||
color: var(--gray-700);
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-1);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.language-button:hover,
|
||
.language-button:focus {
|
||
background: var(--primary-50);
|
||
border-color: var(--primary-300);
|
||
color: var(--primary-700);
|
||
outline: none;
|
||
}
|
||
|
||
.language-button:focus-visible {
|
||
outline: 2px solid var(--primary-500);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
.language-dropdown {
|
||
position: absolute;
|
||
top: 100%;
|
||
right: 0;
|
||
margin-top: var(--space-2);
|
||
background: white;
|
||
border: 1px solid var(--gray-200);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-lg);
|
||
min-width: 150px;
|
||
z-index: 1000;
|
||
display: none;
|
||
}
|
||
|
||
.language-dropdown.show {
|
||
display: block;
|
||
}
|
||
|
||
.language-option {
|
||
display: block;
|
||
padding: var(--space-2) var(--space-3);
|
||
color: var(--gray-700);
|
||
text-decoration: none;
|
||
font-size: 0.875rem;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.language-option:hover,
|
||
.language-option:focus {
|
||
background: var(--primary-50);
|
||
color: var(--primary-700);
|
||
outline: none;
|
||
}
|
||
|
||
.language-option:focus-visible {
|
||
outline: 2px solid var(--primary-500);
|
||
outline-offset: -2px;
|
||
}
|
||
|
||
/* Hero Section */
|
||
.hero {
|
||
padding: calc(120px + var(--space-8)) 0 var(--space-20);
|
||
text-align: center;
|
||
color: white;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.hero::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Ccircle cx='30' cy='30' r='2'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") repeat;
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.hero-content {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.hero h1 {
|
||
font-size: clamp(2rem, 5vw, 3.5rem);
|
||
font-weight: 800;
|
||
margin-bottom: var(--space-4);
|
||
text-shadow: 0 2px 4px rgb(0 0 0 / 0.3);
|
||
line-height: 1.2;
|
||
letter-spacing: -0.02em;
|
||
animation: fadeInUp 0.8s ease-out;
|
||
}
|
||
|
||
.hero .subtitle {
|
||
font-size: clamp(1.125rem, 3vw, 1.25rem);
|
||
margin-bottom: var(--space-8);
|
||
opacity: 0.95;
|
||
max-width: 600px;
|
||
margin-left: auto;
|
||
margin-right: auto;
|
||
line-height: 1.6;
|
||
animation: fadeInUp 0.8s ease-out 0.2s both;
|
||
}
|
||
|
||
/* Form Styles */
|
||
.cta-form {
|
||
background: white;
|
||
border-radius: var(--radius-2xl);
|
||
padding: var(--space-8);
|
||
max-width: 500px;
|
||
margin: 0 auto;
|
||
box-shadow: var(--shadow-xl);
|
||
animation: fadeInUp 0.8s ease-out 0.4s both;
|
||
border: 1px solid var(--gray-200);
|
||
}
|
||
|
||
.form-header {
|
||
text-align: center;
|
||
margin-bottom: var(--space-6);
|
||
}
|
||
|
||
.form-title {
|
||
font-size: 1.5rem;
|
||
font-weight: 700;
|
||
color: var(--gray-900);
|
||
margin-bottom: var(--space-2);
|
||
}
|
||
|
||
.form-description {
|
||
color: var(--gray-600);
|
||
font-size: 1rem;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: var(--space-6);
|
||
text-align: left;
|
||
}
|
||
|
||
.form-label {
|
||
display: block;
|
||
margin-bottom: var(--space-2);
|
||
font-weight: 600;
|
||
color: var(--gray-900);
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
.form-input {
|
||
width: 100%;
|
||
padding: var(--space-3) var(--space-4);
|
||
border: 2px solid var(--gray-300);
|
||
border-radius: var(--radius-lg);
|
||
font-size: 1rem;
|
||
line-height: 1.5;
|
||
transition: all 0.3s ease;
|
||
background: white;
|
||
}
|
||
|
||
.form-input:focus {
|
||
outline: none;
|
||
border-color: var(--primary-500);
|
||
box-shadow: var(--focus-ring);
|
||
background: var(--primary-50);
|
||
}
|
||
|
||
.form-input:invalid {
|
||
border-color: var(--error-500);
|
||
}
|
||
|
||
.form-input:invalid:focus {
|
||
border-color: var(--error-600);
|
||
box-shadow: 0 0 0 3px rgb(239 68 68 / 0.2);
|
||
}
|
||
|
||
.input-error {
|
||
color: var(--error-600);
|
||
font-size: 0.875rem;
|
||
margin-top: var(--space-1);
|
||
display: none;
|
||
}
|
||
|
||
.input-error.show {
|
||
display: block;
|
||
}
|
||
|
||
.input-hint {
|
||
color: var(--gray-500);
|
||
font-size: 0.75rem;
|
||
margin-top: var(--space-1);
|
||
}
|
||
|
||
/* Button Styles */
|
||
.submit-btn {
|
||
width: 100%;
|
||
background: linear-gradient(135deg, var(--primary-600), var(--primary-700));
|
||
color: white;
|
||
padding: var(--space-4) var(--space-6);
|
||
border: none;
|
||
border-radius: var(--radius-lg);
|
||
font-size: 1.125rem;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
position: relative;
|
||
overflow: hidden;
|
||
min-height: 56px; /* WCAG touch target size */
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
.submit-btn:hover {
|
||
background: linear-gradient(135deg, var(--primary-700), var(--primary-800));
|
||
transform: translateY(-2px);
|
||
box-shadow: var(--shadow-xl);
|
||
}
|
||
|
||
.submit-btn:focus {
|
||
outline: none;
|
||
box-shadow: 0 0 0 3px rgb(59 130 246 / 0.5);
|
||
}
|
||
|
||
.submit-btn:active {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.submit-btn:disabled {
|
||
background: var(--gray-400);
|
||
cursor: not-allowed;
|
||
transform: none;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.submit-btn .btn-text {
|
||
transition: opacity 0.3s ease;
|
||
}
|
||
|
||
.submit-btn.loading .btn-text {
|
||
opacity: 0;
|
||
}
|
||
|
||
/* Loading Spinner */
|
||
.spinner {
|
||
position: absolute;
|
||
width: 24px;
|
||
height: 24px;
|
||
border: 3px solid rgba(255, 255, 255, 0.3);
|
||
border-top: 3px solid white;
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
opacity: 0;
|
||
transition: opacity 0.3s ease;
|
||
}
|
||
|
||
.submit-btn.loading .spinner {
|
||
opacity: 1;
|
||
}
|
||
|
||
/* Status Messages */
|
||
.status-message {
|
||
margin-top: var(--space-4);
|
||
padding: var(--space-4);
|
||
border-radius: var(--radius-lg);
|
||
text-align: center;
|
||
font-weight: 500;
|
||
display: none;
|
||
animation: slideDown 0.3s ease-out;
|
||
}
|
||
|
||
.status-message.show {
|
||
display: block;
|
||
}
|
||
|
||
.success-message {
|
||
background: var(--success-50);
|
||
color: var(--success-700);
|
||
border: 1px solid var(--success-200);
|
||
}
|
||
|
||
.error-message {
|
||
background: var(--error-50);
|
||
color: var(--error-700);
|
||
border: 1px solid var(--error-200);
|
||
}
|
||
|
||
/* Pricing Card */
|
||
.pricing {
|
||
background: var(--gray-50);
|
||
border: 1px solid var(--gray-200);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-6);
|
||
text-align: center;
|
||
margin-top: var(--space-6);
|
||
}
|
||
|
||
.price {
|
||
font-size: 2.5rem;
|
||
font-weight: 800;
|
||
color: var(--primary-600);
|
||
margin-bottom: var(--space-1);
|
||
}
|
||
|
||
.price-period {
|
||
color: var(--gray-600);
|
||
font-size: 1rem;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.price-features {
|
||
margin-top: var(--space-4);
|
||
text-align: left;
|
||
}
|
||
|
||
.price-feature {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: var(--space-2);
|
||
margin-bottom: var(--space-2);
|
||
color: var(--gray-700);
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
.price-feature-icon {
|
||
color: var(--success-500);
|
||
flex-shrink: 0;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
/* Features Section */
|
||
.features {
|
||
padding: var(--space-20) 0;
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(10px);
|
||
}
|
||
|
||
.features h2 {
|
||
text-align: center;
|
||
font-size: clamp(2rem, 4vw, 2.5rem);
|
||
margin-bottom: var(--space-12);
|
||
color: var(--gray-900);
|
||
font-weight: 800;
|
||
}
|
||
|
||
.features-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||
gap: var(--space-8);
|
||
margin-bottom: var(--space-8);
|
||
}
|
||
|
||
.feature-card {
|
||
background: white;
|
||
padding: var(--space-8);
|
||
border-radius: var(--radius-2xl);
|
||
box-shadow: var(--shadow-base);
|
||
transition: all 0.3s ease;
|
||
border: 1px solid var(--gray-200);
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.feature-card:hover {
|
||
transform: translateY(-8px);
|
||
box-shadow: var(--shadow-xl);
|
||
border-color: var(--primary-200);
|
||
}
|
||
|
||
.feature-card:focus-within {
|
||
outline: 2px solid var(--primary-500);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
.feature-icon {
|
||
width: 64px;
|
||
height: 64px;
|
||
background: linear-gradient(135deg, var(--primary-500), var(--primary-600));
|
||
border-radius: var(--radius-2xl);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
font-size: 1.75rem;
|
||
margin-bottom: var(--space-4);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.feature-card h3 {
|
||
font-size: 1.375rem;
|
||
font-weight: 700;
|
||
margin-bottom: var(--space-3);
|
||
color: var(--gray-900);
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.feature-card p {
|
||
color: var(--gray-600);
|
||
line-height: 1.6;
|
||
flex-grow: 1;
|
||
}
|
||
|
||
/* Footer */
|
||
.footer {
|
||
background: var(--gray-900);
|
||
color: white;
|
||
padding: var(--space-12) 0 var(--space-8);
|
||
text-align: center;
|
||
}
|
||
|
||
.footer-content {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 0 var(--space-4);
|
||
}
|
||
|
||
.footer-links {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: var(--space-8);
|
||
margin-bottom: var(--space-6);
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.footer-link {
|
||
color: var(--gray-400);
|
||
text-decoration: none;
|
||
font-weight: 500;
|
||
transition: color 0.3s ease;
|
||
padding: var(--space-2);
|
||
border-radius: var(--radius-base);
|
||
}
|
||
|
||
.footer-link:hover,
|
||
.footer-link:focus {
|
||
color: white;
|
||
background: var(--gray-800);
|
||
outline: none;
|
||
}
|
||
|
||
.footer-link:focus-visible {
|
||
outline: 2px solid var(--primary-500);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
.copyright {
|
||
color: var(--gray-500);
|
||
font-size: 0.875rem;
|
||
margin-top: var(--space-4);
|
||
}
|
||
|
||
/* Accessibility */
|
||
.sr-only {
|
||
position: absolute;
|
||
width: 1px;
|
||
height: 1px;
|
||
padding: 0;
|
||
margin: -1px;
|
||
overflow: hidden;
|
||
clip: rect(0, 0, 0, 0);
|
||
white-space: nowrap;
|
||
border: 0;
|
||
}
|
||
|
||
/* Focus styles */
|
||
*:focus-visible {
|
||
outline: 2px solid var(--primary-500);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
/* High contrast mode support */
|
||
@media (prefers-contrast: high) {
|
||
:root {
|
||
--gray-300: #000;
|
||
--gray-600: #000;
|
||
--primary-600: #0000ff;
|
||
--primary-700: #0000cc;
|
||
}
|
||
}
|
||
|
||
/* Reduced motion support */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
animation-duration: 0.01ms !important;
|
||
animation-iteration-count: 1 !important;
|
||
transition-duration: 0.01ms !important;
|
||
scroll-behavior: auto !important;
|
||
}
|
||
}
|
||
|
||
/* Print styles */
|
||
@media print {
|
||
.header,
|
||
.footer,
|
||
.cta-form {
|
||
display: none;
|
||
}
|
||
|
||
.hero {
|
||
background: white;
|
||
color: black;
|
||
}
|
||
|
||
.features {
|
||
background: white;
|
||
}
|
||
}
|
||
|
||
/* Animations */
|
||
@keyframes fadeInUp {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(30px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
@keyframes slideDown {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(-10px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
@keyframes spin {
|
||
to {
|
||
transform: rotate(360deg);
|
||
}
|
||
}
|
||
|
||
/* Mobile responsiveness */
|
||
@media (max-width: 768px) {
|
||
.nav {
|
||
flex-direction: column;
|
||
gap: var(--space-4);
|
||
}
|
||
|
||
.nav-links {
|
||
width: 100%;
|
||
justify-content: center;
|
||
}
|
||
|
||
.hero {
|
||
padding: calc(120px + var(--space-6)) 0 var(--space-12);
|
||
}
|
||
|
||
.cta-form {
|
||
margin: 0 var(--space-4);
|
||
padding: var(--space-6);
|
||
}
|
||
|
||
.features-grid {
|
||
grid-template-columns: 1fr;
|
||
gap: var(--space-6);
|
||
}
|
||
|
||
.feature-card {
|
||
padding: var(--space-6);
|
||
}
|
||
|
||
.footer-links {
|
||
flex-direction: column;
|
||
gap: var(--space-4);
|
||
}
|
||
}
|
||
|
||
/* Tablet responsiveness */
|
||
@media (min-width: 768px) and (max-width: 1024px) {
|
||
.features-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<!-- Skip to main content link for keyboard navigation -->
|
||
<a href="#main-content" class="skip-link">Skip to main content</a>
|
||
|
||
<!-- Header -->
|
||
<header class="header" role="banner">
|
||
<nav class="nav container" role="navigation" aria-label="Main navigation">
|
||
<a href="#" class="logo" aria-label="YourDreamNameHere home">
|
||
<span aria-hidden="true">🚀</span>
|
||
<span>YourDreamNameHere</span>
|
||
</a>
|
||
|
||
<div class="nav-links">
|
||
<a href="#features" class="nav-link">Features</a>
|
||
<a href="#pricing" class="nav-link">Pricing</a>
|
||
<a href="#contact" class="nav-link">Contact</a>
|
||
|
||
<!-- Language selector -->
|
||
<div class="language-selector">
|
||
<button
|
||
class="language-button"
|
||
id="languageButton"
|
||
aria-label="Select language"
|
||
aria-expanded="false"
|
||
aria-haspopup="true"
|
||
>
|
||
<span aria-hidden="true">🌐</span>
|
||
<span id="currentLanguage">EN</span>
|
||
<span aria-hidden="true">▼</span>
|
||
</button>
|
||
|
||
<div class="language-dropdown" id="languageDropdown" role="menu">
|
||
<a href="#" class="language-option" role="menuitem" data-lang="en">English</a>
|
||
<a href="#" class="language-option" role="menuitem" data-lang="es">Español</a>
|
||
<a href="#" class="language-option" role="menuitem" data-lang="fr">Français</a>
|
||
<a href="#" class="language-option" role="menuitem" data-lang="de">Deutsch</a>
|
||
<a href="#" class="language-option" role="menuitem" data-lang="zh">中文</a>
|
||
<a href="#" class="language-option" role="menuitem" data-lang="ja">日本語</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
</header>
|
||
|
||
<!-- Main Content -->
|
||
<main id="main-content" role="main">
|
||
<!-- Hero Section -->
|
||
<section class="hero" aria-labelledby="hero-title">
|
||
<div class="hero-content container">
|
||
<h1 id="hero-title">Launch Your Sovereign Hosting Business</h1>
|
||
<p class="subtitle">
|
||
Transform your entrepreneurial vision into a fully automated hosting empire.
|
||
We handle everything from domain registration to Cloudron installation.
|
||
</p>
|
||
|
||
<!-- CTA Form -->
|
||
<div class="cta-form" role="form" aria-labelledby="form-title">
|
||
<div class="form-header">
|
||
<h2 id="form-title">Start Your Hosting Empire Today</h2>
|
||
<p class="form-description">
|
||
Enter your details and we'll handle the rest. No technical expertise required.
|
||
</p>
|
||
</div>
|
||
|
||
<form id="launchForm" novalidate aria-label="Launch your hosting business">
|
||
<div class="form-group">
|
||
<label for="domain" class="form-label">
|
||
Your Dream Domain Name
|
||
<span aria-hidden="true" class="required-indicator">*</span>
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="domain"
|
||
name="domain"
|
||
class="form-input"
|
||
placeholder="example.com"
|
||
required
|
||
pattern="[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
|
||
aria-describedby="domain-hint domain-error"
|
||
autocomplete="url"
|
||
spellcheck="false"
|
||
>
|
||
<div id="domain-hint" class="input-hint">
|
||
Enter the domain you want to register (e.g., example.com)
|
||
</div>
|
||
<div id="domain-error" class="input-error" role="alert" aria-live="polite">
|
||
Please enter a valid domain name
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="email" class="form-label">
|
||
Your Email Address
|
||
<span aria-hidden="true" class="required-indicator">*</span>
|
||
</label>
|
||
<input
|
||
type="email"
|
||
id="email"
|
||
name="email"
|
||
class="form-input"
|
||
placeholder="your@email.com"
|
||
required
|
||
aria-describedby="email-hint email-error"
|
||
autocomplete="email"
|
||
inputmode="email"
|
||
>
|
||
<div id="email-hint" class="input-hint">
|
||
We'll send your Cloudron admin invitation here
|
||
</div>
|
||
<div id="email-error" class="input-error" role="alert" aria-live="polite">
|
||
Please enter a valid email address
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="cardNumber" class="form-label">
|
||
Credit Card Number
|
||
<span aria-hidden="true" class="required-indicator">*</span>
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="cardNumber"
|
||
name="cardNumber"
|
||
class="form-input"
|
||
placeholder="4242 4242 4242 4242"
|
||
maxlength="19"
|
||
required
|
||
pattern="[0-9]{13,19}"
|
||
aria-describedby="card-hint card-error"
|
||
autocomplete="cc-number"
|
||
inputmode="numeric"
|
||
>
|
||
<div id="card-hint" class="input-hint">
|
||
Secure payment processing via Stripe
|
||
</div>
|
||
<div id="card-error" class="input-error" role="alert" aria-live="polite">
|
||
Please enter a valid credit card number
|
||
</div>
|
||
</div>
|
||
|
||
<div class="pricing" id="pricing">
|
||
<h3 class="sr-only">Pricing information</h3>
|
||
<div class="price" aria-label="$250 per month">$250</div>
|
||
<div class="price-period">per month</div>
|
||
|
||
<div class="price-features" role="list">
|
||
<div class="price-feature" role="listitem">
|
||
<span class="price-feature-icon" aria-hidden="true">✓</span>
|
||
<span>Domain registration via OVH</span>
|
||
</div>
|
||
<div class="price-feature" role="listitem">
|
||
<span class="price-feature-icon" aria-hidden="true">✓</span>
|
||
<span>VPS provisioning and configuration</span>
|
||
</div>
|
||
<div class="price-feature" role="listitem">
|
||
<span class="price-feature-icon" aria-hidden="true">✓</span>
|
||
<span>Cloudron installation and setup</span>
|
||
</div>
|
||
<div class="price-feature" role="listitem">
|
||
<span class="price-feature-icon" aria-hidden="true">✓</span>
|
||
<span>DNS management and configuration</span>
|
||
</div>
|
||
<div class="price-feature" role="listitem">
|
||
<span class="price-feature-icon" aria-hidden="true">✓</span>
|
||
<span>Complete business automation</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<button
|
||
type="submit"
|
||
class="submit-btn"
|
||
id="submitBtn"
|
||
aria-describedby="submit-status"
|
||
>
|
||
<span class="btn-text">🚀 Launch My Hosting Business</span>
|
||
<div class="spinner" aria-hidden="true"></div>
|
||
<span class="sr-only" aria-live="polite">Processing, please wait</span>
|
||
</button>
|
||
|
||
<div id="submit-status" aria-live="polite" aria-atomic="true"></div>
|
||
|
||
<div class="success-message" id="successMessage" role="alert">
|
||
🎉 Welcome aboard! Your hosting business is being provisioned. You'll receive an email when setup is complete.
|
||
</div>
|
||
|
||
<div class="error-message" id="errorMessage" role="alert">
|
||
❌ Something went wrong. Please check your information and try again.
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Features Section -->
|
||
<section class="features" aria-labelledby="features-title">
|
||
<div class="container">
|
||
<h2 id="features-title">Everything You Need to Succeed</h2>
|
||
|
||
<div class="features-grid" role="list">
|
||
<article class="feature-card" role="listitem">
|
||
<div class="feature-icon" aria-hidden="true">🌐</div>
|
||
<h3>Domain Registration</h3>
|
||
<p>
|
||
Automatically register your dream domain through our OVH integration.
|
||
No manual setup required. We handle all the technical details.
|
||
</p>
|
||
</article>
|
||
|
||
<article class="feature-card" role="listitem">
|
||
<div class="feature-icon" aria-hidden="true">🖥️</div>
|
||
<h3>VPS Provisioning</h3>
|
||
<p>
|
||
Instantly provision powerful cloud servers with automatic scaling and
|
||
enterprise-grade security. Optimized for Cloudron performance.
|
||
</p>
|
||
</article>
|
||
|
||
<article class="feature-card" role="listitem">
|
||
<div class="feature-icon" aria-hidden="true">☁️</div>
|
||
<h3>Cloudron Installation</h3>
|
||
<p>
|
||
Get Cloudron automatically installed and configured with your custom
|
||
domain and DNS settings. Production-ready out of the box.
|
||
</p>
|
||
</article>
|
||
|
||
<article class="feature-card" role="listitem">
|
||
<div class="feature-icon" aria-hidden="true">💳</div>
|
||
<h3>Payment Processing</h3>
|
||
<p>
|
||
Integrated Stripe billing with automatic invoicing, subscription management,
|
||
and revenue tracking. PCI compliant and secure.
|
||
</p>
|
||
</article>
|
||
|
||
<article class="feature-card" role="listitem">
|
||
<div class="feature-icon" aria-hidden="true">📊</div>
|
||
<h3>Business Management</h3>
|
||
<p>
|
||
Complete ERP/CRM system with Dolibarr for customer management, billing,
|
||
and business analytics. All your data in one place.
|
||
</p>
|
||
</article>
|
||
|
||
<article class="feature-card" role="listitem">
|
||
<div class="feature-icon" aria-hidden="true">🔒</div>
|
||
<h3>Enterprise Security</h3>
|
||
<p>
|
||
Bank-grade security with SSL certificates, automated backups, and 24/7
|
||
monitoring included. Your business and customer data protected.
|
||
</p>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<!-- Footer -->
|
||
<footer class="footer" role="contentinfo">
|
||
<div class="footer-content">
|
||
<nav class="footer-links" role="navigation" aria-label="Footer navigation">
|
||
<a href="#privacy" class="footer-link">Privacy Policy</a>
|
||
<a href="#terms" class="footer-link">Terms of Service</a>
|
||
<a href="#support" class="footer-link">Support</a>
|
||
<a href="#docs" class="footer-link">Documentation</a>
|
||
<a href="#api" class="footer-link">API</a>
|
||
</nav>
|
||
|
||
<div class="copyright">
|
||
<p>© 2024 YourDreamNameHere. All rights reserved.</p>
|
||
<p>Built with ❤️ for entrepreneurs worldwide.</p>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
<script>
|
||
// Internationalization support
|
||
const translations = {
|
||
en: {
|
||
pageTitle: "YourDreamNameHere - Launch Your Sovereign Hosting Business",
|
||
heroTitle: "Launch Your Sovereign Hosting Business",
|
||
heroSubtitle: "Transform your entrepreneurial vision into a fully automated hosting empire. We handle everything from domain registration to Cloudron installation.",
|
||
formTitle: "Start Your Hosting Empire Today",
|
||
formDescription: "Enter your details and we'll handle the rest. No technical expertise required.",
|
||
domainLabel: "Your Dream Domain Name",
|
||
domainHint: "Enter the domain you want to register (e.g., example.com)",
|
||
domainError: "Please enter a valid domain name",
|
||
emailLabel: "Your Email Address",
|
||
emailHint: "We'll send your Cloudron admin invitation here",
|
||
emailError: "Please enter a valid email address",
|
||
cardLabel: "Credit Card Number",
|
||
cardHint: "Secure payment processing via Stripe",
|
||
cardError: "Please enter a valid credit card number",
|
||
submitText: "🚀 Launch My Hosting Business",
|
||
processingText: "Processing, please wait",
|
||
successMessage: "🎉 Welcome aboard! Your hosting business is being provisioned. You'll receive an email when setup is complete.",
|
||
errorMessage: "❌ Something went wrong. Please check your information and try again.",
|
||
featuresTitle: "Everything You Need to Succeed"
|
||
},
|
||
es: {
|
||
pageTitle: "YourDreamNameHere - Lanza tu Negocio de Hosting Soberano",
|
||
heroTitle: "Lanza tu Negocio de Hosting Soberano",
|
||
heroSubtitle: "Transforma tu visión empresarial en un imperio de hosting completamente automatizado. Nos encargamos de todo, desde el registro de dominios hasta la instalación de Cloudron.",
|
||
formTitle: "Inicia tu Imperio de Hosting Hoy",
|
||
formDescription: "Ingresa tus detalles y nos encargaremos del resto. No se requiere experiencia técnica.",
|
||
domainLabel: "Tu Nombre de Dominio Soñado",
|
||
domainHint: "Ingresa el dominio que quieres registrar (ej., ejemplo.com)",
|
||
domainError: "Por favor, ingresa un nombre de dominio válido",
|
||
emailLabel: "Tu Dirección de Correo Electrónico",
|
||
emailHint: "Te enviaremos la invitación de administrador de Cloudron aquí",
|
||
emailError: "Por favor, ingresa una dirección de correo válida",
|
||
cardLabel: "Número de Tarjeta de Crédito",
|
||
cardHint: "Procesamiento de pago seguro vía Stripe",
|
||
cardError: "Por favor, ingresa un número de tarjeta de crédito válido",
|
||
submitText: "🚀 Lanzar mi Negocio de Hosting",
|
||
processingText: "Procesando, por favor espera",
|
||
successMessage: "🎉 ¡A bordo! Tu negocio de hosting se está aprovisionando. Recibirás un correo cuando la configuración esté completa.",
|
||
errorMessage: "❌ Algo salió mal. Por favor, verifica tu información e intenta nuevamente.",
|
||
featuresTitle: "Todo lo que Necesitas para Tener Éxito"
|
||
},
|
||
fr: {
|
||
pageTitle: "YourDreamNameHere - Lancez votre Activité d'Hébergement Souveraine",
|
||
heroTitle: "Lancez votre Activité d'Hébergement Souveraine",
|
||
heroSubtitle: "Transformez votre vision entrepreneuriale en un empire d'hébergement entièrement automatisé. Nous nous occupons de tout, de l'enregistrement de domaine à l'installation de Cloudron.",
|
||
formTitle: "Commencez votre Empire d'Hébergement Aujourd'hui",
|
||
formDescription: "Entrez vos coordonnées et nous nous occuperons du reste. Aucune expertise technique requise.",
|
||
domainLabel: "Votre Nom de Domaine de Rêve",
|
||
domainHint: "Entrez le domaine que vous souhaitez enregistrer (ex., exemple.com)",
|
||
domainError: "Veuillez entrer un nom de domaine valide",
|
||
emailLabel: "Votre Adresse E-mail",
|
||
emailHint: "Nous vous enverrons votre invitation d'administrateur Cloudron ici",
|
||
emailError: "Veuillez entrer une adresse e-mail valide",
|
||
cardLabel: "Numéro de Carte de Crédit",
|
||
cardHint: "Traitement de paiement sécurisé via Stripe",
|
||
cardError: "Veuillez entrer un numéro de carte de crédit valide",
|
||
submitText: "🚀 Lancer mon Activité d'Hébergement",
|
||
processingText: "Traitement en cours, veuillez patienter",
|
||
successMessage: "🎉 Bienvenue à bord! Votre activité d'hébergement est en cours d'approvisionnement. Vous recevrez un e-mail lorsque la configuration sera terminée.",
|
||
errorMessage: "❌ Une erreur s'est produite. Veuillez vérifier vos informations et réessayer.",
|
||
featuresTitle: "Tout ce dont vous avez besoin pour réussir"
|
||
},
|
||
de: {
|
||
pageTitle: "YourDreamNameHere - Starten Sie Ihr souveränes Hosting-Geschäft",
|
||
heroTitle: "Starten Sie Ihr souveränes Hosting-Geschäft",
|
||
heroSubtitle: "Verwandeln Sie Ihre unternehmerische Vision in ein vollständig automatisiertes Hosting-Imperium. Wir kümmern uns um alles, von der Domainsregistrierung bis zur Cloudron-Installation.",
|
||
formTitle: "Starten Sie heute Ihr Hosting-Imperium",
|
||
formDescription: "Geben Sie Ihre Daten ein und wir kümmern uns um den Rest. Keine technischen Kenntnisse erforderlich.",
|
||
domainLabel: "Ihr Traum-Domainname",
|
||
domainHint: "Geben Sie die Domain ein, die Sie registrieren möchten (z.B., beispiel.com)",
|
||
domainError: "Bitte geben Sie einen gültigen Domainnamen ein",
|
||
emailLabel: "Ihre E-Mail-Adresse",
|
||
emailHint: "Wir senden Ihnen Ihre Cloudron-Admin-Einladung hierher",
|
||
emailError: "Bitte geben Sie eine gültige E-Mail-Adresse ein",
|
||
cardLabel: "Kreditkartennummer",
|
||
cardHint: "Sichere Zahlungsabwicklung über Stripe",
|
||
cardError: "Bitte geben Sie eine gültige Kreditkartennummer ein",
|
||
submitText: "🚀 Mein Hosting-Geschäft starten",
|
||
processingText: "Verarbeitung läuft, bitte warten",
|
||
successMessage: "🎉 Herzlich willkommen! Ihr Hosting-Geschäft wird bereitgestellt. Sie erhalten eine E-Mail, wenn die Einrichtung abgeschlossen ist.",
|
||
errorMessage: "❌ Etwas ist schiefgelaufen. Bitte überprüfen Sie Ihre Informationen und versuchen Sie es erneut.",
|
||
featuresTitle: "Alles was Sie zum Erfolg brauchen"
|
||
},
|
||
zh: {
|
||
pageTitle: "YourDreamNameHere - 启动您的托管业务",
|
||
heroTitle: "启动您的托管业务",
|
||
heroSubtitle: "将您的创业愿景转变为完全自动化的托管帝国。我们从域名注册到Cloudron安装处理一切。",
|
||
formTitle: "今天开始您的托管帝国",
|
||
formDescription: "输入您的详细信息,我们将处理其余部分。无需技术专业知识。",
|
||
domainLabel: "您的梦想域名",
|
||
domainHint: "输入您要注册的域名(例如:example.com)",
|
||
domainError: "请输入有效的域名",
|
||
emailLabel: "您的电子邮件地址",
|
||
emailHint: "我们会将您的Cloudron管理员邀请发送到这里",
|
||
emailError: "请输入有效的电子邮件地址",
|
||
cardLabel: "信用卡号码",
|
||
cardHint: "通过Stripe安全付款处理",
|
||
cardError: "请输入有效的信用卡号码",
|
||
submitText: "🚀 启动我的托管业务",
|
||
processingText: "正在处理,请稍候",
|
||
successMessage: "🎉 欢迎加入!您的托管业务正在配置中。设置完成后您将收到电子邮件。",
|
||
errorMessage: "❌ 出现问题。请检查您的信息并重试。",
|
||
featuresTitle: "成功所需的一切"
|
||
},
|
||
ja: {
|
||
pageTitle: "YourDreamNameHere - あなたのホスティングビジネスを開始",
|
||
heroTitle: "あなたのホスティングビジネスを開始",
|
||
heroSubtitle: "あなたの起業家ビジョンを完全自動化されたホスティング帝国に変換。ドメイン登録からCloudronインストールまですべてを処理。",
|
||
formTitle: "今日、あなたのホスティング帝国を開始",
|
||
formDescription: "詳細を入力すれば、残りは私たちが処理します。技術的専門知識は必要ありません。",
|
||
domainLabel: "あなたの夢のドメイン名",
|
||
domainHint: "登録したいドメインを入力(例:example.com)",
|
||
domainError: "有効なドメイン名を入力してください",
|
||
emailLabel: "あなたのメールアドレス",
|
||
emailHint: "Cloudron管理者招待状をここに送信します",
|
||
emailError: "有効なメールアドレスを入力してください",
|
||
cardLabel: "クレジットカード番号",
|
||
cardHint: "Stripeによる安全な支払い処理",
|
||
cardError: "有効なクレジットカード番号を入力してください",
|
||
submitText: "🚀 私のホスティングビジネスを開始",
|
||
processingText: "処理中です、お待ちください",
|
||
successMessage: "🎉 ようこそ!あなたのホスティングビジネスをプロビジョニング中です。設定完了時にメールをお送りします。",
|
||
errorMessage: "❌ 問題が発生しました。情報を確認して再試行してください。",
|
||
featuresTitle: "成功に必要なすべて"
|
||
}
|
||
};
|
||
|
||
// Current language
|
||
let currentLang = 'en';
|
||
|
||
// DOM Elements
|
||
const form = document.getElementById('launchForm');
|
||
const submitBtn = document.getElementById('submitBtn');
|
||
const successMessage = document.getElementById('successMessage');
|
||
const errorMessage = document.getElementById('errorMessage');
|
||
const cardNumberInput = document.getElementById('cardNumber');
|
||
const languageButton = document.getElementById('languageButton');
|
||
const languageDropdown = document.getElementById('languageDropdown');
|
||
const currentLanguageSpan = document.getElementById('currentLanguage');
|
||
|
||
// Language selector functionality
|
||
languageButton.addEventListener('click', function(e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
|
||
const isExpanded = languageButton.getAttribute('aria-expanded') === 'true';
|
||
languageButton.setAttribute('aria-expanded', !isExpanded);
|
||
languageDropdown.classList.toggle('show');
|
||
});
|
||
|
||
// Close language dropdown when clicking outside
|
||
document.addEventListener('click', function() {
|
||
languageDropdown.classList.remove('show');
|
||
languageButton.setAttribute('aria-expanded', 'false');
|
||
});
|
||
|
||
// Handle language selection
|
||
document.querySelectorAll('.language-option').forEach(option => {
|
||
option.addEventListener('click', function(e) {
|
||
e.preventDefault();
|
||
const lang = this.getAttribute('data-lang');
|
||
setLanguage(lang);
|
||
languageDropdown.classList.remove('show');
|
||
languageButton.setAttribute('aria-expanded', 'false');
|
||
});
|
||
});
|
||
|
||
// Set language function
|
||
function setLanguage(lang) {
|
||
if (translations[lang]) {
|
||
currentLang = lang;
|
||
currentLanguageSpan.textContent = lang.toUpperCase();
|
||
|
||
// Update page title
|
||
document.title = translations[lang].pageTitle;
|
||
|
||
// Update all translatable elements
|
||
updateTranslations();
|
||
|
||
// Save language preference
|
||
localStorage.setItem('preferred-language', lang);
|
||
}
|
||
}
|
||
|
||
// Update all translatable elements
|
||
function updateTranslations() {
|
||
const t = translations[currentLang];
|
||
|
||
// Update hero section
|
||
document.getElementById('hero-title').textContent = t.heroTitle;
|
||
document.querySelector('.subtitle').textContent = t.heroSubtitle;
|
||
|
||
// Update form
|
||
document.getElementById('form-title').textContent = t.formTitle;
|
||
document.querySelector('.form-description').textContent = t.formDescription;
|
||
|
||
// Update form labels
|
||
updateLabel('domain', t);
|
||
updateLabel('email', t);
|
||
updateLabel('cardNumber', t);
|
||
|
||
// Update submit button
|
||
submitBtn.querySelector('.btn-text').textContent = t.submitText;
|
||
|
||
// Update status messages
|
||
successMessage.textContent = t.successMessage;
|
||
errorMessage.textContent = t.errorMessage;
|
||
|
||
// Update features title
|
||
document.getElementById('features-title').textContent = t.featuresTitle;
|
||
}
|
||
|
||
function updateLabel(fieldName, t) {
|
||
const label = document.querySelector(`label[for="${fieldName}"]`);
|
||
const hint = document.getElementById(`${fieldName}-hint`);
|
||
const error = document.getElementById(`${fieldName}-error`);
|
||
|
||
if (label) {
|
||
const labelText = t[`${fieldName}Label`];
|
||
label.innerHTML = labelText + '<span aria-hidden="true" class="required-indicator">*</span>';
|
||
}
|
||
|
||
if (hint) hint.textContent = t[`${fieldName}Hint`];
|
||
if (error) error.textContent = t[`${fieldName}Error`];
|
||
}
|
||
|
||
// Load saved language preference
|
||
const savedLang = localStorage.getItem('preferred-language');
|
||
if (savedLang && translations[savedLang]) {
|
||
setLanguage(savedLang);
|
||
}
|
||
|
||
// Form formatting and validation
|
||
cardNumberInput.addEventListener('input', function(e) {
|
||
// Remove non-digit characters
|
||
let value = e.target.value.replace(/\D/g, '');
|
||
// Format with spaces every 4 digits
|
||
let formattedValue = value.match(/.{1,4}/g)?.join(' ') || value;
|
||
e.target.value = formattedValue;
|
||
});
|
||
|
||
// Enhanced form validation
|
||
function validateField(field) {
|
||
const errorElement = document.getElementById(`${field.id}-error`);
|
||
const isValid = field.checkValidity() && field.value.trim() !== '';
|
||
|
||
if (!isValid) {
|
||
field.setAttribute('aria-invalid', 'true');
|
||
errorElement.classList.add('show');
|
||
} else {
|
||
field.setAttribute('aria-invalid', 'false');
|
||
errorElement.classList.remove('show');
|
||
}
|
||
|
||
return isValid;
|
||
}
|
||
|
||
// Real-time validation
|
||
['domain', 'email', 'cardNumber'].forEach(fieldName => {
|
||
const field = document.getElementById(fieldName);
|
||
|
||
field.addEventListener('blur', () => validateField(field));
|
||
field.addEventListener('input', () => {
|
||
if (field.getAttribute('aria-invalid') === 'true') {
|
||
validateField(field);
|
||
}
|
||
});
|
||
});
|
||
|
||
// Handle form submission
|
||
form.addEventListener('submit', async function(e) {
|
||
e.preventDefault();
|
||
|
||
// Validate all fields
|
||
const fields = ['domain', 'email', 'cardNumber'].map(id => document.getElementById(id));
|
||
const isValid = fields.every(field => validateField(field));
|
||
|
||
if (!isValid) {
|
||
// Focus first invalid field
|
||
const firstInvalid = fields.find(field => field.getAttribute('aria-invalid') === 'true');
|
||
if (firstInvalid) {
|
||
firstInvalid.focus();
|
||
}
|
||
return;
|
||
}
|
||
|
||
const formData = new FormData(form);
|
||
const data = Object.fromEntries(formData);
|
||
|
||
// Show loading state
|
||
setLoadingState(true);
|
||
hideMessages();
|
||
|
||
try {
|
||
const response = await mockAPICall(data);
|
||
|
||
if (response.success) {
|
||
showSuccess();
|
||
form.reset();
|
||
// Announce success to screen readers
|
||
announceToScreenReader(successMessage.textContent);
|
||
} else {
|
||
showError();
|
||
// Announce error to screen readers
|
||
announceToScreenReader(errorMessage.textContent);
|
||
}
|
||
} catch (error) {
|
||
showError();
|
||
console.error('Submission error:', error);
|
||
} finally {
|
||
setLoadingState(false);
|
||
}
|
||
});
|
||
|
||
// Loading state management
|
||
function setLoadingState(loading) {
|
||
if (loading) {
|
||
submitBtn.classList.add('loading');
|
||
submitBtn.disabled = true;
|
||
submitBtn.setAttribute('aria-busy', 'true');
|
||
} else {
|
||
submitBtn.classList.remove('loading');
|
||
submitBtn.disabled = false;
|
||
submitBtn.setAttribute('aria-busy', 'false');
|
||
}
|
||
}
|
||
|
||
function hideMessages() {
|
||
successMessage.classList.remove('show');
|
||
errorMessage.classList.remove('show');
|
||
}
|
||
|
||
function showSuccess() {
|
||
successMessage.classList.add('show');
|
||
errorMessage.classList.remove('show');
|
||
}
|
||
|
||
function showError() {
|
||
errorMessage.classList.add('show');
|
||
successMessage.classList.remove('show');
|
||
}
|
||
|
||
// Screen reader announcements
|
||
function announceToScreenReader(message) {
|
||
const announcement = document.createElement('div');
|
||
announcement.setAttribute('role', 'status');
|
||
announcement.setAttribute('aria-live', 'polite');
|
||
announcement.className = 'sr-only';
|
||
announcement.textContent = message;
|
||
|
||
document.body.appendChild(announcement);
|
||
|
||
setTimeout(() => {
|
||
document.body.removeChild(announcement);
|
||
}, 1000);
|
||
}
|
||
|
||
// Mock API function
|
||
async function mockAPICall(data) {
|
||
// Simulate API delay
|
||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||
|
||
// Mock validation
|
||
if (data.domain && data.email && data.cardNumber) {
|
||
return {
|
||
success: true,
|
||
message: 'Your hosting business is being provisioned!'
|
||
};
|
||
} else {
|
||
return {
|
||
success: false,
|
||
message: 'Please fill in all required fields.'
|
||
};
|
||
}
|
||
}
|
||
|
||
// Keyboard navigation enhancements
|
||
document.addEventListener('keydown', function(e) {
|
||
// Escape key closes dropdowns
|
||
if (e.key === 'Escape') {
|
||
languageDropdown.classList.remove('show');
|
||
languageButton.setAttribute('aria-expanded', 'false');
|
||
}
|
||
});
|
||
|
||
// Focus trap for modals (if added later)
|
||
function createFocusTrap(element) {
|
||
const focusableElements = element.querySelectorAll(
|
||
'a[href], button, textarea, input[type="text"], input[type="email"], input[type="tel"], select, [tabindex]:not([tabindex="-1"])'
|
||
);
|
||
|
||
const firstFocusable = focusableElements[0];
|
||
const lastFocusable = focusableElements[focusableElements.length - 1];
|
||
|
||
element.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Tab') {
|
||
if (e.shiftKey) {
|
||
if (document.activeElement === firstFocusable) {
|
||
lastFocusable.focus();
|
||
e.preventDefault();
|
||
}
|
||
} else {
|
||
if (document.activeElement === lastFocusable) {
|
||
firstFocusable.focus();
|
||
e.preventDefault();
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
// Accessibility enhancements
|
||
// Add proper ARIA labels dynamically
|
||
function enhanceAccessibility() {
|
||
// Add loading state announcement
|
||
const loadingAnnouncement = document.createElement('div');
|
||
loadingAnnouncement.id = 'loading-announcement';
|
||
loadingAnnouncement.setAttribute('role', 'status');
|
||
loadingAnnouncement.setAttribute('aria-live', 'polite');
|
||
loadingAnnouncement.className = 'sr-only';
|
||
document.body.appendChild(loadingAnnouncement);
|
||
}
|
||
|
||
// Initialize accessibility enhancements
|
||
enhanceAccessibility();
|
||
|
||
// Performance optimization
|
||
// Lazy loading for images (if added later)
|
||
if ('IntersectionObserver' in window) {
|
||
const imageObserver = new IntersectionObserver((entries, observer) => {
|
||
entries.forEach(entry => {
|
||
if (entry.isIntersecting) {
|
||
const img = entry.target;
|
||
img.src = img.dataset.src;
|
||
img.removeAttribute('data-src');
|
||
observer.unobserve(img);
|
||
}
|
||
});
|
||
});
|
||
|
||
// Observe images with data-src attribute
|
||
document.querySelectorAll('img[data-src]').forEach(img => {
|
||
imageObserver.observe(img);
|
||
});
|
||
}
|
||
|
||
// Service Worker registration for PWA (if needed)
|
||
if ('serviceWorker' in navigator) {
|
||
window.addEventListener('load', function() {
|
||
// navigator.serviceWorker.register('/sw.js');
|
||
});
|
||
}
|
||
|
||
// Error tracking (integration with analytics can be added here)
|
||
window.addEventListener('error', function(e) {
|
||
console.error('JavaScript error:', e.error);
|
||
// Send to analytics service if needed
|
||
});
|
||
|
||
// Console logging for development
|
||
console.log('🚀 YourDreamNameHere initialized');
|
||
console.log('🌐 Current language:', currentLang);
|
||
console.log('♿ Accessibility features enabled');
|
||
console.log('📱 Responsive design active');
|
||
</script>
|
||
</body>
|
||
</html> |