984 lines
36 KiB
HTML
984 lines
36 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Liquid Metal Adaptive Flow Interface</title>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Arial', sans-serif;
|
|
background: linear-gradient(135deg, #0a0a0a, #1a1a1a, #2a2a2a);
|
|
min-height: 100vh;
|
|
overflow-x: hidden;
|
|
color: #e0e0e0;
|
|
}
|
|
|
|
/* Liquid Metal Base Styles */
|
|
.liquid-surface {
|
|
background: linear-gradient(45deg, #c0c0c0, #e8e8e8, #a8a8a8, #d0d0d0);
|
|
background-size: 400% 400%;
|
|
animation: liquidFlow 8s ease-in-out infinite;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.liquid-surface::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: linear-gradient(90deg,
|
|
transparent 0%,
|
|
rgba(255,255,255,0.3) 25%,
|
|
rgba(255,255,255,0.6) 50%,
|
|
rgba(255,255,255,0.3) 75%,
|
|
transparent 100%);
|
|
animation: mercuryReflection 3s ease-in-out infinite;
|
|
pointer-events: none;
|
|
}
|
|
|
|
@keyframes liquidFlow {
|
|
0%, 100% { background-position: 0% 50%; }
|
|
25% { background-position: 100% 0%; }
|
|
50% { background-position: 100% 100%; }
|
|
75% { background-position: 0% 100%; }
|
|
}
|
|
|
|
@keyframes mercuryReflection {
|
|
0% { transform: translateX(-100%) skewX(-15deg); opacity: 0; }
|
|
50% { opacity: 1; }
|
|
100% { transform: translateX(200%) skewX(-15deg); opacity: 0; }
|
|
}
|
|
|
|
main {
|
|
padding: 2rem;
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
h1 {
|
|
text-align: center;
|
|
margin-bottom: 3rem;
|
|
font-size: 2.5rem;
|
|
background: linear-gradient(45deg, #c0c0c0, #ffffff, #a8a8a8);
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
background-clip: text;
|
|
text-shadow: 0 0 20px rgba(192, 192, 192, 0.5);
|
|
animation: metalShimmer 4s ease-in-out infinite;
|
|
}
|
|
|
|
@keyframes metalShimmer {
|
|
0%, 100% { filter: brightness(1); }
|
|
50% { filter: brightness(1.3); }
|
|
}
|
|
|
|
/* Adaptive Flow Interface Container */
|
|
.hybrid-component {
|
|
background: linear-gradient(135deg, #2a2a2a, #3a3a3a);
|
|
border-radius: 20px;
|
|
padding: 2rem;
|
|
box-shadow:
|
|
0 20px 40px rgba(0,0,0,0.3),
|
|
inset 0 1px 0 rgba(255,255,255,0.1);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.hybrid-component::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: radial-gradient(circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
|
|
rgba(192, 192, 192, 0.1) 0%,
|
|
transparent 50%);
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.hybrid-component:hover::before {
|
|
opacity: 1;
|
|
}
|
|
|
|
/* Flow State Indicator */
|
|
.flow-state {
|
|
position: absolute;
|
|
top: 1rem;
|
|
right: 1rem;
|
|
width: 60px;
|
|
height: 60px;
|
|
border-radius: 50%;
|
|
background: linear-gradient(45deg, #4a90e2, #7bb3f0);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-weight: bold;
|
|
color: white;
|
|
box-shadow: 0 4px 15px rgba(74, 144, 226, 0.4);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.flow-state.adapting {
|
|
animation: liquidPulse 2s ease-in-out infinite;
|
|
background: linear-gradient(45deg, #f39c12, #e67e22);
|
|
}
|
|
|
|
@keyframes liquidPulse {
|
|
0%, 100% { transform: scale(1); box-shadow: 0 4px 15px rgba(243, 156, 18, 0.4); }
|
|
50% { transform: scale(1.1); box-shadow: 0 8px 25px rgba(243, 156, 18, 0.6); }
|
|
}
|
|
|
|
/* Morphing Form Container */
|
|
.form-flow {
|
|
display: grid;
|
|
gap: 1.5rem;
|
|
grid-template-columns: 1fr;
|
|
transition: all 0.6s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
}
|
|
|
|
.form-flow.expanded {
|
|
grid-template-columns: 1fr 1fr;
|
|
}
|
|
|
|
/* Liquid Input Fields */
|
|
.input-group {
|
|
position: relative;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.liquid-input {
|
|
width: 100%;
|
|
padding: 1rem 1.5rem;
|
|
border: none;
|
|
border-radius: 15px;
|
|
background: linear-gradient(135deg, #4a4a4a, #5a5a5a);
|
|
color: #e0e0e0;
|
|
font-size: 1rem;
|
|
transition: all 0.4s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
box-shadow:
|
|
inset 0 2px 5px rgba(0,0,0,0.2),
|
|
0 2px 10px rgba(0,0,0,0.1);
|
|
position: relative;
|
|
z-index: 2;
|
|
}
|
|
|
|
.liquid-input:focus {
|
|
outline: none;
|
|
transform: translateY(-2px);
|
|
box-shadow:
|
|
inset 0 2px 5px rgba(0,0,0,0.2),
|
|
0 8px 25px rgba(74, 144, 226, 0.3),
|
|
0 0 0 2px rgba(74, 144, 226, 0.5);
|
|
background: linear-gradient(135deg, #5a5a5a, #6a6a6a);
|
|
}
|
|
|
|
.liquid-input::placeholder {
|
|
color: #999;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.liquid-input:focus::placeholder {
|
|
color: #bbb;
|
|
transform: translateY(-20px);
|
|
}
|
|
|
|
/* Floating Label */
|
|
.floating-label {
|
|
position: absolute;
|
|
top: 1rem;
|
|
left: 1.5rem;
|
|
color: #999;
|
|
pointer-events: none;
|
|
transition: all 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
z-index: 3;
|
|
}
|
|
|
|
.liquid-input:focus + .floating-label,
|
|
.liquid-input:not(:placeholder-shown) + .floating-label {
|
|
top: -0.5rem;
|
|
left: 1rem;
|
|
font-size: 0.8rem;
|
|
color: #4a90e2;
|
|
background: linear-gradient(90deg, #3a3a3a, #4a4a4a, #3a3a3a);
|
|
padding: 0 0.5rem;
|
|
border-radius: 10px;
|
|
}
|
|
|
|
/* Adaptive Suggestions */
|
|
.suggestion-flow {
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 0;
|
|
right: 0;
|
|
background: linear-gradient(135deg, #3a3a3a, #4a4a4a);
|
|
border-radius: 0 0 15px 15px;
|
|
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
|
|
z-index: 10;
|
|
max-height: 0;
|
|
overflow: hidden;
|
|
transition: max-height 0.4s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
}
|
|
|
|
.suggestion-flow.active {
|
|
max-height: 200px;
|
|
}
|
|
|
|
.suggestion-item {
|
|
padding: 0.8rem 1.5rem;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
border-bottom: 1px solid rgba(255,255,255,0.1);
|
|
}
|
|
|
|
.suggestion-item:hover {
|
|
background: linear-gradient(90deg, #4a90e2, #5ba0f2);
|
|
color: white;
|
|
transform: translateX(5px);
|
|
}
|
|
|
|
.suggestion-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
/* Validation Flow */
|
|
.validation-indicator {
|
|
position: absolute;
|
|
right: 1rem;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
width: 20px;
|
|
height: 20px;
|
|
border-radius: 50%;
|
|
transition: all 0.4s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
z-index: 4;
|
|
}
|
|
|
|
.validation-indicator.valid {
|
|
background: linear-gradient(45deg, #27ae60, #2ecc71);
|
|
animation: validPulse 2s ease-in-out infinite;
|
|
}
|
|
|
|
.validation-indicator.invalid {
|
|
background: linear-gradient(45deg, #e74c3c, #c0392b);
|
|
animation: invalidShake 0.5s ease-in-out;
|
|
}
|
|
|
|
@keyframes validPulse {
|
|
0%, 100% { box-shadow: 0 0 0 0 rgba(46, 204, 113, 0.7); }
|
|
50% { box-shadow: 0 0 0 10px rgba(46, 204, 113, 0); }
|
|
}
|
|
|
|
@keyframes invalidShake {
|
|
0%, 100% { transform: translateY(-50%) translateX(0); }
|
|
25% { transform: translateY(-50%) translateX(-5px); }
|
|
75% { transform: translateY(-50%) translateX(5px); }
|
|
}
|
|
|
|
/* Context-Aware Branching */
|
|
.branch-container {
|
|
position: relative;
|
|
margin-top: 2rem;
|
|
}
|
|
|
|
.branch-path {
|
|
display: none;
|
|
animation: liquidReveal 0.6s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
}
|
|
|
|
.branch-path.active {
|
|
display: block;
|
|
}
|
|
|
|
@keyframes liquidReveal {
|
|
0% {
|
|
opacity: 0;
|
|
transform: translateY(20px) scaleY(0.8);
|
|
}
|
|
100% {
|
|
opacity: 1;
|
|
transform: translateY(0) scaleY(1);
|
|
}
|
|
}
|
|
|
|
/* Morphing Layout Grid */
|
|
.morphing-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
gap: 1.5rem;
|
|
margin-top: 2rem;
|
|
transition: all 0.6s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
}
|
|
|
|
/* Liquid Button */
|
|
.liquid-button {
|
|
background: linear-gradient(45deg, #4a90e2, #5ba0f2);
|
|
border: none;
|
|
border-radius: 15px;
|
|
padding: 1rem 2rem;
|
|
color: white;
|
|
font-size: 1rem;
|
|
font-weight: bold;
|
|
cursor: pointer;
|
|
transition: all 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
box-shadow: 0 4px 15px rgba(74, 144, 226, 0.3);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.liquid-button::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: -100%;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
|
|
transition: left 0.5s ease;
|
|
}
|
|
|
|
.liquid-button:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 25px rgba(74, 144, 226, 0.4);
|
|
}
|
|
|
|
.liquid-button:hover::before {
|
|
left: 100%;
|
|
}
|
|
|
|
.liquid-button:active {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
/* Progress Flow */
|
|
.progress-flow {
|
|
margin-top: 2rem;
|
|
height: 4px;
|
|
background: #2a2a2a;
|
|
border-radius: 2px;
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
|
|
.progress-liquid {
|
|
height: 100%;
|
|
background: linear-gradient(90deg, #4a90e2, #5ba0f2, #4a90e2);
|
|
background-size: 200% 100%;
|
|
border-radius: 2px;
|
|
width: 0%;
|
|
transition: width 0.6s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
animation: liquidProgress 2s linear infinite;
|
|
}
|
|
|
|
@keyframes liquidProgress {
|
|
0% { background-position: 200% 0; }
|
|
100% { background-position: -200% 0; }
|
|
}
|
|
|
|
/* Responsive Adaptations */
|
|
@media (max-width: 768px) {
|
|
.form-flow.expanded {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.morphing-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 2rem;
|
|
}
|
|
}
|
|
|
|
/* 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 Indicators */
|
|
.liquid-input:focus,
|
|
.liquid-button:focus {
|
|
outline: 2px solid #4a90e2;
|
|
outline-offset: 2px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<h1>Adaptive Flow Interface - Liquid Metal Theme</h1>
|
|
<div class="hybrid-component liquid-surface" id="adaptiveFlow">
|
|
<!-- Flow State Indicator -->
|
|
<div class="flow-state" id="flowState">
|
|
<span id="stateText">FLOW</span>
|
|
</div>
|
|
|
|
<!-- Adaptive Form Flow -->
|
|
<div class="form-flow" id="formFlow">
|
|
<!-- Primary Input Section -->
|
|
<div class="input-section">
|
|
<div class="input-group">
|
|
<input type="text" class="liquid-input" id="nameInput" placeholder=" " required>
|
|
<label class="floating-label" for="nameInput">Full Name</label>
|
|
<div class="validation-indicator" id="nameValidation"></div>
|
|
<div class="suggestion-flow" id="nameSuggestions"></div>
|
|
</div>
|
|
|
|
<div class="input-group">
|
|
<input type="email" class="liquid-input" id="emailInput" placeholder=" " required>
|
|
<label class="floating-label" for="emailInput">Email Address</label>
|
|
<div class="validation-indicator" id="emailValidation"></div>
|
|
<div class="suggestion-flow" id="emailSuggestions"></div>
|
|
</div>
|
|
|
|
<div class="input-group">
|
|
<select class="liquid-input" id="typeSelect" required>
|
|
<option value="">Select Purpose</option>
|
|
<option value="business">Business Inquiry</option>
|
|
<option value="personal">Personal Project</option>
|
|
<option value="enterprise">Enterprise Solution</option>
|
|
<option value="startup">Startup Consultation</option>
|
|
</select>
|
|
<label class="floating-label" for="typeSelect">Purpose</label>
|
|
<div class="validation-indicator" id="typeValidation"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Adaptive Branching Section -->
|
|
<div class="input-section">
|
|
<div class="branch-container" id="branchContainer">
|
|
<!-- Business Branch -->
|
|
<div class="branch-path" id="businessBranch">
|
|
<div class="input-group">
|
|
<input type="text" class="liquid-input" id="companyInput" placeholder=" ">
|
|
<label class="floating-label" for="companyInput">Company Name</label>
|
|
<div class="validation-indicator" id="companyValidation"></div>
|
|
</div>
|
|
<div class="input-group">
|
|
<input type="text" class="liquid-input" id="industryInput" placeholder=" ">
|
|
<label class="floating-label" for="industryInput">Industry</label>
|
|
<div class="validation-indicator" id="industryValidation"></div>
|
|
<div class="suggestion-flow" id="industrySuggestions"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Personal Branch -->
|
|
<div class="branch-path" id="personalBranch">
|
|
<div class="input-group">
|
|
<input type="text" class="liquid-input" id="projectInput" placeholder=" ">
|
|
<label class="floating-label" for="projectInput">Project Type</label>
|
|
<div class="validation-indicator" id="projectValidation"></div>
|
|
</div>
|
|
<div class="input-group">
|
|
<input type="text" class="liquid-input" id="timelineInput" placeholder=" ">
|
|
<label class="floating-label" for="timelineInput">Timeline</label>
|
|
<div class="validation-indicator" id="timelineValidation"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Enterprise Branch -->
|
|
<div class="branch-path" id="enterpriseBranch">
|
|
<div class="input-group">
|
|
<input type="text" class="liquid-input" id="scaleInput" placeholder=" ">
|
|
<label class="floating-label" for="scaleInput">Organization Size</label>
|
|
<div class="validation-indicator" id="scaleValidation"></div>
|
|
</div>
|
|
<div class="input-group">
|
|
<input type="text" class="liquid-input" id="budgetInput" placeholder=" ">
|
|
<label class="floating-label" for="budgetInput">Budget Range</label>
|
|
<div class="validation-indicator" id="budgetValidation"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Startup Branch -->
|
|
<div class="branch-path" id="startupBranch">
|
|
<div class="input-group">
|
|
<input type="text" class="liquid-input" id="stageInput" placeholder=" ">
|
|
<label class="floating-label" for="stageInput">Startup Stage</label>
|
|
<div class="validation-indicator" id="stageValidation"></div>
|
|
</div>
|
|
<div class="input-group">
|
|
<input type="text" class="liquid-input" id="fundingInput" placeholder=" ">
|
|
<label class="floating-label" for="fundingInput">Funding Status</label>
|
|
<div class="validation-indicator" id="fundingValidation"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Morphing Action Grid -->
|
|
<div class="morphing-grid" id="actionGrid">
|
|
<button class="liquid-button" id="submitBtn">
|
|
<span>Submit Flow</span>
|
|
</button>
|
|
<button class="liquid-button" id="resetBtn" style="background: linear-gradient(45deg, #95a5a6, #bdc3c7);">
|
|
<span>Reset Flow</span>
|
|
</button>
|
|
<button class="liquid-button" id="saveBtn" style="background: linear-gradient(45deg, #f39c12, #e67e22);">
|
|
<span>Save Progress</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Progress Flow Indicator -->
|
|
<div class="progress-flow">
|
|
<div class="progress-liquid" id="progressBar"></div>
|
|
</div>
|
|
|
|
<!-- Screen Reader Status -->
|
|
<div class="sr-only" aria-live="polite" id="srStatus"></div>
|
|
</div>
|
|
</main>
|
|
|
|
<script>
|
|
class LiquidMetalAdaptiveFlow {
|
|
constructor() {
|
|
this.state = {
|
|
currentBranch: null,
|
|
validationStates: {},
|
|
formProgress: 0,
|
|
isAdapting: false,
|
|
userContext: {},
|
|
suggestions: {
|
|
industries: ['Technology', 'Healthcare', 'Finance', 'Education', 'Manufacturing', 'Retail', 'Consulting'],
|
|
names: ['John Doe', 'Jane Smith', 'Alex Johnson', 'Maria Garcia', 'David Chen'],
|
|
emails: ['user@company.com', 'contact@business.org', 'info@startup.io']
|
|
}
|
|
};
|
|
|
|
this.initializeFlow();
|
|
this.bindEvents();
|
|
this.startAdaptiveMonitoring();
|
|
}
|
|
|
|
initializeFlow() {
|
|
// Initialize liquid metal interactions
|
|
this.setupLiquidEffects();
|
|
|
|
// Set up validation patterns
|
|
this.validationPatterns = {
|
|
name: /^[a-zA-Z\s]{2,}$/,
|
|
email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
required: /^.+$/
|
|
};
|
|
|
|
// Initialize progress tracking
|
|
this.updateProgress();
|
|
}
|
|
|
|
setupLiquidEffects() {
|
|
const component = document.getElementById('adaptiveFlow');
|
|
|
|
// Mouse tracking for liquid effects
|
|
component.addEventListener('mousemove', (e) => {
|
|
const rect = component.getBoundingClientRect();
|
|
const x = ((e.clientX - rect.left) / rect.width) * 100;
|
|
const y = ((e.clientY - rect.top) / rect.height) * 100;
|
|
|
|
component.style.setProperty('--mouse-x', `${x}%`);
|
|
component.style.setProperty('--mouse-y', `${y}%`);
|
|
});
|
|
}
|
|
|
|
bindEvents() {
|
|
// Input validation and suggestion handling
|
|
const inputs = document.querySelectorAll('.liquid-input');
|
|
inputs.forEach(input => {
|
|
input.addEventListener('input', (e) => this.handleInputChange(e));
|
|
input.addEventListener('focus', (e) => this.handleInputFocus(e));
|
|
input.addEventListener('blur', (e) => this.handleInputBlur(e));
|
|
});
|
|
|
|
// Branch selection handling
|
|
const typeSelect = document.getElementById('typeSelect');
|
|
typeSelect.addEventListener('change', (e) => this.handleBranchChange(e));
|
|
|
|
// Button interactions
|
|
document.getElementById('submitBtn').addEventListener('click', () => this.handleSubmit());
|
|
document.getElementById('resetBtn').addEventListener('click', () => this.handleReset());
|
|
document.getElementById('saveBtn').addEventListener('click', () => this.handleSave());
|
|
|
|
// Suggestion item clicks
|
|
document.addEventListener('click', (e) => {
|
|
if (e.target.classList.contains('suggestion-item')) {
|
|
this.applySuggestion(e.target);
|
|
}
|
|
});
|
|
}
|
|
|
|
handleInputChange(event) {
|
|
const input = event.target;
|
|
const value = input.value;
|
|
const fieldName = input.id.replace('Input', '').replace('Select', '');
|
|
|
|
// Update user context
|
|
this.state.userContext[fieldName] = value;
|
|
|
|
// Validate input
|
|
this.validateField(input);
|
|
|
|
// Show adaptive suggestions
|
|
this.showSuggestions(input, value);
|
|
|
|
// Update progress
|
|
this.updateProgress();
|
|
|
|
// Adapt form layout if needed
|
|
this.adaptFormLayout();
|
|
|
|
// Announce changes to screen readers
|
|
this.announceChange(fieldName, value);
|
|
}
|
|
|
|
handleInputFocus(event) {
|
|
const input = event.target;
|
|
const suggestionContainer = input.parentNode.querySelector('.suggestion-flow');
|
|
|
|
if (suggestionContainer) {
|
|
this.showSuggestions(input, input.value);
|
|
}
|
|
}
|
|
|
|
handleInputBlur(event) {
|
|
const input = event.target;
|
|
const suggestionContainer = input.parentNode.querySelector('.suggestion-flow');
|
|
|
|
// Delay hiding suggestions to allow for clicks
|
|
setTimeout(() => {
|
|
if (suggestionContainer) {
|
|
suggestionContainer.classList.remove('active');
|
|
}
|
|
}, 200);
|
|
}
|
|
|
|
validateField(input) {
|
|
const value = input.value;
|
|
const fieldType = input.type || 'text';
|
|
const fieldName = input.id.replace('Input', '').replace('Select', '');
|
|
const indicator = document.getElementById(`${fieldName}Validation`);
|
|
|
|
let isValid = false;
|
|
|
|
if (input.hasAttribute('required') && !value) {
|
|
isValid = false;
|
|
} else if (fieldType === 'email') {
|
|
isValid = this.validationPatterns.email.test(value);
|
|
} else if (fieldName === 'name') {
|
|
isValid = this.validationPatterns.name.test(value);
|
|
} else if (value) {
|
|
isValid = true;
|
|
}
|
|
|
|
// Update validation state
|
|
this.state.validationStates[fieldName] = isValid;
|
|
|
|
// Update indicator
|
|
if (indicator) {
|
|
indicator.className = 'validation-indicator';
|
|
if (value) {
|
|
indicator.classList.add(isValid ? 'valid' : 'invalid');
|
|
}
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
showSuggestions(input, value) {
|
|
const fieldName = input.id.replace('Input', '').replace('Select', '');
|
|
const suggestionContainer = input.parentNode.querySelector('.suggestion-flow');
|
|
|
|
if (!suggestionContainer || !value || value.length < 2) {
|
|
if (suggestionContainer) {
|
|
suggestionContainer.classList.remove('active');
|
|
}
|
|
return;
|
|
}
|
|
|
|
let suggestions = [];
|
|
|
|
// Generate context-aware suggestions
|
|
switch (fieldName) {
|
|
case 'industry':
|
|
suggestions = this.state.suggestions.industries.filter(industry =>
|
|
industry.toLowerCase().includes(value.toLowerCase())
|
|
);
|
|
break;
|
|
case 'name':
|
|
suggestions = this.state.suggestions.names.filter(name =>
|
|
name.toLowerCase().includes(value.toLowerCase())
|
|
);
|
|
break;
|
|
case 'email':
|
|
if (value.includes('@')) {
|
|
const [localPart] = value.split('@');
|
|
suggestions = ['gmail.com', 'company.com', 'business.org'].map(domain =>
|
|
`${localPart}@${domain}`
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (suggestions.length > 0) {
|
|
suggestionContainer.innerHTML = suggestions.map(suggestion =>
|
|
`<div class="suggestion-item" data-value="${suggestion}">${suggestion}</div>`
|
|
).join('');
|
|
suggestionContainer.classList.add('active');
|
|
} else {
|
|
suggestionContainer.classList.remove('active');
|
|
}
|
|
}
|
|
|
|
applySuggestion(suggestionItem) {
|
|
const input = suggestionItem.closest('.input-group').querySelector('.liquid-input');
|
|
const value = suggestionItem.dataset.value;
|
|
|
|
input.value = value;
|
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
|
|
// Hide suggestions
|
|
const suggestionContainer = suggestionItem.closest('.suggestion-flow');
|
|
suggestionContainer.classList.remove('active');
|
|
}
|
|
|
|
handleBranchChange(event) {
|
|
const selectedType = event.target.value;
|
|
this.state.currentBranch = selectedType;
|
|
|
|
// Hide all branches
|
|
const branches = document.querySelectorAll('.branch-path');
|
|
branches.forEach(branch => {
|
|
branch.classList.remove('active');
|
|
});
|
|
|
|
// Show selected branch
|
|
if (selectedType) {
|
|
const targetBranch = document.getElementById(`${selectedType}Branch`);
|
|
if (targetBranch) {
|
|
this.setAdaptingState(true);
|
|
|
|
setTimeout(() => {
|
|
targetBranch.classList.add('active');
|
|
this.adaptFormLayout();
|
|
this.setAdaptingState(false);
|
|
}, 300);
|
|
}
|
|
}
|
|
|
|
this.updateProgress();
|
|
this.announceChange('branch', selectedType);
|
|
}
|
|
|
|
adaptFormLayout() {
|
|
const formFlow = document.getElementById('formFlow');
|
|
const hasActiveBranch = document.querySelector('.branch-path.active');
|
|
|
|
if (hasActiveBranch) {
|
|
formFlow.classList.add('expanded');
|
|
} else {
|
|
formFlow.classList.remove('expanded');
|
|
}
|
|
}
|
|
|
|
updateProgress() {
|
|
const totalFields = document.querySelectorAll('.liquid-input[required]').length;
|
|
const validFields = Object.values(this.state.validationStates).filter(Boolean).length;
|
|
const progress = totalFields > 0 ? (validFields / totalFields) * 100 : 0;
|
|
|
|
this.state.formProgress = progress;
|
|
|
|
const progressBar = document.getElementById('progressBar');
|
|
progressBar.style.width = `${progress}%`;
|
|
}
|
|
|
|
setAdaptingState(isAdapting) {
|
|
this.state.isAdapting = isAdapting;
|
|
const flowState = document.getElementById('flowState');
|
|
const stateText = document.getElementById('stateText');
|
|
|
|
if (isAdapting) {
|
|
flowState.classList.add('adapting');
|
|
stateText.textContent = 'ADAPT';
|
|
} else {
|
|
flowState.classList.remove('adapting');
|
|
stateText.textContent = 'FLOW';
|
|
}
|
|
}
|
|
|
|
startAdaptiveMonitoring() {
|
|
// Monitor user behavior and adapt interface
|
|
setInterval(() => {
|
|
this.analyzeUserBehavior();
|
|
}, 2000);
|
|
}
|
|
|
|
analyzeUserBehavior() {
|
|
// Adaptive logic based on user context
|
|
const context = this.state.userContext;
|
|
|
|
// Auto-suggest based on patterns
|
|
if (context.name && !context.email && context.name.includes(' ')) {
|
|
const [firstName, lastName] = context.name.split(' ');
|
|
const emailSuggestion = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@company.com`;
|
|
|
|
// Store for later suggestion
|
|
if (!this.state.suggestions.emails.includes(emailSuggestion)) {
|
|
this.state.suggestions.emails.unshift(emailSuggestion);
|
|
}
|
|
}
|
|
|
|
// Adapt form complexity based on progress
|
|
if (this.state.formProgress > 80) {
|
|
document.getElementById('actionGrid').style.transform = 'scale(1.02)';
|
|
} else {
|
|
document.getElementById('actionGrid').style.transform = 'scale(1)';
|
|
}
|
|
}
|
|
|
|
handleSubmit() {
|
|
// Validate all required fields
|
|
const requiredInputs = document.querySelectorAll('.liquid-input[required]');
|
|
let allValid = true;
|
|
|
|
requiredInputs.forEach(input => {
|
|
if (!this.validateField(input)) {
|
|
allValid = false;
|
|
}
|
|
});
|
|
|
|
if (allValid) {
|
|
this.setAdaptingState(true);
|
|
|
|
// Simulate submission
|
|
setTimeout(() => {
|
|
alert('Form submitted successfully with liquid flow!');
|
|
this.setAdaptingState(false);
|
|
this.announceChange('form', 'submitted');
|
|
}, 1500);
|
|
} else {
|
|
this.announceChange('validation', 'Please complete all required fields');
|
|
}
|
|
}
|
|
|
|
handleReset() {
|
|
// Reset all inputs
|
|
const inputs = document.querySelectorAll('.liquid-input');
|
|
inputs.forEach(input => {
|
|
input.value = '';
|
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
});
|
|
|
|
// Reset state
|
|
this.state = {
|
|
...this.state,
|
|
currentBranch: null,
|
|
validationStates: {},
|
|
formProgress: 0,
|
|
userContext: {}
|
|
};
|
|
|
|
// Hide all branches
|
|
const branches = document.querySelectorAll('.branch-path');
|
|
branches.forEach(branch => {
|
|
branch.classList.remove('active');
|
|
});
|
|
|
|
this.adaptFormLayout();
|
|
this.updateProgress();
|
|
this.announceChange('form', 'reset');
|
|
}
|
|
|
|
handleSave() {
|
|
// Save current progress
|
|
const progressData = {
|
|
context: this.state.userContext,
|
|
branch: this.state.currentBranch,
|
|
progress: this.state.formProgress,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
localStorage.setItem('liquidFlowProgress', JSON.stringify(progressData));
|
|
|
|
this.setAdaptingState(true);
|
|
setTimeout(() => {
|
|
alert('Progress saved in liquid state!');
|
|
this.setAdaptingState(false);
|
|
this.announceChange('progress', 'saved');
|
|
}, 800);
|
|
}
|
|
|
|
announceChange(type, value) {
|
|
const srStatus = document.getElementById('srStatus');
|
|
let message = '';
|
|
|
|
switch (type) {
|
|
case 'branch':
|
|
message = `Form adapted to ${value} workflow`;
|
|
break;
|
|
case 'validation':
|
|
message = value;
|
|
break;
|
|
case 'form':
|
|
message = `Form ${value}`;
|
|
break;
|
|
case 'progress':
|
|
message = `Progress ${value}`;
|
|
break;
|
|
default:
|
|
message = `${type} updated to ${value}`;
|
|
}
|
|
|
|
srStatus.textContent = message;
|
|
}
|
|
}
|
|
|
|
// Initialize the Liquid Metal Adaptive Flow Interface
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
new LiquidMetalAdaptiveFlow();
|
|
});
|
|
|
|
// Load saved progress if available
|
|
window.addEventListener('load', () => {
|
|
const savedProgress = localStorage.getItem('liquidFlowProgress');
|
|
if (savedProgress) {
|
|
const data = JSON.parse(savedProgress);
|
|
|
|
// Restore form state
|
|
Object.entries(data.context).forEach(([field, value]) => {
|
|
const input = document.getElementById(`${field}Input`) || document.getElementById(`${field}Select`);
|
|
if (input && value) {
|
|
input.value = value;
|
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
}
|
|
});
|
|
|
|
// Restore branch if needed
|
|
if (data.branch) {
|
|
const typeSelect = document.getElementById('typeSelect');
|
|
if (typeSelect) {
|
|
typeSelect.value = data.branch;
|
|
typeSelect.dispatchEvent(new Event('change', { bubbles: true }));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |