| |
|
|
| |
| function initTooltips() { |
| const tooltipElements = document.querySelectorAll('[data-tooltip]'); |
| |
| tooltipElements.forEach(element => { |
| element.addEventListener('mouseenter', (e) => { |
| const tooltipText = element.getAttribute('data-tooltip'); |
| const tooltip = document.createElement('div'); |
| tooltip.className = 'fixed z-50 px-3 py-2 text-sm bg-gray-900 text-white rounded-lg shadow-lg border border-gray-700 pointer-events-none'; |
| tooltip.textContent = tooltipText; |
| document.body.appendChild(tooltip); |
| |
| const rect = element.getBoundingClientRect(); |
| tooltip.style.left = `${rect.left + rect.width / 2 - tooltip.offsetWidth / 2}px`; |
| tooltip.style.top = `${rect.top - tooltip.offsetHeight - 10}px`; |
| |
| element._tooltip = tooltip; |
| }); |
| |
| element.addEventListener('mouseleave', (e) => { |
| if (element._tooltip) { |
| element._tooltip.remove(); |
| delete element._tooltip; |
| } |
| }); |
| }); |
| } |
|
|
| |
| function initThemeToggle() { |
| const themeToggle = document.querySelector('[data-theme-toggle]'); |
| if (!themeToggle) return; |
| |
| themeToggle.addEventListener('click', () => { |
| const html = document.documentElement; |
| const isDark = html.classList.contains('dark'); |
| |
| if (isDark) { |
| html.classList.remove('dark'); |
| localStorage.setItem('theme', 'light'); |
| } else { |
| html.classList.add('dark'); |
| localStorage.setItem('theme', 'dark'); |
| } |
| |
| |
| const icon = themeToggle.querySelector('i[data-feather]'); |
| if (icon) { |
| const newIcon = isDark ? 'sun' : 'moon'; |
| icon.setAttribute('data-feather', newIcon); |
| feather.replace(); |
| } |
| }); |
| } |
|
|
| |
| async function loadGitHubStats() { |
| try { |
| const response = await fetch('https://api.github.com/repos/tailwindlabs/tailwindcss'); |
| const data = await response.json(); |
| |
| const statsElement = document.querySelector('[data-github-stats]'); |
| if (statsElement) { |
| statsElement.innerHTML = ` |
| <div class="grid grid-cols-3 gap-4"> |
| <div class="text-center"> |
| <div class="text-2xl font-bold text-rose-400">${(data.stargazers_count / 1000).toFixed(1)}k</div> |
| <div class="text-gray-400 text-sm">Stars</div> |
| </div> |
| <div class="text-center"> |
| <div class="text-2xl font-bold text-rose-400">${data.forks_count}</div> |
| <div class="text-gray-400 text-sm">Forks</div> |
| </div> |
| <div class="text-center"> |
| <div class="text-2xl font-bold text-rose-400">${(data.watchers_count / 1000).toFixed(1)}k</div> |
| <div class="text-gray-400 text-sm">Watchers</div> |
| </div> |
| </div> |
| `; |
| } |
| } catch (error) { |
| console.log('GitHub stats loading failed, using fallback'); |
| } |
| } |
|
|
| |
| function initCodeRunner() { |
| const runButtons = document.querySelectorAll('[data-run-code]'); |
| |
| runButtons.forEach(button => { |
| button.addEventListener('click', async () => { |
| const originalText = button.textContent; |
| button.disabled = true; |
| button.innerHTML = '<div class="spinner w-5 h-5 border-2 border-rose-400 border-t-transparent rounded-full animate-spin"></div>'; |
| |
| |
| await new Promise(resolve => setTimeout(resolve, 1500)); |
| |
| button.disabled = false; |
| button.textContent = originalText; |
| |
| |
| const notification = document.createElement('div'); |
| notification.className = 'fixed bottom-4 right-4 bg-gradient-to-r from-rose-500 to-pink-500 text-white px-6 py-3 rounded-xl shadow-lg transform transition-all duration-300 translate-y-0 opacity-100'; |
| notification.textContent = 'Code executed successfully!'; |
| document.body.appendChild(notification); |
| |
| setTimeout(() => { |
| notification.classList.add('translate-y-8', 'opacity-0'); |
| setTimeout(() => notification.remove(), 300); |
| }, 3000); |
| }); |
| }); |
| } |
|
|
| |
| function initSearch() { |
| const searchInput = document.querySelector('[data-search-input]'); |
| const searchResults = document.querySelector('[data-search-results]'); |
| |
| if (!searchInput || !searchResults) return; |
| |
| let searchTimeout; |
| |
| searchInput.addEventListener('input', (e) => { |
| clearTimeout(searchTimeout); |
| |
| searchTimeout = setTimeout(() => { |
| const query = e.target.value.trim(); |
| |
| if (query.length < 2) { |
| searchResults.classList.add('hidden'); |
| return; |
| } |
| |
| |
| const results = [ |
| { type: 'file', name: 'main.js', path: '/src/main.js' }, |
| { type: 'component', name: 'Navbar', path: '/components/Navbar.js' }, |
| { type: 'style', name: 'global.css', path: '/styles/global.css' }, |
| { type: 'page', name: 'Dashboard', path: '/pages/dashboard.js' } |
| ]; |
| |
| searchResults.innerHTML = results.map(result => ` |
| <div class="p-3 hover:bg-gray-800/50 rounded-lg cursor-pointer border-b border-gray-700/50 last:border-0"> |
| <div class="flex items-center gap-3"> |
| <i data-feather="${result.type === 'file' ? 'file' : result.type === 'component' ? 'box' : 'layout'}" class="w-4 h-4 text-rose-400"></i> |
| <div> |
| <div class="font-medium text-white">${result.name}</div> |
| <div class="text-gray-400 text-sm">${result.path}</div> |
| </div> |
| </div> |
| </div> |
| `).join(''); |
| |
| searchResults.classList.remove('hidden'); |
| feather.replace(); |
| }, 300); |
| }); |
| |
| |
| document.addEventListener('click', (e) => { |
| if (!searchInput.contains(e.target) && !searchResults.contains(e.target)) { |
| searchResults.classList.add('hidden'); |
| } |
| }); |
| } |
|
|
| |
| document.addEventListener('DOMContentLoaded', () => { |
| |
| initTooltips(); |
| initThemeToggle(); |
| initCodeRunner(); |
| initSearch(); |
| |
| |
| loadGitHubStats(); |
| |
| |
| feather.replace(); |
| |
| |
| document.addEventListener('keydown', (e) => { |
| |
| if ((e.ctrlKey || e.metaKey) && e.key === 'k') { |
| e.preventDefault(); |
| const searchInput = document.querySelector('[data-search-input]'); |
| if (searchInput) { |
| searchInput.focus(); |
| } |
| } |
| |
| |
| if ((e.ctrlKey || e.metaKey) && e.key === '/') { |
| e.preventDefault(); |
| alert('Available shortcuts:\n\nCtrl/Cmd + K: Search\nCtrl/Cmd + /: This help\nCtrl/Cmd + S: Save\nCtrl/Cmd + E: New file'); |
| } |
| }); |
| |
| console.log('CodeCanvas initialized successfully! 🎨'); |
| }); |
|
|
| |
| window.CodeCanvas = { |
| initTooltips, |
| initThemeToggle, |
| loadGitHubStats, |
| initCodeRunner, |
| initSearch |
| }; |