Input text fields are a fundamental component of user interfaces, enabling users to enter and submit data effortlessly. From simple text boxes to more complex input types, these elements play a crucial role in enhancing user experience.
In this article, we will explore ten diverse examples of input text fields, showcasing their versatility and functionality. Whether you're designing a form or a search bar, these examples will provide valuable insights and inspiration.
CODE1
Here's the code:
CODETEXT1
CODE2
Here's the code:
CODETEXT2
CODE3
Here's the code:
CODETEXT3
CODE4
Here's the code:
CODETEXT4
CODE5
Here's the code:
CODETEXT5
Designers and developers love Subframe for its drag-and-drop interface and intuitive, responsive canvas. Create pixel-perfect UI effortlessly, ensuring every detail is just right.
Join the community of satisfied users and elevate your design game. Start for free today!
CODE6
Here's the code:
CODETEXT6
CODE7
Here's the code:
CODETEXT7
CODE8
Here's the code:
CODETEXT8
CODE9
Here's the code:
CODETEXT9
CODE10
Here's the code:
CODETEXT10
Ready to elevate your UI design game? With Subframe, you can create pixel-perfect interfaces, including input text fields, in minutes. Experience unparalleled efficiency with our drag-and-drop editor.
Join the community of designers and developers who trust Subframe for their projects. Start for free and begin creating stunning UIs right away!
<html> <head> <style> :root { --primary-color: #4a6cff; --secondary-color: #f1f4ff; --error-color: #ff5b65; --success-color: #36d29e; --text-color: #2c3e50; --border-color: #e0e5ec; --placeholder-color: #a2a9b8; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #f8fafc; padding: 20px; } .login-container { width: 100%; max-width: 380px; padding: 40px 30px; border-radius: 18px; background: white; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.04); transition: transform 0.3s ease; } .login-container:hover { transform: translateY(-5px); } .login-header { margin-bottom: 30px; } .login-header h1 { font-size: 28px; font-weight: 700; color: var(--text-color); margin-bottom: 10px; } .login-header p { font-size: 16px; color: var(--placeholder-color); line-height: 1.5; } .form-group { position: relative; margin-bottom: 24px; } .form-group label { display: block; font-size: 14px; font-weight: 600; color: var(--text-color); margin-bottom: 8px; transition: color 0.2s ease; } .input-container { position: relative; width: 100%; } .input-field { width: 100%; padding: 16px 18px; font-size: 16px; color: var(--text-color); background: white; border: 2px solid var(--border-color); border-radius: 12px; outline: none; transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); } .input-field::placeholder { color: var(--placeholder-color); } .input-field:focus { border-color: var(--primary-color); box-shadow: 0 0 0 3px rgba(74, 108, 255, 0.1); } .input-field.error { border-color: var(--error-color); animation: shake 0.5s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; } .input-icon { position: absolute; right: 18px; top: 50%; transform: translateY(-50%); color: var(--placeholder-color); transition: all 0.2s ease; } .error-message { display: none; font-size: 13px; color: var(--error-color); margin-top: 6px; opacity: 0; transition: opacity 0.2s ease; } .error-message.visible { display: block; opacity: 1; } .forgot-password { display: block; text-align: right; font-size: 14px; color: var(--primary-color); margin-top: -10px; margin-bottom: 30px; text-decoration: none; position: relative; } .forgot-password:after { content: ''; position: absolute; width: 0; height: 1px; bottom: -2px; left: 0; background-color: var(--primary-color); transition: width 0.3s ease; } .forgot-password:hover:after { width: 100%; } .login-button { position: relative; width: 100%; padding: 16px 24px; background: var(--primary-color); color: white; font-size: 16px; font-weight: 600; border: none; border-radius: 12px; cursor: pointer; overflow: hidden; transition: all 0.3s ease; outline: none; } .login-button:hover { background: #3b5cf7; transform: translateY(-2px); box-shadow: 0 6px 15px rgba(74, 108, 255, 0.2); } .login-button:active { transform: translateY(0); } .login-button .button-loader { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); display: none; } .login-button .button-loader::after { content: ""; display: block; width: 20px; height: 20px; border-radius: 50%; border: 2px solid transparent; border-top-color: white; animation: spin 0.8s linear infinite; } .login-button.loading { pointer-events: none; background: #6f88ff; } .login-button.loading .button-text { opacity: 0; } .login-button.loading .button-loader { display: block; } .login-alternatives { margin-top: 30px; text-align: center; } .login-alternatives p { font-size: 14px; color: var(--placeholder-color); margin-bottom: 16px; position: relative; } .login-alternatives p::before, .login-alternatives p::after { content: ''; position: absolute; top: 50%; width: 30%; height: 1px; background-color: var(--border-color); } .login-alternatives p::before { left: 0; } .login-alternatives p::after { right: 0; } .alternative-buttons { display: flex; justify-content: center; gap: 12px; } .alternative-button { display: flex; align-items: center; justify-content: center; width: 50px; height: 50px; border-radius: 12px; background: white; border: 2px solid var(--border-color); cursor: pointer; transition: all 0.2s ease; } .alternative-button:hover { border-color: var(--primary-color); background: var(--secondary-color); transform: translateY(-3px); } .alternative-button img { width: 24px; height: 24px; } .signup-prompt { margin-top: 30px; text-align: center; font-size: 14px; color: var(--text-color); } .signup-link { color: var(--primary-color); font-weight: 600; text-decoration: none; position: relative; } .signup-link:after { content: ''; position: absolute; width: 0; height: 1px; bottom: -2px; left: 0; background-color: var(--primary-color); transition: width 0.3s ease; } .signup-link:hover:after { width: 100%; } @keyframes shake { 10%, 90% { transform: translateX(-1px); } 20%, 80% { transform: translateX(2px); } 30%, 50%, 70% { transform: translateX(-4px); } 40%, 60% { transform: translateX(4px); } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .password-toggle { background: none; border: none; cursor: pointer; position: absolute; right: 18px; top: 50%; transform: translateY(-50%); color: var(--placeholder-color); } .password-toggle svg { width: 20px; height: 20px; transition: color 0.2s ease; } .password-toggle:hover svg { color: var(--primary-color); } .success-indicator { position: absolute; right: 18px; top: 50%; transform: translateY(-50%); opacity: 0; transition: opacity 0.3s ease; color: var(--success-color); } .success-indicator.visible { opacity: 1; } .progress-bar { position: absolute; bottom: 0; left: 0; height: 3px; width: 0; background: var(--primary-color); transition: width 0.3s ease; border-bottom-left-radius: 12px; transform-origin: left; } @media (max-width: 480px) { .login-container { padding: 30px 20px; } .login-header h1 { font-size: 24px; } .login-header p { font-size: 14px; } .input-field { padding: 14px 16px; } } </style> </head> <body> <div class="login-container"> <div class="login-header"> <h1>Welcome back</h1> <p>Log in to access your workspace and continue your digital journey</p> </div> <form id="login-form"> <div class="form-group"> <label for="email">Email</label> <div class="input-container"> <input type="email" id="email" class="input-field" placeholder="[email protected]" autocomplete="email"> <div class="progress-bar" id="email-progress"></div> <div class="success-indicator" id="email-success"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M7.75 12.75L10 15.25L16.25 8.75" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/> </svg> </div> </div> <div class="error-message" id="email-error"></div> </div> <div class="form-group"> <label for="password">Password</label> <div class="input-container"> <input type="password" id="password" class="input-field" placeholder="Enter your password" autocomplete="current-password"> <div class="progress-bar" id="password-progress"></div> <button type="button" class="password-toggle" id="password-toggle" aria-label="Toggle password visibility"> <svg id="eye-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 5C7.52 5 3.73 7.85 2 12C3.73 16.15 7.52 19 12 19C16.48 19 20.27 16.15 22 12C20.27 7.85 16.48 5 12 5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> <svg id="eye-off-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="display: none;"> <path d="M14.12 14.12C13.8454 14.4148 13.5141 14.6512 13.1462 14.8151C12.7782 14.9791 12.3809 15.0673 11.9781 15.0744C11.5753 15.0815 11.1752 15.0074 10.8016 14.8565C10.4281 14.7056 10.0887 14.4811 9.80385 14.1962C9.51897 13.9113 9.29439 13.572 9.14351 13.1984C8.99262 12.8249 8.91853 12.4247 8.92563 12.0219C8.93274 11.6191 9.02091 11.2219 9.18488 10.8539C9.34884 10.4859 9.58525 10.1547 9.88 9.88002M17.94 17.94C16.2306 19.243 14.1491 19.9649 12 20C7 20 2.73 16.39 1 12C1.73 10.46 2.67 9.06 3.77 7.88L17.94 17.94ZM8.27 3.74C9.42 3.25 10.68 3 12 3C17 3 21.27 6.61 23 11C22.18 12.79 21.03 14.36 19.67 15.59L8.27 3.74Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M1 1L23 23" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> </div> <div class="error-message" id="password-error"></div> </div> <a href="#" class="forgot-password">Forgot password?</a> <button type="submit" class="login-button" id="login-button"> <span class="button-text">Log in</span> <span class="button-loader"></span> </button> </form> <div class="login-alternatives"> <p>Or continue with</p> <div class="alternative-buttons"> <button class="alternative-button" aria-label="Login with Google"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M21.8055 10.0415H21V10H12V14H17.6515C16.827 16.3285 14.6115 18 12 18C8.6865 18 6 15.3135 6 12C6 8.6865 8.6865 6 12 6C13.5295 6 14.921 6.577 15.9805 7.5195L18.809 4.691C17.023 3.0265 14.634 2 12 2C6.4775 2 2 6.4775 2 12C2 17.5225 6.4775 22 12 22C17.5225 22 22 17.5225 22 12C22 11.3295 21.931 10.675 21.8055 10.0415Z" fill="#FFC107"/> <path d="M3.15302 7.3455L6.43852 9.755C7.32752 7.554 9.48052 6 12 6C13.5295 6 14.921 6.577 15.9805 7.5195L18.809 4.691C17.023 3.0265 14.634 2 12 2C8.15902 2 4.82802 4.1685 3.15302 7.3455Z" fill="#FF3D00"/> <path d="M12 22C14.583 22 16.93 21.0115 18.7045 19.404L15.6095 16.785C14.5717 17.5742 13.3037 18.001 12 18C9.39903 18 7.19053 16.3415 6.35853 14.027L3.09753 16.5395C4.75253 19.778 8.11403 22 12 22Z" fill="#4CAF50"/> <path d="M21.8055 10.0415H21V10H12V14H17.6515C17.2571 15.1082 16.5467 16.0766 15.608 16.7855L15.6095 16.7845L18.7045 19.4035C18.4855 19.6025 22 17 22 12C22 11.3295 21.931 10.675 21.8055 10.0415Z" fill="#1976D2"/> </svg> </button> <button class="alternative-button" aria-label="Login with Apple"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M14.94 5.19C15.8552 4.18871 16.3493 2.88414 16.31 1.55C15.0243 1.63787 13.8335 2.28138 13.03 3.33C12.1379 4.29522 11.6353 5.56457 11.64 6.89C12.9355 6.89461 14.1062 6.25794 14.94 5.19Z" fill="black"/> <path d="M19.31 12.64C19.3255 11.8378 19.5196 11.0535 19.8791 10.3466C20.2386 9.63968 20.7544 9.03062 21.39 8.57C20.9265 7.93414 20.3267 7.40322 19.6329 7.01334C18.9391 6.62347 18.1685 6.38428 17.38 6.31C15.73 6.14 14.25 7.26 13.44 7.26C12.63 7.26 11.39 6.33 10.02 6.36C9.11603 6.40664 8.24288 6.68968 7.48749 7.18377C6.73209 7.67785 6.11591 8.36701 5.7 9.18C3.93 12.34 5.25 17.11 7 19.87C7.84 21.21 8.84 22.7 10.17 22.66C11.5 22.61 12.07 21.82 13.67 21.82C15.27 21.82 15.79 22.66 17.18 22.63C18.57 22.6 19.47 21.28 20.28 19.93C20.9071 18.9844 21.3796 17.9407 21.68 16.84C20.87 16.5435 20.1493 16.0433 19.5915 15.3886C19.0336 14.7339 18.6589 13.9538 18.51 13.12V13.12C18.3829 13.2936 18.1404 13.3844 17.895 13.3472C17.6496 13.31 17.4477 13.1511 17.37 12.92C17.2399 12.5182 17.1943 12.0963 17.24 11.68C17.281 11.2657 17.4138 10.8656 17.63 10.51C17.77 10.28 18.02 10.15 18.29 10.16C18.6291 10.1679 18.9557 10.2838 19.22 10.49C19.22 10.49 18.5 11.94 19.31 12.64Z" fill="black"/> </svg> </button> <button class="alternative-button" aria-label="Login with Microsoft"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M11.4 3H3V11.4H11.4V3Z" fill="#F25022"/> <path d="M11.4 12.6H3V21H11.4V12.6Z" fill="#00A4EF"/> <path d="M21 3H12.6V11.4H21V3Z" fill="#7FBA00"/> <path d="M21 12.6H12.6V21H21V12.6Z" fill="#FFB900"/> </svg> </button> </div> </div> <div class="signup-prompt"> Don't have an account? <a href="#" class="signup-link">Sign up</a> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const form = document.getElementById('login-form'); const emailInput = document.getElementById('email'); const passwordInput = document.getElementById('password'); const emailError = document.getElementById('email-error'); const passwordError = document.getElementById('password-error'); const loginButton = document.getElementById('login-button'); const passwordToggle = document.getElementById('password-toggle'); const eyeIcon = document.getElementById('eye-icon'); const eyeOffIcon = document.getElementById('eye-off-icon'); const emailSuccess = document.getElementById('email-success'); const emailProgress = document.getElementById('email-progress'); const passwordProgress = document.getElementById('password-progress'); // Email validation emailInput.addEventListener('input', function() { const value = this.value.trim(); const progress = calculateEmailProgress(value); emailProgress.style.width = `${progress}%`; if (value === '') { emailError.textContent = ''; emailError.classList.remove('visible'); emailSuccess.classList.remove('visible'); } else if (!isValidEmail(value)) { emailError.textContent = 'Please enter a valid email address'; emailError.classList.add('visible'); emailSuccess.classList.remove('visible'); this.classList.add('error'); } else { emailError.textContent = ''; emailError.classList.remove('visible'); emailSuccess.classList.add('visible'); this.classList.remove('error'); } }); // Password validation passwordInput.addEventListener('input', function() { const value = this.value.trim(); const progress = Math.min(value.length * 10, 100); passwordProgress.style.width = `${progress}%`; if (value === '') { passwordError.textContent = ''; passwordError.classList.remove('visible'); } else if (value.length < 6) { passwordError.textContent = 'Password must be at least 6 characters'; passwordError.classList.add('visible'); this.classList.add('error'); } else { passwordError.textContent = ''; passwordError.classList.remove('visible'); this.classList.remove('error'); } }); // Toggle password visibility passwordToggle.addEventListener('click', function() { if (passwordInput.type === 'password') { passwordInput.type = 'text'; eyeIcon.style.display = 'none'; eyeOffIcon.style.display = 'block'; } else { passwordInput.type = 'password'; eyeIcon.style.display = 'block'; eyeOffIcon.style.display = 'none'; } passwordInput.focus(); }); // Form submission form.addEventListener('submit', function(e) { e.preventDefault(); // Validate email const email = emailInput.value.trim(); if (email === '') { emailError.textContent = 'Email is required'; emailError.classList.add('visible'); emailInput.classList.add('error'); return; } else if (!isValidEmail(email)) { emailError.textContent = 'Please enter a valid email address'; emailError.classList.add('visible'); emailInput.classList.add('error'); return; } // Validate password const password = passwordInput.value.trim(); if (password === '') { passwordError.textContent = 'Password is required'; passwordError.classList.add('visible'); passwordInput.classList.add('error'); return; } else if (password.length < 6) { passwordError.textContent = 'Password must be at least 6 characters'; passwordError.classList.add('visible'); passwordInput.classList.add('error'); return; } // Show loading state loginButton.classList.add('loading'); // Simulate API call setTimeout(function() { loginButton.classList.remove('loading'); // Reset form after successful login (for demo purposes) form.reset(); emailProgress.style.width = '0'; passwordProgress.style.width = '0'; emailSuccess.classList.remove('visible'); // Show success message (for demo purposes) const successMessage = document.createElement('div'); successMessage.style.position = 'absolute'; successMessage.style.top = '20px'; successMessage.style.left = '50%'; successMessage.style.transform = 'translateX(-50%)'; successMessage.style.padding = '12px 24px'; successMessage.style.background = 'var(--success-color)'; successMessage.style.color = 'white'; successMessage.style.borderRadius = '8px'; successMessage.style.boxShadow = '0 4px 10px rgba(0, 0, 0, 0.1)'; successMessage.style.zIndex = '1000'; successMessage.textContent = 'Login successful! Welcome back.'; document.body.appendChild(successMessage); setTimeout(function() { successMessage.style.opacity = '0'; successMessage.style.transition = 'opacity 0.5s ease'; setTimeout(function() { document.body.removeChild(successMessage); }, 500); }, 3000); }, 1500); }); // Helper functions function isValidEmail(email) { const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return regex.test(email); } function calculateEmailProgress(email) { if (email.length === 0) return 0; if (email.includes('@') && email.includes('.')) { if (isValidEmail(email)) return 100; return 75; } if (email.includes('@')) return 50; return 25; } // Alternatively login buttons document.querySelectorAll('.alternative-button').forEach(button => { button.addEventListener('click', function() { this.style.transform = 'scale(0.95)'; setTimeout(() => { this.style.transform = 'translateY(-3px)'; }, 150); }); }); // Prevent real form submission and page refresh form.addEventListener('submit', function(e) { e.preventDefault(); return false; }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Modern E-commerce Checkout</title> <style> :root { --primary: #5046e5; --primary-dark: #3c35b5; --secondary: #ff6b6b; --dark: #2a2a2a; --light: #ffffff; --grey: #f5f7fa; --grey-dark: #e1e5ee; --success: #32d296; --warning: #faa05a; --error: #f0506e; --input-shadow: 0 4px 10px rgba(0, 0, 0, 0.05); --card-shadow: 0 10px 40px rgba(0, 0, 0, 0.08); --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background: var(--grey); display: flex; align-items: center; justify-content: center; min-height: 100vh; color: var(--dark); padding: 20px; } .checkout-container { background: var(--light); border-radius: 20px; box-shadow: var(--card-shadow); width: 100%; max-width: 650px; overflow: hidden; position: relative; } .progress-bar { display: flex; position: relative; padding: 25px 30px 5px; background: var(--primary); color: white; } .progress-step { flex: 1; text-align: center; position: relative; z-index: 1; } .step-number { display: flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: 50%; background: rgba(255, 255, 255, 0.2); margin: 0 auto 8px; position: relative; transition: var(--transition); } .progress-step.active .step-number { background: var(--light); color: var(--primary); } .progress-step.completed .step-number:before { content: "✓"; position: absolute; } .step-label { font-size: 0.85rem; font-weight: 500; opacity: 0.7; margin-bottom: 10px; transition: var(--transition); } .progress-step.active .step-label { opacity: 1; } .progress-bar:after { content: ""; height: 2px; background: rgba(255, 255, 255, 0.2); position: absolute; width: 66%; top: 40px; left: 17%; z-index: 0; } .progress-indicator { height: 2px; background: var(--light); position: absolute; top: 40px; left: 17%; z-index: 0; width: 0; transition: width 0.5s ease; } .checkout-form { padding: 30px; } .form-header { margin-bottom: 25px; } .form-header h2 { font-size: 1.6rem; font-weight: 700; margin-bottom: 8px; color: var(--dark); } .form-header p { color: #64748b; font-size: 0.95rem; } .form-section { display: none; } .form-section.active { display: block; animation: fadeIn 0.5s ease forwards; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .form-row { margin-bottom: 20px; } .form-group { margin-bottom: 20px; position: relative; } .form-group label { display: block; margin-bottom: 8px; font-weight: 600; font-size: 0.9rem; color: var(--dark); } .form-control { width: 100%; padding: 16px; border: 2px solid var(--grey-dark); border-radius: 10px; font-size: 1rem; transition: var(--transition); box-shadow: var(--input-shadow); background-color: var(--light); } .form-control:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(80, 70, 229, 0.1); } .form-control.error { border-color: var(--error); } .form-control.valid { border-color: var(--success); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%2332d296' viewBox='0 0 16 16'%3E%3Cpath d='M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 16px center; padding-right: 40px; } .error-message { display: none; color: var(--error); font-size: 0.85rem; margin-top: 6px; animation: shake 0.3s ease-in-out; display: flex; align-items: center; } .error-message::before { content: "!"; display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; background: var(--error); color: white; border-radius: 50%; margin-right: 8px; font-size: 0.75rem; font-weight: bold; } @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } } .form-help { font-size: 0.85rem; color: #64748b; margin-top: 6px; } .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } .form-grid-3 { grid-template-columns: 1.5fr 1fr 1fr; } .form-action { margin-top: 40px; display: flex; justify-content: space-between; } .btn { padding: 16px 30px; border-radius: 10px; font-weight: 600; cursor: pointer; transition: var(--transition); font-size: 1rem; border: none; display: inline-flex; align-items: center; justify-content: center; } .btn-primary { background: var(--primary); color: white; box-shadow: 0 6px 15px rgba(80, 70, 229, 0.2); } .btn-primary:hover { background: var(--primary-dark); transform: translateY(-2px); box-shadow: 0 10px 20px rgba(80, 70, 229, 0.3); } .btn-secondary { background: var(--grey); color: var(--dark); } .btn-secondary:hover { background: var(--grey-dark); } .card-icon { position: absolute; right: 16px; top: 50%; transform: translateY(-50%); width: 40px; height: 28px; border-radius: 4px; background: var(--grey); display: flex; align-items: center; justify-content: center; pointer-events: none; } .credit-card { background: linear-gradient(135deg, var(--primary), var(--primary-dark)); border-radius: 16px; padding: 20px; color: white; margin-bottom: 30px; position: relative; overflow: hidden; box-shadow: 0 8px 20px rgba(80, 70, 229, 0.2); } .credit-card::before { content: ""; position: absolute; top: -50px; right: -50px; width: 150px; height: 150px; border-radius: 50%; background: rgba(255, 255, 255, 0.1); z-index: 0; } .credit-card::after { content: ""; position: absolute; bottom: -80px; left: -20px; width: 200px; height: 200px; border-radius: 50%; background: rgba(255, 255, 255, 0.05); z-index: 0; } .card-number { font-size: 1.3rem; letter-spacing: 2px; margin: 20px 0 30px; font-family: monospace; } .card-details { display: flex; justify-content: space-between; font-size: 0.9rem; } .card-details div { display: flex; flex-direction: column; } .card-label { opacity: 0.7; font-size: 0.75rem; margin-bottom: 5px; } .chip { width: 40px; height: 30px; background: linear-gradient(135deg, #ffb74d, #f57c00); border-radius: 5px; position: relative; overflow: hidden; margin-bottom: 20px; } .chip::before { content: ""; position: absolute; width: 60%; height: 60%; background: rgba(255, 255, 255, 0.15); top: 20%; left: 20%; } .chip::after { content: ""; position: absolute; width: 80%; height: 4px; background: rgba(0, 0, 0, 0.2); top: 50%; left: 10%; transform: translateY(-50%); } .card-brand { position: absolute; top: 20px; right: 20px; font-size: 1.5rem; font-weight: 700; color: rgba(255, 255, 255, 0.9); } @media (max-width: 640px) { .form-grid, .form-grid-3 { grid-template-columns: 1fr; } .step-label { font-size: 0.7rem; } .credit-card { padding: 15px; } .card-number { font-size: 1.1rem; margin: 15px 0 20px; } .checkout-form { padding: 20px; } } /* Tooltip styles */ .tooltip { position: relative; display: inline-block; margin-left: 8px; width: 18px; height: 18px; background: var(--grey-dark); color: var(--dark); border-radius: 50%; font-size: 0.75rem; font-weight: bold; text-align: center; line-height: 18px; cursor: help; } .tooltip .tooltip-text { visibility: hidden; width: 200px; background-color: var(--dark); color: var(--light); text-align: center; border-radius: 6px; padding: 10px; position: absolute; z-index: 1; bottom: 125%; left: 50%; transform: translateX(-50%); opacity: 0; transition: opacity 0.3s; font-weight: normal; font-size: 0.85rem; line-height: 1.4; pointer-events: none; } .tooltip .tooltip-text::after { content: ""; position: absolute; top: 100%; left: 50%; margin-left: -5px; border-width: 5px; border-style: solid; border-color: var(--dark) transparent transparent transparent; } .tooltip:hover .tooltip-text { visibility: visible; opacity: 1; } /* Confetti effect for completion */ .confetti-container { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 9999; display: none; } .confetti { position: absolute; width: 10px; height: 10px; background-color: #ff0; opacity: 0; } .success-message { display: none; text-align: center; padding: 40px 20px; animation: fadeIn 0.5s ease forwards; } .success-icon { width: 80px; height: 80px; background: var(--success); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 20px; position: relative; color: white; font-size: 2.5rem; } .success-icon:before { content: "✓"; } .success-message h2 { font-size: 1.8rem; margin-bottom: 15px; color: var(--dark); } .success-message p { color: #64748b; margin-bottom: 30px; font-size: 1rem; line-height: 1.6; } /* Fancy input highlight effect */ .form-group.focus-within label { color: var(--primary); } /* Live typing effect for credit card */ #cardNumberDisplay { position: relative; } #cardNumberDisplay .typing-indicator { position: absolute; right: 0; top: 50%; transform: translateY(-50%); width: 2px; height: 20px; background: white; animation: blink 1s infinite; } @keyframes blink { 0%, 100% { opacity: 0; } 50% { opacity: 1; } } </style> </head> <body> <div class="checkout-container"> <div class="progress-bar"> <div class="progress-indicator" id="progressBar"></div> <div class="progress-step active" data-step="1"> <div class="step-number">1</div> <div class="step-label">Shipping</div> </div> <div class="progress-step" data-step="2"> <div class="step-number">2</div> <div class="step-label">Payment</div> </div> <div class="progress-step" data-step="3"> <div class="step-number">3</div> <div class="step-label">Confirm</div> </div> </div> <div class="checkout-form"> <!-- Shipping Address Section --> <div class="form-section active" id="section1"> <div class="form-header"> <h2>Shipping Information</h2> <p>Where should we send your stylish new items?</p> </div> <div class="form-row"> <div class="form-grid"> <div class="form-group"> <label for="firstName">First Name</label> <input type="text" class="form-control" id="firstName" placeholder="Enter your first name"> <div class="error-message" id="firstNameError">Please enter your first name</div> </div> <div class="form-group"> <label for="lastName">Last Name</label> <input type="text" class="form-control" id="lastName" placeholder="Enter your last name"> <div class="error-message" id="lastNameError">Please enter your last name</div> </div> </div> </div> <div class="form-group"> <label for="email">Email Address</label> <input type="email" class="form-control" id="email" placeholder="[email protected]"> <div class="error-message" id="emailError">Please enter a valid email address</div> <div class="form-help">We'll send your receipt to this email</div> </div> <div class="form-group"> <label for="address">Street Address</label> <input type="text" class="form-control" id="address" placeholder="123 Main Street"> <div class="error-message" id="addressError">Please enter your street address</div> </div> <div class="form-group"> <label for="addressLine2">Apartment, suite, etc. (optional)</label> <input type="text" class="form-control" id="addressLine2" placeholder="Apt 4B, Floor 2, etc."> </div> <div class="form-row"> <div class="form-grid-3"> <div class="form-group"> <label for="city">City</label> <input type="text" class="form-control" id="city" placeholder="Enter your city"> <div class="error-message" id="cityError">Please enter your city</div> </div> <div class="form-group"> <label for="state">State/Province</label> <input type="text" class="form-control" id="state" placeholder="CA"> <div class="error-message" id="stateError">Please enter your state</div> </div> <div class="form-group"> <label for="zip">ZIP / Postal</label> <input type="text" class="form-control" id="zip" placeholder="90210"> <div class="error-message" id="zipError">Please enter a valid ZIP code</div> </div> </div> </div> <div class="form-group"> <label for="phone">Phone Number</label> <input type="tel" class="form-control" id="phone" placeholder="(555) 123-4567"> <div class="error-message" id="phoneError">Please enter a valid phone number</div> <div class="form-help">For delivery questions only</div> </div> <div class="form-action"> <button class="btn btn-secondary" id="backToCart">Back to Cart</button> <button class="btn btn-primary" id="nextToPayment">Continue to Payment</button> </div> </div> <!-- Payment Information Section --> <div class="form-section" id="section2"> <div class="form-header"> <h2>Payment Details</h2> <p>Secure checkout with encrypted payment</p> </div> <div class="credit-card"> <div class="card-brand">VISA</div> <div class="chip"></div> <div class="card-number" id="cardNumberDisplay">•••• •••• •••• ••••</div> <div class="card-details"> <div> <span class="card-label">CARD HOLDER</span> <span id="cardHolderDisplay">Your Name</span> </div> <div> <span class="card-label">EXPIRES</span> <span id="expiryDisplay">MM/YY</span> </div> </div> </div> <div class="form-group"> <label for="cardName">Cardholder Name</label> <input type="text" class="form-control" id="cardName" placeholder="Name as appears on card"> <div class="error-message" id="cardNameError">Please enter the cardholder name</div> </div> <div class="form-group"> <label for="cardNumber">Card Number</label> <input type="text" class="form-control" id="cardNumber" placeholder="1234 5678 9012 3456" maxlength="19"> <div class="card-icon" id="cardIcon"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <rect x="2" y="5" width="20" height="14" rx="2" stroke="#2A2A2A" stroke-width="2"/> <line x1="2" y1="10" x2="22" y2="10" stroke="#2A2A2A" stroke-width="2"/> </svg> </div> <div class="error-message" id="cardNumberError">Please enter a valid card number</div> </div> <div class="form-row"> <div class="form-grid"> <div class="form-group"> <label for="expiry">Expiration Date</label> <input type="text" class="form-control" id="expiry" placeholder="MM/YY" maxlength="5"> <div class="error-message" id="expiryError">Please enter a valid expiration date</div> </div> <div class="form-group"> <label for="cvv">Security Code (CVV) <span class="tooltip">? <span class="tooltip-text">The 3 or 4-digit code on the back of your card</span> </span></label> <input type="text" class="form-control" id="cvv" placeholder="123" maxlength="4"> <div class="error-message" id="cvvError">Please enter a valid CVV</div> </div> </div> </div> <div class="form-group"> <label for="billingAddress">Billing Address</label> <div class="form-help" style="margin-top: 0; margin-bottom: 10px;"> <input type="checkbox" id="sameAsShipping" checked> <label for="sameAsShipping" style="font-weight: normal; display: inline;">Same as shipping address</label> </div> <input type="text" class="form-control" id="billingAddress" placeholder="123 Main Street" disabled> </div> <div class="form-action"> <button class="btn btn-secondary" id="backToShipping">Back to Shipping</button> <button class="btn btn-primary" id="nextToConfirm">Review Order</button> </div> </div> <!-- Order Confirmation Section --> <div class="form-section" id="section3"> <div class="form-header"> <h2>Order Summary</h2> <p>Please review your information before placing the order</p> </div> <div style="background: var(--grey); padding: 20px; border-radius: 10px; margin-bottom: 25px;"> <h3 style="margin-bottom: 15px; font-size: 1.1rem;">Shipping Information</h3> <p id="shippingInfoSummary" style="line-height: 1.6;"> Alex Johnson<br> 123 Main Street, Apt 4B<br> San Francisco, CA 94103<br> United States<br> (555) 123-4567 </p> </div> <div style="background: var(--grey); padding: 20px; border-radius: 10px; margin-bottom: 25px;"> <h3 style="margin-bottom: 15px; font-size: 1.1rem;">Payment Information</h3> <p id="paymentInfoSummary" style="line-height: 1.6;"> Visa ending in 1234<br> Expiration: 05/25 </p> </div> <div class="form-action"> <button class="btn btn-secondary" id="backToPaymentFromConfirm">Edit Payment</button> <button class="btn btn-primary" id="placeOrder">Place Order</button> </div> </div> <!-- Success Message --> <div class="success-message" id="successSection"> <div class="success-icon"></div> <h2>Order Placed Successfully!</h2> <p>Your order has been received and is being processed. You'll receive a confirmation email shortly with your order details and tracking information.</p> <button class="btn btn-primary" id="doneBtn">Done</button> </div> </div> </div> <div class="confetti-container" id="confettiContainer"></div> <script> document.addEventListener('DOMContentLoaded', function() { // Form elements const sections = document.querySelectorAll('.form-section'); const progressSteps = document.querySelectorAll('.progress-step'); const progressBar = document.getElementById('progressBar'); // Navigation buttons const nextToPaymentBtn = document.getElementById('nextToPayment'); const backToCartBtn = document.getElementById('backToCart'); const nextToConfirmBtn = document.getElementById('nextToConfirm'); const backToShippingBtn = document.getElementById('backToShipping'); const backToPaymentFromConfirmBtn = document.getElementById('backToPaymentFromConfirm'); const placeOrderBtn = document.getElementById('placeOrder'); const doneBtn = document.getElementById('doneBtn'); // Shipping form fields const firstName = document.getElementById('firstName'); const lastName = document.getElementById('lastName'); const email = document.getElementById('email'); const address = document.getElementById('address'); const city = document.getElementById('city'); const state = document.getElementById('state'); const zip = document.getElementById('zip'); const phone = document.getElementById('phone'); // Payment form fields const cardName = document.getElementById('cardName'); const cardNumber = document.getElementById('cardNumber'); const expiry = document.getElementById('expiry'); const cvv = document.getElementById('cvv'); const sameAsShipping = document.getElementById('sameAsShipping'); const billingAddress = document.getElementById('billingAddress'); // Card display elements const cardNumberDisplay = document.getElementById('cardNumberDisplay'); const cardHolderDisplay = document.getElementById('cardHolderDisplay'); const expiryDisplay = document.getElementById('expiryDisplay'); // Summary elements const shippingInfoSummary = document.getElementById('shippingInfoSummary'); const paymentInfoSummary = document.getElementById('paymentInfoSummary'); // Set current section let currentSection = 1; // Update progress bar function updateProgress(step) { // Update progress bar width progressBar.style.width = ((step - 1) / 2 * 100) + '%'; // Update step indicators progressSteps.forEach((stepElem, index) => { if (index + 1 < step) { stepElem.classList.add('completed'); stepElem.classList.remove('active'); } else if (index + 1 === step) { stepElem.classList.add('active'); stepElem.classList.remove('completed'); } else { stepElem.classList.remove('active', 'completed'); } }); // Show appropriate section sections.forEach((section, index) => { if (index + 1 === step) { section.classList.add('active'); } else { section.classList.remove('active'); } }); } // Validate email format function isValidEmail(email) { const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return re.test(String(email).toLowerCase()); } // Validate phone format function isValidPhone(phone) { const re = /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/; return re.test(String(phone)); } // Validate ZIP code function isValidZip(zip) { const re = /(^\d{5}$)|(^\d{5}-\d{4}$)/; return re.test(String(zip)); } // Format credit card number with spaces function formatCardNumber(value) { // Remove non-digit characters const v = value.replace(/\D/g, ''); // Add space every 4 digits const matches = v.match(/\d{1,4}/g); return matches ? matches.join(' ') : ''; } // Format expiry date with slash function formatExpiry(value) { // Remove non-digit characters let v = value.replace(/\D/g, ''); // Insert slash after first 2 digits if (v.length > 2) { v = v.substring(0, 2) + '/' + v.substring(2); } return v; } // Validate card number using Luhn algorithm function isValidCardNumber(number) { // Remove spaces and non-digits const digits = number.replace(/\D/g, ''); if (digits.length < 13 || digits.length > 19) { return false; } let sum = 0; let shouldDouble = false; // Loop through the digits from right to left for (let i = digits.length - 1; i >= 0; i--) { let digit = parseInt(digits.charAt(i)); if (shouldDouble) { digit *= 2; if (digit > 9) { digit -= 9; } } sum += digit; shouldDouble = !shouldDouble; } return sum % 10 === 0; } // Validate expiry date function isValidExpiry(expiry) { const parts = expiry.split('/'); if (parts.length !== 2) return false; let month = parseInt(parts[0]); let year = parseInt('20' + parts[1]); if (isNaN(month) || isNaN(year) || month < 1 || month > 12) { return false; } const currentDate = new Date(); const currentYear = currentDate.getFullYear(); const currentMonth = currentDate.getMonth() + 1; // January is 0 // Card is expired if (year < currentYear || (year === currentYear && month < currentMonth)) { return false; } return true; } // Validate CVV function isValidCVV(cvv) { const re = /^\d{3,4}$/; return re.test(String(cvv)); } // Validate shipping form function validateShippingForm() { let isValid = true; // Validate required fields if (!firstName.value.trim()) { showError(firstName, 'firstNameError', 'Please enter your first name'); isValid = false; } else { hideError(firstName, 'firstNameError'); } if (!lastName.value.trim()) { showError(lastName, 'lastNameError', 'Please enter your last name'); isValid = false; } else { hideError(lastName, 'lastNameError'); } if (!email.value.trim()) { showError(email, 'emailError', 'Please enter your email address'); isValid = false; } else if (!isValidEmail(email.value.trim())) { showError(email, 'emailError', 'Please enter a valid email address'); isValid = false; } else { hideError(email, 'emailError'); } if (!address.value.trim()) { showError(address, 'addressError', 'Please enter your street address'); isValid = false; } else { hideError(address, 'addressError'); } if (!city.value.trim()) { showError(city, 'cityError', 'Please enter your city'); isValid = false; } else { hideError(city, 'cityError'); } if (!state.value.trim()) { showError(state, 'stateError', 'Please enter your state'); isValid = false; } else { hideError(state, 'stateError'); } if (!zip.value.trim()) { showError(zip, 'zipError', 'Please enter your ZIP code'); isValid = false; } else if (!isValidZip(zip.value.trim())) { showError(zip, 'zipError', 'Please enter a valid ZIP code'); isValid = false; } else { hideError(zip, 'zipError'); } if (!phone.value.trim()) { showError(phone, 'phoneError', 'Please enter your phone number'); isValid = false; } else if (!isValidPhone(phone.value.trim())) { showError(phone, 'phoneError', 'Please enter a valid phone number'); isValid = false; } else { hideError(phone, 'phoneError'); } return isValid; } // Validate payment form function validatePaymentForm() { let isValid = true; // Validate card name if (!cardName.value.trim()) { showError(cardName, 'cardNameError', 'Please enter the cardholder name'); isValid = false; } else { hideError(cardName, 'cardNameError'); } // Validate card number if (!cardNumber.value.trim()) { showError(cardNumber, 'cardNumberError', 'Please enter your card number'); isValid = false; } else if (!isValidCardNumber(cardNumber.value)) { showError(cardNumber, 'cardNumberError', 'Please enter a valid card number'); isValid = false; } else { hideError(cardNumber, 'cardNumberError'); } // Validate expiration date if (!expiry.value.trim()) { showError(expiry, 'expiryError', 'Please enter the expiration date'); isValid = false; } else if (!isValidExpiry(expiry.value)) { showError(expiry, 'expiryError', 'Please enter a valid expiration date'); isValid = false; } else { hideError(expiry, 'expiryError'); } // Validate CVV if (!
<html> <head> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', sans-serif; } body { background-color: #f8f9fa; display: flex; justify-content: center; align-items: center; min-height: 700px; padding: 20px; overflow-x: hidden; } .container { background-color: white; border-radius: 24px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); width: 100%; max-width: 650px; padding: 32px; position: relative; overflow: hidden; } .security-badge { position: absolute; top: 20px; right: 20px; display: flex; align-items: center; background: #f1f8ff; padding: 6px 12px; border-radius: 30px; font-size: 12px; color: #2d7ff9; font-weight: 500; transition: all 0.3s ease; } .security-badge:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(45, 127, 249, 0.1); } .security-badge svg { margin-right: 6px; } h1 { color: #3a3a3a; font-size: 26px; margin-bottom: 6px; font-weight: 700; } p.subtitle { color: #777; font-size: 15px; margin-bottom: 30px; line-height: 1.5; } .progress-bar { height: 4px; background-color: #f0f0f0; border-radius: 4px; margin-bottom: 30px; position: relative; overflow: hidden; } .progress-bar-fill { position: absolute; height: 100%; background: linear-gradient(to right, #a6d8f5, #91c9f9); width: 25%; border-radius: 4px; transition: width 0.6s cubic-bezier(0.65, 0, 0.35, 1); } .form-section { margin-bottom: 24px; } .form-section h2 { font-size: 18px; color: #555; margin-bottom: 16px; font-weight: 600; } .form-row { display: flex; gap: 16px; margin-bottom: 20px; } @media (max-width: 600px) { .form-row { flex-direction: column; } } .form-group { position: relative; flex: 1; margin-bottom: 6px; } .form-label { display: block; margin-bottom: 8px; font-size: 14px; color: #555; font-weight: 500; } .form-control { width: 100%; padding: 14px 16px; border: 2px solid #e8eff6; border-radius: 12px; font-size: 15px; color: #444; background-color: #f9fbff; transition: all 0.3s ease; } .form-control:focus { outline: none; border-color: #a6d8f5; box-shadow: 0 0 0 4px rgba(166, 216, 245, 0.2); background-color: #fff; } .form-control.valid { border-color: #a8e0be; background-color: #f9fffc; } .form-control.invalid { border-color: #f8c4c4; background-color: #fff9f9; } .help-icon { position: absolute; right: 12px; top: 47px; cursor: pointer; color: #aaa; transition: all 0.2s ease; } .help-icon:hover { color: #2d7ff9; } .tooltip { position: absolute; top: 40px; right: -10px; width: 250px; padding: 12px; background-color: #fff; border-radius: 12px; box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1); color: #555; font-size: 13px; line-height: 1.5; z-index: 10; visibility: hidden; opacity: 0; transform: translateY(10px); transition: all 0.3s ease; } .help-icon:hover + .tooltip { visibility: visible; opacity: 1; transform: translateY(0); } .validation-message { font-size: 12px; margin-top: 6px; display: flex; align-items: center; height: 20px; transition: all 0.3s ease; } .validation-message.error { color: #e05757; } .validation-message.success { color: #57b876; } .validation-message svg { margin-right: 4px; } .btn { background: linear-gradient(to right, #91c9f9, #a6d8f5); color: white; border: none; padding: 14px 28px; font-size: 16px; border-radius: 12px; cursor: pointer; transition: all 0.3s ease; font-weight: 600; letter-spacing: 0.5px; position: relative; overflow: hidden; } .btn:hover { box-shadow: 0 7px 14px rgba(166, 216, 245, 0.3); transform: translateY(-2px); } .btn:active { transform: translateY(0); } .btn::after { content: ''; position: absolute; top: 50%; left: 50%; width: 150px; height: 150px; background: rgba(255, 255, 255, 0.2); border-radius: 50%; transform: translate(-50%, -50%) scale(0); opacity: 0; transition: transform 0.5s, opacity 0.5s; } .btn:active::after { transform: translate(-50%, -50%) scale(1); opacity: 1; } .actions { display: flex; justify-content: space-between; align-items: center; margin-top: 30px; } .save-and-exit { color: #91c9f9; text-decoration: none; font-size: 15px; font-weight: 500; display: flex; align-items: center; transition: all 0.2s ease; } .save-and-exit:hover { color: #2d7ff9; } .save-and-exit svg { margin-right: 6px; } .password-strength { margin-top: 10px; display: flex; align-items: center; } .strength-bars { display: flex; gap: 4px; margin-right: 10px; } .strength-bar { height: 5px; width: 30px; background-color: #e8e8e8; border-radius: 2px; transition: all 0.3s ease; } .strength-text { font-size: 12px; font-weight: 500; color: #999; transition: all 0.3s ease; } /* Decorative element */ .decorative-shape { position: absolute; width: 300px; height: 300px; border-radius: 50%; background: linear-gradient(45deg, rgba(166, 216, 245, 0.03), rgba(145, 201, 249, 0.07)); top: -150px; right: -150px; z-index: -1; } .decorative-shape-2 { position: absolute; width: 200px; height: 200px; border-radius: 50%; background: linear-gradient(45deg, rgba(166, 216, 245, 0.05), rgba(145, 201, 249, 0.09)); bottom: -100px; left: -100px; z-index: -1; } /* Checkbox styles */ .checkbox-group { margin-bottom: 20px; } .custom-checkbox { display: flex; align-items: flex-start; margin-bottom: 12px; cursor: pointer; } .custom-checkbox input { position: absolute; opacity: 0; height: 0; width: 0; } .checkmark { position: relative; height: 20px; width: 20px; min-width: 20px; background-color: #f9fbff; border: 2px solid #e8eff6; border-radius: 6px; margin-right: 10px; margin-top: 1px; transition: all 0.2s ease; } .custom-checkbox:hover input ~ .checkmark { border-color: #a6d8f5; } .custom-checkbox input:checked ~ .checkmark { background-color: #91c9f9; border-color: #91c9f9; } .checkmark:after { content: ""; position: absolute; display: none; left: 6px; top: 2px; width: 5px; height: 10px; border: solid white; border-width: 0 2px 2px 0; transform: rotate(45deg); } .custom-checkbox input:checked ~ .checkmark:after { display: block; } .checkbox-text { font-size: 14px; color: #555; line-height: 1.4; } /* Additional animations */ @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(145, 201, 249, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(145, 201, 249, 0); } 100% { box-shadow: 0 0 0 0 rgba(145, 201, 249, 0); } } .pulse-animation { animation: pulse 2s infinite; } /* Mobile responsiveness */ @media (max-width: 650px) { .container { padding: 24px; border-radius: 16px; } h1 { font-size: 24px; } .form-row { flex-direction: column; margin-bottom: 0; } .form-group { margin-bottom: 16px; } .actions { flex-direction: column-reverse; gap: 16px; } .btn { width: 100%; } } </style> </head> <body> <div class="container"> <div class="decorative-shape"></div> <div class="decorative-shape-2"></div> <div class="security-badge"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M13.334 7.334V5.334C13.334 2.394 10.94 0 8.00065 0C5.06065 0 2.66732 2.394 2.66732 5.334V7.334C1.56065 7.334 0.666992 8.228 0.666992 9.334V14C0.666992 15.106 1.56065 16 2.66732 16H13.334C14.4407 16 15.334 15.106 15.334 14V9.334C15.334 8.228 14.4407 7.334 13.334 7.334ZM4.66732 5.334C4.66732 3.494 6.16065 2 8.00065 2C9.84065 2 11.334 3.494 11.334 5.334V7.334H4.66732V5.334ZM13.334 14H2.66732V9.334H13.334V14ZM8.00065 12.666C8.73398 12.666 9.33398 12.066 9.33398 11.334C9.33398 10.6 8.73398 10 8.00065 10C7.26732 10 6.66732 10.6 6.66732 11.334C6.66732 12.066 7.26732 12.666 8.00065 12.666Z" fill="#2D7FF9"/> </svg> HIPAA Compliant </div> <h1>Personal Health Profile</h1> <p class="subtitle">Help us provide you with the best care by completing your profile information. Your data is encrypted and secure.</p> <div class="progress-bar"> <div class="progress-bar-fill" id="progressBarFill"></div> </div> <form id="patientForm"> <div class="form-section"> <h2>1. Basic Information</h2> <div class="form-row"> <div class="form-group"> <label class="form-label" for="firstName">First Name</label> <input type="text" class="form-control" id="firstName" placeholder="Your first name"> <div class="validation-message" id="firstNameValidation"></div> </div> <div class="form-group"> <label class="form-label" for="lastName">Last Name</label> <input type="text" class="form-control" id="lastName" placeholder="Your last name"> <div class="validation-message" id="lastNameValidation"></div> </div> </div> <div class="form-row"> <div class="form-group"> <label class="form-label" for="dob">Date of Birth</label> <input type="date" class="form-control" id="dob"> <div class="validation-message" id="dobValidation"></div> </div> <div class="form-group"> <label class="form-label" for="gender">Gender</label> <select class="form-control" id="gender"> <option value="">Select gender</option> <option value="male">Male</option> <option value="female">Female</option> <option value="nonbinary">Non-binary</option> <option value="other">Other</option> <option value="prefer">Prefer not to say</option> </select> <div class="validation-message" id="genderValidation"></div> </div> </div> </div> <div class="form-section"> <h2>2. Contact Details</h2> <div class="form-row"> <div class="form-group"> <label class="form-label" for="email">Email Address</label> <input type="email" class="form-control" id="email" placeholder="[email protected]"> <span class="help-icon"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M8 0C3.6 0 0 3.6 0 8C0 12.4 3.6 16 8 16C12.4 16 16 12.4 16 8C16 3.6 12.4 0 8 0ZM8 14C4.7 14 2 11.3 2 8C2 4.7 4.7 2 8 2C11.3 2 14 4.7 14 8C14 11.3 11.3 14 8 14Z" fill="currentColor"/> <path d="M8 4C7.4 4 7 4.4 7 5C7 5.6 7.4 6 8 6C8.6 6 9 5.6 9 5C9 4.4 8.6 4 8 4Z" fill="currentColor"/> <path d="M8 7C7.4 7 7 7.4 7 8V11C7 11.6 7.4 12 8 12C8.6 12 9 11.6 9 11V8C9 7.4 8.6 7 8 7Z" fill="currentColor"/> </svg> </span> <div class="tooltip">We'll use your email for appointment reminders and secure messaging with your healthcare team.</div> <div class="validation-message" id="emailValidation"></div> </div> <div class="form-group"> <label class="form-label" for="phone">Phone Number</label> <input type="tel" class="form-control" id="phone" placeholder="(555) 123-4567"> <div class="validation-message" id="phoneValidation"></div> </div> </div> <div class="form-group"> <label class="form-label" for="password">Create Password</label> <input type="password" class="form-control" id="password" placeholder="Create a secure password"> <span class="help-icon"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M8 0C3.6 0 0 3.6 0 8C0 12.4 3.6 16 8 16C12.4 16 16 12.4 16 8C16 3.6 12.4 0 8 0ZM8 14C4.7 14 2 11.3 2 8C2 4.7 4.7 2 8 2C11.3 2 14 4.7 14 8C14 11.3 11.3 14 8 14Z" fill="currentColor"/> <path d="M8 4C7.4 4 7 4.4 7 5C7 5.6 7.4 6 8 6C8.6 6 9 5.6 9 5C9 4.4 8.6 4 8 4Z" fill="currentColor"/> <path d="M8 7C7.4 7 7 7.4 7 8V11C7 11.6 7.4 12 8 12C8.6 12 9 11.6 9 11V8C9 7.4 8.6 7 8 7Z" fill="currentColor"/> </svg> </span> <div class="tooltip">Use at least 8 characters with a mix of letters, numbers, and symbols for better security.</div> <div class="validation-message" id="passwordValidation"></div> <div class="password-strength"> <div class="strength-bars"> <div class="strength-bar" id="strengthBar1"></div> <div class="strength-bar" id="strengthBar2"></div> <div class="strength-bar" id="strengthBar3"></div> <div class="strength-bar" id="strengthBar4"></div> </div> <span class="strength-text" id="strengthText">Password strength</span> </div> </div> </div> <div class="form-section"> <h2>3. Medical Information</h2> <div class="form-group"> <label class="form-label" for="allergies">Allergies (if any)</label> <input type="text" class="form-control" id="allergies" placeholder="List any allergies to medications, food, etc."> <span class="help-icon"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M8 0C3.6 0 0 3.6 0 8C0 12.4 3.6 16 8 16C12.4 16 16 12.4 16 8C16 3.6 12.4 0 8 0ZM8 14C4.7 14 2 11.3 2 8C2 4.7 4.7 2 8 2C11.3 2 14 4.7 14 8C14 11.3 11.3 14 8 14Z" fill="currentColor"/> <path d="M8 4C7.4 4 7 4.4 7 5C7 5.6 7.4 6 8 6C8.6 6 9 5.6 9 5C9 4.4 8.6 4 8 4Z" fill="currentColor"/> <path d="M8 7C7.4 7 7 7.4 7 8V11C7 11.6 7.4 12 8 12C8.6 12 9 11.6 9 11V8C9 7.4 8.6 7 8 7Z" fill="currentColor"/> </svg> </span> <div class="tooltip">Include any known allergies to medications, foods, or environmental factors to help us provide safer care.</div> </div> <div class="form-group"> <label class="form-label" for="medications">Current Medications</label> <input type="text" class="form-control" id="medications" placeholder="List any medications you're currently taking"> </div> <div class="checkbox-group"> <label class="form-label">Medical Conditions (check all that apply)</label> <label class="custom-checkbox"> <input type="checkbox" name="conditions" value="diabetes"> <span class="checkmark"></span> <span class="checkbox-text">Diabetes</span> </label> <label class="custom-checkbox"> <input type="checkbox" name="conditions" value="hypertension"> <span class="checkmark"></span> <span class="checkbox-text">Hypertension</span> </label> <label class="custom-checkbox"> <input type="checkbox" name="conditions" value="asthma"> <span class="checkmark"></span> <span class="checkbox-text">Asthma</span> </label> <label class="custom-checkbox"> <input type="checkbox" name="conditions" value="heart"> <span class="checkmark"></span> <span class="checkbox-text">Heart Disease</span> </label> </div> </div> <div class="checkbox-group"> <label class="custom-checkbox"> <input type="checkbox" name="consent" id="consent"> <span class="checkmark"></span> <span class="checkbox-text">I consent to the electronic storage of my health information in accordance with HIPAA guidelines and the portal's privacy policy.</span> </label> <div class="validation-message" id="consentValidation"></div> </div> <div class="actions"> <a href="#" class="save-and-exit"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M8 0C3.6 0 0 3.6 0 8C0 12.4 3.6 16 8 16C12.4 16 16 12.4 16 8C16 3.6 12.4 0 8 0ZM8 14C4.7 14 2 11.3 2 8C2 4.7 4.7 2 8 2C11.3 2 14 4.7 14 8C14 11.3 11.3 14 8 14Z" fill="currentColor"/> <path d="M10.7 5.3C10.3 4.9 9.7 4.9 9.3 5.3L8 6.6L6.7 5.3C6.3 4.9 5.7 4.9 5.3 5.3C4.9 5.7 4.9 6.3 5.3 6.7L6.6 8L5.3 9.3C4.9 9.7 4.9 10.3 5.3 10.7C5.5 10.9 5.7 11 6 11C6.3 11 6.5 10.9 6.7 10.7L8 9.4L9.3 10.7C9.5 10.9 9.8 11 10 11C10.2 11 10.5 10.9 10.7 10.7C11.1 10.3 11.1 9.7 10.7 9.3L9.4 8L10.7 6.7C11.1 6.3 11.1 5.7 10.7 5.3Z" fill="currentColor"/> </svg> Save and exit </a> <button type="submit" class="btn" id="submitBtn">Continue to Next Step</button> </div> </form> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Form elements const form = document.getElementById('patientForm'); const firstName = document.getElementById('firstName'); const lastName = document.getElementById('lastName'); const dob = document.getElementById('dob'); const gender = document.getElementById('gender'); const email = document.getElementById('email'); const phone = document.getElementById('phone'); const password = document.getElementById('password'); const consent = document.getElementById('consent'); // Validation messages const firstNameValidation = document.getElementById('firstNameValidation'); const lastNameValidation = document.getElementById('lastNameValidation'); const dobValidation = document.getElementById('dobValidation'); const genderValidation = document.getElementById('genderValidation'); const emailValidation = document.getElementById('emailValidation'); const phoneValidation = document.getElementById('phoneValidation'); const passwordValidation = document.getElementById('passwordValidation'); const consentValidation = document.getElementById('consentValidation'); // Password strength elements const strengthBar1 = document.getElementById('strengthBar1'); const strengthBar2 = document.getElementById('strengthBar2'); const strengthBar3 = document.getElementById('strengthBar3'); const strengthBar4 = document.getElementById('strengthBar4'); const strengthText = document.getElementById('strengthText'); // Progress bar const progressBarFill = document.getElementById('progressBarFill'); // Form input validation function validateInput(input, validationElement, message, isValid) { if (!isValid) { input.classList.add('invalid'); input.classList.remove('valid'); validationElement.innerHTML = ` <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M6 0C2.7 0 0 2.7 0 6C0 9.3 2.7 12 6 12C9.3 12 12 9.3 12 6C12 2.7 9.3 0 6 0ZM6 10.5C3.525 10.5 1.5 8.475 1.5 6C1.5 3.525 3.525 1.5 6 1.5C8.475 1.5 10.5 3.525 10.5 6C10.5 8.475 8.475 10.5 6 10.5Z" fill="#E05757"/> <path d="M7.5 3.75L6 5.25L4.5 3.75L3.75 4.5L5.25 6L3.75 7.5L4.5 8.25L6 6.75L7.5 8.25L8.25 7.5L6.75 6L8.25 4.5L7.5 3.75Z" fill="#E05757"/> </svg> ${message} `; validationElement.classList.add('error'); validationElement.classList.remove('success'); return false; } else if (input.value) { input.classList.add('valid'); input.classList.remove('invalid'); validationElement.innerHTML = ` <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M6 0C2.7 0 0 2.7 0 6C0 9.3 2.7 12 6 12C9.3 12 12 9.3 12 6C12 2.7 9.3 0 6 0ZM6 10.5C3.525 10.5 1.5 8.475 1.5 6C1.5 3.525 3.525 1.5 6 1.5C8.475 1.5 10.5 3.525 10.5 6C10.5 8.475 8.475 10.5 6 10.5Z" fill="#57B876"/> <path d="M9 3.75L5.25 7.5L3 5.25L2.25 6L5.25 9L9.75 4.5L9 3.75Z" fill="#57B876"/> </svg> Looks good `; validationElement.classList.add('success'); validationElement.classList.remove('error'); return true; } else { input.classList.remove('valid'); input.classList.remove('invalid'); validationElement.innerHTML = ''; validationElement.classList.remove('success', 'error'); return true; } } // Input field event listeners firstName.addEventListener('input', function() { validateInput(firstName, firstNameValidation, 'First name is required', firstName.value.trim() !== ''); updateProgress(); }); lastName.addEventListener('input', function() { validateInput(lastName, lastNameValidation, 'Last name is required', lastName.value.trim() !== ''); updateProgress(); }); dob.addEventListener('change', function() { validateInput(dob, dobValidation, 'Date of birth is required', dob.value !== ''); updateProgress(); }); gender.addEventListener('change', function() { validateInput(gender, genderValidation, 'Please select a gender', gender.value !== ''); updateProgress(); }); email.addEventListener('input', function() { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; validateInput(email, emailValidation, 'Please enter a valid email address', emailRegex.test(email.value)); updateProgress(); }); phone.addEventListener('input', function() { const phoneRegex = /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/; validateInput(phone, phoneValidation, 'Please enter a valid phone number', phoneRegex.test(phone.value)); updateProgress(); // Format phone number if (phoneRegex.test(phone.value)) { const formattedNumber = phone.value.replace(phoneRegex, "($1) $2-$3"); if (phone.value !== formattedNumber) { phone.value = formattedNumber; } } }); password.addEventListener('input', function() { updatePasswordStrength(password.value); updateProgress(); }); consent.addEventListener('change', function() { validateInput(consent, consentValidation, 'You must consent to continue', consent.checked); updateProgress(); }); // Password strength indicator function updatePasswordStrength(password) { // Reset all bars strengthBar1.style.backgroundColor = '#e8e8e8'; strengthBar2.style.backgroundColor = '#e8e8e8'; strengthBar3.style.backgroundColor = '#e8e8e8'; strengthBar4.style.backgroundColor = '#e8e8e8'; if (!password) { strengthText.textContent = 'Password strength'; strengthText.style.color = '#999'; validateInput( document.getElementById('password'), passwordValidation, 'Password is required', false ); return; } let strength = 0; // Length check if (password.length >= 8) { strength += 1; } // Complexity checks if (/[A-Z]/.test(password)) strength += 1; if (/[0-9]/.test(password)) strength += 1; if (/[^A-Za-z0-9]/.test(password)) strength += 1; // Update UI based on strength if (strength >= 1) { strengthBar1.style.backgroundColor = '#f08080'; } if (strength >= 2) { strengthBar1.style.backgroundColor = '#ffb347'; strengthBar2.style.backgroundColor = '#ffb347'; } if (strength >= 3) { strengthBar1.style.backgroundColor = '#aed581'; strengthBar2.style.backgroundColor = '#aed581'; strengthBar3.style.backgroundColor = '#aed581'; } if (strength === 4) { strengthBar1.style.backgroundColor = '#57b876'; strengthBar2.style.backgroundColor = '#57b876'; strengthBar3.style.backgroundColor = '#57b876'; strengthBar4.style.backgroundColor = '#57b876'; } // Update strength text switch (strength) { case 0: case 1: strengthText.textContent = 'Weak'; strengthText.style.color = '#f08080'; validateInput( document.getElementById('password'), passwordValidation, 'Password too weak - use at least 8 characters with numbers and symbols', false ); break; case 2: strengthText.textContent = 'Fair'; strengthText.style.color = '#ffb347'; validateInput( document.getElementById('password'), passwordValidation, 'Add uppercase letters and symbols for a stronger password', false ); break; case 3: strengthText.textContent = 'Good'; strengthText.style.color = '#aed581'; validateInput( document.getElementById('password'), passwordValidation, '', true ); break; case 4: strengthText.textContent = 'Strong'; strengthText.style.color = '#57b876'; validateInput( document.getElementById('password'), passwordValidation, '', true ); break; } } // Update progress bar function updateProgress() { // Count filled fields const inputs = [firstName, lastName, dob, gender, email, phone, password]; let filledInputs = 0; inputs.forEach(input => { if (input.value) filledInputs++; }); // Add consent checkbox if checked if (consent.checked) filledInputs++; // Calculate percentage let progressPercent = Math.min(Math.round((filledInputs / (inputs.length + 1)) * 100), 100); // Update progress bar progressBarFill.style.width = `${progressPercent}%`; // Add pulse animation to continue button if form is complete
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>BubbleChat Messenger</title> <style> :root { --primary: #FF6B6B; --secondary: #4ECDC4; --tertiary: #FFD166; --dark: #2F3542; --light: #F7F7F7; --success: #6BFF9E; --font-primary: 'Quicksand', sans-serif; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: var(--font-primary); } body { background-color: #F0F2F5; display: flex; justify-content: center; align-items: center; min-height: 100vh; overflow-x: hidden; color: var(--dark); } .chat-container { width: 100%; max-width: 680px; height: 680px; background-color: white; border-radius: 24px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; overflow: hidden; position: relative; } .chat-header { padding: 20px; background: linear-gradient(135deg, var(--primary), var(--secondary)); color: white; display: flex; align-items: center; justify-content: space-between; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); position: relative; z-index: 2; } .chat-title { display: flex; align-items: center; gap: 12px; } .chat-title h2 { font-weight: 700; font-size: 18px; } .status-indicator { width: 12px; height: 12px; background-color: var(--success); border-radius: 50%; position: relative; } .status-indicator::after { content: ''; position: absolute; width: 100%; height: 100%; background-color: var(--success); border-radius: 50%; animation: pulse 2s infinite; } .online-count { background-color: rgba(255, 255, 255, 0.2); padding: 6px 12px; border-radius: 20px; font-size: 14px; } .chat-body { flex: 1; padding: 20px; overflow-y: auto; display: flex; flex-direction: column; gap: 15px; background-color: #F8F9FA; position: relative; } .message { max-width: 80%; padding: 12px 16px; border-radius: 18px; position: relative; animation: messageAppear 0.3s ease-out; } .message.received { align-self: flex-start; background-color: white; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); border-bottom-left-radius: 4px; } .message.sent { align-self: flex-end; background-color: var(--primary); color: white; box-shadow: 0 2px 8px rgba(255, 107, 107, 0.3); border-bottom-right-radius: 4px; } .message-meta { font-size: 12px; margin-top: 4px; opacity: 0.7; } .received .message-meta { text-align: left; } .sent .message-meta { text-align: right; color: rgba(255, 255, 255, 0.9); } .chat-input-container { padding: 16px; background-color: white; border-top: 1px solid rgba(0, 0, 0, 0.08); position: relative; z-index: 2; } .input-wrapper { display: flex; gap: 10px; position: relative; } .message-input { flex: 1; padding: 15px 20px; padding-right: 50px; border-radius: 24px; border: none; background-color: #F0F2F5; font-size: 16px; transition: all 0.3s; resize: none; height: 55px; max-height: 150px; overflow-y: auto; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05); } .message-input:focus { outline: none; box-shadow: 0 0 0 2px var(--primary); background-color: white; } .message-input::placeholder { color: #A0A0A0; } .send-button { width: 55px; height: 55px; border-radius: 50%; background: linear-gradient(135deg, var(--primary), #FF8E8E); border: none; color: white; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 4px 10px rgba(255, 107, 107, 0.4); transition: all 0.2s; position: relative; overflow: hidden; } .send-button:hover { transform: translateY(-2px); box-shadow: 0 6px 15px rgba(255, 107, 107, 0.5); } .send-button:active { transform: translateY(0); } .send-button svg { width: 24px; height: 24px; transform: translateX(0px); transition: transform 0.2s; } .send-button:hover svg { transform: translateX(2px); } .character-counter { position: absolute; right: 75px; bottom: 16px; font-size: 14px; color: #A0A0A0; background-color: rgba(255, 255, 255, 0.8); padding: 2px 8px; border-radius: 12px; transition: all 0.2s; opacity: 0; transform: translateY(10px); } .character-counter.visible { opacity: 1; transform: translateY(0); } .character-counter.warning { color: #FF9800; } .character-counter.danger { color: #F44336; } .emoji-picker-toggle { position: absolute; right: 16px; top: 50%; transform: translateY(-50%); background: none; border: none; color: #A0A0A0; font-size: 20px; cursor: pointer; transition: all 0.2s; } .emoji-picker-toggle:hover { color: var(--primary); transform: translateY(-50%) scale(1.1); } .emoji-picker { position: absolute; bottom: 70px; right: 70px; background-color: white; border-radius: 16px; box-shadow: 0 5px 20px rgba(0, 0, 0, 0.15); padding: 12px; display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; z-index: 3; opacity: 0; transform: translateY(20px) scale(0.9); pointer-events: none; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .emoji-picker.visible { opacity: 1; transform: translateY(0) scale(1); pointer-events: all; } .emoji { font-size: 20px; padding: 8px; cursor: pointer; border-radius: 8px; transition: all 0.15s; text-align: center; } .emoji:hover { background-color: #F0F2F5; transform: scale(1.1); } .typing-indicator { display: flex; align-items: center; gap: 4px; color: #A0A0A0; font-style: italic; font-size: 14px; margin-top: -5px; margin-bottom: 10px; padding-left: 5px; height: 20px; } .typing-dot { width: 6px; height: 6px; background-color: #A0A0A0; border-radius: 50%; animation: typingAnimation 1s infinite; } .typing-dot:nth-child(2) { animation-delay: 0.2s; } .typing-dot:nth-child(3) { animation-delay: 0.4s; } .message-input-animated-bg { position: absolute; bottom: 0; left: 0; right: 0; height: 200px; background: linear-gradient(to top, rgba(255, 107, 107, 0.05), transparent); transform: translateY(100%); opacity: 0; transition: all 0.3s; z-index: 1; pointer-events: none; } .message-input-animated-bg.active { transform: translateY(0); opacity: 1; } .bubble { position: absolute; border-radius: 50%; background-color: var(--tertiary); opacity: 0.4; animation: bubbleFloat 6s infinite ease-in-out; } /* Animations */ @keyframes pulse { 0% { opacity: 0.8; transform: scale(1); } 70% { opacity: 0; transform: scale(2); } 100% { opacity: 0; } } @keyframes messageAppear { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } @keyframes typingAnimation { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-4px); } } @keyframes bubbleFloat { 0% { transform: translateY(0) translateX(0); } 50% { transform: translateY(-80px) translateX(20px); } 100% { transform: translateY(0) translateX(0); } } /* Responsive design */ @media (max-width: 600px) { .chat-container { border-radius: 0; height: 100vh; max-height: 100vh; } } /* Loading effect for send button */ .send-button.sending { pointer-events: none; } .send-button.sending svg { animation: spin 1s infinite linear; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } </style> </head> <body> <div class="chat-container"> <div class="chat-header"> <div class="chat-title"> <div class="status-indicator"></div> <h2>BubbleChat</h2> </div> <div class="online-count">24 online</div> </div> <div class="chat-body" id="chatBody"> <div class="message received"> <div class="message-text">Hey there! Welcome to BubbleChat. Have you tried the animated emoji reactions yet?</div> <div class="message-meta">Alex • 10:24 AM</div> </div> <div class="message sent"> <div class="message-text">Not yet! Just discovered this app yesterday. The interface is super cute!</div> <div class="message-meta">10:25 AM</div> </div> <div class="message received"> <div class="message-text">I know right? They just updated with these bubbly animations. Try sending a message with an emoji!</div> <div class="message-meta">Sam • 10:26 AM</div> </div> <div class="typing-indicator" id="typingIndicator" style="display: none;"> <span class="typing-dot"></span> <span class="typing-dot"></span> <span class="typing-dot"></span> <span style="margin-left: 5px;">Someone is typing...</span> </div> </div> <div class="message-input-animated-bg" id="inputBg"></div> <div class="chat-input-container"> <div class="input-wrapper"> <textarea id="messageInput" class="message-input" placeholder="Type your bubbly message..." rows="1"></textarea> <button class="emoji-picker-toggle" id="emojiToggle">😊</button> <div class="character-counter" id="charCounter">0/280</div> <button id="sendButton" class="send-button"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <line x1="22" y1="2" x2="11" y2="13"></line> <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon> </svg> </button> </div> </div> <div class="emoji-picker" id="emojiPicker"> <div class="emoji" data-emoji="😊">😊</div> <div class="emoji" data-emoji="😂">😂</div> <div class="emoji" data-emoji="❤️">❤️</div> <div class="emoji" data-emoji="👍">👍</div> <div class="emoji" data-emoji="🎉">🎉</div> <div class="emoji" data-emoji="✨">✨</div> <div class="emoji" data-emoji="🙌">🙌</div> <div class="emoji" data-emoji="🤔">🤔</div> <div class="emoji" data-emoji="😍">😍</div> <div class="emoji" data-emoji="🔥">🔥</div> <div class="emoji" data-emoji="👋">👋</div> <div class="emoji" data-emoji="🚀">🚀</div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const messageInput = document.getElementById('messageInput'); const charCounter = document.getElementById('charCounter'); const sendButton = document.getElementById('sendButton'); const chatBody = document.getElementById('chatBody'); const emojiToggle = document.getElementById('emojiToggle'); const emojiPicker = document.getElementById('emojiPicker'); const emojis = document.querySelectorAll('.emoji'); const inputBg = document.getElementById('inputBg'); const typingIndicator = document.getElementById('typingIndicator'); const MAX_CHARS = 280; let timeoutId = null; let typingTimeout = null; // Create bubbles createBubbles(); // Auto resize textarea messageInput.addEventListener('input', function() { this.style.height = '55px'; this.style.height = (this.scrollHeight) + 'px'; const charCount = this.value.length; charCounter.textContent = `${charCount}/${MAX_CHARS}`; if (charCount > 0) { charCounter.classList.add('visible'); inputBg.classList.add('active'); } else { charCounter.classList.remove('visible'); inputBg.classList.remove('active'); } if (charCount > MAX_CHARS * 0.8) { charCounter.classList.add('warning'); } else { charCounter.classList.remove('warning'); } if (charCount > MAX_CHARS * 0.95) { charCounter.classList.add('danger'); } else { charCounter.classList.remove('danger'); } // Show typing indicator occasionally if (charCount > 0 && Math.random() > 0.7) { clearTimeout(typingTimeout); typingIndicator.style.display = 'flex'; typingTimeout = setTimeout(() => { typingIndicator.style.display = 'none'; }, 3000); } }); // Send message sendButton.addEventListener('click', sendMessage); messageInput.addEventListener('keydown', function(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } }); // Emoji picker toggle emojiToggle.addEventListener('click', function(e) { e.stopPropagation(); emojiPicker.classList.toggle('visible'); }); // Close emoji picker when clicking outside document.addEventListener('click', function(e) { if (!emojiPicker.contains(e.target) && e.target !== emojiToggle) { emojiPicker.classList.remove('visible'); } }); // Add emoji to message emojis.forEach(emoji => { emoji.addEventListener('click', function() { const emojiChar = this.getAttribute('data-emoji'); messageInput.value += emojiChar; messageInput.focus(); // Trigger input event to update character count messageInput.dispatchEvent(new Event('input')); }); }); function sendMessage() { const message = messageInput.value.trim(); if (message.length === 0) return; if (message.length > MAX_CHARS) { charCounter.classList.add('danger'); charCounter.style.animation = 'none'; setTimeout(() => { charCounter.style.animation = 'shake 0.5s'; }, 10); return; } // Add loading effect sendButton.classList.add('sending'); // Simulate network delay setTimeout(() => { // Create and append message const messageElement = document.createElement('div'); messageElement.classList.add('message', 'sent'); const messageText = document.createElement('div'); messageText.classList.add('message-text'); messageText.textContent = message; const messageTime = document.createElement('div'); messageTime.classList.add('message-meta'); messageTime.textContent = getCurrentTime(); messageElement.appendChild(messageText); messageElement.appendChild(messageTime); chatBody.appendChild(messageElement); // Auto-scroll chatBody.scrollTop = chatBody.scrollHeight; // Reset input messageInput.value = ''; messageInput.style.height = '55px'; charCounter.classList.remove('visible', 'warning', 'danger'); inputBg.classList.remove('active'); // Remove loading effect sendButton.classList.remove('sending'); // Randomly show a response after a delay if (Math.random() > 0.3) { setTimeout(() => { typingIndicator.style.display = 'flex'; setTimeout(() => { typingIndicator.style.display = 'none'; const responses = [ "That's so cool! Have you tried using the emoji reactions?", "Nice! The bouncy animations make this chat so fun 😊", "I love how the bubbles float up when you type!", "This design is so playful! Makes chatting much more enjoyable 🎉", "The rounded corners and colors brighten my day 💕" ]; const responseElement = document.createElement('div'); responseElement.classList.add('message', 'received'); const responseText = document.createElement('div'); responseText.classList.add('message-text'); responseText.textContent = responses[Math.floor(Math.random() * responses.length)]; const responseInfo = document.createElement('div'); responseInfo.classList.add('message-meta'); responseInfo.textContent = `Random Friend • ${getCurrentTime()}`; responseElement.appendChild(responseText); responseElement.appendChild(responseInfo); chatBody.appendChild(responseElement); chatBody.scrollTop = chatBody.scrollHeight; }, 1500 + Math.random() * 1000); }, 1000 + Math.random() * 2000); } }, 300); } function getCurrentTime() { const now = new Date(); let hours = now.getHours(); let minutes = now.getMinutes(); const ampm = hours >= 12 ? 'PM' : 'AM'; hours = hours % 12; hours = hours ? hours : 12; minutes = minutes < 10 ? '0' + minutes : minutes; return `${hours}:${minutes} ${ampm}`; } function createBubbles() { const container = document.querySelector('.chat-container'); const bubbleCount = 5; for (let i = 0; i < bubbleCount; i++) { const bubble = document.createElement('div'); bubble.classList.add('bubble'); // Random size between 20px and 60px const size = Math.floor(Math.random() * 40) + 20; bubble.style.width = `${size}px`; bubble.style.height = `${size}px`; // Random position at the bottom const left = Math.floor(Math.random() * 80) + 10; // 10-90% bubble.style.left = `${left}%`; bubble.style.bottom = `-${size}px`; // Random delay bubble.style.animationDelay = `${Math.random() * 5}s`; // Random color from the theme const colors = [ 'rgba(255, 107, 107, 0.3)', // primary 'rgba(78, 205, 196, 0.3)', // secondary 'rgba(255, 209, 102, 0.3)' // tertiary ]; bubble.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; container.appendChild(bubble); } } }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Mobile Registration Form</title> <style> :root { --primary-color: #6C63FF; --secondary-color: #FF6584; --success-color: #2ECC71; --text-color: #2D3748; --text-light: #718096; --background: #F8FAFC; --error-color: #E53E3E; --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.12); --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1); --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1); --border-radius: 12px; --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } body { background-color: var(--background); color: var(--text-color); min-height: 100vh; display: flex; justify-content: center; align-items: center; padding: 1rem; } .registration-container { width: 100%; max-width: 450px; background: #fff; border-radius: var(--border-radius); box-shadow: var(--shadow-lg); overflow: hidden; position: relative; } .gradient-header { height: 6px; background: linear-gradient(90deg, var(--primary-color), var(--secondary-color)); } .form-content { padding: 2rem; } h1 { margin-bottom: 0.5rem; font-size: 1.75rem; color: var(--primary-color); font-weight: 700; } .welcome-text { color: var(--text-light); margin-bottom: 2rem; font-size: 1rem; line-height: 1.5; } .form-group { margin-bottom: 1.5rem; position: relative; } .form-label { font-size: 1rem; font-weight: 600; margin-bottom: 0.5rem; display: block; transition: var(--transition); color: var(--text-color); } .input-container { position: relative; } .form-input { width: 100%; padding: 1rem; font-size: 1.1rem; border: 2px solid #E2E8F0; border-radius: var(--border-radius); transition: var(--transition); outline: none; background: #F7FAFC; } .form-input:focus { border-color: var(--primary-color); box-shadow: 0 0 0 3px rgba(108, 99, 255, 0.2); background: #fff; } .form-input.invalid { border-color: var(--error-color); box-shadow: 0 0 0 3px rgba(229, 62, 62, 0.2); } .input-icon { position: absolute; right: 1rem; top: 50%; transform: translateY(-50%); color: var(--text-light); transition: var(--transition); } .icon-valid, .icon-invalid { display: none; } .feedback-text { margin-top: 0.5rem; font-size: 0.875rem; transition: var(--transition); height: 1.25rem; color: var(--error-color); opacity: 0; } .show-feedback { opacity: 1; } .btn { display: block; width: 100%; padding: 1rem; font-size: 1.1rem; font-weight: 600; text-align: center; background-color: var(--primary-color); color: white; border: none; border-radius: var(--border-radius); cursor: pointer; transition: var(--transition); margin-top: 2rem; position: relative; overflow: hidden; } .btn:hover { background-color: #5A52D5; transform: translateY(-2px); box-shadow: var(--shadow-md); } .btn:active { transform: translateY(0); box-shadow: var(--shadow-sm); } .btn-ripple { position: absolute; background: rgba(255, 255, 255, 0.3); border-radius: 50%; transform: scale(0); animation: ripple 0.6s linear; pointer-events: none; } @keyframes ripple { to { transform: scale(4); opacity: 0; } } .form-progress { display: flex; justify-content: space-between; margin-bottom: 2rem; } .progress-step { flex: 1; height: 4px; background: #E2E8F0; position: relative; margin: 0 3px; border-radius: 2px; overflow: hidden; } .progress-step-fill { position: absolute; left: 0; top: 0; height: 100%; width: 0; background: var(--primary-color); transition: width 0.5s ease; } .progress-step.active .progress-step-fill { width: 100%; } .input-focus-ring { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; border-radius: var(--border-radius); box-shadow: 0 0 0 0 rgba(108, 99, 255, 0); transition: box-shadow 0.3s ease; } .form-input:focus + .input-focus-ring { box-shadow: 0 0 0 3px rgba(108, 99, 255, 0.3); } .success-message { display: none; align-items: center; justify-content: center; flex-direction: column; text-align: center; } .success-icon { width: 80px; height: 80px; background: var(--success-color); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-bottom: 1.5rem; color: white; font-size: 2.5rem; position: relative; overflow: hidden; } .success-icon svg { opacity: 0; transform: scale(0.5); transition: all 0.5s ease; } .success-icon.animate svg { opacity: 1; transform: scale(1); } .success-title { font-size: 1.5rem; font-weight: 700; margin-bottom: 0.5rem; color: var(--success-color); } .success-text { color: var(--text-light); margin-bottom: 2rem; } /* Wave animation for loading button */ .btn-loading { background: linear-gradient(90deg, var(--primary-color) 0%, #5A52D5 50%, var(--primary-color) 100%); background-size: 200% 100%; animation: loading-wave 1.5s infinite linear; pointer-events: none; } @keyframes loading-wave { 0% { background-position: 200% 0; } 100% { background-position: 0 0; } } /* Password strength meter */ .password-strength { margin-top: 0.5rem; display: flex; gap: 0.25rem; } .strength-bar { flex: 1; height: 4px; background: #E2E8F0; border-radius: 2px; transition: var(--transition); } .strength-text { font-size: 0.75rem; margin-top: 0.25rem; color: var(--text-light); } .strength-weak .strength-bar:nth-child(1) { background: var(--error-color); } .strength-medium .strength-bar:nth-child(1), .strength-medium .strength-bar:nth-child(2) { background: #F6AD55; } .strength-strong .strength-bar:nth-child(1), .strength-strong .strength-bar:nth-child(2), .strength-strong .strength-bar:nth-child(3) { background: #68D391; } .strength-very-strong .strength-bar { background: var(--success-color); } /* Custom checkmark animation */ .checkmark { width: 40px; height: 40px; position: relative; } .checkmark__circle { stroke-dasharray: 166; stroke-dashoffset: 166; stroke-width: 2; stroke-miterlimit: 10; stroke: var(--success-color); fill: none; animation: stroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards; } .checkmark__check { transform-origin: 50% 50%; stroke-dasharray: 48; stroke-dashoffset: 48; animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards; } @keyframes stroke { 100% { stroke-dashoffset: 0; } } /* Responsive adjustments */ @media (max-width: 400px) { .form-content { padding: 1.5rem; } h1 { font-size: 1.5rem; } .form-input, .btn { padding: 0.875rem; font-size: 1rem; } } </style> </head> <body> <div class="registration-container"> <div class="gradient-header"></div> <div class="form-content"> <div class="form-wrapper"> <h1>Join Pocket</h1> <p class="welcome-text">Enter your details to create a free account and start organizing your mobile life.</p> <div class="form-progress"> <div class="progress-step active"> <div class="progress-step-fill"></div> </div> <div class="progress-step"> <div class="progress-step-fill"></div> </div> <div class="progress-step"> <div class="progress-step-fill"></div> </div> <div class="progress-step"> <div class="progress-step-fill"></div> </div> </div> <form id="registrationForm"> <div class="form-group" id="emailGroup"> <label class="form-label" for="email">Email</label> <div class="input-container"> <input type="email" id="email" class="form-input" placeholder="[email protected]" autocomplete="email"> <div class="input-focus-ring"></div> <div class="input-icon icon-valid"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M9 12L11 14L15 10M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="#2ECC71" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> <div class="input-icon icon-invalid"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 8V12M12 16H12.01M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="#E53E3E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> </div> <div class="feedback-text" id="emailFeedback"></div> </div> <div class="form-group" id="passwordGroup"> <label class="form-label" for="password">Password</label> <div class="input-container"> <input type="password" id="password" class="form-input" placeholder="At least 8 characters" autocomplete="new-password"> <div class="input-focus-ring"></div> <div class="input-icon" id="passwordToggle"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M15 12C15 13.6569 13.6569 15 12 15C10.3431 15 9 13.6569 9 12C9 10.3431 10.3431 9 12 9C13.6569 9 15 10.3431 15 12Z" stroke="#718096" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12 5C7.23858 5 3.36509 7.94758 2.03153 12C3.36509 16.0524 7.23858 19 12 19C16.7614 19 20.6349 16.0524 21.9685 12C20.6349 7.94758 16.7614 5 12 5Z" stroke="#718096" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> </div> <div class="password-strength"> <div class="strength-bar"></div> <div class="strength-bar"></div> <div class="strength-bar"></div> <div class="strength-bar"></div> </div> <div class="strength-text">Password strength: Type to check</div> <div class="feedback-text" id="passwordFeedback"></div> </div> <div class="form-group" id="phoneGroup"> <label class="form-label" for="phone">Phone Number</label> <div class="input-container"> <input type="tel" id="phone" class="form-input" placeholder="(555) 123-4567" autocomplete="tel"> <div class="input-focus-ring"></div> </div> <div class="feedback-text" id="phoneFeedback"></div> </div> <button type="button" id="registerBtn" class="btn"> Create Account </button> </form> </div> <div class="success-message"> <div class="success-icon"> <svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path class="checkmark__check" stroke="white" stroke-width="3" fill="none" d="M6 12L10 16L18 8" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> <h2 class="success-title">All Set!</h2> <p class="success-text">Your account has been created successfully. Welcome to Pocket!</p> <button type="button" class="btn" id="continueBtn">Continue to App</button> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', () => { // DOM elements const form = document.getElementById('registrationForm'); const emailInput = document.getElementById('email'); const passwordInput = document.getElementById('password'); const phoneInput = document.getElementById('phone'); const registerBtn = document.getElementById('registerBtn'); const continueBtn = document.getElementById('continueBtn'); const formWrapper = document.querySelector('.form-wrapper'); const successMessage = document.querySelector('.success-message'); const progressSteps = document.querySelectorAll('.progress-step'); const passwordToggle = document.getElementById('passwordToggle'); const strengthBars = document.querySelectorAll('.strength-bar'); const strengthText = document.querySelector('.strength-text'); // Feedback elements const emailFeedback = document.getElementById('emailFeedback'); const passwordFeedback = document.getElementById('passwordFeedback'); const phoneFeedback = document.getElementById('phoneFeedback'); // Form validation state const formState = { email: false, password: false, phone: false }; // Button ripple effect document.querySelectorAll('.btn').forEach(btn => { btn.addEventListener('click', function(e) { const rect = e.target.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; const ripple = document.createElement('span'); ripple.classList.add('btn-ripple'); ripple.style.left = `${x}px`; ripple.style.top = `${y}px`; this.appendChild(ripple); setTimeout(() => { ripple.remove(); }, 600); }); }); // Input feedback with haptic vibration simulation const inputs = [emailInput, passwordInput, phoneInput]; inputs.forEach(input => { input.addEventListener('focus', function() { // Simulate haptic feedback if available if (navigator.vibrate) { navigator.vibrate(10); } // Update UI to show focus state this.parentNode.classList.add('input-focused'); // Update progress steps updateProgressStep(inputs.indexOf(this)); }); input.addEventListener('blur', function() { this.parentNode.classList.remove('input-focused'); validateInput(this); }); }); // Toggle password visibility passwordToggle.addEventListener('click', () => { if (passwordInput.type === 'password') { passwordInput.type = 'text'; passwordToggle.innerHTML = ` <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M13.8 9.2L10.2 12.8M10.2 9.2L13.8 12.8M21 12C21 12 16.9706 17 12 17C7.02944 17 3 12 3 12C3 12 7.02944 7 12 7C16.9706 7 21 12 21 12Z" stroke="#718096" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> `; } else { passwordInput.type = 'password'; passwordToggle.innerHTML = ` <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M15 12C15 13.6569 13.6569 15 12 15C10.3431 15 9 13.6569 9 12C9 10.3431 10.3431 9 12 9C13.6569 9 15 10.3431 15 12Z" stroke="#718096" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12 5C7.23858 5 3.36509 7.94758 2.03153 12C3.36509 16.0524 7.23858 19 12 19C16.7614 19 20.6349 16.0524 21.9685 12C20.6349 7.94758 16.7614 5 12 5Z" stroke="#718096" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> `; } }); // Form submission registerBtn.addEventListener('click', handleFormSubmit); continueBtn.addEventListener('click', () => { // Reset form for demo purposes resetForm(); }); // Real-time password strength meter passwordInput.addEventListener('input', checkPasswordStrength); // Format phone number as user types phoneInput.addEventListener('input', formatPhoneNumber); // Update progress step function updateProgressStep(stepIndex) { progressSteps.forEach((step, index) => { if (index <= stepIndex) { step.classList.add('active'); } else { step.classList.remove('active'); } }); } // Validate individual input function validateInput(input) { switch(input.id) { case 'email': validateEmail(); break; case 'password': validatePassword(); break; case 'phone': validatePhone(); break; } // Enable/disable submit button based on form validity updateSubmitButton(); } // Email validation function validateEmail() { const email = emailInput.value.trim(); const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (email === '') { showInputError(emailInput, emailFeedback, 'Email is required'); formState.email = false; } else if (!emailRegex.test(email)) { showInputError(emailInput, emailFeedback, 'Please enter a valid email address'); formState.email = false; } else { showInputSuccess(emailInput, emailFeedback); formState.email = true; } } // Password validation and strength meter function validatePassword() { const password = passwordInput.value; if (password === '') { showInputError(passwordInput, passwordFeedback, 'Password is required'); formState.password = false; } else if (password.length < 8) { showInputError(passwordInput, passwordFeedback, 'Password must be at least 8 characters'); formState.password = false; } else { showInputSuccess(passwordInput, passwordFeedback); formState.password = true; } } // Phone validation function validatePhone() { const phone = phoneInput.value.replace(/\D/g, ''); if (phone === '') { showInputError(phoneInput, phoneFeedback, 'Phone number is required'); formState.phone = false; } else if (phone.length < 10) { showInputError(phoneInput, phoneFeedback, 'Please enter a complete phone number'); formState.phone = false; } else { showInputSuccess(phoneInput, phoneFeedback); formState.phone = true; } } // Show input error function showInputError(input, feedback, message) { input.classList.add('invalid'); input.classList.remove('valid'); feedback.textContent = message; feedback.classList.add('show-feedback'); // Show error icon, hide success icon const errorIcon = input.parentNode.querySelector('.icon-invalid'); const successIcon = input.parentNode.querySelector('.icon-valid'); if (errorIcon) errorIcon.style.display = 'block'; if (successIcon) successIcon.style.display = 'none'; } // Show input success function showInputSuccess(input, feedback) { input.classList.remove('invalid'); input.classList.add('valid'); feedback.textContent = ''; feedback.classList.remove('show-feedback'); // Show success icon, hide error icon const errorIcon = input.parentNode.querySelector('.icon-invalid'); const successIcon = input.parentNode.querySelector('.icon-valid'); if (errorIcon) errorIcon.style.display = 'none'; if (successIcon) successIcon.style.display = 'block'; } // Check password strength function checkPasswordStrength() { const password = passwordInput.value; const strengthContainer = document.querySelector('.password-strength'); // Reset classes strengthContainer.className = 'password-strength'; if (!password) { strengthText.textContent = 'Password strength: Type to check'; return; } // Calculate score let score = 0; // Length check if (password.length >= 8) score++; if (password.length >= 12) score++; // Complexity checks if (/[A-Z]/.test(password)) score++; if (/[a-z]/.test(password)) score++; if (/[0-9]/.test(password)) score++; if (/[^A-Za-z0-9]/.test(password)) score++; // Set strength indicator if (score <= 2) { strengthContainer.classList.add('strength-weak'); strengthText.textContent = 'Password strength: Weak'; } else if (score <= 4) { strengthContainer.classList.add('strength-medium'); strengthText.textContent = 'Password strength: Medium'; } else if (score <= 5) { strengthContainer.classList.add('strength-strong'); strengthText.textContent = 'Password strength: Strong'; } else { strengthContainer.classList.add('strength-very-strong'); strengthText.textContent = 'Password strength: Very Strong'; } } // Format phone number as user types function formatPhoneNumber() { let value = phoneInput.value.replace(/\D/g, ''); let formattedValue = ''; if (value.length > 0) { formattedValue = '(' + value.substring(0, 3); } if (value.length > 3) { formattedValue += ') ' + value.substring(3, 6); } if (value.length > 6) { formattedValue += '-' + value.substring(6, 10); } phoneInput.value = formattedValue; } // Update submit button state function updateSubmitButton() { const isFormValid = formState.email && formState.password && formState.phone; if (isFormValid) { registerBtn.disabled = false; registerBtn.classList.add('btn-enabled'); } else { registerBtn.disabled = true; registerBtn.classList.remove('btn-enabled'); } } // Handle form submission function handleFormSubmit(e) { e.preventDefault(); // Validate all inputs one more time validateEmail(); validatePassword(); validatePhone(); const isFormValid = formState.email && formState.password && formState.phone; if (isFormValid) { // Show loading state registerBtn.textContent = 'Creating Account...'; registerBtn.classList.add('btn-loading'); // Simulate API call setTimeout(() => { // Hide form, show success message formWrapper.style.display = 'none'; successMessage.style.display = 'flex'; // Animate success icon setTimeout(() => { document.querySelector('.success-icon').classList.add('animate'); }, 100); }, 1500); } else { // If there are errors, find the first invalid input and focus it if (!formState.email) { emailInput.focus(); } else if (!formState.password) { passwordInput.focus(); } else if (!formState.phone) { phoneInput.focus(); } } } // Reset form for demo purposes function resetForm() { formWrapper.style.display = 'block'; successMessage.style.display = 'none'; // Reset inputs emailInput.value = ''; passwordInput.value = ''; phoneInput.value = ''; // Reset button state registerBtn.textContent = 'Create Account'; registerBtn.classList.remove('btn-loading'); // Reset validation state formState.email = false; formState.password = false; formState.phone = false; // Reset UI [emailInput, passwordInput, phoneInput].forEach(input => { input.classList.remove('valid', 'invalid'); }); [emailFeedback, passwordFeedback, phoneFeedback].forEach(feedback => { feedback.textContent = ''; feedback.classList.remove('show-feedback'); }); // Reset password strength document.querySelector('.password-strength').className = 'password-strength'; strengthText.textContent = 'Password strength: Type to check'; // Reset progress steps progressSteps.forEach((step, index) => { if (index === 0) { step.classList.add('active'); } else { step.classList.remove('active'); } }); // Reset icons document.querySelectorAll('.icon-valid, .icon-invalid').forEach(icon => { icon.style.display = 'none'; }); } }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>LearnFlow - Student Sign-up</title> <style> @import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&display=swap'); :root { --primary: #4B89DC; --primary-light: #6FA0E9; --primary-dark: #3A6FB8; --accent: #FF7F50; --success: #2ECC71; --error: #E74C3C; --neutral-light: #F8F9FA; --neutral: #E9ECEF; --neutral-dark: #CED4DA; --text: #343A40; --text-light: #6C757D; --white: #FFFFFF; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Quicksand', sans-serif; } body { width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; background-color: var(--neutral-light); background-image: radial-gradient(circle at 25% 15%, rgba(75, 137, 220, 0.05) 5%, transparent 15%), radial-gradient(circle at 75% 35%, rgba(255, 127, 80, 0.05) 5%, transparent 15%), radial-gradient(circle at 50% 65%, rgba(75, 137, 220, 0.05) 5%, transparent 15%), radial-gradient(circle at 15% 85%, rgba(255, 127, 80, 0.05) 5%, transparent 15%), radial-gradient(circle at 85% 70%, rgba(46, 204, 113, 0.05) 5%, transparent 15%); padding: 20px; } .signup-container { width: 100%; max-width: 600px; background: var(--white); border-radius: 20px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); padding: 40px; overflow: hidden; position: relative; } .signup-header { text-align: center; margin-bottom: 30px; } .signup-header h1 { color: var(--primary); font-weight: 700; font-size: 28px; margin-bottom: 10px; } .signup-header p { color: var(--text-light); font-size: 16px; line-height: 1.6; } .highlight { color: var(--accent); font-weight: 600; } .form-group { margin-bottom: 24px; position: relative; } .form-group label { display: block; color: var(--text); font-weight: 600; margin-bottom: 8px; font-size: 15px; transition: all 0.3s ease; } .form-group input { width: 100%; padding: 14px 16px; border: 2px solid var(--neutral-dark); border-radius: 12px; font-size: 16px; color: var(--text); background: var(--white); transition: all 0.3s ease; } .form-group input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 4px rgba(75, 137, 220, 0.15); } .form-group .help-text { margin-top: 8px; font-size: 13px; color: var(--text-light); transition: all 0.3s ease; } .form-group .validation-icon { position: absolute; right: 15px; top: 42px; font-size: 18px; opacity: 0; transition: all 0.3s ease; } .form-group.success input { border-color: var(--success); } .form-group.success .validation-icon.success { opacity: 1; color: var(--success); } .form-group.error input { border-color: var(--error); } .form-group.error .validation-icon.error { opacity: 1; color: var(--error); } .form-group.error .help-text { color: var(--error); } .btn-signup { width: 100%; padding: 14px; background: var(--primary); color: white; border: none; border-radius: 12px; font-size: 16px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; } .btn-signup:hover { background: var(--primary-dark); transform: translateY(-2px); box-shadow: 0 4px 12px rgba(75, 137, 220, 0.3); } .btn-signup:active { transform: translateY(0); box-shadow: 0 2px 6px rgba(75, 137, 220, 0.3); } .btn-signup .btn-text { position: relative; z-index: 2; } .signup-footer { text-align: center; margin-top: 20px; font-size: 14px; color: var(--text-light); } .signup-footer a { color: var(--primary); text-decoration: none; font-weight: 600; transition: all 0.3s ease; } .signup-footer a:hover { color: var(--primary-dark); text-decoration: underline; } .password-toggle { position: absolute; right: 15px; top: 42px; cursor: pointer; color: var(--text-light); transition: all 0.3s ease; z-index: 3; } .password-toggle:hover { color: var(--primary); } .educational-interests { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px; } .interest-tag { padding: 8px 14px; background: var(--neutral); border-radius: 20px; font-size: 14px; color: var(--text); cursor: pointer; transition: all 0.3s ease; user-select: none; } .interest-tag:hover { background: var(--neutral-dark); } .interest-tag.selected { background: var(--primary-light); color: white; } /* Progress indicator */ .form-progress { width: 100%; height: 6px; background: var(--neutral); border-radius: 3px; margin-bottom: 30px; overflow: hidden; } .progress-bar { height: 100%; width: 0%; background: linear-gradient(90deg, var(--primary), var(--accent)); border-radius: 3px; transition: width 0.5s ease; } /* Toast notification */ .toast { position: fixed; top: 20px; right: 20px; padding: 15px 20px; background: var(--success); color: white; border-radius: 12px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15); transform: translateX(150%); transition: transform 0.4s ease; z-index: 1000; font-weight: 600; } .toast.show { transform: translateX(0); } /* Animation for the button */ @keyframes ripple { 0% { transform: scale(0); opacity: 0.6; } 100% { transform: scale(2); opacity: 0; } } .ripple { position: absolute; border-radius: 50%; background: rgba(255, 255, 255, 0.5); transform: scale(0); animation: ripple 0.6s linear; pointer-events: none; } /* Responsive adjustments */ @media (max-width: 600px) { .signup-container { padding: 30px 20px; border-radius: 15px; } .signup-header h1 { font-size: 24px; } .form-group input { padding: 12px 14px; } } </style> </head> <body> <div class="signup-container"> <div class="signup-header"> <h1>Join <span class="highlight">LearnFlow</span> Today</h1> <p>Start your learning journey with thousands of courses tailored to your pace and interests.</p> </div> <div class="form-progress"> <div class="progress-bar" id="progressBar"></div> </div> <form id="signupForm"> <div class="form-group" id="nameGroup"> <label for="fullName">Full Name</label> <input type="text" id="fullName" placeholder="e.g., Alex Johnson"> <span class="validation-icon success">✓</span> <span class="validation-icon error">✗</span> <div class="help-text">This is how instructors will address you in the course.</div> </div> <div class="form-group" id="emailGroup"> <label for="email">Email Address</label> <input type="email" id="email" placeholder="[email protected]"> <span class="validation-icon success">✓</span> <span class="validation-icon error">✗</span> <div class="help-text">We'll send course updates and learning resources here.</div> </div> <div class="form-group" id="passwordGroup"> <label for="password">Password</label> <input type="password" id="password" placeholder="Create a secure password"> <span class="validation-icon success">✓</span> <span class="validation-icon error">✗</span> <span class="password-toggle" id="passwordToggle">👁️</span> <div class="help-text">Use at least 8 characters with letters, numbers and symbols.</div> </div> <div class="form-group"> <label>Learning Interests</label> <div class="educational-interests"> <div class="interest-tag" data-interest="programming">Programming</div> <div class="interest-tag" data-interest="design">Design</div> <div class="interest-tag" data-interest="business">Business</div> <div class="interest-tag" data-interest="languages">Languages</div> <div class="interest-tag" data-interest="science">Science</div> </div> <div class="help-text">Select topics that interest you for personalized recommendations.</div> </div> <button type="button" class="btn-signup" id="signupButton"> <span class="btn-text">Create My Learning Account</span> </button> </form> <div class="signup-footer"> Already have an account? <a href="#">Log in</a> to continue learning </div> </div> <div class="toast" id="toast">Account created successfully! Redirecting to your dashboard...</div> <script> document.addEventListener('DOMContentLoaded', function() { const fullNameInput = document.getElementById('fullName'); const emailInput = document.getElementById('email'); const passwordInput = document.getElementById('password'); const passwordToggle = document.getElementById('passwordToggle'); const signupButton = document.getElementById('signupButton'); const progressBar = document.getElementById('progressBar'); const toast = document.getElementById('toast'); const interestTags = document.querySelectorAll('.interest-tag'); // Form validation state const formState = { name: false, email: false, password: false, interests: [] }; // Update progress bar function updateProgress() { const progressFields = [formState.name, formState.email, formState.password, formState.interests.length > 0]; const completedFields = progressFields.filter(field => field).length; const progressPercentage = (completedFields / progressFields.length) * 100; progressBar.style.width = `${progressPercentage}%`; } // Name validation fullNameInput.addEventListener('input', function() { const nameGroup = document.getElementById('nameGroup'); if (this.value.length >= 3 && /^[a-zA-Z\s]+$/.test(this.value)) { nameGroup.classList.add('success'); nameGroup.classList.remove('error'); formState.name = true; } else { nameGroup.classList.remove('success'); if (this.value.length > 0) { nameGroup.classList.add('error'); } else { nameGroup.classList.remove('error'); } formState.name = false; } updateProgress(); }); // Email validation emailInput.addEventListener('input', function() { const emailGroup = document.getElementById('emailGroup'); const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (emailRegex.test(this.value)) { emailGroup.classList.add('success'); emailGroup.classList.remove('error'); formState.email = true; } else { emailGroup.classList.remove('success'); if (this.value.length > 0) { emailGroup.classList.add('error'); } else { emailGroup.classList.remove('error'); } formState.email = false; } updateProgress(); }); // Password validation passwordInput.addEventListener('input', function() { const passwordGroup = document.getElementById('passwordGroup'); // Password strength: at least 8 chars, with letters and numbers const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*#?&]{8,}$/; if (passwordRegex.test(this.value)) { passwordGroup.classList.add('success'); passwordGroup.classList.remove('error'); formState.password = true; } else { passwordGroup.classList.remove('success'); if (this.value.length > 0) { passwordGroup.classList.add('error'); } else { passwordGroup.classList.remove('error'); } formState.password = false; } updateProgress(); }); // Password toggle passwordToggle.addEventListener('click', function() { if (passwordInput.type === 'password') { passwordInput.type = 'text'; this.textContent = '👁️🗨️'; } else { passwordInput.type = 'password'; this.textContent = '👁️'; } }); // Interest tags interestTags.forEach(tag => { tag.addEventListener('click', function() { const interest = this.getAttribute('data-interest'); if (this.classList.contains('selected')) { // Deselect this.classList.remove('selected'); formState.interests = formState.interests.filter(item => item !== interest); } else { // Select this.classList.add('selected'); formState.interests.push(interest); } updateProgress(); }); }); // Button ripple effect signupButton.addEventListener('click', function(e) { const x = e.clientX - e.target.getBoundingClientRect().left; const y = e.clientY - e.target.getBoundingClientRect().top; const ripple = document.createElement('span'); ripple.classList.add('ripple'); ripple.style.left = `${x}px`; ripple.style.top = `${y}px`; this.appendChild(ripple); setTimeout(() => { ripple.remove(); }, 600); // Form submission logic if (formState.name && formState.email && formState.password) { signupButton.disabled = true; signupButton.querySelector('.btn-text').textContent = 'Creating Account...'; // Simulate API call setTimeout(() => { toast.classList.add('show'); setTimeout(() => { toast.classList.remove('show'); }, 5000); // Reset form document.getElementById('signupForm').reset(); document.getElementById('nameGroup').classList.remove('success'); document.getElementById('emailGroup').classList.remove('success'); document.getElementById('passwordGroup').classList.remove('success'); interestTags.forEach(tag => { tag.classList.remove('selected'); }); formState.name = false; formState.email = false; formState.password = false; formState.interests = []; updateProgress(); signupButton.disabled = false; signupButton.querySelector('.btn-text').textContent = 'Create My Learning Account'; }, 1500); } else { // Highlight unfilled required fields if (!formState.name) { fullNameInput.focus(); } else if (!formState.email) { emailInput.focus(); } else if (!formState.password) { passwordInput.focus(); } } }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; } body { background-color: #1a1a2e; color: #e7e7e7; display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; } .dashboard-container { width: 650px; max-width: 100%; background-color: #16213e; border-radius: 16px; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5); padding: 25px; position: relative; overflow: hidden; } .dashboard-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .dashboard-title { font-size: 24px; font-weight: 700; color: #00b4d8; letter-spacing: -0.5px; } .user-info { display: flex; align-items: center; gap: 10px; } .user-avatar { width: 36px; height: 36px; border-radius: 50%; background-color: #00b4d8; display: flex; align-items: center; justify-content: center; font-weight: 700; color: #16213e; } .search-container { position: relative; margin-bottom: 25px; } .search-input { width: 100%; padding: 15px 45px; background-color: #0f3460; border: 2px solid #0f3460; border-radius: 12px; color: #ffffff; font-size: 16px; transition: all 0.3s ease; } .search-input:focus { outline: none; border-color: #00b4d8; box-shadow: 0 0 0 3px rgba(0, 180, 216, 0.2); } .search-icon { position: absolute; left: 15px; top: 50%; transform: translateY(-50%); color: #8d99ae; transition: color 0.3s ease; } .search-input:focus + .search-icon { color: #00b4d8; } .clear-search { position: absolute; right: 15px; top: 50%; transform: translateY(-50%); background: none; border: none; color: #8d99ae; cursor: pointer; opacity: 0; transition: all 0.3s ease; } .clear-search.visible { opacity: 1; } .clear-search:hover { color: #ff5a5f; } .filter-tags { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 25px; } .filter-tag { background-color: #0f3460; border: 1px solid #243b55; border-radius: 20px; padding: 8px 15px; display: flex; align-items: center; gap: 8px; font-size: 14px; cursor: pointer; transition: all 0.2s ease; } .filter-tag:hover { background-color: #1a508b; } .filter-tag.active { background-color: #00b4d8; border-color: #00b4d8; color: #0f3460; font-weight: 600; } .filter-tag-icon { font-size: 16px; } .results-container { max-height: 360px; overflow-y: auto; padding-right: 5px; } .results-container::-webkit-scrollbar { width: 5px; } .results-container::-webkit-scrollbar-track { background: #1a1a2e; border-radius: 10px; } .results-container::-webkit-scrollbar-thumb { background: #243b55; border-radius: 10px; } .results-container::-webkit-scrollbar-thumb:hover { background: #00b4d8; } .search-suggestions { background-color: #243b55; border-radius: 10px; margin-top: 10px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); overflow: hidden; display: none; position: absolute; width: 100%; z-index: 10; } .suggestion-item { padding: 12px 15px; cursor: pointer; transition: background-color 0.2s ease; display: flex; align-items: center; gap: 10px; } .suggestion-item:not(:last-child) { border-bottom: 1px solid #1a1a2e; } .suggestion-item:hover { background-color: #1a508b; } .suggestion-category { font-size: 12px; color: #00b4d8; margin-left: auto; padding: 3px 8px; background-color: rgba(0, 180, 216, 0.1); border-radius: 4px; } .data-item { background-color: #243b55; border-radius: 10px; padding: 18px; margin-bottom: 15px; transition: all 0.3s ease; position: relative; overflow: hidden; } .data-item:hover { transform: translateY(-2px); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); } .data-item-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .data-title { font-weight: 600; font-size: 17px; display: flex; align-items: center; gap: 10px; } .data-title-highlight { color: #00b4d8; } .data-status { padding: 4px 10px; border-radius: 6px; font-size: 13px; font-weight: 600; } .data-status.active { background-color: rgba(0, 210, 91, 0.2); color: #00d25b; } .data-status.pending { background-color: rgba(255, 153, 0, 0.2); color: #ff9900; } .data-status.inactive { background-color: rgba(255, 89, 95, 0.2); color: #ff595f; } .data-meta { display: flex; align-items: center; gap: 20px; margin-bottom: 15px; font-size: 14px; color: #8d99ae; } .data-meta-item { display: flex; align-items: center; gap: 5px; } .data-description { font-size: 14px; line-height: 1.5; color: #e7e7e7; margin-bottom: 15px; } .data-tags { display: flex; flex-wrap: wrap; gap: 8px; } .data-tag { background-color: #1a1a2e; border-radius: 4px; padding: 5px 10px; font-size: 12px; color: #8d99ae; } .data-indicator { position: absolute; top: 0; left: 0; height: 100%; width: 4px; } .data-indicator.critical { background-color: #ff595f; } .data-indicator.warning { background-color: #ff9900; } .data-indicator.normal { background-color: #00d25b; } .data-indicator.important { background-color: #00b4d8; } .no-results { text-align: center; padding: 40px 0; color: #8d99ae; font-size: 15px; display: none; } .no-results-icon { font-size: 28px; margin-bottom: 10px; color: #0f3460; } .search-stats { display: flex; justify-content: space-between; align-items: center; padding: 10px 0 15px; font-size: 14px; color: #8d99ae; } .stats-count { color: #00b4d8; font-weight: 600; } .pulse-animation { animation: pulse 1.5s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(0, 180, 216, 0.5); } 70% { box-shadow: 0 0 0 8px rgba(0, 180, 216, 0); } 100% { box-shadow: 0 0 0 0 rgba(0, 180, 216, 0); } } .highlight { background-color: rgba(0, 180, 216, 0.3); padding: 0 3px; border-radius: 2px; color: #ffffff; } /* Animation for search suggestions */ @keyframes slideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } .search-suggestions.active { display: block; animation: slideDown 0.3s ease; } /* Animation for filter tags */ @keyframes popIn { 0% { transform: scale(0.8); opacity: 0; } 70% { transform: scale(1.1); } 100% { transform: scale(1); opacity: 1; } } .filter-tag.new { animation: popIn 0.4s ease; } /* Data item entrance animation */ @keyframes fadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .data-item { animation: fadeInUp 0.4s ease; animation-fill-mode: both; } .data-item:nth-child(2) { animation-delay: 0.1s; } .data-item:nth-child(3) { animation-delay: 0.2s; } .data-item:nth-child(4) { animation-delay: 0.3s; } /* Badge styling */ .data-badge { position: absolute; top: 15px; right: 15px; background-color: #ff595f; color: white; border-radius: 50%; width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; } /* Responsive styles */ @media (max-width: 480px) { .dashboard-container { padding: 15px; border-radius: 10px; } .dashboard-header { margin-bottom: 15px; } .dashboard-title { font-size: 20px; } .search-input { padding: 12px 40px; font-size: 14px; } .data-item { padding: 15px; } .data-title { font-size: 15px; } .data-description { font-size: 13px; } .filter-tags { gap: 8px; } .filter-tag { padding: 6px 12px; font-size: 12px; } } /* Dark overlay */ .overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: none; z-index: 5; } .overlay.active { display: block; } /* Keyboard shortcut tip */ .keyboard-tip { position: absolute; bottom: 15px; right: 15px; background-color: rgba(15, 52, 96, 0.8); padding: 8px 12px; border-radius: 6px; font-size: 12px; color: #8d99ae; display: flex; align-items: center; gap: 6px; pointer-events: none; opacity: 0; transition: opacity 0.3s ease; } .keyboard-tip.visible { opacity: 1; } .key { background-color: #243b55; padding: 2px 6px; border-radius: 4px; color: #e7e7e7; font-weight: 600; box-shadow: 0 2px 0 rgba(0, 0, 0, 0.2); } </style> </head> <body> <div class="dashboard-container"> <div class="dashboard-header"> <h1 class="dashboard-title">DevOps Control Panel</h1> <div class="user-info"> <div class="user-avatar">AM</div> </div> </div> <div class="search-container"> <input type="text" class="search-input" placeholder="Search systems, deployments, incidents..." id="searchInput"> <svg class="search-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M11 19C15.4183 19 19 15.4183 19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11C3 15.4183 6.58172 19 11 19Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M21 21L16.65 16.65" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> <button class="clear-search" id="clearSearch"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M18 6L6 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M6 6L18 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> <div class="search-suggestions" id="searchSuggestions"> <!-- Dynamically populated --> </div> </div> <div class="filter-tags" id="filterTags"> <div class="filter-tag" data-filter="all"> <svg class="filter-tag-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M22 3H2L10 12.46V19L14 21V12.46L22 3Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> All Items </div> <div class="filter-tag" data-filter="critical"> <svg class="filter-tag-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 8V12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12 16H12.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M10.93 2.93L3 10.93V14.93H7L15 22.93V18.93H19V14.93L10.93 2.93Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Critical </div> <div class="filter-tag" data-filter="active"> <svg class="filter-tag-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M20 6L9 17L4 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Active </div> <div class="filter-tag" data-filter="pending"> <svg class="filter-tag-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 8V12L15 15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Pending </div> </div> <div class="search-stats" id="searchStats"> <div>Showing <span class="stats-count" id="resultsCount">4</span> results</div> <div>Updated <span id="lastUpdated">2 mins ago</span></div> </div> <div class="results-container" id="resultsContainer"> <div class="data-item" data-type="server" data-status="active" data-priority="critical"> <div class="data-indicator critical"></div> <div class="data-item-header"> <div class="data-title"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <rect x="2" y="2" width="20" height="8" rx="2" stroke="currentColor" stroke-width="2"/> <rect x="2" y="14" width="20" height="8" rx="2" stroke="currentColor" stroke-width="2"/> <circle cx="6" cy="6" r="1" fill="currentColor"/> <circle cx="6" cy="18" r="1" fill="currentColor"/> </svg> API Gateway (us-east-1) </div> <div class="data-status active">Active</div> </div> <div class="data-meta"> <div class="data-meta-item"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 9V11.5L13.5 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/> </svg> Last incident: 42m ago </div> <div class="data-meta-item"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M5 12H5.01M12 12H12.01M19 12H19.01M6 12C6 12.5523 5.55228 13 5 13C4.44772 13 4 12.5523 4 12C4 11.4477 4.44772 11 5 11C5.55228 11 6 11.4477 6 12ZM13 12C13 12.5523 12.5523 13 12 13C11.4477 13 11 12.5523 11 12C11 11.4477 11.4477 11 12 11C12.5523 11 13 11.4477 13 12ZM20 12C20 12.5523 19.5523 13 19 13C18.4477 13 18 12.5523 18 12C18 11.4477 18.4477 11 19 11C19.5523 11 20 11.4477 20 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Request rate: 843/s </div> </div> <p class="data-description">High latency detected in transaction processing queue. Average response time exceeds threshold by 350ms.</p> <div class="data-tags"> <div class="data-tag">Microservice</div> <div class="data-tag">Load Balancing</div> <div class="data-tag">High Priority</div> </div> <div class="data-badge">3</div> </div> <div class="data-item" data-type="deployment" data-status="pending" data-priority="warning"> <div class="data-indicator warning"></div> <div class="data-item-header"> <div class="data-title"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 3V21M3 12H21" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> <path d="M17 8L17 16M7 8L7 16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> </svg> User Auth Service v2.4.1 </div> <div class="data-status pending">Pending</div> </div> <div class="data-meta"> <div class="data-meta-item"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 9V11.5L13.5 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/> </svg> Scheduled: 14:30 UTC </div> <div class="data-meta-item"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M16 2V6M8 2V6M3 10H21M5 4H19C20.1046 4 21 4.89543 21 6V20C21 21.1046 20.1046 22 19 22H5C3.89543 22 3 21.1046 3 20V6C3 4.89543 3.89543 4 5 4Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Canary release </div> </div> <p class="data-description">OAuth implementation with JWT refresh tokens. 3 dependencies require security patch before deployment can proceed.</p> <div class="data-tags"> <div class="data-tag">JWT</div> <div class="data-tag">OAuth</div> <div class="data-tag">Security</div> </div> </div> <div class="data-item" data-type="database" data-status="inactive" data-priority="normal"> <div class="data-indicator normal"></div> <div class="data-item-header"> <div class="data-title"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 8C16.4183 8 20 6.65685 20 5C20 3.34315 16.4183 2 12 2C7.58172 2 4 3.34315 4 5C4 6.65685 7.58172 8 12 8Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M4 5V19C4 20.6569 7.58172 22 12 22C16.4183 22 20 20.6569 20 19V5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M4 12C4 13.6569 7.58172 15 12 15C16.4183 15 20 13.6569 20 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> MongoDB Analytics Cluster </div> <div class="data-status inactive">Inactive</div> </div> <div class="data-meta"> <div class="data-meta-item"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M5 8H19M5 8C3.89543 8 3 7.10457 3 6C3 4.89543 3.89543 4 5 4H19C20.1046 4 21 4.89543 21 6C21 7.10457 20.1046 8 19 8M5 8L5 18C5 19.1046 5.89543 20 7 20H17C18.1046 20 19 19.1046 19 18V8M10 12H14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Storage usage: 73% </div> <div class="data-meta-item"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M10 13C10.4295 13.5741 10.9774 14.0492 11.6066 14.3929C12.2357 14.7367 12.9315 14.9411 13.6467 14.9923C14.3618 15.0435 15.0796 14.9404 15.7513 14.6897C16.4231 14.4391 17.0331 14.0471 17.54 13.54L20.54 10.54C21.4508 9.59699 21.9548 8.33397 21.9434 7.02299C21.932 5.71201 21.4061 4.45794 20.4791 3.53087C19.552 2.60379 18.298 2.07791 16.987 2.06648C15.676 2.05504 14.413 2.55909 13.47 3.47L11.75 5.18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M14 11C13.5705 10.4259 13.0226 9.95083 12.3934 9.60706C11.7642 9.26329 11.0684 9.05886 10.3533 9.00768C9.63816 8.95649 8.92037 9.05961 8.24861 9.31025C7.57685 9.5609 6.96684 9.95293 6.45996 10.46L3.45996 13.46C2.54917 14.403 2.04519 15.666 2.05657 16.977C2.06796 18.288 2.59384 19.543 3.52092 20.4701C4.44799 21.3971 5.70207 21.923 7.01305 21.9344C8.32403 21.9458 9.58704 21.4418 10.53 20.53L12.24 18.82" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Connections: 0 </div> </div> <p class="data-description">Scheduled maintenance for index optimization. All queries redirected to replica set until completion.</p> <div class="data-tags"> <div class="data-tag">Database</div> <div class="data-tag">NoSQL</div> <div class="data-tag">Maintenance</div> </div> </div> <div class="data-item" data-type="system" data-status="active" data-priority="important"> <div class="data-indicator important"></div> <div class="data-item-header"> <div class="data-title"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M21 16V8.00002C20.9996 7.6493 20.9071 7.30483 20.7315 7.00119C20.556 6.69754 20.3037 6.44539 20 6.27002L13 2.27002C12.696 2.09449 12.3511 2.00208 12 2.00208C11.6489 2.00208 11.304 2.09449 11 2.27002L4 6.27002C3.69626 6.44539 3.44398 6.69754 3.26846 7.00119C3.09294 7.30483 3.00036 7.6493 3 8.00002V16C3.00036 16.3508 3.09294 16.6952 3.26846 16.9989C3.44398 17.3025 3.69626 17.5547 4 17.73L11 21.73C11.304 21.9056 11.6489 21.998 12 21.998C12.3511 21.998 12.696 21.9056 13 21.73L20 17.73C20.3037 17.5547 20.556 17.3025 20.7315 16.9989C20.9071 16.6952 20.9996 16.3508 21 16Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M3.27002 6.96002L12 12.01L20.73 6.96002" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12 22.08V12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Kubernetes Cluster (prod) </div> <div class="data-status active">Active</div> </div> <div class="data-meta"> <div class="data-meta-item"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M22 12H18L15 21L9 3L6 12H2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> CPU: 78% | RAM: 64% </div> <div class="data-meta-item"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M13 2L3 14H12L11 22L21 10H12L13 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Nodes: 8/8 healthy </div> </div> <p class="data-description">Auto-scaling triggered by increased traffic from APAC region. Additional worker nodes provisioned.</p> <div class="data-tags"> <div class="data-tag">Kubernetes</div> <div class="data-tag">Containers</div> <div class="data-tag">Auto-scaling</div> </div> </div> </div> <div class="no-results" id="noResults"> <div class="no-results-icon">🔍</div> <p>No matching results found</p> <p>Try adjusting your search or filters</p> </div> <div class="keyboard-tip" id="keyboardTip"> <span>Press</span> <span class="key">/</span> <span>to search</span> </div> </div> <div class="overlay" id="overlay"></div> <script> // DOM Elements const searchInput = document.getElementById('searchInput'); const clearSearchBtn = document.getElementById('clearSearch'); const searchSuggestions = document.getElementById('searchSuggestions'); const filterTags = document.getElementById('filterTags'); const resultsContainer = document.getElementById('resultsContainer'); const noResults = document.getElementById('noResults'); const resultsCount = document.getElementById('resultsCount'); const overlay = document.getElementById('overlay'); const keyboardTip = document.getElementById('keyboardTip'); // Show keyboard tip after 2 seconds setTimeout(() => { keyboardTip.classList.add('visible'); setTimeout(() => { keyboardTip.classList.remove('visible'); }, 4000); }, 2000); // Data suggestions const suggestions = [ { text: 'API Gateway', category: 'Server' }, { text: 'Kubernetes', category: 'System' }, { text: 'User Auth Service', category: 'Deployment' }, { text: 'MongoDB', category: 'Database' }, { text: 'OAuth implementation', category: 'Deployment' }, { text: 'NoSQL database', category: 'Database' }, { text: 'Microservices', category: 'Architecture' }, { text: 'JWT tokens', category: 'Security' }, { text: 'Critical incidents', category: 'Monitoring' }, { text: 'Load balancer', category: 'Infrastructure' }, { text: 'High latency', category: 'Performance' }, { text: 'Auto-scaling', category: 'Operation' } ]; // Handle search input events searchInput.addEventListener('focus', () => { if (searchInput.value) { showSuggestions(); } overlay.classList.add('active'); }); searchInput.addEventListener('keyup', (e) => { if (e.key === 'Escape') { hideSuggestions(); overlay.classList.remove('active'); searchInput.blur(); return; } if (searchInput.value) { clearSearchBtn.classList.add('visible'); showSuggestions(); filterResults(searchInput.value); } else { clearSearchBtn.classList.remove('visible'); hideS
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { display: flex; justify-content: center; align-items: center; min-height: 700px; background: linear-gradient(135deg, #1a1a2e, #16213e); padding: 20px; overflow: hidden; } .post-composer { width: 100%; max-width: 600px; background: rgba(255, 255, 255, 0.08); backdrop-filter: blur(10px); border-radius: 24px; box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4), 0 0 80px rgba(137, 43, 226, 0.2) inset; padding: 30px; color: #fff; position: relative; overflow: hidden; transition: all 0.4s ease; } .post-composer::before { content: ''; position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: radial-gradient( circle at center, transparent 30%, rgba(137, 43, 226, 0.1) 70%, transparent 100% ); opacity: 0; transform: scale(0.8); z-index: -1; transition: opacity 0.8s ease, transform 1.2s ease; } .post-composer.focused::before { opacity: 1; transform: scale(1); } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .title { font-size: 24px; font-weight: 700; background: linear-gradient(90deg, #ff7b54, #ff49db); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; text-shadow: 0 2px 10px rgba(255, 123, 84, 0.3); } .post-type { display: flex; gap: 10px; } .type-btn { background: transparent; border: none; color: #aaa; cursor: pointer; font-size: 14px; padding: 6px 12px; border-radius: 30px; transition: all 0.3s ease; position: relative; overflow: hidden; } .type-btn::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(90deg, #ff7b54, #ff49db); border-radius: 30px; z-index: -1; transition: opacity 0.3s ease; opacity: 0; } .type-btn.active { color: #fff; font-weight: 600; } .type-btn.active::before { opacity: 1; } .type-btn:hover:not(.active) { color: #fff; background: rgba(255, 255, 255, 0.1); } .textarea-container { position: relative; margin-bottom: 20px; border-radius: 16px; transition: all 0.3s ease; background: rgba(255, 255, 255, 0.05); overflow: hidden; } .textarea-container.focused { box-shadow: 0 0 0 2px rgba(255, 123, 84, 0.5), 0 0 20px rgba(255, 73, 219, 0.3); } .post-textarea { width: 100%; min-height: 180px; max-height: 300px; background: transparent; border: none; outline: none; color: #fff; padding: 20px; font-size: 16px; line-height: 1.6; resize: none; transition: all 0.3s ease; } .post-textarea::placeholder { color: rgba(255, 255, 255, 0.4); } .character-count { position: absolute; bottom: 15px; right: 15px; font-size: 12px; color: rgba(255, 255, 255, 0.6); display: flex; align-items: center; gap: 5px; transition: all 0.3s ease; } .count-circle { width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; background: rgba(255, 255, 255, 0.1); position: relative; transition: all 0.3s ease; } .count-circle::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border-radius: 50%; border: 2px solid transparent; transition: all 0.3s ease; } .count-circle.warning::before { border-color: #ffcc00; animation: pulse 1.5s infinite; } .count-circle.danger::before { border-color: #ff3860; animation: pulse 1s infinite; } @keyframes pulse { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.1); opacity: 0.7; } 100% { transform: scale(1); opacity: 1; } } .actions { display: flex; justify-content: space-between; align-items: center; } .add-media { display: flex; gap: 12px; } .media-btn { width: 40px; height: 40px; border: none; background: rgba(255, 255, 255, 0.1); border-radius: 12px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.3s ease; color: #fff; font-size: 18px; } .media-btn:hover { background: rgba(255, 255, 255, 0.2); transform: translateY(-3px); } .media-btn:active { transform: translateY(0); } .publish-btn { background: linear-gradient(90deg, #ff7b54, #ff49db); border: none; border-radius: 12px; padding: 12px 28px; color: #fff; font-weight: 600; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; display: flex; align-items: center; gap: 8px; } .publish-btn::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0)); transform: skewX(-15deg); transition: all 0.5s ease; } .publish-btn:hover { transform: translateY(-3px); box-shadow: 0 10px 20px rgba(255, 123, 84, 0.2); } .publish-btn:hover::before { left: 100%; } .publish-btn:active { transform: translateY(0); } .tags-container { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 15px; } .tag { background: rgba(255, 255, 255, 0.1); border-radius: 20px; padding: 6px 12px; font-size: 12px; color: rgba(255, 255, 255, 0.8); cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; gap: 5px; } .tag:hover { background: rgba(255, 255, 255, 0.2); transform: translateY(-2px); } .tag-hash { color: #ff7b54; font-weight: 600; } .suggestions { margin-top: 20px; display: flex; flex-direction: column; gap: 10px; opacity: 0; transform: translateY(20px); transition: all 0.3s ease; } .suggestions.show { opacity: 1; transform: translateY(0); } .suggestion-title { font-size: 14px; color: rgba(255, 255, 255, 0.6); } .suggestions-list { display: flex; flex-wrap: wrap; gap: 8px; } .suggestion-item { background: rgba(255, 255, 255, 0.05); border-radius: 8px; padding: 8px 12px; font-size: 12px; color: rgba(255, 255, 255, 0.8); cursor: pointer; transition: all 0.3s ease; border: 1px solid rgba(255, 255, 255, 0.1); } .suggestion-item:hover { background: rgba(255, 255, 255, 0.1); border-color: rgba(255, 123, 84, 0.5); } .mood-indicator { display: flex; align-items: center; gap: 10px; margin-top: 10px; padding: 10px; border-radius: 12px; background: rgba(255, 255, 255, 0.05); transition: all 0.3s ease; opacity: 0; transform: translateY(10px); } .mood-indicator.show { opacity: 1; transform: translateY(0); } .mood-icon { font-size: 20px; } .mood-text { font-size: 13px; color: rgba(255, 255, 255, 0.7); } .emoji-picker { position: absolute; bottom: 60px; right: 15px; background: rgba(30, 30, 60, 0.95); backdrop-filter: blur(10px); border-radius: 12px; padding: 10px; display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); z-index: 10; transform-origin: bottom right; transform: scale(0); opacity: 0; transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .emoji-picker.show { transform: scale(1); opacity: 1; } .emoji { width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 18px; border-radius: 6px; transition: all 0.2s ease; } .emoji:hover { background: rgba(255, 255, 255, 0.1); transform: scale(1.15); } .floating-particle { position: absolute; width: 6px; height: 6px; border-radius: 50%; pointer-events: none; z-index: 10; opacity: 0; } @keyframes floatUp { 0% { opacity: 1; transform: translateY(0) rotate(0deg); } 100% { opacity: 0; transform: translateY(-100px) rotate(360deg); } } @media (max-width: 600px) { .post-composer { padding: 20px; border-radius: 16px; } .header { flex-direction: column; align-items: flex-start; gap: 15px; } .post-type { width: 100%; justify-content: space-between; } .type-btn { font-size: 12px; padding: 5px 10px; } .post-textarea { min-height: 150px; font-size: 14px; } .actions { flex-direction: column; gap: 20px; } .add-media, .publish-btn { width: 100%; } .add-media { justify-content: space-between; } .publish-btn { justify-content: center; } .suggestions-list { max-width: 100%; overflow-x: auto; padding-bottom: 5px; flex-wrap: nowrap; } } </style> </head> <body> <div class="post-composer"> <div class="header"> <h2 class="title">Express Yourself</h2> <div class="post-type"> <button class="type-btn active" data-type="text">Text</button> <button class="type-btn" data-type="image">Photo</button> <button class="type-btn" data-type="video">Video</button> <button class="type-btn" data-type="poll">Poll</button> </div> </div> <div class="textarea-container"> <textarea class="post-textarea" placeholder="What's on your creative mind? Share your thoughts, stories, or ideas..."></textarea> <div class="character-count"> <span class="count-text">0/280</span> <div class="count-circle">0%</div> </div> <div class="emoji-picker"></div> </div> <div class="mood-indicator"> <div class="mood-icon">😊</div> <div class="mood-text">Your post sounds upbeat and positive!</div> </div> <div class="actions"> <div class="add-media"> <button class="media-btn" id="image-btn"><i>📷</i></button> <button class="media-btn" id="video-btn"><i>🎬</i></button> <button class="media-btn" id="emoji-btn"><i>😊</i></button> <button class="media-btn" id="gif-btn"><i>GIF</i></button> </div> <button class="publish-btn"> <span>Share with the world</span> <i>✨</i> </button> </div> <div class="tags-container"> <div class="tag"><span class="tag-hash">#</span>CreativeMinds</div> <div class="tag"><span class="tag-hash">#</span>Inspiration</div> <div class="tag"><span class="tag-hash">#</span>YourStory</div> </div> <div class="suggestions"> <div class="suggestion-title">Writing suggestions:</div> <div class="suggestions-list"> <div class="suggestion-item">Add a question to engage your audience</div> <div class="suggestion-item">Share a personal story</div> <div class="suggestion-item">Add a call to action</div> <div class="suggestion-item">Include relevant keywords</div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const postComposer = document.querySelector('.post-composer'); const textareaContainer = document.querySelector('.textarea-container'); const textarea = document.querySelector('.post-textarea'); const characterCount = document.querySelector('.count-text'); const countCircle = document.querySelector('.count-circle'); const emojiBtn = document.getElementById('emoji-btn'); const emojiPicker = document.querySelector('.emoji-picker'); const publishBtn = document.querySelector('.publish-btn'); const typeButtons = document.querySelectorAll('.type-btn'); const moodIndicator = document.querySelector('.mood-indicator'); const suggestions = document.querySelector('.suggestions'); // Character limit const MAX_CHARS = 280; // Initialize emoji picker const emojis = ['😀', '😂', '🥰', '😍', '🤩', '😎', '🙄', '😴', '🤔', '👍', '👏', '🙌', '💪', '❤️', '🔥', '✨', '🎉', '🌈', '🌟', '💯', '🚀', '🎯', '💡', '📷', '🎬']; emojis.forEach(emoji => { const emojiElement = document.createElement('div'); emojiElement.classList.add('emoji'); emojiElement.textContent = emoji; emojiElement.addEventListener('click', () => { textarea.value += emoji; updateCharCount(); createParticles(emojiElement); emojiPicker.classList.remove('show'); }); emojiPicker.appendChild(emojiElement); }); // Focus effect textarea.addEventListener('focus', () => { textareaContainer.classList.add('focused'); postComposer.classList.add('focused'); suggestions.classList.add('show'); }); textarea.addEventListener('blur', () => { textareaContainer.classList.remove('focused'); setTimeout(() => { if (!textarea.matches(':focus')) { postComposer.classList.remove('focused'); } }, 200); }); // Character counter textarea.addEventListener('input', updateCharCount); function updateCharCount() { const length = textarea.value.length; const remaining = MAX_CHARS - length; const percentage = Math.floor((length / MAX_CHARS) * 100); characterCount.textContent = `${length}/${MAX_CHARS}`; countCircle.textContent = `${percentage}%`; countCircle.classList.remove('warning', 'danger'); if (percentage >= 80 && percentage < 90) { countCircle.classList.add('warning'); } else if (percentage >= 90) { countCircle.classList.add('danger'); } analyzeMood(textarea.value); } // Emoji picker toggle emojiBtn.addEventListener('click', (e) => { e.stopPropagation(); emojiPicker.classList.toggle('show'); createParticles(emojiBtn); }); // Close emoji picker when clicking outside document.addEventListener('click', (e) => { if (!emojiPicker.contains(e.target) && e.target !== emojiBtn) { emojiPicker.classList.remove('show'); } }); // Post type buttons typeButtons.forEach(button => { button.addEventListener('click', () => { typeButtons.forEach(btn => btn.classList.remove('active')); button.classList.add('active'); // Change placeholder based on type if (button.dataset.type === 'image') { textarea.placeholder = "Describe this amazing photo you're about to share..."; } else if (button.dataset.type === 'video') { textarea.placeholder = "What's happening in your video? Tell us more..."; } else if (button.dataset.type === 'poll') { textarea.placeholder = "Ask a question for your poll and engage your audience..."; } else { textarea.placeholder = "What's on your creative mind? Share your thoughts, stories, or ideas..."; } createParticles(button); }); }); // Publish button effect publishBtn.addEventListener('click', () => { createParticles(publishBtn, 20); // Visual feedback on publish publishBtn.innerHTML = '<span>Shared!</span> <i>🎉</i>'; publishBtn.style.background = 'linear-gradient(90deg, #52de97, #2ab7ca)'; setTimeout(() => { publishBtn.innerHTML = '<span>Share with the world</span> <i>✨</i>'; publishBtn.style.background = 'linear-gradient(90deg, #ff7b54, #ff49db)'; textarea.value = ''; updateCharCount(); moodIndicator.classList.remove('show'); }, 2000); }); // Analyze mood of text function analyzeMood(text) { if (text.length < 10) { moodIndicator.classList.remove('show'); return; } // Simple mood analysis based on keywords const positiveWords = ['happy', 'love', 'great', 'awesome', 'amazing', 'excited', 'joy', 'wonderful', 'good', 'excellent']; const negativeWords = ['sad', 'angry', 'bad', 'terrible', 'hate', 'awful', 'disappointed', 'upset', 'fail', 'poor']; let positiveCount = 0; let negativeCount = 0; const words = text.toLowerCase().split(/\s+/); words.forEach(word => { if (positiveWords.some(pw => word.includes(pw))) positiveCount++; if (negativeWords.some(nw => word.includes(nw))) negativeCount++; }); const moodIcon = document.querySelector('.mood-icon'); const moodText = document.querySelector('.mood-text'); if (positiveCount > negativeCount) { moodIcon.textContent = '😊'; moodText.textContent = 'Your post sounds upbeat and positive!'; moodIndicator.style.background = 'rgba(82, 222, 151, 0.15)'; } else if (negativeCount > positiveCount) { moodIcon.textContent = '😔'; moodText.textContent = 'Your post has a somewhat negative tone. Consider adding some positivity?'; moodIndicator.style.background = 'rgba(255, 107, 107, 0.15)'; } else if (text.includes('?')) { moodIcon.textContent = '🤔'; moodText.textContent = 'Great question! This should engage your audience.'; moodIndicator.style.background = 'rgba(42, 183, 202, 0.15)'; } else { moodIcon.textContent = '😐'; moodText.textContent = 'Your post seems neutral. Add some emotion to engage more readers!'; moodIndicator.style.background = 'rgba(255, 255, 255, 0.05)'; } moodIndicator.classList.add('show'); } // Create floating particles function createParticles(element, count = 6) { const rect = element.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; for (let i = 0; i < count; i++) { const particle = document.createElement('div'); particle.classList.add('floating-particle'); // Random position around the element const angle = Math.random() * Math.PI * 2; const distance = Math.random() * 20; const x = centerX + Math.cos(angle) * distance; const y = centerY + Math.sin(angle) * distance; // Random color const hue = Math.floor(Math.random() * 60) + 340; // Red to pink range particle.style.background = `hsl(${hue}, 100%, 65%)`; // Random size const size = Math.random() * 5 + 3; particle.style.width = `${size}px`; particle.style.height = `${size}px`; // Position particle.style.left = `${x}px`; particle.style.top = `${y}px`; // Animation const duration = Math.random() * 1 + 1; particle.style.animation = `floatUp ${duration}s ease-out forwards`; document.body.appendChild(particle); // Remove after animation completes setTimeout(() => { if (particle.parentNode) { particle.parentNode.removeChild(particle); } }, duration * 1000); } } // Tag interactions const tags = document.querySelectorAll('.tag'); tags.forEach(tag => { tag.addEventListener('click', () => { const tagText = tag.textContent.replace('#', ''); textarea.value += ` #${tagText}`; updateCharCount(); createParticles(tag); }); }); // Suggestion interactions const suggestions_items = document.querySelectorAll('.suggestion-item'); suggestions_items.forEach(item => { item.addEventListener('click', () => { const currentText = textarea.value; if (currentText && !currentText.endsWith(' ')) { textarea.value += ' '; } // Add suggestion based hints to the textarea if (item.textContent.includes('question')) { textarea.value += "What do you think about this? "; } else if (item.textContent.includes('personal story')) { textarea.value += "Here's something that happened to me recently: "; } else if (item.textContent.includes('call to action')) { textarea.value += "Let me know your thoughts in the comments! "; } else if (item.textContent.includes('keywords')) { textarea.value += "#creativity #inspiration "; } updateCharCount(); createParticles(item); textarea.focus(); }); }); // Auto resize textarea function autoResize() { textarea.style.height = 'auto'; textarea.style.height = textarea.scrollHeight + 'px'; } textarea.addEventListener('input', autoResize); // Initialize updateCharCount(); autoResize(); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Festival Registration</title> <style> @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;800&family=Montserrat:wght@700&display=swap'); :root { --primary: #FF5678; --secondary: #6236FF; --accent: #FFD166; --dark: #2A2A5E; --light: #F9F7FE; --success: #06D6A0; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Poppins', sans-serif; background-color: var(--light); display: flex; justify-content: center; align-items: center; min-height: 100vh; overflow: hidden; color: var(--dark); padding: 20px; } .container { width: 100%; max-width: 600px; padding: 2rem; background: white; border-radius: 24px; box-shadow: 0 15px 50px rgba(0, 0, 0, 0.1); position: relative; overflow: hidden; transition: all 0.3s ease; } .bg-pattern { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 0; opacity: 0.06; background-image: radial-gradient(var(--secondary) 2px, transparent 2px), radial-gradient(var(--primary) 2px, transparent 2px); background-size: 30px 30px; background-position: 0 0, 15px 15px; } .content { position: relative; z-index: 1; } h1 { font-family: 'Montserrat', sans-serif; font-size: 2.2rem; margin-bottom: 0.5rem; color: var(--dark); background: linear-gradient(90deg, var(--primary), var(--secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; text-align: center; } .tagline { font-size: 1.1rem; text-align: center; margin-bottom: 2rem; color: var(--dark); opacity: 0.8; } .form-group { margin-bottom: 2rem; position: relative; } .email-input { width: 100%; padding: 1.2rem 1.5rem; font-size: 1rem; border: 2px solid rgba(98, 54, 255, 0.2); border-radius: 12px; background: rgba(255, 255, 255, 0.9); transition: all 0.3s ease; outline: none; font-family: 'Poppins', sans-serif; } .email-input:focus { border-color: var(--secondary); box-shadow: 0 0 0 4px rgba(98, 54, 255, 0.15); transform: translateY(-4px); } .email-input::placeholder { color: rgba(42, 42, 94, 0.5); } .label { position: absolute; left: 1.5rem; top: 1.2rem; transition: all 0.3s ease; pointer-events: none; color: rgba(42, 42, 94, 0.6); } .email-input:focus ~ .label, .email-input:not(:placeholder-shown) ~ .label { transform: translateY(-3.2rem) scale(0.85); color: var(--secondary); font-weight: 600; } .submit-btn { width: 100%; padding: 1.2rem; background: linear-gradient(45deg, var(--secondary), var(--primary)); color: white; border: none; border-radius: 12px; font-size: 1.1rem; font-weight: 600; cursor: pointer; transition: all 0.3s ease; transform-style: preserve-3d; position: relative; overflow: hidden; font-family: 'Poppins', sans-serif; } .submit-btn: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: 0.5s; } .submit-btn:hover { transform: translateY(-5px); box-shadow: 0 7px 25px rgba(98, 54, 255, 0.4); } .submit-btn:hover:before { left: 100%; } .confetti { position: absolute; width: 10px; height: 10px; background-color: var(--accent); opacity: 0; pointer-events: none; z-index: 2; } .event-types { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 2rem; } .event-type { padding: 8px 16px; background-color: white; border: 2px solid rgba(98, 54, 255, 0.2); border-radius: 20px; font-size: 0.9rem; cursor: pointer; transition: all 0.2s ease; } .event-type:hover { background-color: rgba(98, 54, 255, 0.05); } .event-type.active { background-color: var(--secondary); color: white; border-color: var(--secondary); animation: pulse 1.5s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(98, 54, 255, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(98, 54, 255, 0); } 100% { box-shadow: 0 0 0 0 rgba(98, 54, 255, 0); } } .error-message { color: var(--primary); font-size: 0.9rem; margin-top: 0.5rem; display: none; } .success-container { display: none; text-align: center; padding: 2rem 0; } .success-icon { font-size: 4rem; color: var(--success); margin-bottom: 1rem; display: inline-block; animation: bounce 1s ease infinite; } @keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-20px); } } .success-message { font-size: 1.5rem; font-weight: 600; margin-bottom: 1rem; } .events-container { margin-top: 2rem; } .events-title { font-size: 1.2rem; margin-bottom: 1rem; color: var(--dark); font-weight: 600; } .floating-shape { position: absolute; border-radius: 50%; opacity: 0.5; z-index: 0; filter: blur(20px); } .shape1 { width: 150px; height: 150px; background-color: var(--primary); top: -75px; right: -75px; animation: float 15s ease-in-out infinite; } .shape2 { width: 100px; height: 100px; background-color: var(--secondary); bottom: -50px; left: -50px; animation: float 18s ease-in-out infinite reverse; } .shape3 { width: 70px; height: 70px; background-color: var(--accent); top: 50%; right: -35px; animation: float 12s ease-in-out infinite 2s; } @keyframes float { 0% { transform: translate(0, 0) rotate(0deg); } 25% { transform: translate(-20px, 20px) rotate(90deg); } 50% { transform: translate(20px, 40px) rotate(180deg); } 75% { transform: translate(40px, -20px) rotate(270deg); } 100% { transform: translate(0, 0) rotate(360deg); } } @media (max-width: 500px) { h1 { font-size: 1.8rem; } .tagline { font-size: 1rem; } .container { padding: 1.5rem; } } </style> </head> <body> <div class="container"> <div class="bg-pattern"></div> <div class="floating-shape shape1"></div> <div class="floating-shape shape2"></div> <div class="floating-shape shape3"></div> <div class="content"> <h1>Join the Celebration!</h1> <p class="tagline">Get first access to Boston's hottest seasonal festivals, food events, and exclusive performances</p> <div class="form-container"> <div class="events-container"> <p class="events-title">I'm interested in:</p> <div class="event-types"> <div class="event-type" data-type="music">Music Festivals</div> <div class="event-type" data-type="food">Food & Wine</div> <div class="event-type" data-type="art">Art Exhibitions</div> <div class="event-type" data-type="tech">Tech Meetups</div> <div class="event-type" data-type="all">All Events</div> </div> </div> <div class="form-group"> <input type="email" class="email-input" id="email" placeholder=" " autocomplete="off"> <label for="email" class="label">Your email address</label> <p class="error-message" id="error-message">Please enter a valid email address</p> </div> <button class="submit-btn" id="submit-btn">Notify Me About Upcoming Events</button> </div> <div class="success-container" id="success-container"> <div class="success-icon">🎉</div> <p class="success-message">You're on the list!</p> <p>We'll notify you about the hottest events in town. Get ready to celebrate!</p> </div> </div> </div> <script> // Event type selection const eventTypes = document.querySelectorAll('.event-type'); eventTypes.forEach(type => { type.addEventListener('click', function() { // If all events is selected, deselect others if (this.dataset.type === 'all') { eventTypes.forEach(t => { if (t.dataset.type !== 'all') { t.classList.remove('active'); } }); } else { // Deselect "All Events" if any specific event is selected document.querySelector('.event-type[data-type="all"]').classList.remove('active'); } this.classList.toggle('active'); }); }); // Email validation const emailInput = document.getElementById('email'); const errorMessage = document.getElementById('error-message'); emailInput.addEventListener('focus', function() { this.parentElement.style.transform = 'scale(1.02)'; this.parentElement.style.transition = 'all 0.3s ease'; }); emailInput.addEventListener('blur', function() { this.parentElement.style.transform = 'scale(1)'; }); // Confetti animation function function createConfetti(x, y) { const colors = ['#FF5678', '#6236FF', '#FFD166', '#06D6A0']; for (let i = 0; i < 50; i++) { const confetti = document.createElement('div'); confetti.className = 'confetti'; document.body.appendChild(confetti); // Random properties const size = Math.random() * 10 + 5; const color = colors[Math.floor(Math.random() * colors.length)]; const shape = Math.random() > 0.5 ? '50%' : '0%'; confetti.style.width = `${size}px`; confetti.style.height = `${size}px`; confetti.style.backgroundColor = color; confetti.style.borderRadius = shape; confetti.style.left = `${x}px`; confetti.style.top = `${y}px`; confetti.style.opacity = '1'; // Animation const angle = Math.random() * Math.PI * 2; const velocity = Math.random() * 60 + 40; const tx = Math.cos(angle) * (Math.random() * 200) + x; const ty = Math.sin(angle) * (Math.random() * 200) + y - velocity; confetti.animate([ { transform: `translate(0, 0) rotate(0deg)`, opacity: 1 }, { transform: `translate(${tx - x}px, ${ty - y}px) rotate(${Math.random() * 360}deg)`, opacity: 0 } ], { duration: Math.random() * 1000 + 1000, easing: 'cubic-bezier(0,.9,.57,1)', fill: 'forwards' }); // Remove confetti element after animation setTimeout(() => { confetti.remove(); }, 2000); } } // Form submission const submitBtn = document.getElementById('submit-btn'); const formContainer = document.querySelector('.form-container'); const successContainer = document.getElementById('success-container'); submitBtn.addEventListener('click', function(e) { e.preventDefault(); const email = emailInput.value.trim(); const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { errorMessage.style.display = 'block'; emailInput.focus(); return; } errorMessage.style.display = 'none'; // Get selected event types const selectedTypes = []; document.querySelectorAll('.event-type.active').forEach(type => { selectedTypes.push(type.dataset.type); }); // Button animation and confetti submitBtn.innerHTML = 'Yay! You\'re In!'; submitBtn.style.backgroundColor = 'var(--success)'; // Get button position for confetti origin const rect = submitBtn.getBoundingClientRect(); const x = rect.left + rect.width / 2; const y = rect.top + rect.height / 2; createConfetti(x, y); // Show success message after a delay setTimeout(() => { formContainer.style.display = 'none'; successContainer.style.display = 'block'; }, 1000); }); // Focus animation for input emailInput.addEventListener('input', function() { if (this.value.trim() !== '') { errorMessage.style.display = 'none'; } }); // Initialize with "All Events" selected by default document.querySelector('.event-type[data-type="all"]').classList.add('active'); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; } body { background-color: #f9f7f3; height: 700px; width: 700px; display: flex; flex-direction: column; overflow: hidden; } .container { width: 100%; height: 100%; display: flex; flex-direction: column; padding: 25px; position: relative; overflow: hidden; } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; color: #333; } .header h1 { font-size: 22px; font-weight: 600; position: relative; } .header h1::after { content: ''; position: absolute; bottom: -5px; left: 0; width: 40px; height: 3px; background: linear-gradient(90deg, #6d28d9, #8b5cf6); } .toolbar { display: flex; gap: 15px; margin-bottom: 15px; flex-wrap: wrap; } .toolbar button { background: none; border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; color: #555; font-size: 14px; border-radius: 6px; padding: 8px 12px; transition: all 0.2s ease; background-color: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.08); } .toolbar button:hover { background-color: #f3f4f6; color: #333; } .toolbar button.active { background-color: #8b5cf6; color: white; } .toolbar button i { margin-right: 5px; } .editor-container { flex: 1; position: relative; overflow: hidden; border-radius: 12px; background-color: #ffffff; box-shadow: 0 4px 15px rgba(0,0,0,0.05); display: flex; flex-direction: column; } .editor-header { padding: 15px 20px; border-bottom: 1px solid #f0f0f0; display: flex; justify-content: space-between; align-items: center; } .editor-title { width: 100%; font-size: 16px; font-weight: 600; color: #222; border: none; background: none; outline: none; } .editor-controls { display: flex; gap: 10px; } .control-btn { background: none; border: none; cursor: pointer; width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: all 0.2s ease; } .control-btn:hover { background-color: #f5f5f5; } .control-btn:disabled { opacity: 0.4; cursor: not-allowed; } .control-btn svg { width: 16px; height: 16px; fill: #666; } .editor-content { flex: 1; position: relative; overflow-y: auto; padding: 25px 30px; } .editor-content::-webkit-scrollbar { width: 8px; } .editor-content::-webkit-scrollbar-track { background: #f9f9f9; } .editor-content::-webkit-scrollbar-thumb { background: #ddd; border-radius: 4px; } .typewriter-cursor { position: absolute; width: 2px; background-color: #6d28d9; animation: blink 1s infinite; display: none; } @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } } #editor { outline: none; min-height: 100%; line-height: 1.7; color: #333; font-size: 16px; white-space: pre-wrap; word-break: break-word; padding-bottom: 60px; } #editor:focus + .typewriter-cursor { display: block; } #editor p { margin-bottom: 16px; } .editor-footer { padding: 12px 20px; border-top: 1px solid #f0f0f0; display: flex; justify-content: space-between; align-items: center; font-size: 13px; color: #777; } .word-count { display: flex; gap: 15px; } .status { display: flex; align-items: center; gap: 5px; } .status-indicator { width: 8px; height: 8px; border-radius: 50%; background-color: #10b981; } /* Highlight styles */ .highlight { animation: highlightAnim 1s forwards; background-color: rgba(139, 92, 246, 0.15); border-radius: 3px; } @keyframes highlightAnim { 0% { background-color: rgba(139, 92, 246, 0.3); } 100% { background-color: rgba(139, 92, 246, 0.15); } } /* History notification */ .history-notification { position: absolute; top: 15px; right: 20px; background-color: #333; color: white; border-radius: 6px; padding: 8px 14px; font-size: 13px; opacity: 0; transform: translateY(-10px); transition: all 0.3s ease; z-index: 100; pointer-events: none; } .history-notification.show { opacity: 1; transform: translateY(0); } /* Focus mode */ .focus-mode .toolbar, .focus-mode .editor-header, .focus-mode .editor-footer { opacity: 0; transition: opacity 0.5s ease; } .focus-mode .editor-container { box-shadow: 0 10px 30px rgba(0,0,0,0.12); } .focus-mode:hover .toolbar, .focus-mode:hover .editor-header, .focus-mode:hover .editor-footer { opacity: 1; } /* Responsive adjustments */ @media (max-width: 600px) { .container { padding: 15px; } .editor-content { padding: 20px; } .toolbar { gap: 8px; } .toolbar button { padding: 6px 10px; font-size: 12px; } .header h1 { font-size: 18px; } } /* Typewriter line animation */ .typewriter-line { position: absolute; height: 28px; background-color: rgba(139, 92, 246, 0.08); width: 100%; left: 0; top: 0; z-index: -1; transform: translateY(-50%); transition: top 0.3s ease; border-radius: 3px; pointer-events: none; } </style> </head> <body> <div class="container" id="main-container"> <div class="header"> <h1>Scribe Editor</h1> <div class="time" id="time">12:45 PM</div> </div> <div class="toolbar" id="toolbar"> <button id="heading-btn" title="Heading"><i class="fas fa-heading"></i>Heading</button> <button id="bold-btn" title="Bold"><i class="fas fa-bold"></i>Bold</button> <button id="italic-btn" title="Italic"><i class="fas fa-italic"></i>Italic</button> <button id="focus-btn" title="Focus Mode"><i class="fas fa-eye"></i>Focus Mode</button> <button id="insights-btn" title="Insights"><i class="fas fa-chart-bar"></i>Insights</button> </div> <div class="editor-container" id="editor-container"> <div class="editor-header"> <input type="text" class="editor-title" id="document-title" placeholder="Untitled Document" value="The Power of Simple Writing"> <div class="editor-controls"> <button class="control-btn" id="undo-btn" title="Undo (Ctrl+Z)" disabled> <svg viewBox="0 0 24 24"> <path d="M12.5,8C9.85,8 7.45,9 5.6,10.6L2,7V16H11L7.38,12.38C8.77,11.22 10.54,10.5 12.5,10.5C16.04,10.5 19.05,12.81 20.1,16L22.47,15.22C21.08,11.03 17.15,8 12.5,8Z"></path> </svg> </button> <button class="control-btn" id="redo-btn" title="Redo (Ctrl+Y)" disabled> <svg viewBox="0 0 24 24"> <path d="M18.4,10.6C16.55,9 14.15,8 11.5,8C6.85,8 2.92,11.03 1.54,15.22L3.9,16C4.95,12.81 7.95,10.5 11.5,10.5C13.45,10.5 15.23,11.22 16.62,12.38L13,16H22V7L18.4,10.6Z"></path> </svg> </button> </div> </div> <div class="editor-content"> <div id="editor" contenteditable="true" spellcheck="true"> <p>Clear, concise writing is the backbone of effective communication. As William Zinsser notes in his classic "On Writing Well," the secret to good writing is to strip every sentence to its cleanest components.</p> <p>When crafting content for your audience, remember these principles:</p> <p>1. <b>Start with the essential</b>: What one thing must your reader understand?</p> <p>2. <b>Remove redundancies</b>: Say it once, clearly, rather than several times poorly.</p> <p>3. <b>Use concrete language</b>: Specificity builds credibility and engagement.</p> <p>The best writing feels effortless to read precisely because the writer has done the hard work of distillation first.</p> <p>As you edit this piece, focus on creating a rhythm that pulls your reader forward. Notice how shorter sentences following longer ones create momentum and emphasis.</p> <p>Now it's your turn. What story needs telling today?</p> </div> <div class="typewriter-cursor"></div> <div class="typewriter-line"></div> </div> <div class="editor-footer"> <div class="word-count"> <span id="word-count">120 words</span> <span id="read-time">1 min read</span> </div> <div class="status"> <div class="status-indicator"></div> <span>Saved</span> </div> </div> </div> <div class="history-notification" id="history-notification">Changes saved</div> </div> <script> // DOM Elements const editor = document.getElementById('editor'); const wordCount = document.getElementById('word-count'); const readTime = document.getElementById('read-time'); const undoBtn = document.getElementById('undo-btn'); const redoBtn = document.getElementById('redo-btn'); const focusBtn = document.getElementById('focus-btn'); const container = document.getElementById('main-container'); const historyNotification = document.getElementById('history-notification'); const toolbar = document.getElementById('toolbar'); const timeDisplay = document.getElementById('time'); const typewriterCursor = document.querySelector('.typewriter-cursor'); const typewriterLine = document.querySelector('.typewriter-line'); // History management let history = []; let historyIndex = -1; let lastChangeTime = Date.now(); // Initial save saveState(); // Update word count and read time function updateStats() { const text = editor.innerText.trim(); const words = text ? text.split(/\s+/).length : 0; wordCount.textContent = words + ' words'; // Assuming average reading speed of 200 words per minute const minutes = Math.max(1, Math.ceil(words / 200)); readTime.textContent = minutes + ' min read'; } // Save current state to history function saveState() { // Don't save if nothing has changed if (historyIndex >= 0 && editor.innerHTML === history[historyIndex]) { return; } // If we're not at the end of the history, remove everything after current point if (historyIndex < history.length - 1) { history = history.slice(0, historyIndex + 1); } history.push(editor.innerHTML); historyIndex = history.length - 1; // Update UI undoBtn.disabled = historyIndex <= 0; redoBtn.disabled = historyIndex >= history.length - 1; // Update stats updateStats(); } // Debounced save state let saveTimeout; function debouncedSaveState() { clearTimeout(saveTimeout); saveTimeout = setTimeout(() => { saveState(); showNotification('Changes saved'); lastChangeTime = Date.now(); }, 500); } // Show notification function showNotification(message) { historyNotification.textContent = message; historyNotification.classList.add('show'); setTimeout(() => { historyNotification.classList.remove('show'); }, 1500); } // Undo function function undo() { if (historyIndex > 0) { historyIndex--; editor.innerHTML = history[historyIndex]; undoBtn.disabled = historyIndex <= 0; redoBtn.disabled = false; showNotification('Undo'); updateStats(); } } // Redo function function redo() { if (historyIndex < history.length - 1) { historyIndex++; editor.innerHTML = history[historyIndex]; redoBtn.disabled = historyIndex >= history.length - 1; undoBtn.disabled = false; showNotification('Redo'); updateStats(); } } // Update cursor and typewriter line position function updateCursorPosition() { const selection = window.getSelection(); if (selection.rangeCount === 0) return; const range = selection.getRangeAt(0); if (!editor.contains(range.commonAncestorContainer)) return; const rect = range.getBoundingClientRect(); const editorRect = editor.getBoundingClientRect(); if (rect.top === 0 && rect.left === 0) return; // Position the cursor typewriterCursor.style.height = `${rect.height}px`; typewriterCursor.style.left = `${rect.left - editorRect.left}px`; typewriterCursor.style.top = `${rect.top - editorRect.top}px`; // Position the typewriter line typewriterLine.style.top = `${rect.top - editorRect.top + (rect.height/2)}px`; } // Format text (basic implementation) function formatText(command, value = null) { document.execCommand(command, false, value); editor.focus(); debouncedSaveState(); } // Toggle focus mode function toggleFocusMode() { container.classList.toggle('focus-mode'); focusBtn.classList.toggle('active'); if (container.classList.contains('focus-mode')) { showNotification('Focus mode enabled'); } else { showNotification('Focus mode disabled'); } } // Format as heading function formatHeading() { const selection = window.getSelection(); const range = selection.getRangeAt(0); // Find the paragraph containing the selection let node = range.startContainer; while (node && node.nodeName !== 'P' && node !== editor) { node = node.parentNode; } if (node && node.nodeName === 'P') { // Check if it's already a heading if (node.style.fontSize === '22px' && node.style.fontWeight === 'bold') { // If it is, reset to normal node.style.fontSize = ''; node.style.fontWeight = ''; node.style.marginBottom = ''; } else { // Make it a heading node.style.fontSize = '22px'; node.style.fontWeight = 'bold'; node.style.marginBottom = '16px'; } debouncedSaveState(); } } // Initialize time display function updateTime() { const now = new Date(); const hours = now.getHours(); const minutes = now.getMinutes(); const ampm = hours >= 12 ? 'PM' : 'AM'; const formattedHours = hours % 12 || 12; const formattedMinutes = minutes < 10 ? '0' + minutes : minutes; timeDisplay.textContent = `${formattedHours}:${formattedMinutes} ${ampm}`; } // Event Listeners editor.addEventListener('input', debouncedSaveState); editor.addEventListener('keydown', (e) => { // Ctrl+Z for undo if (e.ctrlKey && e.key === 'z') { e.preventDefault(); undo(); } // Ctrl+Y for redo if (e.ctrlKey && e.key === 'y') { e.preventDefault(); redo(); } // Ensure cursor is visible setTimeout(updateCursorPosition, 0); }); // Update cursor position on selection change document.addEventListener('selectionchange', () => { if (document.activeElement === editor) { updateCursorPosition(); } }); editor.addEventListener('focus', updateCursorPosition); editor.addEventListener('click', updateCursorPosition); // Button click handlers undoBtn.addEventListener('click', undo); redoBtn.addEventListener('click', redo); focusBtn.addEventListener('click', toggleFocusMode); document.getElementById('bold-btn').addEventListener('click', () => formatText('bold')); document.getElementById('italic-btn').addEventListener('click', () => formatText('italic')); document.getElementById('heading-btn').addEventListener('click', formatHeading); // Initialize stats updateStats(); updateTime(); setInterval(updateTime, 60000); // Update time every minute // Simulate typing effect on load to draw attention to the editor editor.focus(); const range = document.createRange(); const sel = window.getSelection(); // Set cursor at the end of content range.selectNodeContents(editor); range.collapse(false); sel.removeAllRanges(); sel.addRange(range); updateCursorPosition(); // Add highlight animation to show editing capability setTimeout(() => { const lastParagraph = editor.lastElementChild; lastParagraph.classList.add('highlight'); }, 1000); </script> </body> </html>