Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Profile Builder - WYSIWYG Link in Bio</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <style> | |
| #profileCard::-webkit-scrollbar { | |
| display: none; | |
| } | |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); | |
| body { | |
| font-family: 'Inter', sans-serif; | |
| } | |
| .glass-card { | |
| background: rgba(255, 255, 255, 0.08); | |
| backdrop-filter: blur(10px); | |
| -webkit-backdrop-filter: blur(10px); | |
| border-radius: 12px; | |
| border: 1px solid rgba(255, 255, 255, 0.18); | |
| } | |
| .gradient-text { | |
| background: linear-gradient(90deg, #3b82f6, #8b5cf6); | |
| -webkit-background-clip: text; | |
| background-clip: text; | |
| color: transparent; | |
| } | |
| .social-icon-placeholder { | |
| width: 12px; | |
| height: 12px; | |
| border-radius: 50%; | |
| background: #3b82f6; | |
| margin: 0 2px; | |
| display: inline-block; | |
| } | |
| .editable { | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| min-height: 1.2em; | |
| } | |
| .editable:focus { | |
| outline: none; | |
| background: transparent; | |
| border-radius: 4px; | |
| } | |
| .editable:hover { | |
| background: transparent; | |
| border-radius: 4px; | |
| } | |
| .editable:empty:before { | |
| content: attr(data-placeholder); | |
| color: rgba(255, 255, 255, 0.6); | |
| } | |
| .editable:focus { | |
| background: transparent ; | |
| border: none ; | |
| outline: none ; | |
| } | |
| .editable:hover { | |
| background: transparent ; | |
| } | |
| #editableName { | |
| background: transparent ; | |
| border: none ; | |
| outline: none ; | |
| z-index: 20; | |
| position: relative; | |
| } | |
| .social-dropdown { | |
| display: none; | |
| position: absolute; | |
| background: rgba(0, 0, 0, 0.95); | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| border-radius: 8px; | |
| padding: 8px; | |
| z-index: 1000; | |
| min-width: 200px; | |
| max-height: 200px; | |
| overflow-y: auto; | |
| box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); | |
| bottom: 100%; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| margin-bottom: 8px; | |
| } | |
| .social-option { | |
| display: flex; | |
| align-items: center; | |
| padding: 8px 12px; | |
| margin: 2px 0; | |
| border-radius: 6px; | |
| transition: all 0.2s ease; | |
| cursor: pointer; | |
| color: white; | |
| text-decoration: none; | |
| } | |
| .social-option:hover { | |
| background: rgba(59, 130, 246, 0.3); | |
| } | |
| .social-option i { | |
| margin-right: 10px; | |
| width: 20px; | |
| height: 20px; | |
| } | |
| .image-upload-container { | |
| position: relative; | |
| cursor: pointer; | |
| } | |
| .image-upload-overlay { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: rgba(0, 0, 0, 0.7); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| opacity: 0; | |
| transition: opacity 0.3s ease; | |
| border-radius: 50%; | |
| } | |
| .image-upload-container:hover .image-upload-overlay { | |
| opacity: 1; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-900 text-white min-h-screen"> | |
| <!-- Profile Section --> | |
| <div id="vanta-bg" class="min-h-screen w-full flex items-center justify-center px-4 relative"> | |
| <div class="glass-card p-6 w-full max-w-md mx-auto text-center relative" style="aspect-ratio: 9/19; max-height: 95vh; overflow-y: auto; -ms-overflow-style: none; scrollbar-width: none;" id="profileCard"> | |
| <!-- Navigation Arrows --> | |
| <button id="prevCard" class="absolute left-2 top-1/2 transform -translate-y-1/2 bg-gray-800/50 hover:bg-gray-700/50 rounded-full p-2 z-50"> | |
| <i data-feather="chevron-left" class="w-5 h-5"></i> | |
| </button> | |
| <button id="nextCard" class="absolute right-2 top-1/2 transform -translate-y-1/2 bg-gray-800/50 hover:bg-gray-700/50 rounded-full p-2 z-50"> | |
| <i data-feather="chevron-right" class="w-5 h-5"></i> | |
| </button> | |
| <!-- Control Buttons --> | |
| <div class="absolute top-2 left-2 z-50"> | |
| <a href="card-selector.html" class="bg-indigo-600 hover:bg-indigo-700 px-3 py-1 rounded-full text-xs font-medium transition flex items-center"> | |
| <i data-feather="plus" class="w-3 h-3 mr-1"></i> Add Card | |
| </a> | |
| </div> | |
| <div class="absolute top-2 right-2 z-50 space-y-1"> | |
| <button id="saveProfile" class="bg-indigo-600 hover:bg-indigo-700 px-3 py-1 rounded-full text-xs font-medium transition flex items-center"> | |
| <i data-feather="save" class="w-3 h-3 mr-1"></i> Save | |
| </button> | |
| <button id="editSettingsBtn" class="bg-gray-800 hover:bg-gray-700 px-3 py-1 rounded-full text-xs font-medium transition flex items-center"> | |
| <i data-feather="edit" class="w-3 h-3 mr-1"></i> Edit BG | |
| </button> | |
| <div id="settingsDropdown" class="hidden absolute right-0 mt-1 w-24 bg-gray-800 rounded-md shadow-lg z-50"> | |
| <button id="profileColorBtn" class="block w-full text-left px-3 py-2 text-xs hover:bg-gray-700"> | |
| <i data-feather="droplet" class="w-3 h-3 mr-1 inline"></i> Profile | |
| </button> | |
| <button id="bgAnimationBtn" class="block w-full text-left px-3 py-2 text-xs hover:bg-gray-700"> | |
| <i data-feather="activity" class="w-3 h-3 mr-1 inline"></i> Animation | |
| </button> | |
| </div> | |
| </div> | |
| <div class="flex flex-col justify-center h-full"> | |
| <!-- Profile Image Upload --> | |
| <div class="image-upload-container w-32 h-32 mx-auto mb-6 rounded-full overflow-hidden border-4 border-indigo-500 border-dashed"> | |
| <img id="profileImage" src="http://static.photos/technology/320x240/42" alt="Profile" class="w-full h-full object-cover rounded-full"> | |
| <div class="image-upload-overlay rounded-full"> | |
| <span class="text-white text-sm font-medium">Click to Upload</span> | |
| </div> | |
| <input type="file" id="imageUpload" accept="image/*" class="hidden"> | |
| </div> | |
| <!-- Editable Name --> | |
| <div class="relative mb-3"> | |
| <h1 id="editableName" class="text-3xl font-bold text-white text-center min-h-[1.5em] px-2 py-1 gradient-text" contenteditable="true" data-placeholder="Tap to Add your Name">Tap to Add your Name</h1> | |
| </div> | |
| <!-- Contact Button --> | |
| <div class="relative mb-4 w-full sm:w-4/5 md:w-3/5 mx-auto"> | |
| <div id="contactButton" class="px-4 py-2 border border-indigo-500 rounded-full hover:bg-indigo-900/30 transition text-xs w-full block flex items-center justify-center"> | |
| <span id="phoneText">📞 Call Me: Add your number</span> | |
| <input type="tel" id="phoneInput" class="hidden bg-transparent border-none outline-none text-center w-full" placeholder="Enter phone number"> | |
| </div> | |
| </div> | |
| <!-- Editable Title --> | |
| <p id="editableTitle" class="text-xl text-gray-300 mb-4 editable" contenteditable="true" data-placeholder="Tap to Add your Title"></p> | |
| <!-- Editable Description --> | |
| <p id="editableDescription" class="text-base text-gray-400 mb-8 px-2 editable" contenteditable="true" data-placeholder="Tap to Add a Description about Yourself"></p> | |
| <!-- Social Media Section --> | |
| <div class="mb-8"> | |
| <div class="flex justify-center flex-wrap gap-3 mb-4" id="socialIconsContainer"> | |
| <!-- Social media icons will be added here --> | |
| <div class="flex items-center justify-center space-x-1 mb-2 w-full"> | |
| <span class="social-icon-placeholder"></span> | |
| <span class="social-icon-placeholder"></span> | |
| <span class="social-icon-placeholder"></span> | |
| <span class="text-xs text-gray-400">Click + to add social media</span> | |
| </div> | |
| <!-- Plus button for adding social media --> | |
| <div class="relative"> | |
| <button id="addSocialButton" class="w-12 h-12 rounded-full bg-indigo-600 hover:bg-indigo-700 flex items-center justify-center transition"> | |
| <i data-feather="plus" class="w-5 h-5"></i> | |
| </button> | |
| <div id="socialDropdown" class="social-dropdown"> | |
| <a class="social-option" data-platform="instagram"> | |
| <i data-feather="instagram"></i> Instagram | |
| </a> | |
| <a class="social-option" data-platform="facebook"> | |
| <i data-feather="facebook"></i> Facebook | |
| </a> | |
| <a class="social-option" data-platform="twitter"> | |
| <i data-feather="twitter"></i> Twitter | |
| </a> | |
| <a class="social-option" data-platform="tiktok"> | |
| <i data-feather="video"></i> TikTok | |
| </a> | |
| <a class="social-option" data-platform="youtube"> | |
| <i data-feather="youtube"></i> YouTube | |
| </a> | |
| <a class="social-option" data-platform="linkedin"> | |
| <i data-feather="linkedin"></i> LinkedIn | |
| </a> | |
| <a class="social-option" data-platform="snapchat"> | |
| <i data-feather="camera"></i> Snapchat | |
| </a> | |
| <a class="social-option" data-platform="pinterest"> | |
| <i data-feather="image"></i> Pinterest | |
| </a> | |
| <a class="social-option" data-platform="reddit"> | |
| <i data-feather="message-circle"></i> Reddit | |
| </a> | |
| <a class="social-option" data-platform="github"> | |
| <i data-feather="github"></i> GitHub | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Action Buttons --> | |
| <div class="flex justify-center space-x-3 mt-auto"> | |
| <button class="px-4 py-2 bg-indigo-600 rounded-full hover:bg-indigo-700 transition text-sm">Projects</button> | |
| <button class="px-4 py-2 border border-indigo-500 rounded-full hover:bg-indigo-900/30 transition text-sm">About Me</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Scripts --> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.waves.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.fog.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.cells.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.net.min.js"></script> | |
| <script> | |
| VANTA.GLOBE({ | |
| el: "#vanta-bg", | |
| mouseControls: true, | |
| touchControls: true, | |
| gyroControls: false, | |
| minHeight: 200.00, | |
| minWidth: 200.00, | |
| scale: 1.00, | |
| scaleMobile: 1.00, | |
| color: 0x3b82f6, | |
| backgroundColor: 0x111827, | |
| size: 0.8 | |
| }); | |
| feather.replace(); | |
| // Smooth scrolling for anchor links | |
| document.querySelectorAll('a[href^="#"]').forEach(anchor => { | |
| anchor.addEventListener('click', function (e) { | |
| e.preventDefault(); | |
| document.querySelector(this.getAttribute('href')).scrollIntoView({ | |
| behavior: 'smooth' | |
| }); | |
| }); | |
| }); | |
| // Image upload functionality | |
| document.getElementById('imageUpload').addEventListener('change', function(e) { | |
| const file = e.target.files[0]; | |
| if (file) { | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| document.getElementById('profileImage').src = e.target.result; | |
| } | |
| reader.readAsDataURL(file); | |
| } | |
| }); | |
| // Make image container clickable | |
| document.querySelector('.image-upload-container').addEventListener('click', function() { | |
| document.getElementById('imageUpload').click(); | |
| }); | |
| // Social media dropdown functionality | |
| document.getElementById('addSocialButton').addEventListener('click', function(e) { | |
| e.stopPropagation(); | |
| const dropdown = document.getElementById('socialDropdown'); | |
| dropdown.style.display = dropdown.style.display === 'block' ? 'none' : 'block'; | |
| }); | |
| // Close dropdown when clicking outside | |
| document.addEventListener('click', function(e) { | |
| if (!e.target.closest('#socialDropdown') && !e.target.closest('#addSocialButton')) { | |
| document.getElementById('socialDropdown').style.display = 'none'; | |
| } | |
| }); | |
| // Initialize placeholder functionality for all editable elements except heading | |
| document.querySelectorAll('.editable').forEach(editable => { | |
| // Clear placeholder text when focusing | |
| editable.addEventListener('focus', function() { | |
| if (this.textContent === this.getAttribute('data-placeholder')) { | |
| this.textContent = ''; | |
| } | |
| this.style.background = 'transparent'; | |
| }); | |
| // Restore placeholder if empty when blurring | |
| editable.addEventListener('blur', function() { | |
| if (this.textContent.trim() === '') { | |
| this.textContent = this.getAttribute('data-placeholder'); | |
| } | |
| this.style.background = 'transparent'; | |
| }); | |
| }); | |
| // Special handling for heading element | |
| const editableName = document.getElementById('editableName'); | |
| editableName.addEventListener('focus', function() { | |
| if (this.textContent === this.getAttribute('data-placeholder')) { | |
| this.textContent = ''; | |
| } | |
| this.style.background = 'transparent'; | |
| this.style.border = 'none'; | |
| this.style.outline = 'none'; | |
| }); | |
| editableName.addEventListener('blur', function() { | |
| if (this.textContent.trim() === '') { | |
| this.textContent = this.getAttribute('data-placeholder'); | |
| } | |
| this.style.background = 'transparent'; | |
| this.style.border = 'none'; | |
| this.style.outline = 'none'; | |
| }); | |
| // Force clear any existing background/border styles | |
| editableName.style.background = 'transparent'; | |
| editableName.style.border = 'none'; | |
| editableName.style.outline = 'none'; | |
| function addSocialIcon(platform, handle) { | |
| const container = document.getElementById('socialIconsContainer'); | |
| // Create social icon element | |
| const iconWrapper = document.createElement('div'); | |
| iconWrapper.className = 'relative group'; | |
| const icon = document.createElement('a'); | |
| icon.href = getSocialUrl(platform, handle); | |
| icon.target = '_blank'; | |
| icon.className = 'w-12 h-12 rounded-full bg-gray-800 hover:bg-indigo-600 flex items-center justify-center transition transform hover:scale-110'; | |
| icon.innerHTML = `<i data-feather="${getFeatherIconName(platform)}" class="w-5 h-5"></i>`; | |
| // Add remove button | |
| const removeBtn = document.createElement('button'); | |
| removeBtn.className = 'absolute -top-1 -right-1 w-4 h-4 bg-red-500 rounded-full text-white text-xs flex items-center justify-center opacity-0 group-hover:opacity-100 transition'; | |
| removeBtn.innerHTML = '×'; | |
| removeBtn.onclick = function(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| container.removeChild(iconWrapper); | |
| }; | |
| iconWrapper.appendChild(icon); | |
| iconWrapper.appendChild(removeBtn); | |
| // Insert before the plus button | |
| const addButton = document.getElementById('addSocialButton').parentNode; | |
| container.insertBefore(iconWrapper, addButton); | |
| feather.replace(); | |
| } | |
| function getFeatherIconName(platform) { | |
| const iconMap = { | |
| instagram: 'instagram', | |
| facebook: 'facebook', | |
| twitter: 'twitter', | |
| tiktok: 'video', | |
| youtube: 'youtube', | |
| linkedin: 'linkedin', | |
| snapchat: 'camera', | |
| pinterest: 'image', | |
| reddit: 'message-circle', | |
| github: 'github' | |
| }; | |
| return iconMap[platform] || 'link'; | |
| } | |
| function getSocialUrl(platform, handle) { | |
| const urls = { | |
| instagram: `https://instagram.com/${handle}`, | |
| facebook: `https://facebook.com/${handle}`, | |
| twitter: `https://twitter.com/${handle}`, | |
| tiktok: `https://tiktok.com/@${handle}`, | |
| youtube: `https://youtube.com/@${handle}`, | |
| linkedin: `https://linkedin.com/in/${handle}`, | |
| snapchat: `https://snapchat.com/add/${handle}`, | |
| pinterest: `https://pinterest.com/${handle}`, | |
| reddit: `https://reddit.com/user/${handle}`, | |
| github: `https://github.com/${handle}` | |
| }; | |
| return urls[platform] || '#'; | |
| } | |
| // Phone number input handling | |
| const phoneInput = document.getElementById('phoneInput'); | |
| const phoneText = document.getElementById('phoneText'); | |
| const contactButton = document.getElementById('contactButton'); | |
| contactButton.addEventListener('click', function(e) { | |
| if (e.target !== phoneInput) { | |
| phoneText.classList.add('hidden'); | |
| phoneInput.classList.remove('hidden'); | |
| phoneInput.focus(); | |
| if (phoneInput.value === '') { | |
| phoneInput.value = phoneText.textContent.replace('📞 Call Me: ', ''); | |
| } | |
| } | |
| }); | |
| phoneInput.addEventListener('blur', function() { | |
| const phoneNumber = this.value.trim(); | |
| if (phoneNumber) { | |
| phoneText.textContent = `📞 Call Me: ${phoneNumber}`; | |
| contactButton.href = `tel:${phoneNumber}`; | |
| } else { | |
| phoneText.textContent = '📞 Call Me: Add your number'; | |
| contactButton.removeAttribute('href'); | |
| } | |
| phoneText.classList.remove('hidden'); | |
| phoneInput.classList.add('hidden'); | |
| }); | |
| phoneInput.addEventListener('input', function() { | |
| this.value = this.value.replace(/[^\d+]/g, ''); | |
| }); | |
| // Social media platform selection | |
| document.querySelectorAll('.social-option').forEach(option => { | |
| option.addEventListener('click', function(e) { | |
| e.preventDefault(); | |
| const platform = this.getAttribute('data-platform'); | |
| // Create modal for handle input | |
| const modal = document.createElement('div'); | |
| modal.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50'; | |
| modal.innerHTML = ` | |
| <div class="bg-gray-800 p-6 rounded-lg max-w-sm w-full mx-4"> | |
| <h3 class="text-lg font-medium mb-4">Add your ${platform} handle</h3> | |
| <input type="text" id="handleInput" class="w-full bg-gray-700 border border-gray-600 rounded px-3 py-2 mb-4 text-white" placeholder="Your handle"> | |
| <div class="flex justify-end space-x-2"> | |
| <button id="cancelHandle" class="px-4 py-2 text-gray-300 hover:text-white">Cancel</button> | |
| <button id="saveHandle" class="px-4 py-2 bg-indigo-600 rounded hover:bg-indigo-700">Add</button> | |
| </div> | |
| </div> | |
| `; | |
| document.body.appendChild(modal); | |
| const handleInput = document.getElementById('handleInput'); | |
| const cancelBtn = document.getElementById('cancelHandle'); | |
| const saveBtn = document.getElementById('saveHandle'); | |
| handleInput.focus(); | |
| cancelBtn.addEventListener('click', function() { | |
| document.body.removeChild(modal); | |
| }); | |
| saveBtn.addEventListener('click', function() { | |
| const handle = handleInput.value.trim(); | |
| if (handle) { | |
| addSocialIcon(platform, handle); | |
| // Remove placeholder dots | |
| const placeholderDots = document.querySelectorAll('.social-icon-placeholder'); | |
| if (placeholderDots.length > 0) { | |
| const placeholderContainer = placeholderDots[0].parentNode; | |
| if (placeholderContainer) { | |
| placeholderContainer.remove(); | |
| } | |
| } | |
| } | |
| document.body.removeChild(modal); | |
| document.getElementById('socialDropdown').style.display = 'none'; | |
| }); | |
| // Close modal when clicking outside | |
| modal.addEventListener('click', function(e) { | |
| if (e.target === modal) { | |
| document.body.removeChild(modal); | |
| } | |
| }); | |
| // Handle Enter key | |
| handleInput.addEventListener('keypress', function(e) { | |
| if (e.key === 'Enter') { | |
| saveBtn.click(); | |
| } | |
| }); | |
| }); | |
| }); | |
| function addSocialIcon(platform, handle) { | |
| const container = document.getElementById('socialIconsContainer'); | |
| // Create social icon element | |
| const iconWrapper = document.createElement('div'); | |
| iconWrapper.className = 'relative group'; | |
| const icon = document.createElement('a'); | |
| icon.href = getSocialUrl(platform, handle); | |
| icon.target = '_blank'; | |
| icon.className = 'w-12 h-12 rounded-full bg-gray-800 hover:bg-indigo-600 flex items-center justify-center transition transform hover:scale-110'; | |
| icon.innerHTML = `<i data-feather="${getFeatherIconName(platform)}" class="w-5 h-5"></i>`; | |
| // Add remove button | |
| const removeBtn = document.createElement('button'); | |
| removeBtn.className = 'absolute -top-1 -right-1 w-4 h-4 bg-red-500 rounded-full text-white text-xs flex items-center justify-center opacity-0 group-hover:opacity-100 transition'; | |
| removeBtn.innerHTML = '×'; | |
| removeBtn.onclick = function(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| container.removeChild(iconWrapper); | |
| }; | |
| iconWrapper.appendChild(icon); | |
| iconWrapper.appendChild(removeBtn); | |
| // Insert before the plus button | |
| const addButton = document.getElementById('addSocialButton').parentNode; | |
| container.insertBefore(iconWrapper, addButton); | |
| feather.replace(); | |
| } | |
| function getFeatherIconName(platform) { | |
| const iconMap = { | |
| instagram: 'instagram', | |
| facebook: 'facebook', | |
| twitter: 'twitter', | |
| tiktok: 'video', | |
| youtube: 'youtube', | |
| linkedin: 'linkedin', | |
| snapchat: 'camera', | |
| pinterest: 'image', | |
| reddit: 'message-circle', | |
| github: 'github' | |
| }; | |
| return iconMap[platform] || 'link'; | |
| } | |
| function getSocialUrl(platform, handle) { | |
| const urls = { | |
| instagram: `https://instagram.com/${handle}`, | |
| facebook: `https://facebook.com/${handle}`, | |
| twitter: `https://twitter.com/${handle}`, | |
| tiktok: `https://tiktok.com/@${handle}`, | |
| youtube: `https://youtube.com/@${handle}`, | |
| linkedin: `https://linkedin.com/in/${handle}`, | |
| snapchat: `https://snapchat.com/add/${handle}`, | |
| pinterest: `https://pinterest.com/${handle}`, | |
| reddit: `https://reddit.com/user/${handle}`, | |
| github: `https://github.com/${handle}` | |
| }; | |
| return urls[platform] || '#'; | |
| } | |
| // Settings dropdown toggle | |
| document.getElementById('editSettingsBtn').addEventListener('click', function(e) { | |
| e.stopPropagation(); | |
| document.getElementById('settingsDropdown').classList.toggle('hidden'); | |
| }); | |
| // Close dropdown when clicking outside | |
| document.addEventListener('click', function(e) { | |
| if (!e.target.closest('#settingsDropdown') && !e.target.closest('#editSettingsBtn')) { | |
| document.getElementById('settingsDropdown').classList.add('hidden'); | |
| } | |
| }); | |
| // Background color options | |
| const bgColors = [ | |
| 'rgba(30, 41, 59, 0.5)', | |
| 'rgba(124, 58, 237, 0.5)', | |
| 'rgba(16, 185, 129, 0.5)', | |
| 'rgba(245, 158, 11, 0.5)', | |
| 'rgba(139, 92, 246, 0.5)' | |
| ]; | |
| let currentBgColor = 0; | |
| document.getElementById('profileColorBtn').addEventListener('click', function() { | |
| currentBgColor = (currentBgColor + 1) % bgColors.length; | |
| document.querySelector('.glass-card').style.backgroundColor = bgColors[currentBgColor]; | |
| }); | |
| // Animation options | |
| const animations = ['GLOBE', 'WAVES', 'FOG', 'CELLS', 'NET']; | |
| let currentAnimation = 0; | |
| let vantaEffect = null; | |
| document.getElementById('bgAnimationBtn').addEventListener('click', function() { | |
| currentAnimation = (currentAnimation + 1) % animations.length; | |
| if (vantaEffect) vantaEffect.destroy(); | |
| const animationType = animations[currentAnimation]; | |
| const config = { | |
| el: "#vanta-bg", | |
| mouseControls: true, | |
| touchControls: true, | |
| gyroControls: false, | |
| minHeight: 200.00, | |
| minWidth: 200.00, | |
| scale: 1.00, | |
| scaleMobile: 1.00, | |
| color: 0x3b82f6, | |
| backgroundColor: 0x111827 | |
| }; | |
| if (animationType === 'GLOBE') { | |
| vantaEffect = VANTA.GLOBE(config); | |
| } else if (animationType === 'WAVES') { | |
| vantaEffect = VANTA.WAVES({ | |
| ...config, | |
| color: 0x8b5cf6 | |
| }); | |
| } else if (animationType === 'FOG') { | |
| vantaEffect = VANTA.FOG({ | |
| ...config, | |
| highlightColor: 0x3b82f6, | |
| midtoneColor: 0x8b5cf6, | |
| baseColor: 0x0 | |
| }); | |
| } else if (animationType === 'CELLS') { | |
| vantaEffect = VANTA.CELLS({ | |
| ...config, | |
| color1: 0x3b82f6, | |
| color2: 0x8b5cf6, | |
| size: 1.20 | |
| }); | |
| } else if (animationType === 'NET') { | |
| vantaEffect = VANTA.NET({ | |
| ...config, | |
| points: 12.00, | |
| maxDistance: 22.00 | |
| }); | |
| } | |
| }); | |
| // Save profile functionality | |
| document.getElementById('saveProfile').addEventListener('click', function() { | |
| const profileData = { | |
| name: document.getElementById('editableName').textContent, | |
| title: document.getElementById('editableTitle').textContent, | |
| description: document.getElementById('editableDescription').textContent, | |
| phone: phoneInput.value || document.getElementById('contactButton').textContent, | |
| image: document.getElementById('profileImage').src, | |
| bgColor: currentBgColor, | |
| bgAnimation: currentAnimation | |
| }; | |
| localStorage.setItem('profileData', JSON.stringify(profileData)); | |
| // Show save confirmation | |
| const saveBtn = document.getElementById('saveProfile'); | |
| const originalText = saveBtn.innerHTML; | |
| saveBtn.innerHTML = '<i data-feather="check" class="w-4 h-4 mr-1"></i> Saved!'; | |
| setTimeout(() => { | |
| saveBtn.innerHTML = originalText; | |
| feather.replace(); | |
| }, 2000); | |
| feather.replace(); | |
| }); | |
| // Load saved profile | |
| const savedProfile = localStorage.getItem('profileData'); | |
| if (savedProfile) { | |
| const profileData = JSON.parse(savedProfile); | |
| // Set content only if it's not empty or placeholder | |
| if (profileData.name && profileData.name !== 'Tap to Add your Name') { | |
| document.getElementById('editableName').textContent = profileData.name; | |
| } | |
| if (profileData.title && profileData.title !== 'Tap to Add your Title') { | |
| document.getElementById('editableTitle').textContent = profileData.title; | |
| } | |
| if (profileData.description && profileData.description !== 'Tap to Add a Description about Yourself') { | |
| document.getElementById('editableDescription').textContent = profileData.description; | |
| } | |
| if (profileData.phone && profileData.phone !== 'Tap to Add Phone Number') { | |
| phoneInput.value = profileData.phone.replace(/[^\d+]/g, ''); | |
| phoneText.classList.remove('hidden'); | |
| document.getElementById('contactButton').href = `tel:${profileData.phone.replace(/[^\d+]/g, '')}`; | |
| phoneText.textContent = `📞 Call Me: ${profileData.phone.replace(/[^\d+]/g, '')}`; | |
| } | |
| if (profileData.image && profileData.image !== 'http://static.photos/technology/320x240/42') { | |
| document.getElementById('profileImage').src = profileData.image; | |
| } | |
| if (profileData.bgColor !== undefined) { | |
| currentBgColor = profileData.bgColor; | |
| document.querySelector('.glass-card').style.backgroundColor = bgColors[currentBgColor]; | |
| } | |
| // Load phone number | |
| if (profileData.phone && profileData.phone !== 'Add your number') { | |
| phoneInput.value = profileData.phone.replace(/[^\d+]/g, ''); | |
| phoneText.textContent = `📞 Call Me: ${profileData.phone.replace(/[^\d+]/g, '')}`; | |
| contactButton.href = `tel:${profileData.phone.replace(/[^\d+]/g, '')}`; | |
| } | |
| if (profileData.bgAnimation !== undefined) { | |
| currentAnimation = profileData.bgAnimation; | |
| document.getElementById('bgAnimationBtn').click(); | |
| } | |
| } | |
| </script> | |
| <!-- Card Selection Modal --> | |
| <div id="cardModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
| <div class="bg-gray-800 rounded-lg p-6 max-w-2xl w-full max-h-[80vh] overflow-y-auto"> | |
| <h3 class="text-xl font-bold mb-4">Select Card Type</h3> | |
| <div class="grid grid-cols-2 gap-4"> | |
| <div class="card-option p-4 border border-gray-700 rounded-lg cursor-pointer hover:bg-indigo-900/30 transition" data-card="training"> | |
| <i data-feather="award" class="w-6 h-6 mb-2"></i> | |
| <h4 class="font-medium">Training Card</h4> | |
| <p class="text-sm text-gray-400">Commands your dog understands</p> | |
| </div> | |
| <div class="card-option p-4 border border-gray-700 rounded-lg cursor-pointer hover:bg-indigo-900/30 transition" data-card="favorites"> | |
| <i data-feather="heart" class="w-6 h-6 mb-2"></i> | |
| <h4 class="font-medium">Favorite Things</h4> | |
| <p class="text-sm text-gray-400">Toys, snacks & routines</p> | |
| </div> | |
| <div class="card-option p-4 border border-gray-700 rounded-lg cursor-pointer hover:bg-indigo-900/30 transition" data-card="gallery"> | |
| <i data-feather="image" class="w-6 h-6 mb-2"></i> | |
| <h4 class="font-medium">Photo Gallery</h4> | |
| <p class="text-sm text-gray-400">Pictures for identification</p> | |
| </div> | |
| <div class="card-option p-4 border border-gray-700 rounded-lg cursor-pointer hover:bg-indigo-900/30 transition" data-card="video"> | |
| <i data-feather="video" class="w-6 h-6 mb-2"></i> | |
| <h4 class="font-medium">Video Card</h4> | |
| <p class="text-sm text-gray-400">Embed video showing behavior</p> | |
| </div> | |
| <div class="card-option p-4 border border-gray-700 rounded-lg cursor-pointer hover:bg-indigo-900/30 transition" data-card="lost"> | |
| <i data-feather="alert-circle" class="w-6 h-6 mb-2"></i> | |
| <h4 class="font-medium">Lost Poster</h4> | |
| <p class="text-sm text-gray-400">Auto-generated missing dog flyer</p> | |
| </div> | |
| <div class="card-option p-4 border border-gray-700 rounded-lg cursor-pointer hover:bg-indigo-900/30 transition" data-card="id"> | |
| <i data-feather="credit-card" class="w-6 h-6 mb-2"></i> | |
| <h4 class="font-medium">Dog ID Card</h4> | |
| <p class="text-sm text-gray-400">Basic info & QR code</p> | |
| </div> | |
| <div class="card-option p-4 border border-gray-700 rounded-lg cursor-pointer hover:bg-indigo-900/30 transition" data-card="location"> | |
| <i data-feather="home" class="w-6 h-6 mb-2"></i> | |
| <h4 class="font-medium">Home Location</h4> | |
| <p class="text-sm text-gray-400">Safe return address</p> | |
| </div> | |
| <div class="card-option p-4 border border-gray-700 rounded-lg cursor-pointer hover:bg-indigo-900/30 transition" data-card="moments"> | |
| <i data-feather="star" class="w-6 h-6 mb-2"></i> | |
| <h4 class="font-medium">Favorite Moments</h4> | |
| <p class="text-sm text-gray-400">Fun pictures & gifs</p> | |
| </div> | |
| <div class="card-option p-4 border border-gray-700 rounded-lg cursor-pointer hover:bg-indigo-900/30 transition" data-card="reward"> | |
| <i data-feather="gift" class="w-6 h-6 mb-2"></i> | |
| <h4 class="font-medium">Reward Card</h4> | |
| <p class="text-sm text-gray-400">Optional reward info</p> | |
| </div> | |
| </div> | |
| <div class="mt-4 flex justify-end"> | |
| <button id="closeCardModal" class="px-4 py-2 bg-gray-700 rounded hover:bg-gray-600">Cancel</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Card navigation functionality | |
| document.getElementById('addCardBtn').addEventListener('click', function() { | |
| window.location.href = 'card-selector.html'; | |
| }); | |
| // Set up page order for navigation | |
| const pages = [ | |
| 'index.html', | |
| 'training-card.html', | |
| 'favorites-card.html', | |
| 'gallery-card.html', | |
| 'video-card.html', | |
| 'lost-card.html', | |
| 'id-card.html', | |
| 'location-card.html', | |
| 'moments-card.html', | |
| 'reward-card.html' | |
| ]; | |
| // Navigation functionality | |
| document.getElementById('nextCard').addEventListener('click', function() { | |
| const currentIndex = pages.indexOf(window.location.pathname.split('/').pop()); | |
| const nextIndex = (currentIndex + 1) % pages.length; | |
| window.location.href = pages[nextIndex]; | |
| }); | |
| document.getElementById('prevCard').addEventListener('click', function() { | |
| const currentIndex = pages.indexOf(window.location.pathname.split('/').pop()); | |
| const prevIndex = (currentIndex - 1 + pages.length) % pages.length; | |
| window.location.href = pages[prevIndex]; | |
| }); | |
| // Swipe detection for mobile | |
| let touchStartX = 0; | |
| let touchEndX = 0; | |
| document.getElementById('profileCard').addEventListener('touchstart', function(e) { | |
| touchStartX = e.changedTouches[0].screenX; | |
| }, false); | |
| document.getElementById('profileCard').addEventListener('touchend', function(e) { | |
| touchEndX = e.changedTouches[0].screenX; | |
| handleSwipe(); | |
| }, false); | |
| function handleSwipe() { | |
| if (touchEndX < touchStartX - 50) { | |
| // Swipe left - next card | |
| document.getElementById('nextCard').click(); | |
| } else if (touchEndX > touchStartX + 50) { | |
| // Swipe right - previous card | |
| document.getElementById('prevCard').click(); | |
| } | |
| } | |
| </script> | |
| </body> | |
| </html> | |