(() => { // State let chats = loadChats(); let currentChatId = null; let abortController = null; let currentModel = null; let modelLoading = false; let previewVisible = false; let generatedHTML = ''; let selectedLocalModel = null; // Templates for different project types const templates = { vibecode: { name: "VibeCode App", description: "Modern web app with vibecoding aesthetics", structure: { html: ` VibeApp

VibeApp

Modern vibes, clean code, smooth UX

Dashboard

Clean overview of your data

Analytics

Real-time insights

Settings

Configure your vibe

`, js: `// VibeApp JavaScript console.log('VibeApp loaded!'); document.addEventListener('DOMContentLoaded', function() { // Add smooth animations const cards = document.querySelectorAll('.glass'); cards.forEach((card, index) => { card.style.opacity = '0'; card.style.transform = 'translateY(20px)'; setTimeout(() => { card.style.transition = 'all 0.5s ease'; card.style.opacity = '1'; card.style.transform = 'translateY(0)'; }, index * 100); }); });` } }, website: { name: "Clean Website", description: "Professional business website", structure: { html: ` Professional Website

Professional Solutions

We create amazing digital experiences

`, js: `// Professional Website JavaScript document.addEventListener('DOMContentLoaded', function() { console.log('Website loaded successfully'); });` } }, saas: { name: "SaaS Dashboard", description: "Analytics & admin panel", structure: { html: ` SaaS Dashboard

Dashboard

Overview

Total Users

1,234

Revenue

$12,345

Growth

+23%

Churn

-2.1%

Revenue Chart

`, js: `// SaaS Dashboard JavaScript document.addEventListener('DOMContentLoaded', function() { // Initialize chart const ctx = document.getElementById('revenueChart').getContext('2d'); new Chart(ctx, { type: 'line', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], datasets: [{ label: 'Revenue', data: [12000, 19000, 15000, 25000, 22000, 30000], borderColor: 'rgb(59, 130, 246)', backgroundColor: 'rgba(59, 130, 246, 0.1)', tension: 0.4 }] }, options: { responsive: true, scales: { y: { beginAtZero: true } } } }); });` } } }; // Elements const els = { mobileMenuBtn: document.getElementById('mobile-menu-btn'), chatList: document.getElementById('chat-list'), newChatBtn: document.getElementById('new-chat'), exportChatBtn: document.getElementById('export-chat'), togglePreviewBtn: document.getElementById('toggle-preview'), messages: document.getElementById('messages'), welcome: document.getElementById('welcome'), prompt: document.getElementById('prompt'), sendBtn: document.getElementById('send-btn'), stopBtn: document.getElementById('stop-btn'), hfToken: document.getElementById('hf-token'), modelSelect: document.getElementById('model-select'), templateSelect: document.getElementById('template-select'), statusText: document.getElementById('status-text'), modelStatus: document.getElementById('model-status'), previewPanel: document.getElementById('preview-panel'), previewFrame: document.getElementById('preview-frame'), refreshPreview: document.getElementById('refresh-preview'), openPreview: document.getElementById('open-preview'), closePreview: document.getElementById('close-preview'), }; // Init init(); function init() { // Load saved settings const savedToken = localStorage.getItem('hf_token') || ''; els.hfToken.value = savedToken; // Events els.newChatBtn.addEventListener('click', newChat); els.exportChatBtn.addEventListener('click', exportCurrentChat); els.togglePreviewBtn.addEventListener('click', togglePreview); els.sendBtn.addEventListener('click', onSend); els.stopBtn.addEventListener('click', stopGeneration); els.prompt.addEventListener('keydown', onPromptKeyDown); els.hfToken.addEventListener('change', () => { localStorage.setItem('hf_token', els.hfToken.value.trim()); toast('Hugging Face token saved.'); }); els.modelSelect.addEventListener('change', () => { localStorage.setItem('selected_model', els.modelSelect.value); updateModelStatus('Model changed. Will load on first use.'); handleModelSelectionChange(); }); els.templateSelect.addEventListener('change', () => { localStorage.setItem('selected_template', els.templateSelect.value); }); // Local model upload events els.uploadModelBtn.addEventListener('click', () => { els.modelFileInput.click(); }); els.modelFileInput.addEventListener('change', handleModelFileSelect); // Template selection events els.templateSelect.addEventListener('change', () => { localStorage.setItem('selected_template', els.templateSelect.value); }); // Enhanced button interactions addButtonInteractions(); // Preview events els.refreshPreview.addEventListener('click', refreshPreview); els.openPreview.addEventListener('click', openPreviewInWindow); els.closePreview.addEventListener('click', togglePreview); // Restore settings const savedModel = localStorage.getItem('selected_model'); if (savedModel) els.modelSelect.value = savedModel; const savedLocalModel = localStorage.getItem('selected_local_model'); if (savedLocalModel) { selectedLocalModel = JSON.parse(savedLocalModel); updateLocalModelDisplay(); } const savedTemplate = localStorage.getItem('selected_template'); if (savedTemplate) els.templateSelect.value = savedTemplate; // Render chat list renderChatList(); // Auto-select last chat or create new if (chats.length > 0) { openChat(chats[chats.length - 1].id); } else { newChat(); } // Auto-resize textarea autoResize(els.prompt); els.prompt.addEventListener('input', () => autoResize(els.prompt)); } function addButtonInteractions() { // Add ripple effect to all buttons document.querySelectorAll('button').forEach(button => { button.addEventListener('click', function(e) { const ripple = document.createElement('span'); 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.width = ripple.style.height = size + 'px'; ripple.style.left = x + 'px'; ripple.style.top = y + 'px'; ripple.classList.add('ripple'); this.appendChild(ripple); setTimeout(() => { ripple.remove(); }, 600); }); }); } // Add CSS for ripple effect const style = document.createElement('style'); style.textContent = ` .ripple { position: absolute; border-radius: 50%; background: rgba(255, 255, 255, 0.3); transform: scale(0); animation: ripple-animation 0.6s linear; pointer-events: none; } @keyframes ripple-animation { to { transform: scale(4); opacity: 0; } } `; document.head.appendChild(style); function loadChats() { try { return JSON.parse(localStorage.getItem('deepsite_chats') || '[]'); } catch { return []; } } function saveChats() { localStorage.setItem('deepsite_chats', JSON.stringify(chats)); } function renderChatList() { els.chatList.innerHTML = ''; if (chats.length === 0) { els.chatList.innerHTML = '
  • No chats yet
  • '; return; } chats.forEach(c => { const li = document.createElement('li'); li.className = 'group'; li.innerHTML = `
    ${formatDate(c.createdAt)}
    `; li.addEventListener('click', (e) => { const actBtn = e.target.closest('button[data-action]'); if (actBtn) { e.stopPropagation(); const action = actBtn.getAttribute('data-action'); if (action === 'rename') renameChat(c.id); if (action === 'delete') deleteChat(c.id); return; } openChat(c.id); }); els.chatList.appendChild(li); }); } function newChat() { const id = uid(); const chat = { id, title: 'New Chat', createdAt: Date.now(), messages: [] }; chats.push(chat); saveChats(); renderChatList(); openChat(id); } function openChat(id) { currentChatId = id; const chat = chats.find(c => c.id === id); if (!chat) return; renderMessages(chat); renderChatList(); els.prompt.focus(); } function deleteChat(id) { const idx = chats.findIndex(c => c.id === id); if (idx === -1) return; chats.splice(idx, 1); saveChats(); renderChatList(); if (currentChatId === id) { if (chats.length > 0) openChat(chats[chats.length - 1].id); else newChat(); } } function renameChat(id) { const chat = chats.find(c => c.id === id); if (!chat) return; const title = prompt('Rename chat:', chat.title); if (title && title.trim()) { chat.title = title.trim(); saveChats(); renderChatList(); } } function renderMessages(chat) { els.messages.innerHTML = ''; if (!chat.messages || chat.messages.length === 0) { els.messages.appendChild(els.welcome); els.welcome.classList.remove('hidden'); } else { els.welcome.classList.add('hidden'); chat.messages.forEach(m => { const el = renderMessage(m); els.messages.appendChild(el); }); scrollToBottom(); } } function renderMessage(message) { const wrap = document.createElement('div'); wrap.className = `message ${message.role}`; const avatar = document.createElement('div'); avatar.className = 'avatar'; avatar.textContent = message.role === 'user' ? 'U' : 'AI'; const bubble = document.createElement('div'); bubble.className = 'bubble'; bubble.innerHTML = escapeHTML(message.content || ''); wrap.appendChild(avatar); wrap.appendChild(bubble); return wrap; } async function onSend() { const text = els.prompt.value.trim(); if (!text) return; // Ensure chat exists if (!currentChatId) newChat(); const chat = chats.find(c => c.id === currentChatId); // Show status setStatus('Thinking...'); // Append user message const userMsg = { role: 'user', content: text }; chat.messages.push(userMsg); const userEl = renderMessage(userMsg); els.messages.appendChild(userEl); els.welcome.classList.add('hidden'); scrollToBottom(); // Clear prompt els.prompt.value = ''; autoResize(els.prompt); // Prepare assistant message placeholder const assistantMsg = { role: 'assistant', content: '', type: 'code' }; chat.messages.push(assistantMsg); const assistantEl = renderMessage(assistantMsg); assistantEl.querySelector('.bubble').innerHTML = ''; els.messages.appendChild(assistantEl); // UI state els.sendBtn.disabled = true; els.stopBtn.classList.remove('hidden'); setStatus('Generating code...'); // Create enhanced prompt for code generation const template = els.templateSelect.value; const enhancedPrompt = createEnhancedPrompt(text, template); try { // Simulate AI response with template-based generation const generatedCode = await generateCode(enhancedPrompt, template); if (generatedCode) { assistantMsg.content = generatedCode; const bubble = assistantEl.querySelector('.bubble'); bubble.innerHTML = formatCodeDisplay(generatedCode); // Auto-update preview if visible if (previewVisible) { updatePreview(generatedCode); } // Add "Run Preview" button addPreviewButton(assistantEl, generatedCode); } } catch (error) { console.error('Generation error:', error); toast('Generation failed. Please try again.'); const bubble = assistantEl.querySelector('.bubble'); if (bubble && !bubble.textContent.trim()) { bubble.textContent = 'Sorry, something went wrong while generating the code.'; } } finally { setStatus('Ready'); els.sendBtn.disabled = false; els.stopBtn.classList.add('hidden'); saveChats(); } } function createEnhancedPrompt(userInput, template) { const systemPrompts = { vibecode: `You are an expert full-stack developer specializing in modern, trendy web applications with vibecoding aesthetics. Create clean, responsive code using: - Tailwind CSS for styling - Modern JavaScript (ES6+) - Gradient backgrounds and glassmorphism effects - Smooth animations and transitions - Mobile-first responsive design Generate complete, functional HTML code for: ${userInput}`, website: `You are a professional web developer creating clean, modern websites. Focus on: - Semantic HTML structure - Tailwind CSS for professional styling - Responsive design principles - Accessibility best practices - Clean, maintainable code Generate complete HTML for: ${userInput}`, saas: `You are a SaaS developer creating admin dashboards and business applications. Create: - Professional dashboard layouts - Data visualization components - User management interfaces - Analytics and reporting features - Modern UI/UX patterns Generate complete HTML for: ${userInput}`, landing: `You are a landing page specialist creating conversion-optimized pages. Focus on: - Hero sections with compelling CTAs - Feature showcases - Social proof sections - Contact/lead capture forms - Mobile-optimized designs Generate complete HTML for: ${userInput}`, portfolio: `You are a portfolio designer creating impressive personal websites. Create: - Creative layouts showcasing projects - About sections with personality - Contact forms and social links - Interactive elements - Performance-optimized code Generate complete HTML for: ${userInput}`, ecommerce: `You are an e-commerce developer creating online store interfaces. Build: - Product catalog layouts - Shopping cart functionality - Checkout processes - Search and filtering - Modern e-commerce UX Generate complete HTML for: ${userInput}`, blog: `You are a blog/CMS developer creating content-focused websites. Create: - Clean reading layouts - Article metadata - Comment systems - Author profiles - Content organization Generate complete HTML for: ${userInput}` }; return systemPrompts[template] || systemPrompts.vibecode; } async function generateCode(prompt, template) { // For demo purposes, return template-based generated code // In a real implementation, this would call the local model // Simulate processing time await new Promise(resolve => setTimeout(resolve, 1500)); const templateStruct = templates[template] || templates.vibecode; // Enhance the template based on user input let generatedHTML = templateStruct.structure.html; let generatedJS = templateStruct.structure.js; // Simple keyword replacement based on user input const keywords = prompt.toLowerCase(); if (keywords.includes('dark') || keywords.includes('night')) { generatedHTML = generatedHTML.replace('bg-white', 'bg-gray-900') .replace('text-gray-900', 'text-white') .replace('text-gray-600', 'text-gray-300'); } if (keywords.includes('colorful') || keywords.includes('rainbow')) { generatedHTML = generatedHTML.replace( 'background: linear-gradient(135deg, #667eea 0%, #764ba2 100%)', 'background: linear-gradient(135deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4, #feca57)' ); } if (keywords.includes('dashboard') || keywords.includes('analytics')) { generatedHTML = generatedHTML.replace('VibeApp', 'DataViz Dashboard') .replace('Modern vibes, clean code, smooth UX', 'Real-time insights and analytics'); } return { html: generatedHTML, js: generatedJS, preview: generatedHTML.replace('', ``) }; } function formatCodeDisplay(codeObj) { return `

    Generated HTML

    ${escapeHTML(codeObj.html)}

    JavaScript

    ${escapeHTML(codeObj.js)}
    `; } function addPreviewButton(assistantEl, codeObj) { // Already handled in formatCodeDisplay } function runPreview(previewHTML) { generatedHTML = previewHTML; if (!previewVisible) { togglePreview(); } updatePreview(previewHTML); } function togglePreview() { previewVisible = !previewVisible; if (previewVisible) { els.previewPanel.classList.remove('hidden'); els.togglePreviewBtn.textContent = 'Hide Preview'; if (generatedHTML) { updatePreview(generatedHTML); } } else { els.previewPanel.classList.add('hidden'); els.togglePreviewBtn.textContent = 'Preview'; } } function updatePreview(htmlContent) { // Create a complete HTML document if needed if (!htmlContent.includes('Generated Code${htmlContent}`; } // Update iframe els.previewFrame.srcdoc = htmlContent; toast('Preview updated!'); } function refreshPreview() { if (generatedHTML) { updatePreview(generatedHTML); toast('Preview refreshed!'); } } function openPreviewInWindow() { if (generatedHTML) { const newWindow = window.open('', '_blank'); newWindow.document.write(generatedHTML); newWindow.document.close(); } } function stopGeneration() { abortController = null; els.stopBtn.classList.add('hidden'); els.sendBtn.disabled = false; setStatus('Stopped'); } function onPromptKeyDown(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); onSend(); } } function exportCurrentChat() { const chat = chats.find(c => c.id === currentChatId); if (!chat) return; const data = { title: chat.title, model: els.modelSelect.value, createdAt: chat.createdAt, messages: chat.messages }; const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${sanitizeFilename(chat.title || 'chat')}.json`; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); } function scrollToBottom() { els.messages.scrollTo({ top: els.messages.scrollHeight, behavior: 'smooth' }); } function autoResize(el) { el.style.height = 'auto'; el.style.height = Math.min(el.scrollHeight, 200) + 'px'; } function setStatus(text) { els.statusText.textContent = text; } function toast(msg) { // Simple non-blocking toast const t = document.createElement('div'); t.textContent = msg; t.className = 'fixed bottom-4 left-1/2 -translate-x-1/2 px-4 py-2 bg-gray-900 text-white text-sm rounded-md shadow-lg z-[60]'; document.body.appendChild(t); setTimeout(() => t.remove(), 2200); } function updateModelStatus(msg) { els.modelStatus.textContent = msg ? `• ${msg}` : ''; } // Quick template functions window.quickTemplate = function(template) { els.templateSelect.value = template; const templateInfo = templates[template]; if (templateInfo) { els.prompt.value = `Create a ${templateInfo.description}`; autoResize(els.prompt); } }; window.runPreview = runPreview; function uid() { return Math.random().toString(36).slice(2) + Date.now().toString(36); } function escapeHTML(str) { return String(str).replace(/[&<>"']/g, s => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[s])); } function formatDate(ts) { try { return new Date(ts).toLocaleString(); } catch { return ''; } } function sanitizeFilename(name) { return String(name).replace(/[^\w\-]+/g, '_').slice(0, 64); } async function safeText(res) { try { return await res.text(); } catch { return ''; } } })();