biosphere-clone-hub / index.html
MidouEmail's picture
Promote version 263df98 to main
6d65498 verified
raw
history blame
25.4 kB
<!DOCTYPE html>
<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>
@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 !important;
border: none !important;
outline: none !important;
}
.editable:hover {
background: transparent !important;
}
#editableName {
background: transparent !important;
border: none !important;
outline: none !important;
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">
<!-- Builder Controls -->
<div class="fixed top-4 right-4 z-50">
<button id="saveProfile" class="bg-indigo-600 hover:bg-indigo-700 px-4 py-2 rounded-full text-sm font-medium transition">
Save Profile
</button>
</div>
<!-- Hero Section -->
<div id="vanta-bg" class="min-h-screen flex items-center justify-center px-4">
<div class="glass-card p-6 max-w-md w-full mx-auto text-center" style="aspect-ratio: 9/19; max-height: 95vh;">
<div class="flex flex-col justify-center h-full">
<!-- Profile Image Upload -->
<div class="image-upload-container w-56 h-56 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">
<div class="image-upload-overlay">
<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-3/5 mx-auto">
<a id="contactButton" href="tel:" class="px-4 py-2 border border-indigo-500 rounded-full hover:bg-indigo-900/30 transition text-xs w-full block editable" contenteditable="true" data-placeholder="Tap to Add Phone Number"></a>
</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>
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] || '#';
}
// Update contact button href when editing
document.getElementById('contactButton').addEventListener('input', function() {
const phoneNumber = this.textContent.replace(/[^\d+]/g, '');
this.href = `tel:${phoneNumber}`;
});
// 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] || '#';
}
// 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: document.getElementById('contactButton').textContent,
image: document.getElementById('profileImage').src
};
localStorage.setItem('profileData', JSON.stringify(profileData));
alert('Profile saved successfully!');
});
// 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') {
document.getElementById('contactButton').textContent = profileData.phone;
document.getElementById('contactButton').href = `tel:${profileData.phone.replace(/[^\d+]/g, '')}`;
}
if (profileData.image && profileData.image !== 'http://static.photos/technology/320x240/42') {
document.getElementById('profileImage').src = profileData.image;
}
}
</script>
</body>
</html>