Initial: Apple-style step-by-step form with FastAPI backend
> > - 3-field wizard (Email → Name → Domain) > - Apple design system (SF Pro, #f5f5f7, #0071e3) > - Slide animations, step dots, checkmark draw > - POSTs to 192.168.1.121:8080/api/submit
This commit is contained in:
688
index.html
Normal file
688
index.html
Normal file
@@ -0,0 +1,688 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tell us about you</title>
|
||||
<style>
|
||||
/* ===== Apple Reset & Base ===== */
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
:root {
|
||||
--blue: #0071e3;
|
||||
--blue-hover: #0077ed;
|
||||
--link: #0066cc;
|
||||
--fg: #1d1d1f;
|
||||
--fg-secondary: rgba(0,0,0,0.8);
|
||||
--fg-tertiary: rgba(0,0,0,0.48);
|
||||
--bg-light: #f5f5f7;
|
||||
--bg-dark: #000000;
|
||||
--white: #ffffff;
|
||||
--shadow: rgba(0,0,0,0.22) 3px 5px 30px 0px;
|
||||
--nav-bg: rgba(0,0,0,0.8);
|
||||
}
|
||||
|
||||
html { height: 100%; }
|
||||
|
||||
body {
|
||||
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
font-size: 17px;
|
||||
font-weight: 400;
|
||||
line-height: 1.47;
|
||||
letter-spacing: -0.022px;
|
||||
color: var(--fg);
|
||||
background: var(--white);
|
||||
min-height: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* ===== Apple Glass Nav ===== */
|
||||
.nav {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
height: 48px;
|
||||
background: var(--nav-bg);
|
||||
backdrop-filter: saturate(180%) blur(20px);
|
||||
-webkit-backdrop-filter: saturate(180%) blur(20px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nav-brand {
|
||||
color: var(--white);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
letter-spacing: -0.016px;
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
/* ===== Main Section ===== */
|
||||
.section {
|
||||
background: var(--bg-light);
|
||||
min-height: calc(100vh - 48px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 24px 80px;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
/* ===== Typography ===== */
|
||||
.heading {
|
||||
font-size: 40px;
|
||||
font-weight: 600;
|
||||
line-height: 1.10;
|
||||
letter-spacing: normal;
|
||||
color: var(--fg);
|
||||
text-align: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.caption {
|
||||
font-size: 17px;
|
||||
font-weight: 400;
|
||||
line-height: 1.47;
|
||||
letter-spacing: -0.022px;
|
||||
color: var(--fg-secondary);
|
||||
text-align: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
/* ===== Step Indicator ===== */
|
||||
.step-track {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.step-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--fg-tertiary);
|
||||
transition: background 0.35s cubic-bezier(0.4, 0, 0.2, 1), transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.step-dot.active {
|
||||
background: var(--blue);
|
||||
transform: scale(1.5);
|
||||
}
|
||||
|
||||
.step-dot.done {
|
||||
background: #34c759;
|
||||
}
|
||||
|
||||
/* ===== Step Counter ===== */
|
||||
.step-label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
letter-spacing: -0.01px;
|
||||
color: var(--fg-tertiary);
|
||||
text-align: center;
|
||||
margin-bottom: 28px;
|
||||
transition: opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.step-label.pulse {
|
||||
animation: labelPulse 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
@keyframes labelPulse {
|
||||
0% { opacity: 0.4; transform: translateY(-4px); }
|
||||
100% { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* ===== Form Steps ===== */
|
||||
.step {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.step.current {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.step.animate-forward {
|
||||
animation: slideInLeft 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.step.animate-back {
|
||||
animation: slideInRight 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
@keyframes slideInLeft {
|
||||
from { opacity: 0; transform: translateX(28px); }
|
||||
to { opacity: 1; transform: translateX(0); }
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from { opacity: 0; transform: translateX(-28px); }
|
||||
to { opacity: 1; transform: translateX(0); }
|
||||
}
|
||||
|
||||
.field-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: var(--white);
|
||||
border-radius: 10px;
|
||||
border: 1.5px solid transparent;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.field-wrapper:focus-within {
|
||||
border-color: var(--blue);
|
||||
box-shadow: 0 0 0 3px rgba(0,113,227,0.18);
|
||||
}
|
||||
|
||||
.field-icon {
|
||||
position: absolute;
|
||||
left: 14px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 18px;
|
||||
color: var(--fg-tertiary);
|
||||
pointer-events: none;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.field-wrapper:focus-within .field-icon {
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
.field-input {
|
||||
width: 100%;
|
||||
padding: 14px 14px 14px 42px;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
font-size: 17px;
|
||||
font-weight: 400;
|
||||
line-height: 1.47;
|
||||
letter-spacing: -0.022px;
|
||||
color: var(--fg);
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.field-input::placeholder {
|
||||
color: var(--fg-tertiary);
|
||||
}
|
||||
|
||||
.field-error {
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
letter-spacing: -0.01px;
|
||||
color: #e03131;
|
||||
margin-top: 6px;
|
||||
margin-left: 14px;
|
||||
opacity: 0;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: opacity 0.2s, max-height 0.2s;
|
||||
}
|
||||
|
||||
.field-error.shown {
|
||||
opacity: 1;
|
||||
max-height: 24px;
|
||||
}
|
||||
|
||||
.field-wrapper.error {
|
||||
border-color: #e03131;
|
||||
}
|
||||
|
||||
/* ===== Buttons Row ===== */
|
||||
.btn-row {
|
||||
margin-top: 28px;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
padding: 14px 24px;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
font-size: 17px;
|
||||
font-weight: 400;
|
||||
line-height: 1.47;
|
||||
letter-spacing: -0.022px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: var(--white);
|
||||
background: var(--blue);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--blue-hover);
|
||||
box-shadow: 0 2px 14px rgba(0,113,227,0.35);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
color: var(--blue);
|
||||
background: transparent;
|
||||
border: 1.5px solid var(--blue);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: var(--blue);
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
.btn:focus-visible {
|
||||
outline: 2px solid var(--blue);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* ===== Success State (inline) ===== */
|
||||
.success-card {
|
||||
display: none;
|
||||
text-align: center;
|
||||
padding: 32px 0;
|
||||
}
|
||||
|
||||
.success-card.visible {
|
||||
display: block;
|
||||
animation: fadeInUp 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from { opacity: 0; transform: translateY(12px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.checkmark-wrap {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin: 0 auto 16px;
|
||||
}
|
||||
|
||||
.checkmark-circle {
|
||||
fill: none;
|
||||
stroke: #34c759;
|
||||
stroke-width: 2.5;
|
||||
stroke-dasharray: 166;
|
||||
stroke-dashoffset: 166;
|
||||
}
|
||||
|
||||
.success-card.visible .checkmark-circle {
|
||||
animation: circleDraw 0.45s 0.05s cubic-bezier(0.65, 0, 0.45, 1) forwards;
|
||||
}
|
||||
|
||||
.checkmark-tick {
|
||||
fill: none;
|
||||
stroke: #34c759;
|
||||
stroke-width: 2.5;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-dasharray: 48;
|
||||
stroke-dashoffset: 48;
|
||||
}
|
||||
|
||||
.success-card.visible .checkmark-tick {
|
||||
animation: tickDraw 0.3s 0.35s cubic-bezier(0.65, 0, 0.45, 1) forwards;
|
||||
}
|
||||
|
||||
@keyframes circleDraw {
|
||||
to { stroke-dashoffset: 0; }
|
||||
}
|
||||
|
||||
@keyframes tickDraw {
|
||||
to { stroke-dashoffset: 0; }
|
||||
}
|
||||
|
||||
.success-title {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
line-height: 1.14;
|
||||
letter-spacing: 0.007px;
|
||||
color: var(--fg);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.success-sub {
|
||||
font-size: 15px;
|
||||
font-weight: 400;
|
||||
line-height: 1.47;
|
||||
letter-spacing: -0.02px;
|
||||
color: var(--fg-secondary);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.btn-restart {
|
||||
display: inline-block;
|
||||
padding: 10px 36px;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
font-size: 17px;
|
||||
font-weight: 400;
|
||||
letter-spacing: -0.022px;
|
||||
color: var(--blue);
|
||||
background: transparent;
|
||||
border: 1.5px solid var(--blue);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease, color 0.15s ease;
|
||||
}
|
||||
|
||||
.btn-restart:hover {
|
||||
background: var(--blue);
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
/* ===== Footer ===== */
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
letter-spacing: -0.01px;
|
||||
color: var(--fg-tertiary);
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
/* ===== Responsive ===== */
|
||||
@media (max-width: 480px) {
|
||||
.heading { font-size: 32px; }
|
||||
.caption { font-size: 15px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Apple Glass Nav -->
|
||||
<nav class="nav">
|
||||
<span class="nav-brand">Form</span>
|
||||
</nav>
|
||||
|
||||
<!-- Form Section -->
|
||||
<section class="section">
|
||||
<div class="form-container">
|
||||
<h1 class="heading">Tell us about you</h1>
|
||||
<p class="caption">Three quick things and we're ready.</p>
|
||||
|
||||
<!-- Step Dots -->
|
||||
<div class="step-track" id="stepTrack">
|
||||
<div class="step-dot" data-step="1"></div>
|
||||
<div class="step-dot" data-step="2"></div>
|
||||
<div class="step-dot" data-step="3"></div>
|
||||
</div>
|
||||
|
||||
<!-- Step Label -->
|
||||
<div class="step-label" id="stepLabel">Step 1 of 3</div>
|
||||
|
||||
<!-- Step 1: Email -->
|
||||
<div class="step current" data-step="1" id="step1">
|
||||
<div class="field-wrapper" id="emailWrapper">
|
||||
<span class="field-icon">✉</span>
|
||||
<input class="field-input" type="email" id="email" placeholder="Email address" autocomplete="email">
|
||||
</div>
|
||||
<div class="field-error" id="emailError">Please enter a valid email.</div>
|
||||
<div class="btn-row">
|
||||
<button type="button" class="btn btn-primary" id="next1">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: Name -->
|
||||
<div class="step" data-step="2" id="step2">
|
||||
<div class="field-wrapper" id="nameWrapper">
|
||||
<span class="field-icon">👤</span>
|
||||
<input class="field-input" type="text" id="name" placeholder="Your name" autocomplete="name">
|
||||
</div>
|
||||
<div class="field-error" id="nameError">Don't be a stranger — what's your name?</div>
|
||||
<div class="btn-row">
|
||||
<button type="button" class="btn btn-secondary" id="back2">Back</button>
|
||||
<button type="button" class="btn btn-primary" id="next2">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: Domain -->
|
||||
<div class="step" data-step="3" id="step3">
|
||||
<div class="field-wrapper" id="domainWrapper">
|
||||
<span class="field-icon">🌐</span>
|
||||
<input class="field-input" type="text" id="domain" placeholder="Domain name" autocomplete="url">
|
||||
</div>
|
||||
<div class="field-error" id="domainError">Please enter your domain name.</div>
|
||||
<div class="btn-row">
|
||||
<button type="button" class="btn btn-secondary" id="back3">Back</button>
|
||||
<button type="button" class="btn btn-primary" id="submitBtn">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Success State -->
|
||||
<div class="success-card" id="successCard">
|
||||
<div class="checkmark-wrap">
|
||||
<svg viewBox="0 0 52 52" width="64" height="64">
|
||||
<circle class="checkmark-circle" cx="26" cy="26" r="24"/>
|
||||
<path class="checkmark-tick" d="M16 27l7 7 13-13"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="success-title">Success!</h2>
|
||||
<p class="success-sub">We'll be in touch.</p>
|
||||
<button class="btn-restart" id="restartBtn">Start over</button>
|
||||
</div>
|
||||
|
||||
<p class="footer">Your info stays with us. Always.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const totalSteps = 3;
|
||||
let currentStep = 1;
|
||||
|
||||
const steps = Array.from(document.querySelectorAll('.step'));
|
||||
const dots = Array.from(document.querySelectorAll('.step-dot'));
|
||||
const label = document.getElementById('stepLabel');
|
||||
const success = document.getElementById('successCard');
|
||||
const heading = document.querySelector('.heading');
|
||||
const caption = document.querySelector('.caption');
|
||||
const track = document.getElementById('stepTrack');
|
||||
|
||||
const fields = {
|
||||
email: { input: document.getElementById('email'), wrapper: document.getElementById('emailWrapper'), error: document.getElementById('emailError') },
|
||||
name: { input: document.getElementById('name'), wrapper: document.getElementById('nameWrapper'), error: document.getElementById('nameError') },
|
||||
domain: { input: document.getElementById('domain'), wrapper: document.getElementById('domainWrapper'), error: document.getElementById('domainError') }
|
||||
};
|
||||
|
||||
const API_URL = 'http://192.168.1.121:8080';
|
||||
|
||||
function validateEmail(v) {
|
||||
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v.trim());
|
||||
}
|
||||
|
||||
function clearErrors() {
|
||||
Object.values(fields).forEach(f => {
|
||||
f.wrapper.classList.remove('error');
|
||||
f.error.classList.remove('shown');
|
||||
});
|
||||
}
|
||||
|
||||
function showStep(n, dir) {
|
||||
const prevEl = document.getElementById('step' + currentStep);
|
||||
|
||||
steps.forEach(s => {
|
||||
s.classList.remove('current', 'animate-forward', 'animate-back');
|
||||
});
|
||||
|
||||
const stepEl = document.getElementById('step' + n);
|
||||
if (stepEl) {
|
||||
stepEl.classList.add('current');
|
||||
if (dir) stepEl.classList.add(dir);
|
||||
}
|
||||
|
||||
dots.forEach((d, i) => {
|
||||
d.classList.remove('active', 'done');
|
||||
if (i + 1 < n) d.classList.add('done');
|
||||
if (i + 1 === n) d.classList.add('active');
|
||||
});
|
||||
|
||||
// Pulse the step label
|
||||
label.classList.remove('pulse');
|
||||
void label.offsetWidth; // force reflow
|
||||
label.textContent = 'Step ' + n + ' of ' + totalSteps;
|
||||
label.classList.add('pulse');
|
||||
|
||||
// Focus the input in the new step
|
||||
const input = stepEl ? stepEl.querySelector('input') : null;
|
||||
if (input) setTimeout(() => input.focus(), 100);
|
||||
|
||||
currentStep = n;
|
||||
}
|
||||
|
||||
function validateStep(n) {
|
||||
clearErrors();
|
||||
if (n === 1) {
|
||||
const v = fields.email.input.value.trim();
|
||||
if (!v || !validateEmail(v)) {
|
||||
fields.email.wrapper.classList.add('error');
|
||||
fields.email.error.classList.add('shown');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (n === 2) {
|
||||
const v = fields.name.input.value.trim();
|
||||
if (!v) {
|
||||
fields.name.wrapper.classList.add('error');
|
||||
fields.name.error.classList.add('shown');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (n === 3) {
|
||||
const v = fields.domain.input.value.trim();
|
||||
if (!v) {
|
||||
fields.domain.wrapper.classList.add('error');
|
||||
fields.domain.error.classList.add('shown');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function showSuccess() {
|
||||
// Reset SVG strokes for replay
|
||||
const circle = success.querySelector('.checkmark-circle');
|
||||
const tick = success.querySelector('.checkmark-tick');
|
||||
if (circle) {
|
||||
circle.style.animation = 'none';
|
||||
circle.offsetHeight;
|
||||
circle.style.animation = '';
|
||||
}
|
||||
if (tick) {
|
||||
tick.style.animation = 'none';
|
||||
tick.offsetHeight;
|
||||
tick.style.animation = '';
|
||||
}
|
||||
|
||||
steps.forEach(s => s.classList.remove('current'));
|
||||
heading.style.display = 'none';
|
||||
caption.style.display = 'none';
|
||||
track.style.display = 'none';
|
||||
label.style.display = 'none';
|
||||
success.classList.remove('visible');
|
||||
void success.offsetWidth; // force reflow to retrigger animation
|
||||
success.classList.add('visible');
|
||||
}
|
||||
|
||||
async function submitForm() {
|
||||
const payload = {
|
||||
email: fields.email.input.value.trim(),
|
||||
name: fields.name.input.value.trim(),
|
||||
domain: fields.domain.input.value.trim()
|
||||
};
|
||||
|
||||
try {
|
||||
const resp = await fetch(API_URL + '/api/submit', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
if (resp.ok) {
|
||||
const data = await resp.json();
|
||||
console.log('Submitted:', data);
|
||||
showSuccess();
|
||||
} else {
|
||||
const err = await resp.json().catch(() => ({}));
|
||||
alert('Error: ' + (err.error || err.detail || 'Submission failed. Please try again.'));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Fetch error:', e);
|
||||
alert('Could not reach the server. Please check your connection.');
|
||||
}
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
success.classList.remove('visible');
|
||||
heading.style.display = '';
|
||||
caption.style.display = '';
|
||||
track.style.display = '';
|
||||
label.style.display = '';
|
||||
Object.values(fields).forEach(f => f.input.value = '');
|
||||
clearErrors();
|
||||
currentStep = 1;
|
||||
showStep(1);
|
||||
}
|
||||
|
||||
// Clear error on input for all fields
|
||||
Object.values(fields).forEach(f => {
|
||||
f.input.addEventListener('input', function() {
|
||||
f.wrapper.classList.remove('error');
|
||||
f.error.classList.remove('shown');
|
||||
});
|
||||
});
|
||||
|
||||
// Allow Enter key to advance
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Enter' && currentStep <= totalSteps) {
|
||||
e.preventDefault();
|
||||
if (validateStep(currentStep)) {
|
||||
if (currentStep < totalSteps) {
|
||||
showStep(currentStep + 1, 'animate-forward');
|
||||
} else {
|
||||
submitForm();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Step 1: Next
|
||||
document.getElementById('next1').addEventListener('click', function() {
|
||||
if (validateStep(1)) showStep(2, 'animate-forward');
|
||||
});
|
||||
|
||||
// Step 2: Back / Next
|
||||
document.getElementById('back2').addEventListener('click', function() {
|
||||
showStep(1, 'animate-back');
|
||||
});
|
||||
document.getElementById('next2').addEventListener('click', function() {
|
||||
if (validateStep(2)) showStep(3, 'animate-forward');
|
||||
});
|
||||
|
||||
// Step 3: Back / Submit
|
||||
document.getElementById('back3').addEventListener('click', function() {
|
||||
showStep(2, 'animate-back');
|
||||
});
|
||||
document.getElementById('submitBtn').addEventListener('click', function() {
|
||||
if (validateStep(3)) submitForm();
|
||||
});
|
||||
|
||||
// Restart
|
||||
document.getElementById('restartBtn').addEventListener('click', resetForm);
|
||||
|
||||
// Start
|
||||
showStep(1);
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user