socialhub / script.js
vscode's picture
Upload 4 files
e1fabf0 verified
// ===== GLOBAL VARIABLES AND INITIALIZATION =====
let currentPlatformURL = '';
let currentPlatformName = '';
let currentPlatform = '';
let currentNoteEditPlatform = '';
let timeTrackingInterval = null;
let startTime = null;
let currentImageData = null;
let currentDescription = '';
let currentCaptions = '';
let currentHashtags = '';
// ===== STORAGE MANAGER =====
const StorageManager = {
// Get favorites
getFavorites: () => {
const favorites = localStorage.getItem('socialHub_favorites');
return favorites ? JSON.parse(favorites) : [];
},
// Set favorites
setFavorites: (favorites) => {
localStorage.setItem('socialHub_favorites', JSON.stringify(favorites));
},
// Toggle favorite
toggleFavorite: (platform) => {
const favorites = StorageManager.getFavorites();
const index = favorites.indexOf(platform);
if (index > -1) {
favorites.splice(index, 1);
} else {
favorites.push(platform);
}
StorageManager.setFavorites(favorites);
return favorites;
},
// Get notes
getNotes: () => {
const notes = localStorage.getItem('socialHub_notes');
return notes ? JSON.parse(notes) : {};
},
// Set note
setNote: (platform, note) => {
const notes = StorageManager.getNotes();
if (note.trim()) {
notes[platform] = note;
} else {
delete notes[platform];
}
localStorage.setItem('socialHub_notes', JSON.stringify(notes));
},
// Get analytics
getAnalytics: () => {
const analytics = localStorage.getItem('socialHub_analytics');
return analytics ? JSON.parse(analytics) : {};
},
// Update analytics
updateAnalytics: (platform) => {
const analytics = StorageManager.getAnalytics();
if (!analytics[platform]) {
analytics[platform] = { visits: 0, time: 0, lastVisit: null };
}
analytics[platform].visits++;
analytics[platform].lastVisit = new Date().toISOString();
localStorage.setItem('socialHub_analytics', JSON.stringify(analytics));
},
// Update time spent
updateTimeSpent: (platform, seconds) => {
const analytics = StorageManager.getAnalytics();
if (!analytics[platform]) {
analytics[platform] = { visits: 0, time: 0, lastVisit: null };
}
analytics[platform].time = (analytics[platform].time || 0) + seconds;
localStorage.setItem('socialHub_analytics', JSON.stringify(analytics));
},
// Get recent activity
getRecentActivity: () => {
const recent = localStorage.getItem('socialHub_recent');
return recent ? JSON.parse(recent) : [];
},
// Add to recent
addToRecent: (platform, name, icon) => {
let recent = StorageManager.getRecentActivity();
recent = recent.filter(item => item.platform !== platform);
recent.unshift({ platform, name, icon, timestamp: new Date().toISOString() });
recent = recent.slice(0, 10);
localStorage.setItem('socialHub_recent', JSON.stringify(recent));
},
// Get theme
getTheme: () => {
return localStorage.getItem('socialHub_theme') || 'dark';
},
// Set theme
setTheme: (theme) => {
localStorage.setItem('socialHub_theme', theme);
},
// Get custom platforms
getCustomPlatforms: () => {
const custom = localStorage.getItem('socialHub_custom');
return custom ? JSON.parse(custom) : [];
},
// Add custom platform
addCustomPlatform: (platform) => {
const custom = StorageManager.getCustomPlatforms();
custom.push(platform);
localStorage.setItem('socialHub_custom', JSON.stringify(custom));
},
// Remove custom platform
removeCustomPlatform: (id) => {
let custom = StorageManager.getCustomPlatforms();
custom = custom.filter(p => p.id !== id);
localStorage.setItem('socialHub_custom', JSON.stringify(custom));
}
};
// ===== Particles Background Animation =====
const canvas = document.getElementById('particles');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let particlesArray = [];
const numberOfParticles = 100;
class Particle {
constructor() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.size = Math.random() * 2 + 1;
this.speedX = Math.random() * 1 - 0.5;
this.speedY = Math.random() * 1 - 0.5;
this.opacity = Math.random() * 0.5 + 0.2;
}
update() {
this.x += this.speedX;
this.y += this.speedY;
if (this.x > canvas.width || this.x < 0) {
this.speedX = -this.speedX;
}
if (this.y > canvas.height || this.y < 0) {
this.speedY = -this.speedY;
}
}
draw() {
ctx.fillStyle = `rgba(0, 212, 255, ${this.opacity})`;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill();
}
}
function initParticles() {
particlesArray = [];
for (let i = 0; i < numberOfParticles; i++) {
particlesArray.push(new Particle());
}
}
function animateParticles() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < particlesArray.length; i++) {
particlesArray[i].update();
particlesArray[i].draw();
// Connect particles with lines
for (let j = i; j < particlesArray.length; j++) {
const dx = particlesArray[i].x - particlesArray[j].x;
const dy = particlesArray[i].y - particlesArray[j].y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
ctx.strokeStyle = `rgba(0, 212, 255, ${0.2 * (1 - distance / 100)})`;
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(particlesArray[i].x, particlesArray[i].y);
ctx.lineTo(particlesArray[j].x, particlesArray[j].y);
ctx.stroke();
}
}
}
requestAnimationFrame(animateParticles);
}
// ===== Window Resize Handler =====
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
initParticles();
});
// ===== Search Functionality =====
const searchInput = document.getElementById('searchInput');
const socialCards = document.querySelectorAll('.social-card');
searchInput.addEventListener('input', (e) => {
const searchTerm = e.target.value.toLowerCase();
const activeFilter = document.querySelector('.filter-tab.active')?.getAttribute('data-filter') || 'all';
socialCards.forEach(card => {
const platform = card.getAttribute('data-platform');
const platformName = card.querySelector('.platform-name').textContent.toLowerCase();
const platformDesc = card.querySelector('.platform-desc').textContent.toLowerCase();
const category = card.getAttribute('data-category');
const isFavorite = StorageManager.getFavorites().includes(platform);
const matchesSearch = platform.includes(searchTerm) ||
platformName.includes(searchTerm) ||
platformDesc.includes(searchTerm);
const matchesFilter = activeFilter === 'all' ||
(activeFilter === 'favorites' && isFavorite) ||
(activeFilter === 'recent' && isInRecentActivity(platform)) ||
(activeFilter !== 'favorites' && activeFilter !== 'recent' && category === activeFilter);
if (matchesSearch && matchesFilter) {
card.classList.remove('hidden');
} else {
card.classList.add('hidden');
}
});
});
function isInRecentActivity(platform) {
const recent = StorageManager.getRecentActivity();
return recent.some(item => item.platform === platform);
}
// ===== FILTER FUNCTIONALITY =====
const filterTabs = document.querySelectorAll('.filter-tab');
const recentTimeline = document.getElementById('recentTimeline');
filterTabs.forEach(tab => {
tab.addEventListener('click', () => {
// Update active tab
filterTabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
const filter = tab.getAttribute('data-filter');
// Show/hide recent timeline
if (filter === 'recent') {
updateRecentTimeline();
recentTimeline.style.display = 'block';
} else {
recentTimeline.style.display = 'none';
}
// Filter cards
filterCards(filter);
});
});
function filterCards(filter) {
const favorites = StorageManager.getFavorites();
socialCards.forEach(card => {
const platform = card.getAttribute('data-platform');
const category = card.getAttribute('data-category');
const searchTerm = searchInput.value.toLowerCase();
const platformName = card.querySelector('.platform-name').textContent.toLowerCase();
const platformDesc = card.querySelector('.platform-desc').textContent.toLowerCase();
const matchesSearch = !searchTerm || platform.includes(searchTerm) ||
platformName.includes(searchTerm) || platformDesc.includes(searchTerm);
let show = false;
if (filter === 'all') {
show = true;
} else if (filter === 'favorites') {
show = favorites.includes(platform);
} else if (filter === 'recent') {
show = isInRecentActivity(platform);
} else {
show = category === filter;
}
if (show && matchesSearch) {
card.classList.remove('hidden');
} else {
card.classList.add('hidden');
}
});
}
// ===== FAVORITES FUNCTIONALITY =====
function initializeFavorites() {
const favorites = StorageManager.getFavorites();
socialCards.forEach(card => {
const platform = card.getAttribute('data-platform');
const favBtn = card.querySelector('.favorite-btn');
if (favorites.includes(platform)) {
favBtn.classList.add('active');
favBtn.querySelector('i').classList.remove('far');
favBtn.querySelector('i').classList.add('fas');
}
favBtn.addEventListener('click', (e) => {
e.stopPropagation();
e.preventDefault();
toggleFavorite(platform, favBtn);
});
});
}
function toggleFavorite(platform, btn) {
const favorites = StorageManager.toggleFavorite(platform);
const isFavorite = favorites.includes(platform);
if (isFavorite) {
btn.classList.add('active');
btn.querySelector('i').classList.remove('far');
btn.querySelector('i').classList.add('fas');
showNotification(`Added to favorites!`, 'success');
} else {
btn.classList.remove('active');
btn.querySelector('i').classList.remove('fas');
btn.querySelector('i').classList.add('far');
showNotification(`Removed from favorites`, 'info');
}
updateAnalyticsDisplay();
}
// ===== NOTES FUNCTIONALITY =====
const noteModal = document.getElementById('noteModal');
const noteTextarea = document.getElementById('noteTextarea');
const notePlatformName = document.getElementById('notePlatformName');
const saveNoteBtn = document.getElementById('saveNoteBtn');
const deleteNoteBtn = document.getElementById('deleteNoteBtn');
function initializeNotes() {
const notes = StorageManager.getNotes();
socialCards.forEach(card => {
const platform = card.getAttribute('data-platform');
const noteBtn = card.querySelector('.note-btn');
const noteIndicator = card.querySelector('.note-indicator');
if (notes[platform]) {
noteBtn.classList.add('has-note');
noteIndicator.style.display = 'inline-flex';
}
noteBtn.addEventListener('click', (e) => {
e.stopPropagation();
e.preventDefault();
openNoteModal(platform, card.querySelector('.platform-name').textContent);
});
});
}
function openNoteModal(platform, name) {
currentNoteEditPlatform = platform;
notePlatformName.textContent = name;
const notes = StorageManager.getNotes();
noteTextarea.value = notes[platform] || '';
noteModal.classList.add('active');
document.body.style.overflow = 'hidden';
noteTextarea.focus();
}
saveNoteBtn.addEventListener('click', () => {
const note = noteTextarea.value;
StorageManager.setNote(currentNoteEditPlatform, note);
// Update UI
const card = document.querySelector(`[data-platform="${currentNoteEditPlatform}"]`);
const noteBtn = card.querySelector('.note-btn');
const noteIndicator = card.querySelector('.note-indicator');
if (note.trim()) {
noteBtn.classList.add('has-note');
noteIndicator.style.display = 'inline-flex';
showNotification('Note saved!', 'success');
} else {
noteBtn.classList.remove('has-note');
noteIndicator.style.display = 'none';
showNotification('Note deleted', 'info');
}
noteModal.classList.remove('active');
document.body.style.overflow = '';
});
deleteNoteBtn.addEventListener('click', () => {
noteTextarea.value = '';
saveNoteBtn.click();
});
// ===== Card Click Analytics (Optional) =====
// Platform URLs mapping
const platformURLs = {
facebook: 'https://www.facebook.com',
instagram: 'https://www.instagram.com',
twitter: 'https://www.twitter.com',
linkedin: 'https://www.linkedin.com',
youtube: 'https://www.youtube.com',
tiktok: 'https://www.tiktok.com',
reddit: 'https://www.reddit.com',
whatsapp: 'https://web.whatsapp.com',
telegram: 'https://web.telegram.org',
discord: 'https://discord.com/app',
snapchat: 'https://www.snapchat.com',
pinterest: 'https://www.pinterest.com'
};
// Platform icons mapping
const platformIcons = {
facebook: 'fab fa-facebook-f',
instagram: 'fab fa-instagram',
twitter: 'fab fa-twitter',
linkedin: 'fab fa-linkedin-in',
youtube: 'fab fa-youtube',
tiktok: 'fab fa-tiktok',
reddit: 'fab fa-reddit-alien',
whatsapp: 'fab fa-whatsapp',
telegram: 'fab fa-telegram-plane',
discord: 'fab fa-discord',
snapchat: 'fab fa-snapchat-ghost',
pinterest: 'fab fa-pinterest-p'
};
// Modal elements
const modal = document.getElementById('platformModal');
const modalFrame = document.getElementById('platformFrame');
const loadingSpinner = document.querySelector('.loading-spinner');
const closeBtn = document.querySelector('.close-btn');
const platformIcon = document.querySelector('.platform-icon');
const platformTitle = document.querySelector('.platform-title');
const modalContent = document.querySelector('.modal-content');
// Auth section elements
const authSection = document.getElementById('authSection');
const platformSection = document.getElementById('platformSection');
const googleSignInBtn = document.getElementById('googleSignIn');
const platformSignInBtn = document.getElementById('platformSignIn');
const guestAccessBtn = document.getElementById('guestAccess');
const refreshBtn = document.querySelector('.refresh-btn');
const fullscreenBtn = document.querySelector('.fullscreen-btn');
const logoutBtn = document.querySelector('.logout-btn');
const platformIconLarge = document.querySelector('.platform-icon-large');
const platformIconSmall = document.querySelector('.platform-icon-small');
const platformNameText = document.querySelector('.platform-name-text');
const platformLoginText = document.querySelector('.platform-login-text');
socialCards.forEach(card => {
const launchBtn = card.querySelector('.launch-btn');
launchBtn.addEventListener('click', (e) => {
e.preventDefault();
const platform = card.getAttribute('data-platform');
const platformName = card.querySelector('.platform-name').textContent;
const url = platformURLs[platform];
const icon = platformIcons[platform];
console.log(`Opening ${platform} in modal`);
// Update analytics
StorageManager.updateAnalytics(platform);
StorageManager.addToRecent(platform, platformName, icon);
updateVisitBadge(card, platform);
updateAnalyticsDisplay();
// Open platform in modal
openPlatformModal(url, platformName, platform);
// Add a visual feedback
card.style.transform = 'scale(0.95)';
setTimeout(() => {
card.style.transform = '';
}, 200);
});
});
// Open platform in modal
function openPlatformModal(url, name, platform) {
currentPlatformURL = url;
currentPlatformName = name;
currentPlatform = platform;
// Set platform info in header
platformTitle.textContent = name;
platformIcon.className = 'platform-icon ' + platformIcons[platform];
// Set platform info in auth section
platformNameText.textContent = name;
platformIconLarge.className = 'platform-icon-large ' + platformIcons[platform];
platformIconSmall.className = 'platform-icon-small ' + platformIcons[platform];
platformLoginText.textContent = `Login with ${name} Account`;
// Show modal with auth section
modal.classList.add('active');
document.body.style.overflow = 'hidden';
// Show auth section, hide platform section
authSection.style.display = 'flex';
platformSection.style.display = 'none';
}
// Close modal
function closePlatformModal() {
modal.classList.remove('active');
document.body.style.overflow = '';
modalContent.classList.remove('fullscreen');
// Stop time tracking
stopTimeTracking();
// Clear iframe and reset to auth section
setTimeout(() => {
modalFrame.src = '';
authSection.style.display = 'flex';
platformSection.style.display = 'none';
loadingSpinner.classList.remove('hidden');
}, 300);
}
// Load platform with authentication
function loadPlatform(authMethod) {
console.log(`Loading ${currentPlatformName} with ${authMethod} authentication`);
// Hide auth section, show platform section
authSection.style.display = 'none';
platformSection.style.display = 'block';
// Show loading
loadingSpinner.classList.remove('hidden');
// Load iframe
modalFrame.src = currentPlatformURL;
// Hide loading when iframe loads (or after timeout)
modalFrame.onload = () => {
setTimeout(() => {
loadingSpinner.classList.add('hidden');
}, 500);
};
// Fallback timeout for platforms that block iframes
setTimeout(() => {
loadingSpinner.classList.add('hidden');
}, 3000);
}
// Google Sign-In
googleSignInBtn.addEventListener('click', () => {
console.log('Google Sign-In clicked');
showNotification('Google Sign-In feature coming soon! Opening platform directly...', 'info');
// Open platform in a large popup window
const width = 1200;
const height = 800;
const left = (screen.width - width) / 2;
const top = (screen.height - height) / 2;
setTimeout(() => {
window.open(
currentPlatformURL,
currentPlatformName,
`width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no,scrollbars=yes,resizable=yes`
);
closePlatformModal();
}, 1000);
});
// Platform Sign-In
platformSignInBtn.addEventListener('click', () => {
console.log('Platform Sign-In clicked');
showNotification(`Opening ${currentPlatformName} in new window...`, 'success');
// Start time tracking
startTimeTracking(currentPlatform);
// Open platform in a large popup window
const width = 1200;
const height = 800;
const left = (screen.width - width) / 2;
const top = (screen.height - height) / 2;
window.open(
currentPlatformURL,
currentPlatformName,
`width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no,scrollbars=yes,resizable=yes`
);
// Close the modal since platform opened in new window
setTimeout(() => {
closePlatformModal();
}, 500);
});
// Guest Access / Web Version
guestAccessBtn.addEventListener('click', () => {
console.log('Guest access clicked');
showNotification(`Opening ${currentPlatformName} web version...`, 'info');
// Open platform in a large popup window
const width = 1200;
const height = 800;
const left = (screen.width - width) / 2;
const top = (screen.height - height) / 2;
window.open(
currentPlatformURL,
currentPlatformName + '_Web',
`width=${width},height=${height},left=${left},top=${top},toolbar=yes,menubar=no,scrollbars=yes,resizable=yes,location=yes`
);
// Close the modal
setTimeout(() => {
closePlatformModal();
}, 500);
});
// Notification system
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.innerHTML = `
<i class="fas fa-${type === 'success' ? 'check-circle' : type === 'warning' ? 'exclamation-triangle' : 'info-circle'}"></i>
<span>${message}</span>
`;
document.body.appendChild(notification);
// Animate in
setTimeout(() => notification.classList.add('show'), 10);
// Remove after 3 seconds
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => notification.remove(), 300);
}, 3000);
}
// Close button
closeBtn.addEventListener('click', closePlatformModal);
// Close on background click
modal.addEventListener('click', (e) => {
if (e.target === modal) {
closePlatformModal();
}
});
// Refresh button
refreshBtn.addEventListener('click', () => {
loadingSpinner.classList.remove('hidden');
modalFrame.src = modalFrame.src;
setTimeout(() => {
loadingSpinner.classList.add('hidden');
}, 2000);
});
// Fullscreen button
fullscreenBtn.addEventListener('click', () => {
modalContent.classList.toggle('fullscreen');
const icon = fullscreenBtn.querySelector('i');
if (modalContent.classList.contains('fullscreen')) {
icon.classList.remove('fa-expand');
icon.classList.add('fa-compress');
fullscreenBtn.title = 'Exit Fullscreen';
} else {
icon.classList.remove('fa-compress');
icon.classList.add('fa-expand');
fullscreenBtn.title = 'Fullscreen';
}
});
// Logout button - returns to auth screen
logoutBtn.addEventListener('click', () => {
showNotification('Logged out successfully', 'success');
authSection.style.display = 'flex';
platformSection.style.display = 'none';
modalFrame.src = '';
});
// Escape key to close modal
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && modal.classList.contains('active')) {
closePlatformModal();
}
});
// ===== Card Hover Sound Effect (Optional) =====
socialCards.forEach(card => {
card.addEventListener('mouseenter', () => {
card.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)';
});
});
// ===== Smooth Scroll =====
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
// ===== Dynamic Time-based Greeting (Optional Enhancement) =====
function updateGreeting() {
const hour = new Date().getHours();
const subtitle = document.querySelector('.subtitle');
if (hour >= 5 && hour < 12) {
subtitle.textContent = 'Good morning! Connect to your favorite platforms';
} else if (hour >= 12 && hour < 17) {
subtitle.textContent = 'Good afternoon! Connect to your favorite platforms';
} else if (hour >= 17 && hour < 21) {
subtitle.textContent = 'Good evening! Connect to your favorite platforms';
} else {
subtitle.textContent = 'Connect to your favorite platforms instantly';
}
}
// ===== Loading Animation =====
window.addEventListener('load', () => {
document.body.style.opacity = '0';
setTimeout(() => {
document.body.style.transition = 'opacity 0.5s ease';
document.body.style.opacity = '1';
}, 100);
});
// ===== Initialize Everything =====
initParticles();
animateParticles();
updateGreeting();
initializeFavorites();
initializeNotes();
initializeAnalytics();
initializeTheme();
initializeCustomPlatforms();
initializeStatusIndicators();
initializeKeyboardShortcuts();
initializeHeaderControls();
// ===== ANALYTICS FUNCTIONS =====
function initializeAnalytics() {
const analytics = StorageManager.getAnalytics();
socialCards.forEach(card => {
const platform = card.getAttribute('data-platform');
updateVisitBadge(card, platform);
});
}
function updateVisitBadge(card, platform) {
const analytics = StorageManager.getAnalytics();
const visitBadge = card.querySelector('.visit-badge');
if (analytics[platform] && analytics[platform].visits > 0) {
visitBadge.textContent = `${analytics[platform].visits} visits`;
visitBadge.style.display = 'inline-flex';
}
}
function updateAnalyticsDisplay() {
const analytics = StorageManager.getAnalytics();
const favorites = StorageManager.getFavorites();
let totalVisits = 0;
let totalTime = 0;
let mostUsedPlatform = '-';
let maxVisits = 0;
Object.keys(analytics).forEach(platform => {
totalVisits += analytics[platform].visits || 0;
totalTime += analytics[platform].time || 0;
if (analytics[platform].visits > maxVisits) {
maxVisits = analytics[platform].visits;
mostUsedPlatform = platform;
}
});
document.getElementById('totalVisits').textContent = totalVisits;
document.getElementById('totalFavorites').textContent = favorites.length;
const hours = Math.floor(totalTime / 3600);
const minutes = Math.floor((totalTime % 3600) / 60);
document.getElementById('totalTime').textContent = `${hours}h ${minutes}m`;
if (mostUsedPlatform !== '-') {
const card = document.querySelector(`[data-platform="${mostUsedPlatform}"]`);
if (card) {
mostUsedPlatform = card.querySelector('.platform-name').textContent;
}
}
document.getElementById('mostUsed').textContent = mostUsedPlatform;
updateUsageChart(analytics);
}
function updateUsageChart(analytics) {
const chartContainer = document.getElementById('usageChart');
chartContainer.innerHTML = '';
const sorted = Object.entries(analytics)
.sort((a, b) => b[1].visits - a[1].visits)
.slice(0, 10);
if (sorted.length === 0) {
chartContainer.innerHTML = '<p style="color: var(--text-secondary); text-align: center;">No usage data yet</p>';
return;
}
const maxVisits = sorted[0][1].visits;
sorted.forEach(([platform, data]) => {
const card = document.querySelector(`[data-platform="${platform}"]`);
const name = card ? card.querySelector('.platform-name').textContent : platform;
const percentage = (data.visits / maxVisits) * 100;
const barHTML = `
<div class="chart-bar">
<div class="chart-label">${name}</div>
<div class="chart-bar-container">
<div class="chart-bar-fill" style="width: ${percentage}%">
${data.visits}
</div>
</div>
</div>
`;
chartContainer.innerHTML += barHTML;
});
}
// ===== THEME TOGGLE =====
function initializeTheme() {
const theme = StorageManager.getTheme();
applyTheme(theme);
}
function applyTheme(theme) {
const themeToggle = document.getElementById('themeToggle');
const icon = themeToggle.querySelector('i');
if (theme === 'light') {
document.body.classList.add('light-mode');
icon.classList.remove('fa-moon');
icon.classList.add('fa-sun');
} else {
document.body.classList.remove('light-mode');
icon.classList.remove('fa-sun');
icon.classList.add('fa-moon');
}
}
// ===== RECENT ACTIVITY TIMELINE =====
function updateRecentTimeline() {
const recent = StorageManager.getRecentActivity();
const timelineItems = document.getElementById('timelineItems');
if (recent.length === 0) {
timelineItems.innerHTML = '<p style="color: var(--text-secondary); text-align: center;">No recent activity</p>';
return;
}
timelineItems.innerHTML = '';
recent.forEach(item => {
const timeAgo = getTimeAgo(new Date(item.timestamp));
const itemHTML = `
<div class="timeline-item" data-platform="${item.platform}">
<i class="${item.icon}"></i>
<div class="timeline-info">
<h4>${item.name}</h4>
<span>${timeAgo}</span>
</div>
</div>
`;
timelineItems.innerHTML += itemHTML;
});
// Add click handlers
timelineItems.querySelectorAll('.timeline-item').forEach(item => {
item.addEventListener('click', () => {
const platform = item.getAttribute('data-platform');
const card = document.querySelector(`[data-platform="${platform}"]`);
if (card) {
card.querySelector('.launch-btn').click();
}
});
});
}
function getTimeAgo(date) {
const seconds = Math.floor((new Date() - date) / 1000);
if (seconds < 60) return 'Just now';
if (seconds < 3600) return `${Math.floor(seconds / 60)} minutes ago`;
if (seconds < 86400) return `${Math.floor(seconds / 3600)} hours ago`;
return `${Math.floor(seconds / 86400)} days ago`;
}
// ===== CUSTOM PLATFORMS =====
function initializeCustomPlatforms() {
const customPlatforms = StorageManager.getCustomPlatforms();
const socialGrid = document.getElementById('socialGrid');
customPlatforms.forEach(platform => {
addCustomPlatformCard(platform, socialGrid);
});
}
function addCustomPlatformCard(platform, container) {
const cardHTML = `
<div class="social-card" data-platform="${platform.id}" data-category="${platform.category}" data-custom="true">
<div class="card-inner">
<div class="card-front" style="background: ${platform.color};">
<div class="card-top-controls">
<button class="favorite-btn" title="Add to Favorites">
<i class="far fa-star"></i>
</button>
<button class="note-btn" title="Add Note">
<i class="far fa-sticky-note"></i>
</button>
<button class="delete-custom-btn" title="Delete Platform" style="background: rgba(255, 71, 87, 0.8);">
<i class="fas fa-trash"></i>
</button>
<div class="status-indicator" title="Status: Online"></div>
</div>
<div class="platform-logo">
<i class="${platform.icon}"></i>
</div>
<h3 class="platform-name">${platform.name}</h3>
<div class="platform-badges">
<span class="visit-badge" style="display: none;">0 visits</span>
<span class="note-indicator" style="display: none;"><i class="fas fa-sticky-note"></i></span>
</div>
<p class="platform-desc">Custom platform</p>
<div class="card-stats">
<span><i class="fas fa-globe"></i> Custom</span>
</div>
</div>
</div>
<a href="${platform.url}" target="_blank" class="launch-btn" data-url="${platform.url}">
<i class="fas fa-external-link-alt"></i> Launch
</a>
</div>
`;
container.innerHTML += cardHTML;
// Re-initialize features for new card
const newCard = container.lastElementChild;
initializeCardFeatures(newCard, platform.id);
}
function initializeCardFeatures(card, platform) {
// Favorite button
const favBtn = card.querySelector('.favorite-btn');
const favorites = StorageManager.getFavorites();
if (favorites.includes(platform)) {
favBtn.classList.add('active');
favBtn.querySelector('i').classList.remove('far');
favBtn.querySelector('i').classList.add('fas');
}
favBtn.addEventListener('click', (e) => {
e.stopPropagation();
e.preventDefault();
toggleFavorite(platform, favBtn);
});
// Note button
const noteBtn = card.querySelector('.note-btn');
const notes = StorageManager.getNotes();
if (notes[platform]) {
noteBtn.classList.add('has-note');
card.querySelector('.note-indicator').style.display = 'inline-flex';
}
noteBtn.addEventListener('click', (e) => {
e.stopPropagation();
e.preventDefault();
openNoteModal(platform, card.querySelector('.platform-name').textContent);
});
// Delete custom platform button
const deleteBtn = card.querySelector('.delete-custom-btn');
if (deleteBtn) {
deleteBtn.addEventListener('click', (e) => {
e.stopPropagation();
e.preventDefault();
if (confirm('Delete this custom platform?')) {
StorageManager.removeCustomPlatform(platform);
card.remove();
showNotification('Platform deleted', 'success');
}
});
}
// Launch button
const launchBtn = card.querySelector('.launch-btn');
launchBtn.addEventListener('click', (e) => {
e.preventDefault();
const platformName = card.querySelector('.platform-name').textContent;
const url = launchBtn.getAttribute('data-url');
const icon = card.querySelector('.platform-logo i').className;
StorageManager.updateAnalytics(platform);
StorageManager.addToRecent(platform, platformName, icon);
updateVisitBadge(card, platform);
updateAnalyticsDisplay();
openPlatformModal(url, platformName, platform);
card.style.transform = 'scale(0.95)';
setTimeout(() => {
card.style.transform = '';
}, 200);
});
}
// ===== STATUS INDICATORS =====
function initializeStatusIndicators() {
// Simulated status check - in real app, you'd ping the services
// For now, all are marked as online
document.querySelectorAll('.status-indicator').forEach(indicator => {
indicator.classList.remove('offline');
});
}
// ===== KEYBOARD SHORTCUTS =====
function initializeKeyboardShortcuts() {
document.addEventListener('keydown', (e) => {
// Don't trigger if typing in input
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
return;
}
// ? - Show shortcuts
if (e.key === '?') {
e.preventDefault();
document.getElementById('shortcutsModal').classList.add('active');
}
// Ctrl+K - Analytics
if (e.ctrlKey && e.key === 'k') {
e.preventDefault();
document.getElementById('analyticsModal').classList.add('active');
updateAnalyticsDisplay();
}
// Ctrl+D - Theme toggle
if (e.ctrlKey && e.key === 'd') {
e.preventDefault();
document.getElementById('themeToggle').click();
}
// Ctrl+I - AI Caption Generator
if (e.ctrlKey && e.key === 'i') {
e.preventDefault();
document.getElementById('aiCaptionBtn').click();
}
// 1-9 - Quick launch
if (e.key >= '1' && e.key <= '9') {
const index = parseInt(e.key) - 1;
const visibleCards = Array.from(socialCards).filter(card => !card.classList.contains('hidden'));
if (visibleCards[index]) {
visibleCards[index].querySelector('.launch-btn').click();
}
}
});
}
// ===== HEADER CONTROLS =====
function initializeHeaderControls() {
// Theme toggle
document.getElementById('themeToggle').addEventListener('click', () => {
const currentTheme = StorageManager.getTheme();
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
StorageManager.setTheme(newTheme);
applyTheme(newTheme);
showNotification(`Switched to ${newTheme} mode`, 'success');
});
// AI Caption Generator button (already initialized above)
// document.getElementById('aiCaptionBtn') - handled in AI section
// Shortcuts button
document.getElementById('shortcutsBtn').addEventListener('click', () => {
document.getElementById('shortcutsModal').classList.add('active');
});
// Analytics button
document.getElementById('analyticsBtn').addEventListener('click', () => {
document.getElementById('analyticsModal').classList.add('active');
updateAnalyticsDisplay();
});
// Add platform button
document.getElementById('addPlatformBtn').addEventListener('click', () => {
document.getElementById('addPlatformModal').classList.add('active');
});
}
// ===== ADD CUSTOM PLATFORM FORM =====
document.getElementById('addPlatformForm').addEventListener('submit', (e) => {
e.preventDefault();
const platform = {
id: 'custom_' + Date.now(),
name: document.getElementById('customPlatformName').value,
url: document.getElementById('customPlatformURL').value,
icon: document.getElementById('customPlatformIcon').value,
color: document.getElementById('customPlatformColor').value,
category: document.getElementById('customPlatformCategory').value
};
StorageManager.addCustomPlatform(platform);
addCustomPlatformCard(platform, document.getElementById('socialGrid'));
document.getElementById('addPlatformModal').classList.remove('active');
document.getElementById('addPlatformForm').reset();
showNotification('Custom platform added!', 'success');
});
// ===== TIME TRACKING =====
function startTimeTracking(platform) {
startTime = Date.now();
const tracker = document.getElementById('timeTracker');
tracker.style.display = 'flex';
timeTrackingInterval = setInterval(() => {
const elapsed = Math.floor((Date.now() - startTime) / 1000);
const minutes = Math.floor(elapsed / 60);
const seconds = elapsed % 60;
document.getElementById('trackerTime').textContent =
`${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
}, 1000);
}
function stopTimeTracking() {
if (timeTrackingInterval) {
clearInterval(timeTrackingInterval);
const elapsed = Math.floor((Date.now() - startTime) / 1000);
StorageManager.updateTimeSpent(currentPlatform, elapsed);
document.getElementById('timeTracker').style.display = 'none';
updateAnalyticsDisplay();
}
}
document.getElementById('stopTracking').addEventListener('click', stopTimeTracking);
// ===== AI CAPTION GENERATOR =====
// Groq API Configuration (from your original code)
const GROQ_API_KEY = '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';
const GROQ_API_URL = 'https://api.groq.com/openai/v1/chat/completions';
const HF_IMAGE_API = 'https://api-inference.huggingface.co/models/Salesforce/blip-image-captioning-base';
const HF_API_TOKEN = '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';
// AI Caption Button
document.getElementById('aiCaptionBtn').addEventListener('click', () => {
document.getElementById('aiCaptionModal').classList.add('active');
document.body.style.overflow = 'hidden';
});
// Image Upload Handler
const imageInput = document.getElementById('imageInput');
const uploadArea = document.getElementById('uploadArea');
const uploadSection = document.getElementById('uploadSection');
const resultsSection = document.getElementById('resultsSection');
const imagePreview = document.getElementById('imagePreview');
imageInput.addEventListener('change', handleImageUpload);
// Drag and drop
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
uploadArea.style.borderColor = 'var(--accent-color)';
uploadArea.style.background = 'rgba(0, 212, 255, 0.15)';
});
uploadArea.addEventListener('dragleave', () => {
uploadArea.style.borderColor = 'rgba(0, 212, 255, 0.3)';
uploadArea.style.background = 'rgba(0, 212, 255, 0.05)';
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.style.borderColor = 'rgba(0, 212, 255, 0.3)';
uploadArea.style.background = 'rgba(0, 212, 255, 0.05)';
const files = e.dataTransfer.files;
if (files.length > 0 && files[0].type.startsWith('image/')) {
imageInput.files = files;
handleImageUpload();
}
});
async function handleImageUpload() {
const file = imageInput.files[0];
if (!file) return;
// Show preview
const reader = new FileReader();
reader.onload = (e) => {
imagePreview.src = e.target.result;
currentImageData = e.target.result;
};
reader.readAsDataURL(file);
// Switch to results view
uploadSection.style.display = 'none';
resultsSection.style.display = 'grid';
// Reset loading states
showLoadingState();
// Generate AI content
await generateAIContent(file);
}
function showLoadingState() {
document.getElementById('aiDescription').innerHTML = '<div class="loading-dots"><span></span><span></span><span></span></div>';
document.getElementById('aiCaptions').innerHTML = '<div class="loading-dots"><span></span><span></span><span></span></div>';
document.getElementById('aiHashtags').innerHTML = '<div class="loading-dots"><span></span><span></span><span></span></div>';
}
async function generateAIContent(imageFile) {
try {
console.log('=== Starting AI Generation ===');
console.log('Image file:', imageFile.name, imageFile.type, imageFile.size, 'bytes');
// Step 1: Get image description using BLIP
showNotification('Analyzing image with AI...', 'info');
const description = await getImageDescription(imageFile);
currentDescription = description;
console.log('✓ Image description:', description);
document.getElementById('aiDescription').innerHTML = `<p>${description}</p>`;
// Step 2: Generate captions
showNotification('Generating creative captions...', 'info');
const captions = await generateCaptions(description);
currentCaptions = captions;
console.log('✓ Captions generated:', captions);
document.getElementById('aiCaptions').innerHTML = formatCaptions(captions);
// Step 3: Generate hashtags
showNotification('Creating hashtags...', 'info');
const hashtags = await generateHashtags(description);
currentHashtags = hashtags;
console.log('✓ Hashtags created:', hashtags);
document.getElementById('aiHashtags').innerHTML = `<p>${hashtags}</p>`;
console.log('=== AI Generation Complete ===');
showNotification('AI generation complete! ✨', 'success');
} catch (error) {
console.error('=== AI Generation Error ===');
console.error('Error:', error);
showNotification('AI generation failed. Using fallback content...', 'warning');
useFallbackGeneration();
}
}
async function getImageDescription(imageFile) {
try {
// Convert image to base64 for API
const imageData = await imageFile.arrayBuffer();
const blob = new Blob([imageData]);
const response = await fetch(HF_IMAGE_API, {
method: 'POST',
headers: {
'Authorization': `Bearer ${HF_API_TOKEN}`,
},
body: blob
});
if (!response.ok) {
const errorText = await response.text();
console.error('HF API Error:', errorText);
// If model is loading, wait and retry
if (response.status === 503) {
showNotification('AI model is loading, retrying in 3 seconds...', 'info');
await new Promise(resolve => setTimeout(resolve, 3000));
return getImageDescription(imageFile); // Retry
}
throw new Error('Image API request failed');
}
const result = await response.json();
console.log('Image description result:', result);
// Extract description from response
const description = result[0]?.generated_text || result?.generated_text || 'an interesting image';
return description.trim();
} catch (error) {
console.error('Image description error:', error);
showNotification('Using basic image analysis...', 'warning');
return 'a photo with interesting elements';
}
}
async function generateCaptions(description) {
const prompt = `Generate exactly 3 unique, creative, and engaging social media captions for a photo that shows: "${description}". Make them catchy and suitable for Instagram, Facebook, or Twitter. Format as:
1. [first caption]
2. [second caption]
3. [third caption]
Only provide the numbered captions, nothing else.`;
try {
console.log('Generating captions for:', description);
const response = await fetch(GROQ_API_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${GROQ_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'llama-3.1-8b-instant',
messages: [
{
role: 'system',
content: 'You are a creative social media caption writer. Generate engaging, concise captions.'
},
{
role: 'user',
content: prompt
}
],
max_tokens: 200,
temperature: 0.8
})
});
if (!response.ok) {
const errorText = await response.text();
console.error('Groq API Error:', errorText);
throw new Error('Caption API request failed');
}
const result = await response.json();
console.log('Caption result:', result);
const generatedText = result.choices[0]?.message?.content || '';
return generatedText.trim() || getFallbackCaptions(description);
} catch (error) {
console.error('Caption generation error:', error);
showNotification('Using fallback captions...', 'warning');
return getFallbackCaptions(description);
}
}
async function generateHashtags(description) {
const prompt = `Generate exactly 10 relevant and trending hashtags for a photo that shows: "${description}". Only provide the hashtags with # symbol, separated by spaces. No explanations.`;
try {
console.log('Generating hashtags for:', description);
const response = await fetch(GROQ_API_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${GROQ_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'llama-3.1-8b-instant',
messages: [
{
role: 'system',
content: 'You are a social media expert. Generate relevant hashtags based on image descriptions.'
},
{
role: 'user',
content: prompt
}
],
max_tokens: 100,
temperature: 0.7
})
});
if (!response.ok) {
const errorText = await response.text();
console.error('Hashtag API Error:', errorText);
throw new Error('Hashtag API request failed');
}
const result = await response.json();
console.log('Hashtag result:', result);
let hashtags = result.choices[0]?.message?.content || '';
// Clean up hashtags - ensure they have # and are properly formatted
hashtags = hashtags.split(/\s+/)
.map(tag => tag.trim())
.filter(tag => tag.length > 0)
.map(tag => tag.startsWith('#') ? tag : '#' + tag)
.slice(0, 10)
.join(' ');
return hashtags || getFallbackHashtags(description);
} catch (error) {
console.error('Hashtag generation error:', error);
return getFallbackHashtags(description);
}
}
function getFallbackHashtags(description) {
// Extract keywords from description and create hashtags
const words = description.split(' ')
.filter(w => w.length > 3)
.map(w => w.replace(/[^a-zA-Z]/g, ''))
.filter(w => w.length > 0);
const baseHashtags = words.slice(0, 5).map(w => '#' + w.toLowerCase());
const genericHashtags = [
'#photography', '#photooftheday', '#instagood',
'#beautiful', '#instadaily', '#picoftheday',
'#instagram', '#love', '#amazing', '#art'
];
const allHashtags = [...new Set([...baseHashtags, ...genericHashtags])].slice(0, 10);
return allHashtags.join(' ');
}
function getFallbackCaptions(description) {
// Create captions based on the actual description
const mainSubject = description.split(' ').slice(0, 3).join(' ');
return `1. Capturing the beauty of ${description} 📸✨
2. ${description.charAt(0).toUpperCase() + description.slice(1)} - moments like these make life special 🌟
3. Just ${mainSubject}... living my best life! 💫 #blessed`;
}
function formatCaptions(captions) {
// Split captions by numbers or newlines
const captionArray = captions.split(/\d+\./).filter(c => c.trim());
let html = '';
captionArray.forEach((caption, index) => {
if (caption.trim()) {
html += `<p><strong>Caption ${index + 1}:</strong> ${caption.trim()}</p>`;
}
});
return html || `<p>${captions}</p>`;
}
function useFallbackGeneration() {
currentDescription = 'a wonderful moment captured in time';
currentCaptions = getFallbackCaptions(currentDescription);
currentHashtags = '#photography #photooftheday #instagood #beautiful #instadaily #picoftheday #instagram #love #amazing #art';
document.getElementById('aiDescription').innerHTML = `<p>${currentDescription}</p>`;
document.getElementById('aiCaptions').innerHTML = formatCaptions(currentCaptions);
document.getElementById('aiHashtags').innerHTML = `<p>${currentHashtags}</p>`;
}
// Copy functionality
document.getElementById('copyCaptionBtn').addEventListener('click', () => {
copyToClipboard(currentCaptions, 'Caption copied!');
});
document.getElementById('copyHashtagsBtn').addEventListener('click', () => {
copyToClipboard(currentHashtags, 'Hashtags copied!');
});
document.getElementById('copyAllBtn').addEventListener('click', () => {
const allText = `${currentCaptions}\n\n${currentHashtags}`;
copyToClipboard(allText, 'All content copied!');
});
function copyToClipboard(text, message) {
navigator.clipboard.writeText(text).then(() => {
showNotification(message, 'success');
}).catch(() => {
showNotification('Copy failed', 'warning');
});
}
// Post to platform
document.querySelectorAll('.platform-post-btn').forEach(btn => {
btn.addEventListener('click', () => {
const platform = btn.getAttribute('data-platform');
postToPlatform(platform);
});
});
function postToPlatform(platform) {
// Copy caption and hashtags to clipboard first
const fullContent = `${currentCaptions.split('\n')[0]}\n\n${currentHashtags}`;
copyToClipboard(fullContent, `Content copied! Opening ${platform}...`);
// Open platform in popup
const platformURL = platformURLs[platform];
if (platformURL) {
setTimeout(() => {
const width = 1200;
const height = 800;
const left = (screen.width - width) / 2;
const top = (screen.height - height) / 2;
window.open(
platformURL,
platform,
`width=${width},height=${height},left=${left},top=${top},toolbar=yes,menubar=no,scrollbars=yes,resizable=yes`
);
showNotification(`Paste your caption and upload the image on ${platform}!`, 'info');
}, 500);
}
}
// ===== Performance Optimization =====
// Throttle scroll events
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
window.requestAnimationFrame(() => {
// Add scroll-based animations here if needed
ticking = false;
});
ticking = true;
}
});
// ===== Keyboard Navigation =====
document.addEventListener('keydown', (e) => {
// Don't trigger shortcuts if modal is open (except Escape)
if (modal.classList.contains('active') && e.key !== 'Escape') {
return;
}
if (e.key === '/') {
e.preventDefault();
searchInput.focus();
}
if (e.key === 'Escape') {
if (modal.classList.contains('active')) {
closePlatformModal();
} else {
searchInput.blur();
searchInput.value = '';
searchInput.dispatchEvent(new Event('input'));
}
}
});
// ===== Show keyboard shortcut hint =====
const searchContainer = document.querySelector('.search-container');
const hintElement = document.createElement('div');
hintElement.style.cssText = `
position: absolute;
right: 4rem;
top: 50%;
transform: translateY(-50%);
font-size: 0.8rem;
color: var(--text-secondary);
opacity: 0.6;
pointer-events: none;
`;
hintElement.innerHTML = '<kbd style="background: rgba(0,212,255,0.1); padding: 2px 6px; border-radius: 3px; font-size: 0.7rem;">/ to search</kbd>';
searchContainer.appendChild(hintElement);
searchInput.addEventListener('focus', () => {
hintElement.style.opacity = '0';
});
searchInput.addEventListener('blur', () => {
if (!searchInput.value) {
hintElement.style.opacity = '0.6';
}
});
// ===== Add ripple effect on card click =====
socialCards.forEach(card => {
card.addEventListener('click', function(e) {
const ripple = document.createElement('div');
const rect = this.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
const x = e.clientX - rect.left - size / 2;
const y = e.clientY - rect.top - size / 2;
ripple.style.cssText = `
position: absolute;
width: ${size}px;
height: ${size}px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
left: ${x}px;
top: ${y}px;
pointer-events: none;
animation: rippleEffect 0.6s ease-out;
`;
this.style.position = 'relative';
this.style.overflow = 'hidden';
this.appendChild(ripple);
setTimeout(() => ripple.remove(), 600);
});
});
// Add ripple animation to stylesheet dynamically
const style = document.createElement('style');
style.textContent = `
@keyframes rippleEffect {
0% {
transform: scale(0);
opacity: 1;
}
100% {
transform: scale(2);
opacity: 0;
}
}
kbd {
font-family: 'Courier New', monospace;
}
`;
document.head.appendChild(style);
console.log('%c🚀 Social Hub Loaded Successfully!', 'color: #00d4ff; font-size: 20px; font-weight: bold;');
console.log('%cPress "/" to search platforms', 'color: #00ff88; font-size: 14px;');
console.log('%cPress "Ctrl+I" to open AI Caption Generator', 'color: #00ff88; font-size: 14px;');
console.log('%c🤖 AI Features: Real-time image analysis with Groq + Hugging Face', 'color: #ffa502; font-size: 12px;');