infinite-agents-public/legacy/themed_hybrid_all/ui_hybrid_8.html

853 lines
28 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Digital Minimalism Form Wizard</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary: #000000;
--secondary: #666666;
--tertiary: #999999;
--background: #ffffff;
--surface: #fafafa;
--accent: #0066ff;
--error: #ff3333;
--success: #00cc88;
--border: #e5e5e5;
--shadow: rgba(0, 0, 0, 0.05);
--transition: 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background-color: var(--background);
color: var(--primary);
line-height: 1.6;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
main {
width: 100%;
max-width: 800px;
}
h1 {
font-size: 1.5rem;
font-weight: 300;
margin-bottom: 3rem;
text-align: center;
letter-spacing: -0.02em;
}
.hybrid-component {
background: var(--surface);
border: 1px solid var(--border);
padding: 3rem;
position: relative;
}
/* Progress Line - Minimal */
.progress-line {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 2px;
background: var(--border);
overflow: hidden;
}
.progress-fill {
height: 100%;
background: var(--accent);
width: 0%;
transition: width var(--transition);
}
/* Step Indicators - Geometric Dots */
.step-indicators {
display: flex;
justify-content: space-between;
margin-bottom: 4rem;
position: relative;
}
.step-indicator {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
z-index: 2;
}
.step-dot {
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--background);
border: 2px solid var(--border);
transition: all var(--transition);
margin-bottom: 0.75rem;
}
.step-indicator.active .step-dot {
background: var(--accent);
border-color: var(--accent);
transform: scale(1.2);
}
.step-indicator.completed .step-dot {
background: var(--success);
border-color: var(--success);
}
.step-label {
font-size: 0.75rem;
color: var(--tertiary);
text-transform: uppercase;
letter-spacing: 0.05em;
transition: color var(--transition);
}
.step-indicator.active .step-label,
.step-indicator.completed .step-label {
color: var(--primary);
}
/* Step Connection Line */
.step-connection {
position: absolute;
top: 6px;
left: 0;
right: 0;
height: 1px;
background: var(--border);
z-index: 1;
}
/* Form Steps */
.form-steps {
min-height: 300px;
position: relative;
}
.form-step {
display: none;
animation: fadeIn var(--transition) ease-out;
}
.form-step.active {
display: block;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Form Groups */
.form-group {
margin-bottom: 2rem;
}
.form-label {
display: block;
font-size: 0.875rem;
color: var(--secondary);
margin-bottom: 0.5rem;
font-weight: 500;
}
.form-input {
width: 100%;
padding: 0.75rem 0;
font-size: 1rem;
border: none;
border-bottom: 1px solid var(--border);
background: transparent;
transition: border-color var(--transition);
font-family: inherit;
}
.form-input:focus {
outline: none;
border-color: var(--accent);
}
.form-input.error {
border-color: var(--error);
}
/* Validation Messages */
.validation-message {
font-size: 0.75rem;
margin-top: 0.25rem;
height: 1rem;
color: var(--error);
opacity: 0;
transform: translateY(-5px);
transition: all var(--transition);
}
.validation-message.show {
opacity: 1;
transform: translateY(0);
}
/* Radio Groups */
.radio-group {
display: flex;
gap: 2rem;
margin-top: 1rem;
}
.radio-option {
display: flex;
align-items: center;
cursor: pointer;
}
.radio-input {
width: 20px;
height: 20px;
border: 2px solid var(--border);
border-radius: 50%;
margin-right: 0.5rem;
position: relative;
transition: border-color var(--transition);
}
.radio-option input[type="radio"] {
display: none;
}
.radio-option input[type="radio"]:checked + .radio-input {
border-color: var(--accent);
}
.radio-option input[type="radio"]:checked + .radio-input::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--accent);
}
/* Navigation */
.form-navigation {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 3rem;
padding-top: 2rem;
border-top: 1px solid var(--border);
}
.nav-button {
background: none;
border: 1px solid var(--border);
padding: 0.75rem 2rem;
font-size: 0.875rem;
cursor: pointer;
transition: all var(--transition);
font-family: inherit;
display: flex;
align-items: center;
gap: 0.5rem;
}
.nav-button:hover {
border-color: var(--primary);
background: var(--primary);
color: var(--background);
}
.nav-button.primary {
background: var(--primary);
color: var(--background);
border-color: var(--primary);
}
.nav-button.primary:hover {
background: var(--accent);
border-color: var(--accent);
}
.nav-button:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.nav-button:disabled:hover {
background: none;
color: var(--primary);
border-color: var(--border);
}
/* Arrow Icons */
.arrow {
width: 16px;
height: 16px;
position: relative;
}
.arrow::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 8px;
height: 8px;
border-right: 2px solid currentColor;
border-bottom: 2px solid currentColor;
transform: translate(-50%, -50%) rotate(-45deg);
}
.arrow.left::before {
transform: translate(-50%, -50%) rotate(135deg);
}
/* Save State Indicator */
.save-state {
position: absolute;
top: 1rem;
right: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.75rem;
color: var(--tertiary);
opacity: 0;
transition: opacity var(--transition);
}
.save-state.show {
opacity: 1;
}
.save-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--success);
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% {
opacity: 0.3;
}
50% {
opacity: 1;
}
}
/* Summary Step */
.summary-section {
margin-bottom: 2rem;
}
.summary-label {
font-size: 0.75rem;
color: var(--tertiary);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 0.25rem;
}
.summary-value {
font-size: 1rem;
color: var(--primary);
}
/* Success State */
.success-message {
text-align: center;
padding: 3rem;
animation: fadeIn var(--transition) ease-out;
}
.success-icon {
width: 48px;
height: 48px;
margin: 0 auto 1.5rem;
position: relative;
}
.success-icon::before {
content: '';
position: absolute;
top: 50%;
left: 25%;
width: 10px;
height: 16px;
border-right: 2px solid var(--success);
border-bottom: 2px solid var(--success);
transform: translateY(-60%) rotate(45deg);
}
.success-icon::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 2px solid var(--success);
border-radius: 50%;
}
/* Responsive */
@media (max-width: 640px) {
.hybrid-component {
padding: 2rem 1.5rem;
}
.step-label {
font-size: 0.625rem;
}
.nav-button {
padding: 0.625rem 1.5rem;
font-size: 0.75rem;
}
}
</style>
</head>
<body>
<main>
<h1>Form Wizard - Digital Minimalism Theme</h1>
<div class="hybrid-component">
<!-- Progress Line -->
<div class="progress-line">
<div class="progress-fill" id="progressFill"></div>
</div>
<!-- Save State Indicator -->
<div class="save-state" id="saveState">
<div class="save-indicator"></div>
<span>Auto-saved</span>
</div>
<!-- Step Indicators -->
<div class="step-indicators">
<div class="step-connection"></div>
<div class="step-indicator active" data-step="1">
<div class="step-dot"></div>
<span class="step-label">Personal</span>
</div>
<div class="step-indicator" data-step="2">
<div class="step-dot"></div>
<span class="step-label">Account</span>
</div>
<div class="step-indicator" data-step="3">
<div class="step-dot"></div>
<span class="step-label">Preferences</span>
</div>
<div class="step-indicator" data-step="4">
<div class="step-dot"></div>
<span class="step-label">Review</span>
</div>
</div>
<!-- Form Steps -->
<div class="form-steps">
<!-- Step 1: Personal Information -->
<div class="form-step active" data-step="1">
<div class="form-group">
<label class="form-label" for="firstName">First Name</label>
<input type="text" class="form-input" id="firstName" required>
<div class="validation-message" id="firstNameError">Please enter your first name</div>
</div>
<div class="form-group">
<label class="form-label" for="lastName">Last Name</label>
<input type="text" class="form-input" id="lastName" required>
<div class="validation-message" id="lastNameError">Please enter your last name</div>
</div>
<div class="form-group">
<label class="form-label" for="email">Email Address</label>
<input type="email" class="form-input" id="email" required>
<div class="validation-message" id="emailError">Please enter a valid email address</div>
</div>
</div>
<!-- Step 2: Account Setup -->
<div class="form-step" data-step="2">
<div class="form-group">
<label class="form-label" for="username">Username</label>
<input type="text" class="form-input" id="username" required>
<div class="validation-message" id="usernameError">Username must be at least 3 characters</div>
</div>
<div class="form-group">
<label class="form-label" for="password">Password</label>
<input type="password" class="form-input" id="password" required>
<div class="validation-message" id="passwordError">Password must be at least 8 characters</div>
</div>
<div class="form-group">
<label class="form-label" for="confirmPassword">Confirm Password</label>
<input type="password" class="form-input" id="confirmPassword" required>
<div class="validation-message" id="confirmPasswordError">Passwords do not match</div>
</div>
</div>
<!-- Step 3: Preferences -->
<div class="form-step" data-step="3">
<div class="form-group">
<label class="form-label">Notification Frequency</label>
<div class="radio-group">
<label class="radio-option">
<input type="radio" name="notifications" value="daily" checked>
<div class="radio-input"></div>
<span>Daily</span>
</label>
<label class="radio-option">
<input type="radio" name="notifications" value="weekly">
<div class="radio-input"></div>
<span>Weekly</span>
</label>
<label class="radio-option">
<input type="radio" name="notifications" value="never">
<div class="radio-input"></div>
<span>Never</span>
</label>
</div>
</div>
<div class="form-group">
<label class="form-label">Theme Preference</label>
<div class="radio-group">
<label class="radio-option">
<input type="radio" name="theme" value="light" checked>
<div class="radio-input"></div>
<span>Light</span>
</label>
<label class="radio-option">
<input type="radio" name="theme" value="dark">
<div class="radio-input"></div>
<span>Dark</span>
</label>
<label class="radio-option">
<input type="radio" name="theme" value="auto">
<div class="radio-input"></div>
<span>Auto</span>
</label>
</div>
</div>
</div>
<!-- Step 4: Review -->
<div class="form-step" data-step="4">
<div class="summary-section">
<div class="summary-label">Personal Information</div>
<div class="summary-value" id="summaryName">-</div>
<div class="summary-value" id="summaryEmail">-</div>
</div>
<div class="summary-section">
<div class="summary-label">Account Details</div>
<div class="summary-value" id="summaryUsername">-</div>
</div>
<div class="summary-section">
<div class="summary-label">Preferences</div>
<div class="summary-value" id="summaryNotifications">-</div>
<div class="summary-value" id="summaryTheme">-</div>
</div>
</div>
<!-- Success State -->
<div class="form-step" data-step="success">
<div class="success-message">
<div class="success-icon"></div>
<h2 style="font-weight: 300; margin-bottom: 0.5rem;">Account Created</h2>
<p style="color: var(--secondary);">Welcome to your minimal digital experience.</p>
</div>
</div>
</div>
<!-- Navigation -->
<div class="form-navigation">
<button class="nav-button" id="prevBtn" disabled>
<span class="arrow left"></span>
Previous
</button>
<button class="nav-button primary" id="nextBtn">
Next
<span class="arrow"></span>
</button>
</div>
</div>
</main>
<script>
// Form Wizard State
const formWizard = {
currentStep: 1,
totalSteps: 4,
formData: {},
saveTimeout: null
};
// DOM Elements
const progressFill = document.getElementById('progressFill');
const saveState = document.getElementById('saveState');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
// Initialize form data from localStorage
function initializeFormData() {
const savedData = localStorage.getItem('formWizardData');
if (savedData) {
formWizard.formData = JSON.parse(savedData);
restoreFormData();
}
}
// Save form data
function saveFormData() {
// Collect current step data
collectStepData();
// Save to localStorage
localStorage.setItem('formWizardData', JSON.stringify(formWizard.formData));
// Show save indicator
saveState.classList.add('show');
clearTimeout(formWizard.saveTimeout);
formWizard.saveTimeout = setTimeout(() => {
saveState.classList.remove('show');
}, 2000);
}
// Restore form data
function restoreFormData() {
// Restore all form fields
Object.keys(formWizard.formData).forEach(key => {
const element = document.getElementById(key);
if (element) {
if (element.type === 'radio') {
const radio = document.querySelector(`input[name="${element.name}"][value="${formWizard.formData[key]}"]`);
if (radio) radio.checked = true;
} else {
element.value = formWizard.formData[key];
}
}
});
}
// Collect data from current step
function collectStepData() {
const currentStepElement = document.querySelector(`.form-step[data-step="${formWizard.currentStep}"]`);
if (!currentStepElement) return;
// Text inputs
currentStepElement.querySelectorAll('.form-input').forEach(input => {
if (input.value) {
formWizard.formData[input.id] = input.value;
}
});
// Radio inputs
currentStepElement.querySelectorAll('input[type="radio"]:checked').forEach(radio => {
formWizard.formData[radio.name] = radio.value;
});
}
// Validate current step
function validateStep() {
const currentStepElement = document.querySelector(`.form-step[data-step="${formWizard.currentStep}"]`);
if (!currentStepElement) return true;
let isValid = true;
// Validate text inputs
currentStepElement.querySelectorAll('.form-input[required]').forEach(input => {
const errorElement = document.getElementById(input.id + 'Error');
if (!input.value.trim()) {
input.classList.add('error');
if (errorElement) errorElement.classList.add('show');
isValid = false;
} else if (input.type === 'email' && !isValidEmail(input.value)) {
input.classList.add('error');
if (errorElement) errorElement.classList.add('show');
isValid = false;
} else if (input.id === 'username' && input.value.length < 3) {
input.classList.add('error');
if (errorElement) errorElement.classList.add('show');
isValid = false;
} else if (input.id === 'password' && input.value.length < 8) {
input.classList.add('error');
if (errorElement) errorElement.classList.add('show');
isValid = false;
} else if (input.id === 'confirmPassword') {
const password = document.getElementById('password').value;
if (input.value !== password) {
input.classList.add('error');
if (errorElement) errorElement.classList.add('show');
isValid = false;
} else {
input.classList.remove('error');
if (errorElement) errorElement.classList.remove('show');
}
} else {
input.classList.remove('error');
if (errorElement) errorElement.classList.remove('show');
}
});
return isValid;
}
// Email validation
function isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
// Update progress
function updateProgress() {
const progress = ((formWizard.currentStep - 1) / formWizard.totalSteps) * 100;
progressFill.style.width = progress + '%';
}
// Update step indicators
function updateStepIndicators() {
document.querySelectorAll('.step-indicator').forEach((indicator, index) => {
const stepNum = index + 1;
indicator.classList.remove('active', 'completed');
if (stepNum < formWizard.currentStep) {
indicator.classList.add('completed');
} else if (stepNum === formWizard.currentStep) {
indicator.classList.add('active');
}
});
}
// Show step
function showStep(stepNumber) {
// Hide all steps
document.querySelectorAll('.form-step').forEach(step => {
step.classList.remove('active');
});
// Show current step
const currentStepElement = document.querySelector(`.form-step[data-step="${stepNumber}"]`);
if (currentStepElement) {
currentStepElement.classList.add('active');
}
// Update navigation buttons
prevBtn.disabled = stepNumber === 1;
if (stepNumber === formWizard.totalSteps) {
nextBtn.textContent = 'Submit';
nextBtn.innerHTML = 'Submit <span class="arrow"></span>';
} else {
nextBtn.textContent = 'Next';
nextBtn.innerHTML = 'Next <span class="arrow"></span>';
}
// Update progress and indicators
updateProgress();
updateStepIndicators();
// Update summary if on review step
if (stepNumber === 4) {
updateSummary();
}
}
// Update summary
function updateSummary() {
document.getElementById('summaryName').textContent =
`${formWizard.formData.firstName || ''} ${formWizard.formData.lastName || ''}`;
document.getElementById('summaryEmail').textContent =
formWizard.formData.email || '-';
document.getElementById('summaryUsername').textContent =
`Username: ${formWizard.formData.username || '-'}`;
document.getElementById('summaryNotifications').textContent =
`Notifications: ${formWizard.formData.notifications || 'daily'}`;
document.getElementById('summaryTheme').textContent =
`Theme: ${formWizard.formData.theme || 'light'}`;
}
// Next step
function nextStep() {
if (formWizard.currentStep === formWizard.totalSteps) {
// Submit form
if (validateStep()) {
collectStepData();
saveFormData();
showStep('success');
progressFill.style.width = '100%';
// Clear saved data after successful submission
localStorage.removeItem('formWizardData');
// Hide navigation
document.querySelector('.form-navigation').style.display = 'none';
}
} else {
if (validateStep()) {
collectStepData();
saveFormData();
formWizard.currentStep++;
showStep(formWizard.currentStep);
}
}
}
// Previous step
function prevStep() {
if (formWizard.currentStep > 1) {
formWizard.currentStep--;
showStep(formWizard.currentStep);
}
}
// Event Listeners
nextBtn.addEventListener('click', nextStep);
prevBtn.addEventListener('click', prevStep);
// Auto-save on input change
document.querySelectorAll('.form-input, input[type="radio"]').forEach(input => {
input.addEventListener('change', () => {
saveFormData();
});
});
// Clear validation on input
document.querySelectorAll('.form-input').forEach(input => {
input.addEventListener('input', () => {
const errorElement = document.getElementById(input.id + 'Error');
if (input.value.trim()) {
input.classList.remove('error');
if (errorElement) errorElement.classList.remove('show');
}
});
});
// Initialize
initializeFormData();
showStep(formWizard.currentStep);
</script>
</body>
</html>