| |
|
| | let currentPlatformURL = '';
|
| | let currentPlatformName = '';
|
| | let currentPlatform = '';
|
| | let currentNoteEditPlatform = '';
|
| | let timeTrackingInterval = null;
|
| | let startTime = null;
|
| | let currentImageData = null;
|
| | let currentDescription = '';
|
| | let currentCaptions = '';
|
| | let currentHashtags = '';
|
| |
|
| |
|
| | const StorageManager = {
|
| |
|
| | getFavorites: () => {
|
| | const favorites = localStorage.getItem('socialHub_favorites');
|
| | return favorites ? JSON.parse(favorites) : [];
|
| | },
|
| |
|
| |
|
| | setFavorites: (favorites) => {
|
| | localStorage.setItem('socialHub_favorites', JSON.stringify(favorites));
|
| | },
|
| |
|
| |
|
| | 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;
|
| | },
|
| |
|
| |
|
| | getNotes: () => {
|
| | const notes = localStorage.getItem('socialHub_notes');
|
| | return notes ? JSON.parse(notes) : {};
|
| | },
|
| |
|
| |
|
| | setNote: (platform, note) => {
|
| | const notes = StorageManager.getNotes();
|
| | if (note.trim()) {
|
| | notes[platform] = note;
|
| | } else {
|
| | delete notes[platform];
|
| | }
|
| | localStorage.setItem('socialHub_notes', JSON.stringify(notes));
|
| | },
|
| |
|
| |
|
| | getAnalytics: () => {
|
| | const analytics = localStorage.getItem('socialHub_analytics');
|
| | return analytics ? JSON.parse(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));
|
| | },
|
| |
|
| |
|
| | 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));
|
| | },
|
| |
|
| |
|
| | getRecentActivity: () => {
|
| | const recent = localStorage.getItem('socialHub_recent');
|
| | return recent ? JSON.parse(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));
|
| | },
|
| |
|
| |
|
| | getTheme: () => {
|
| | return localStorage.getItem('socialHub_theme') || 'dark';
|
| | },
|
| |
|
| |
|
| | setTheme: (theme) => {
|
| | localStorage.setItem('socialHub_theme', theme);
|
| | },
|
| |
|
| |
|
| | getCustomPlatforms: () => {
|
| | const custom = localStorage.getItem('socialHub_custom');
|
| | return custom ? JSON.parse(custom) : [];
|
| | },
|
| |
|
| |
|
| | addCustomPlatform: (platform) => {
|
| | const custom = StorageManager.getCustomPlatforms();
|
| | custom.push(platform);
|
| | localStorage.setItem('socialHub_custom', JSON.stringify(custom));
|
| | },
|
| |
|
| |
|
| | removeCustomPlatform: (id) => {
|
| | let custom = StorageManager.getCustomPlatforms();
|
| | custom = custom.filter(p => p.id !== id);
|
| | localStorage.setItem('socialHub_custom', JSON.stringify(custom));
|
| | }
|
| | };
|
| |
|
| |
|
| | 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();
|
| |
|
| |
|
| | 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.addEventListener('resize', () => {
|
| | canvas.width = window.innerWidth;
|
| | canvas.height = window.innerHeight;
|
| | initParticles();
|
| | });
|
| |
|
| |
|
| | 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);
|
| | }
|
| |
|
| |
|
| | const filterTabs = document.querySelectorAll('.filter-tab');
|
| | const recentTimeline = document.getElementById('recentTimeline');
|
| |
|
| | filterTabs.forEach(tab => {
|
| | tab.addEventListener('click', () => {
|
| |
|
| | filterTabs.forEach(t => t.classList.remove('active'));
|
| | tab.classList.add('active');
|
| |
|
| | const filter = tab.getAttribute('data-filter');
|
| |
|
| |
|
| | if (filter === 'recent') {
|
| | updateRecentTimeline();
|
| | recentTimeline.style.display = 'block';
|
| | } else {
|
| | recentTimeline.style.display = 'none';
|
| | }
|
| |
|
| |
|
| | 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');
|
| | }
|
| | });
|
| | }
|
| |
|
| |
|
| | 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();
|
| | }
|
| |
|
| |
|
| | 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);
|
| |
|
| |
|
| | 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();
|
| | });
|
| |
|
| |
|
| |
|
| | 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'
|
| | };
|
| |
|
| |
|
| | 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'
|
| | };
|
| |
|
| |
|
| | 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');
|
| |
|
| |
|
| | 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`);
|
| |
|
| |
|
| | 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);
|
| | });
|
| | });
|
| |
|
| |
|
| | function openPlatformModal(url, name, platform) {
|
| | currentPlatformURL = url;
|
| | currentPlatformName = name;
|
| | currentPlatform = platform;
|
| |
|
| |
|
| | platformTitle.textContent = name;
|
| | platformIcon.className = 'platform-icon ' + platformIcons[platform];
|
| |
|
| |
|
| | platformNameText.textContent = name;
|
| | platformIconLarge.className = 'platform-icon-large ' + platformIcons[platform];
|
| | platformIconSmall.className = 'platform-icon-small ' + platformIcons[platform];
|
| | platformLoginText.textContent = `Login with ${name} Account`;
|
| |
|
| |
|
| | modal.classList.add('active');
|
| | document.body.style.overflow = 'hidden';
|
| |
|
| |
|
| | authSection.style.display = 'flex';
|
| | platformSection.style.display = 'none';
|
| | }
|
| |
|
| |
|
| | function closePlatformModal() {
|
| | modal.classList.remove('active');
|
| | document.body.style.overflow = '';
|
| | modalContent.classList.remove('fullscreen');
|
| |
|
| |
|
| | stopTimeTracking();
|
| |
|
| |
|
| | setTimeout(() => {
|
| | modalFrame.src = '';
|
| | authSection.style.display = 'flex';
|
| | platformSection.style.display = 'none';
|
| | loadingSpinner.classList.remove('hidden');
|
| | }, 300);
|
| | }
|
| |
|
| |
|
| | function loadPlatform(authMethod) {
|
| | console.log(`Loading ${currentPlatformName} with ${authMethod} authentication`);
|
| |
|
| |
|
| | authSection.style.display = 'none';
|
| | platformSection.style.display = 'block';
|
| |
|
| |
|
| | loadingSpinner.classList.remove('hidden');
|
| |
|
| |
|
| | modalFrame.src = currentPlatformURL;
|
| |
|
| |
|
| | modalFrame.onload = () => {
|
| | setTimeout(() => {
|
| | loadingSpinner.classList.add('hidden');
|
| | }, 500);
|
| | };
|
| |
|
| |
|
| | setTimeout(() => {
|
| | loadingSpinner.classList.add('hidden');
|
| | }, 3000);
|
| | }
|
| |
|
| |
|
| | googleSignInBtn.addEventListener('click', () => {
|
| | console.log('Google Sign-In clicked');
|
| | showNotification('Google Sign-In feature coming soon! Opening platform directly...', 'info');
|
| |
|
| |
|
| | 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);
|
| | });
|
| |
|
| |
|
| | platformSignInBtn.addEventListener('click', () => {
|
| | console.log('Platform Sign-In clicked');
|
| | showNotification(`Opening ${currentPlatformName} in new window...`, 'success');
|
| |
|
| |
|
| | startTimeTracking(currentPlatform);
|
| |
|
| |
|
| | 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`
|
| | );
|
| |
|
| |
|
| | setTimeout(() => {
|
| | closePlatformModal();
|
| | }, 500);
|
| | });
|
| |
|
| |
|
| | guestAccessBtn.addEventListener('click', () => {
|
| | console.log('Guest access clicked');
|
| | showNotification(`Opening ${currentPlatformName} web version...`, 'info');
|
| |
|
| |
|
| | 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`
|
| | );
|
| |
|
| |
|
| | setTimeout(() => {
|
| | closePlatformModal();
|
| | }, 500);
|
| | });
|
| |
|
| |
|
| | 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);
|
| |
|
| |
|
| | setTimeout(() => notification.classList.add('show'), 10);
|
| |
|
| |
|
| | setTimeout(() => {
|
| | notification.classList.remove('show');
|
| | setTimeout(() => notification.remove(), 300);
|
| | }, 3000);
|
| | }
|
| |
|
| |
|
| | closeBtn.addEventListener('click', closePlatformModal);
|
| |
|
| |
|
| | modal.addEventListener('click', (e) => {
|
| | if (e.target === modal) {
|
| | closePlatformModal();
|
| | }
|
| | });
|
| |
|
| |
|
| | refreshBtn.addEventListener('click', () => {
|
| | loadingSpinner.classList.remove('hidden');
|
| | modalFrame.src = modalFrame.src;
|
| |
|
| | setTimeout(() => {
|
| | loadingSpinner.classList.add('hidden');
|
| | }, 2000);
|
| | });
|
| |
|
| |
|
| | 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';
|
| | }
|
| | });
|
| |
|
| |
|
| | logoutBtn.addEventListener('click', () => {
|
| | showNotification('Logged out successfully', 'success');
|
| | authSection.style.display = 'flex';
|
| | platformSection.style.display = 'none';
|
| | modalFrame.src = '';
|
| | });
|
| |
|
| |
|
| | document.addEventListener('keydown', (e) => {
|
| | if (e.key === 'Escape' && modal.classList.contains('active')) {
|
| | closePlatformModal();
|
| | }
|
| | });
|
| |
|
| |
|
| | socialCards.forEach(card => {
|
| | card.addEventListener('mouseenter', () => {
|
| | card.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)';
|
| | });
|
| | });
|
| |
|
| |
|
| | 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'
|
| | });
|
| | }
|
| | });
|
| | });
|
| |
|
| |
|
| | 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';
|
| | }
|
| | }
|
| |
|
| |
|
| | window.addEventListener('load', () => {
|
| | document.body.style.opacity = '0';
|
| | setTimeout(() => {
|
| | document.body.style.transition = 'opacity 0.5s ease';
|
| | document.body.style.opacity = '1';
|
| | }, 100);
|
| | });
|
| |
|
| |
|
| | initParticles();
|
| | animateParticles();
|
| | updateGreeting();
|
| | initializeFavorites();
|
| | initializeNotes();
|
| | initializeAnalytics();
|
| | initializeTheme();
|
| | initializeCustomPlatforms();
|
| | initializeStatusIndicators();
|
| | initializeKeyboardShortcuts();
|
| | initializeHeaderControls();
|
| |
|
| |
|
| | 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;
|
| | });
|
| | }
|
| |
|
| |
|
| | 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');
|
| | }
|
| | }
|
| |
|
| |
|
| | 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;
|
| | });
|
| |
|
| |
|
| | 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`;
|
| | }
|
| |
|
| |
|
| | 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;
|
| |
|
| |
|
| | const newCard = container.lastElementChild;
|
| | initializeCardFeatures(newCard, platform.id);
|
| | }
|
| |
|
| | function initializeCardFeatures(card, platform) {
|
| |
|
| | 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);
|
| | });
|
| |
|
| |
|
| | 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);
|
| | });
|
| |
|
| |
|
| | 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');
|
| | }
|
| | });
|
| | }
|
| |
|
| |
|
| | 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);
|
| | });
|
| | }
|
| |
|
| |
|
| | function initializeStatusIndicators() {
|
| |
|
| |
|
| | document.querySelectorAll('.status-indicator').forEach(indicator => {
|
| | indicator.classList.remove('offline');
|
| | });
|
| | }
|
| |
|
| |
|
| | function initializeKeyboardShortcuts() {
|
| | document.addEventListener('keydown', (e) => {
|
| |
|
| | if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
|
| | return;
|
| | }
|
| |
|
| |
|
| | if (e.key === '?') {
|
| | e.preventDefault();
|
| | document.getElementById('shortcutsModal').classList.add('active');
|
| | }
|
| |
|
| |
|
| | if (e.ctrlKey && e.key === 'k') {
|
| | e.preventDefault();
|
| | document.getElementById('analyticsModal').classList.add('active');
|
| | updateAnalyticsDisplay();
|
| | }
|
| |
|
| |
|
| | if (e.ctrlKey && e.key === 'd') {
|
| | e.preventDefault();
|
| | document.getElementById('themeToggle').click();
|
| | }
|
| |
|
| |
|
| | if (e.ctrlKey && e.key === 'i') {
|
| | e.preventDefault();
|
| | document.getElementById('aiCaptionBtn').click();
|
| | }
|
| |
|
| |
|
| | 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();
|
| | }
|
| | }
|
| | });
|
| | }
|
| |
|
| |
|
| | function initializeHeaderControls() {
|
| |
|
| | 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');
|
| | });
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | document.getElementById('shortcutsBtn').addEventListener('click', () => {
|
| | document.getElementById('shortcutsModal').classList.add('active');
|
| | });
|
| |
|
| |
|
| | document.getElementById('analyticsBtn').addEventListener('click', () => {
|
| | document.getElementById('analyticsModal').classList.add('active');
|
| | updateAnalyticsDisplay();
|
| | });
|
| |
|
| |
|
| | document.getElementById('addPlatformBtn').addEventListener('click', () => {
|
| | document.getElementById('addPlatformModal').classList.add('active');
|
| | });
|
| | }
|
| |
|
| |
|
| | 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');
|
| | });
|
| |
|
| |
|
| | 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);
|
| |
|
| |
|
| |
|
| | 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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';
|
| |
|
| |
|
| | document.getElementById('aiCaptionBtn').addEventListener('click', () => {
|
| | document.getElementById('aiCaptionModal').classList.add('active');
|
| | document.body.style.overflow = 'hidden';
|
| | });
|
| |
|
| |
|
| | 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);
|
| |
|
| |
|
| | 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;
|
| |
|
| |
|
| | const reader = new FileReader();
|
| | reader.onload = (e) => {
|
| | imagePreview.src = e.target.result;
|
| | currentImageData = e.target.result;
|
| | };
|
| | reader.readAsDataURL(file);
|
| |
|
| |
|
| | uploadSection.style.display = 'none';
|
| | resultsSection.style.display = 'grid';
|
| |
|
| |
|
| | showLoadingState();
|
| |
|
| |
|
| | 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');
|
| |
|
| |
|
| | 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>`;
|
| |
|
| |
|
| | showNotification('Generating creative captions...', 'info');
|
| | const captions = await generateCaptions(description);
|
| | currentCaptions = captions;
|
| |
|
| | console.log('✓ Captions generated:', captions);
|
| | document.getElementById('aiCaptions').innerHTML = formatCaptions(captions);
|
| |
|
| |
|
| | 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 {
|
| |
|
| | 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 (response.status === 503) {
|
| | showNotification('AI model is loading, retrying in 3 seconds...', 'info');
|
| | await new Promise(resolve => setTimeout(resolve, 3000));
|
| | return getImageDescription(imageFile);
|
| | }
|
| |
|
| | throw new Error('Image API request failed');
|
| | }
|
| |
|
| | const result = await response.json();
|
| | console.log('Image description result:', result);
|
| |
|
| |
|
| | 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 || '';
|
| |
|
| |
|
| | 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) {
|
| |
|
| | 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) {
|
| |
|
| | 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) {
|
| |
|
| | 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>`;
|
| | }
|
| |
|
| |
|
| | 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');
|
| | });
|
| | }
|
| |
|
| |
|
| | document.querySelectorAll('.platform-post-btn').forEach(btn => {
|
| | btn.addEventListener('click', () => {
|
| | const platform = btn.getAttribute('data-platform');
|
| | postToPlatform(platform);
|
| | });
|
| | });
|
| |
|
| | function postToPlatform(platform) {
|
| |
|
| | const fullContent = `${currentCaptions.split('\n')[0]}\n\n${currentHashtags}`;
|
| | copyToClipboard(fullContent, `Content copied! Opening ${platform}...`);
|
| |
|
| |
|
| | 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);
|
| | }
|
| | }
|
| |
|
| |
|
| |
|
| | let ticking = false;
|
| | window.addEventListener('scroll', () => {
|
| | if (!ticking) {
|
| | window.requestAnimationFrame(() => {
|
| |
|
| | ticking = false;
|
| | });
|
| | ticking = true;
|
| | }
|
| | });
|
| |
|
| |
|
| | document.addEventListener('keydown', (e) => {
|
| |
|
| | 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'));
|
| | }
|
| | }
|
| | });
|
| |
|
| |
|
| | 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';
|
| | }
|
| | });
|
| |
|
| |
|
| | 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);
|
| | });
|
| | });
|
| |
|
| |
|
| | 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;');
|
| |
|