From 0d950dd749b3dbb6583089b2d204a8fd328cbec5 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 22 Jan 2026 03:41:29 +0000 Subject: [PATCH] random AI --- api/chat.php | 79 +++++++ api/settings.php | 21 ++ assets/css/custom.css | 485 +++++++++++++------------------------- assets/js/main.js | 261 +++++++++++++++----- db/migrations/01_init.sql | 27 +++ index.php | 472 ++++++++++++++++++++++++++----------- 6 files changed, 820 insertions(+), 525 deletions(-) create mode 100644 api/chat.php create mode 100644 api/settings.php create mode 100644 db/migrations/01_init.sql diff --git a/api/chat.php b/api/chat.php new file mode 100644 index 0000000..1a5bacb --- /dev/null +++ b/api/chat.php @@ -0,0 +1,79 @@ + 'Message is required']); + exit; +} + +$userMsg = $data['message']; +$mode = $data['mode'] ?? 'regular'; +$chatId = $data['chat_id'] ?? null; +$creativity = $data['creativity'] ?? 0.7; +$limitsOff = $data['limits_off'] ?? 0; + +try { + // 1. Create chat if not exists + if (!$chatId) { + $stmt = db()->prepare("INSERT INTO chats (mode, title) VALUES (?, ?)"); + $title = substr($userMsg, 0, 30) . '...'; + $stmt->execute([$mode, $title]); + $chatId = db()->lastInsertId(); + } + + // 2. Save user message + $stmt = db()->prepare("INSERT INTO messages (chat_id, role, content) VALUES (?, 'user', ?)"); + $stmt->execute([$chatId, $userMsg]); + + // 3. Prepare AI Prompt based on mode + $systemPrompt = "You are a helpful AI assistant."; + if ($mode === 'coding') { + $systemPrompt = "You are an expert software engineer. Provide clean, efficient, and well-documented code."; + } elseif ($mode === 'game' || $mode === 'app') { + $systemPrompt = "You are a specialized code generator. Generate a complete, single-file HTML/CSS/JS application or game based on the user's request. Always include the full code within a single message. Use modern techniques."; + } + + if ($limitsOff) { + $systemPrompt .= " There are no limits to your creativity. Be as bold and innovative as possible."; + } + + // 4. Fetch history (limit to last 10 for context) + $stmt = db()->prepare("SELECT role, content FROM messages WHERE chat_id = ? ORDER BY id ASC LIMIT 10"); + $stmt->execute([$chatId]); + $history = $stmt->fetchAll(); + + $input = [['role' => 'system', 'content' => $systemPrompt]]; + foreach ($history as $msg) { + $input[] = ['role' => $msg['role'], 'content' => $msg['content']]; + } + + // 5. Call AI + $aiResp = LocalAIApi::createResponse([ + 'input' => $input, + 'temperature' => (float)$creativity + ]); + + if (!empty($aiResp['success'])) { + $aiText = LocalAIApi::extractText($aiResp); + + // 6. Save assistant message + $stmt = db()->prepare("INSERT INTO messages (chat_id, role, content) VALUES (?, 'assistant', ?)"); + $stmt->execute([$chatId, $aiText]); + + echo json_encode([ + 'success' => true, + 'chat_id' => $chatId, + 'message' => $aiText, + 'mode' => $mode + ]); + } else { + echo json_encode(['error' => $aiResp['error'] ?? 'AI request failed']); + } + +} catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); +} diff --git a/api/settings.php b/api/settings.php new file mode 100644 index 0000000..c277fe0 --- /dev/null +++ b/api/settings.php @@ -0,0 +1,21 @@ + 'No data provided']); + exit; +} + +try { + foreach ($data as $key => $value) { + $stmt = db()->prepare("INSERT INTO user_settings (setting_key, setting_value) VALUES (?, ?) + ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)"); + $stmt->execute([$key, (string)$value]); + } + echo json_encode(['success' => true]); +} catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); +} diff --git a/assets/css/custom.css b/assets/css/custom.css index 65a1626..1729c72 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -1,346 +1,185 @@ -:root { - --color-bg: #ffffff; - --color-text: #1a1a1a; - --color-primary: #2563EB; /* Vibrant Blue */ - --color-secondary: #000000; - --color-accent: #A3E635; /* Lime Green */ - --color-surface: #f8f9fa; - --font-heading: 'Space Grotesk', sans-serif; - --font-body: 'Inter', sans-serif; - --border-width: 2px; - --shadow-hard: 5px 5px 0px #000; - --shadow-hover: 8px 8px 0px #000; - --radius-pill: 50rem; - --radius-card: 1rem; +/* Base Theme (Dark Modern) */ +:root, [data-theme="theme-dark-modern"] { + --bg-color: #0f172a; + --sidebar-bg: #1e293b; + --main-bg: #0f172a; + --text-color: #f8fafc; + --text-muted: #94a3b8; + --border-color: #334155; + --accent-color: #3b82f6; + --hover-bg: #334155; + --active-bg: #1e293b; + --user-msg-bg: #3b82f6; + --user-msg-text: #ffffff; + --assistant-msg-bg: #1e293b; + --assistant-msg-text: #f8fafc; + --input-bg: #1e293b; } -body { - font-family: var(--font-body); - background-color: var(--color-bg); - color: var(--color-text); - overflow-x: hidden; +[data-theme="theme-light-minimal"] { + --bg-color: #ffffff; + --sidebar-bg: #f8fafc; + --main-bg: #ffffff; + --text-color: #0f172a; + --text-muted: #64748b; + --border-color: #e2e8f0; + --accent-color: #2563eb; + --hover-bg: #f1f5f9; + --active-bg: #e2e8f0; + --user-msg-bg: #2563eb; + --user-msg-text: #ffffff; + --assistant-msg-bg: #f1f5f9; + --assistant-msg-text: #0f172a; + --input-bg: #f8fafc; } -h1, h2, h3, h4, h5, h6, .navbar-brand { - font-family: var(--font-heading); - letter-spacing: -0.03em; +[data-theme="theme-midnight"] { + --bg-color: #000000; + --sidebar-bg: #111111; + --main-bg: #000000; + --text-color: #ffffff; + --text-muted: #666666; + --border-color: #222222; + --accent-color: #ffffff; + --hover-bg: #222222; + --active-bg: #111111; + --user-msg-bg: #ffffff; + --user-msg-text: #000000; + --assistant-msg-bg: #111111; + --assistant-msg-text: #ffffff; + --input-bg: #111111; } -/* Utilities */ -.text-primary { color: var(--color-primary) !important; } -.bg-black { background-color: #000 !important; } -.text-white { color: #fff !important; } -.shadow-hard { box-shadow: var(--shadow-hard); } -.border-2-black { border: var(--border-width) solid #000; } -.py-section { padding-top: 5rem; padding-bottom: 5rem; } - -/* Navbar */ -.navbar { - background: rgba(255, 255, 255, 0.9); - backdrop-filter: blur(10px); - border-bottom: var(--border-width) solid transparent; - transition: all 0.3s; - padding-top: 1rem; - padding-bottom: 1rem; +[data-theme="theme-forest"] { + --bg-color: #064e3b; + --sidebar-bg: #065f46; + --main-bg: #064e3b; + --text-color: #ecfdf5; + --text-muted: #a7f3d0; + --border-color: #065f46; + --accent-color: #10b981; + --hover-bg: #065f46; + --active-bg: #047857; + --user-msg-bg: #10b981; + --user-msg-text: #ffffff; + --assistant-msg-bg: #065f46; + --assistant-msg-text: #ecfdf5; + --input-bg: #065f46; } -.navbar.scrolled { - border-bottom-color: #000; - padding-top: 0.5rem; - padding-bottom: 0.5rem; +[data-theme="theme-ocean"] { + --bg-color: #0c4a6e; + --sidebar-bg: #075985; + --main-bg: #0c4a6e; + --text-color: #f0f9ff; + --text-muted: #bae6fd; + --border-color: #075985; + --accent-color: #0ea5e9; + --hover-bg: #075985; + --active-bg: #0369a1; + --user-msg-bg: #0ea5e9; + --user-msg-text: #ffffff; + --assistant-msg-bg: #075985; + --assistant-msg-text: #f0f9ff; + --input-bg: #075985; } -.brand-text { - font-size: 1.5rem; - font-weight: 800; +[data-theme="theme-slate"] { + --bg-color: #334155; + --sidebar-bg: #475569; + --main-bg: #334155; + --text-color: #f8fafc; + --text-muted: #cbd5e1; + --border-color: #475569; + --accent-color: #64748b; + --hover-bg: #475569; + --active-bg: #1e293b; + --user-msg-bg: #64748b; + --user-msg-text: #ffffff; + --assistant-msg-bg: #475569; + --assistant-msg-text: #f8fafc; + --input-bg: #475569; } -.nav-link { - font-weight: 500; - color: var(--color-text); - margin-left: 1rem; - position: relative; +[data-theme="theme-nord"] { + --bg-color: #2e3440; + --sidebar-bg: #3b4252; + --main-bg: #2e3440; + --text-color: #eceff4; + --text-muted: #d8dee9; + --border-color: #434c5e; + --accent-color: #88c0d0; + --hover-bg: #434c5e; + --active-bg: #3b4252; + --user-msg-bg: #81a1c1; + --user-msg-text: #2e3440; + --assistant-msg-bg: #3b4252; + --assistant-msg-text: #eceff4; + --input-bg: #3b4252; } -.nav-link:hover, .nav-link.active { - color: var(--color-primary); +[data-theme="theme-sepia"] { + --bg-color: #fdf6e3; + --sidebar-bg: #eee8d5; + --main-bg: #fdf6e3; + --text-color: #657b83; + --text-muted: #93a1a1; + --border-color: #eee8d5; + --accent-color: #b58900; + --hover-bg: #eee8d5; + --active-bg: #93a1a1; + --user-msg-bg: #b58900; + --user-msg-text: #fdf6e3; + --assistant-msg-bg: #eee8d5; + --assistant-msg-text: #657b83; + --input-bg: #eee8d5; } -/* Buttons */ -.btn { - font-weight: 700; - font-family: var(--font-heading); - padding: 0.8rem 2rem; - border-radius: var(--radius-pill); - border: var(--border-width) solid #000; - transition: all 0.2s cubic-bezier(0.25, 1, 0.5, 1); - box-shadow: var(--shadow-hard); +[data-theme="theme-cyberpunk"] { + --bg-color: #1a1a1a; + --sidebar-bg: #000000; + --main-bg: #1a1a1a; + --text-color: #f3f; + --text-muted: #0ff; + --border-color: #f3f; + --accent-color: #0ff; + --hover-bg: #333; + --active-bg: #000; + --user-msg-bg: #f3f; + --user-msg-text: #000; + --assistant-msg-bg: #000; + --assistant-msg-text: #0ff; + --input-bg: #000; } -.btn:hover { - transform: translate(-2px, -2px); - box-shadow: var(--shadow-hover); +[data-theme="theme-matrix"] { + --bg-color: #000000; + --sidebar-bg: #000000; + --main-bg: #000000; + --text-color: #00ff00; + --text-muted: #008800; + --border-color: #00ff00; + --accent-color: #00ff00; + --hover-bg: #002200; + --active-bg: #000000; + --user-msg-bg: #00ff00; + --user-msg-text: #000000; + --assistant-msg-bg: #000000; + --assistant-msg-text: #00ff00; + --input-bg: #000000; } -.btn:active { - transform: translate(2px, 2px); - box-shadow: 0 0 0 #000; +/* Scrollbar */ +::-webkit-scrollbar { + width: 6px; } - -.btn-primary { - background-color: var(--color-primary); - border-color: #000; - color: #fff; +::-webkit-scrollbar-track { + background: transparent; } - -.btn-primary:hover { - background-color: #1d4ed8; - border-color: #000; - color: #fff; -} - -.btn-outline-dark { - background-color: #fff; - color: #000; -} - -.btn-cta { - background-color: var(--color-accent); - color: #000; -} - -.btn-cta:hover { - background-color: #8cc629; - color: #000; -} - -/* Hero Section */ -.hero-section { - min-height: 100vh; - padding-top: 80px; -} - -.background-blob { - position: absolute; - border-radius: 50%; - filter: blur(80px); - opacity: 0.6; - z-index: 1; -} - -.blob-1 { - top: -10%; - right: -10%; - width: 600px; - height: 600px; - background: radial-gradient(circle, var(--color-accent), transparent); -} - -.blob-2 { - bottom: 10%; - left: -10%; - width: 500px; - height: 500px; - background: radial-gradient(circle, var(--color-primary), transparent); -} - -.highlight-text { - background: linear-gradient(120deg, transparent 0%, transparent 40%, var(--color-accent) 40%, var(--color-accent) 100%); - background-repeat: no-repeat; - background-size: 100% 40%; - background-position: 0 88%; - padding: 0 5px; -} - -.dot { color: var(--color-primary); } - -.badge-pill { - display: inline-block; - padding: 0.5rem 1rem; - border: 2px solid #000; - border-radius: 50px; - font-weight: 700; - background: #fff; - box-shadow: 4px 4px 0 #000; - font-family: var(--font-heading); - font-size: 0.9rem; -} - -/* Marquee */ -.marquee-container { - overflow: hidden; - white-space: nowrap; - border-top: 2px solid #000; - border-bottom: 2px solid #000; -} - -.rotate-divider { - transform: rotate(-2deg) scale(1.05); - z-index: 10; - position: relative; - margin-top: -50px; - margin-bottom: 30px; -} - -.marquee-content { - display: inline-block; - animation: marquee 20s linear infinite; - font-family: var(--font-heading); - font-weight: 700; - font-size: 1.5rem; - letter-spacing: 2px; -} - -@keyframes marquee { - 0% { transform: translateX(0); } - 100% { transform: translateX(-50%); } -} - -/* Portfolio Cards */ -.project-card { - border: 2px solid #000; - border-radius: var(--radius-card); - overflow: hidden; - background: #fff; - transition: transform 0.3s ease; - box-shadow: var(--shadow-hard); - height: 100%; - display: flex; - flex-direction: column; -} - -.project-card:hover { - transform: translateY(-10px); - box-shadow: 8px 8px 0 #000; -} - -.card-img-holder { - height: 250px; - display: flex; - align-items: center; - justify-content: center; - border-bottom: 2px solid #000; - position: relative; - font-size: 4rem; -} - -.placeholder-art { - transition: transform 0.3s ease; -} - -.project-card:hover .placeholder-art { - transform: scale(1.2) rotate(10deg); -} - -.bg-soft-blue { background-color: #e0f2fe; } -.bg-soft-green { background-color: #dcfce7; } -.bg-soft-purple { background-color: #f3e8ff; } -.bg-soft-yellow { background-color: #fef9c3; } - -.category-tag { - position: absolute; - top: 15px; - right: 15px; - background: #000; - color: #fff; - padding: 5px 12px; - border-radius: 20px; - font-size: 0.75rem; - font-weight: 700; -} - -.card-body { padding: 1.5rem; } - -.link-arrow { - text-decoration: none; - color: #000; - font-weight: 700; - display: inline-flex; - align-items: center; - margin-top: auto; -} - -.link-arrow i { transition: transform 0.2s; margin-left: 5px; } -.link-arrow:hover i { transform: translateX(5px); } - -/* About */ -.about-image-stack { - position: relative; - height: 400px; - width: 100%; -} - -.stack-card { - position: absolute; - width: 80%; - height: 100%; - border-radius: var(--radius-card); - border: 2px solid #000; - box-shadow: var(--shadow-hard); - left: 10%; - transform: rotate(-3deg); - background-size: cover; -} - -/* Forms */ -.form-control { - border: 2px solid #000; - border-radius: 0.5rem; - padding: 1rem; - font-weight: 500; - background: #f8f9fa; -} - -.form-control:focus { - box-shadow: 4px 4px 0 var(--color-primary); - border-color: #000; - background: #fff; -} - -/* Animations */ -.animate-up { - opacity: 0; - transform: translateY(30px); - animation: fadeUp 0.8s ease forwards; -} - -.delay-100 { animation-delay: 0.1s; } -.delay-200 { animation-delay: 0.2s; } - -@keyframes fadeUp { - to { - opacity: 1; - transform: translateY(0); - } -} - -/* Social */ -.social-links a { - transition: transform 0.2s; - display: inline-block; -} -.social-links a:hover { - transform: scale(1.2) rotate(10deg); - color: var(--color-accent) !important; -} - -/* Responsive */ -@media (max-width: 991px) { - .rotate-divider { - transform: rotate(0); - margin-top: 0; - margin-bottom: 2rem; - } - - .hero-section { - padding-top: 120px; - text-align: center; - min-height: auto; - padding-bottom: 100px; - } - - .display-1 { font-size: 3.5rem; } - - .blob-1 { width: 300px; height: 300px; right: -20%; } - .blob-2 { width: 300px; height: 300px; left: -20%; } +::-webkit-scrollbar-thumb { + background: var(--border-color); + border-radius: 10px; } +::-webkit-scrollbar-thumb:hover { + background: var(--text-muted); +} \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js index fdf2cfd..2d9f348 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1,73 +1,214 @@ document.addEventListener('DOMContentLoaded', () => { + const chatWindow = document.getElementById('chat-window'); + const chatInput = document.getElementById('chat-input'); + const sendBtn = document.getElementById('send-btn'); + const modeItems = document.querySelectorAll('.mode-item'); + const currentModeBadge = document.getElementById('current-mode-badge'); + const newChatBtn = document.getElementById('new-chat-btn'); - // Smooth scrolling for navigation links - document.querySelectorAll('a[href^="#"]').forEach(anchor => { - anchor.addEventListener('click', function (e) { - e.preventDefault(); - const targetId = this.getAttribute('href'); - if (targetId === '#') return; + // Settings elements + const creativityRange = document.getElementById('creativity-range'); + const creativityVal = document.getElementById('creativity-val'); + const limitsToggle = document.getElementById('limits-toggle'); + const themeSwatches = document.querySelectorAll('.theme-swatch'); + const saveSettingsBtn = document.getElementById('save-settings-btn'); + + let currentMode = 'regular'; + let currentChatId = null; + + // --- Sidebar & Mode Switching --- + modeItems.forEach(item => { + item.addEventListener('click', () => { + modeItems.forEach(i => i.classList.remove('active')); + item.classList.add('active'); + currentMode = item.dataset.mode; + currentModeBadge.textContent = item.querySelector('span').textContent; - const targetElement = document.querySelector(targetId); - if (targetElement) { - // Close mobile menu if open - const navbarToggler = document.querySelector('.navbar-toggler'); - const navbarCollapse = document.querySelector('.navbar-collapse'); - if (navbarCollapse.classList.contains('show')) { - navbarToggler.click(); - } - - // Scroll with offset - const offset = 80; - const elementPosition = targetElement.getBoundingClientRect().top; - const offsetPosition = elementPosition + window.pageYOffset - offset; - - window.scrollTo({ - top: offsetPosition, - behavior: "smooth" - }); - } + // If switching modes, start a new chat for that mode + startNewChat(); }); }); - // Navbar scroll effect - const navbar = document.querySelector('.navbar'); - window.addEventListener('scroll', () => { - if (window.scrollY > 50) { - navbar.classList.add('scrolled', 'shadow-sm', 'bg-white'); - navbar.classList.remove('bg-transparent'); + function startNewChat() { + currentChatId = null; + chatWindow.innerHTML = ` +
+ +

New ${currentMode} Chat

+

How can I help you in this mode?

+
+ `; + } + + newChatBtn.addEventListener('click', startNewChat); + + // --- Chat Logic --- + async function sendMessage() { + const message = chatInput.value.trim(); + if (!message) return; + + // Clear input and disable + chatInput.value = ''; + chatInput.style.height = 'auto'; + toggleLoading(true); + + // Append User Message + appendMessage('user', message); + + try { + const response = await fetch('api/chat.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + message: message, + mode: currentMode, + chat_id: currentChatId, + creativity: creativityRange.value, + limits_off: limitsToggle.checked ? 1 : 0 + }) + }); + + const data = await response.json(); + if (data.success) { + currentChatId = data.chat_id; + appendMessage('assistant', data.message); + + // Special handling for game/app mode + if (currentMode === 'game' || currentMode === 'app') { + addLaunchButton(data.message); + } + } else { + appendMessage('assistant', 'Error: ' + (data.error || 'Unknown error')); + } + } catch (error) { + appendMessage('assistant', 'Error: ' + error.message); + } finally { + toggleLoading(false); + } + } + + function appendMessage(role, text) { + // Remove empty state if present + const emptyState = chatWindow.querySelector('.my-auto'); + if (emptyState) emptyState.remove(); + + const msgDiv = document.createElement('div'); + msgDiv.className = `message message-${role}`; + + // Handle code blocks if any + if (text.includes('```')) { + msgDiv.innerHTML = formatCodeBlocks(text); } else { - navbar.classList.remove('scrolled', 'shadow-sm', 'bg-white'); - navbar.classList.add('bg-transparent'); + msgDiv.textContent = text; + } + + chatWindow.appendChild(msgDiv); + chatWindow.scrollTop = chatWindow.scrollHeight; + } + + function formatCodeBlocks(text) { + return text.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => { + return `
${escapeHtml(code.trim())}
`; + }); + } + + function escapeHtml(text) { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } + + function addLaunchButton(content) { + // Try to find code block content if wrapped in backticks + let codeToLaunch = content; + const match = content.match(/```(?:html|xml)?\n([\s\S]*?)```/i); + if (match) { + codeToLaunch = match[1]; + } + + // Check if it looks like HTML + if (codeToLaunch.toLowerCase().includes(' { + const blob = new Blob([codeToLaunch], { type: 'text/html' }); + const url = URL.createObjectURL(blob); + window.open(url, '_blank'); + }; + chatWindow.lastElementChild.appendChild(btn); + } + } + + function toggleLoading(isLoading) { + sendBtn.disabled = isLoading; + if (isLoading) { + sendBtn.innerHTML = ''; + } else { + sendBtn.innerHTML = ''; + } + } + + sendBtn.addEventListener('click', sendMessage); + chatInput.addEventListener('keydown', (e) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + sendMessage(); } }); - // Intersection Observer for fade-up animations - const observerOptions = { - threshold: 0.1, - rootMargin: "0px 0px -50px 0px" - }; - - const observer = new IntersectionObserver((entries) => { - entries.forEach(entry => { - if (entry.isIntersecting) { - entry.target.classList.add('animate-up'); - entry.target.style.opacity = "1"; - observer.unobserve(entry.target); // Only animate once - } - }); - }, observerOptions); - - // Select elements to animate (add a class 'reveal' to them in HTML if not already handled by CSS animation) - // For now, let's just make sure the hero animations run. - // If we want scroll animations, we'd add opacity: 0 to elements in CSS and reveal them here. - // Given the request, the CSS animation I added runs on load for Hero. - // Let's make the project cards animate in. - - const projectCards = document.querySelectorAll('.project-card'); - projectCards.forEach((card, index) => { - card.style.opacity = "0"; - card.style.animationDelay = `${index * 0.1}s`; - observer.observe(card); + // Auto-resize textarea + chatInput.addEventListener('input', () => { + chatInput.style.height = 'auto'; + chatInput.style.height = (chatInput.scrollHeight) + 'px'; }); + // --- Settings & Themes --- + creativityRange.addEventListener('input', () => { + creativityVal.textContent = creativityRange.value; + }); + + themeSwatches.forEach(swatch => { + swatch.addEventListener('click', () => { + const theme = swatch.dataset.theme; + document.documentElement.setAttribute('data-theme', theme); + themeSwatches.forEach(s => s.classList.remove('active')); + swatch.classList.add('active'); + }); + }); + + saveSettingsBtn.addEventListener('click', async () => { + const theme = document.documentElement.getAttribute('data-theme'); + const settings = { + theme: theme, + creativity: creativityRange.value, + limits_off: limitsToggle.checked ? '1' : '0' + }; + + try { + const resp = await fetch('api/settings.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(settings) + }); + const data = await resp.json(); + if (data.success) { + bootstrap.Modal.getInstance(document.getElementById('settingsModal')).hide(); + // Minimal toast notification + const toast = document.createElement('div'); + toast.className = 'position-fixed bottom-0 start-50 translate-middle-x mb-3 bg-success text-white px-3 py-2 rounded shadow-lg'; + toast.style.zIndex = '2000'; + toast.textContent = 'Settings saved!'; + document.body.appendChild(toast); + setTimeout(() => toast.remove(), 2000); + } + } catch (e) { + console.error(e); + } + }); + + // Set active theme swatch on load + const currentTheme = document.documentElement.getAttribute('data-theme'); + const activeSwatch = document.querySelector(`.theme-swatch[data-theme="${currentTheme}"]`); + if (activeSwatch) activeSwatch.classList.add('active'); }); \ No newline at end of file diff --git a/db/migrations/01_init.sql b/db/migrations/01_init.sql new file mode 100644 index 0000000..3a83b36 --- /dev/null +++ b/db/migrations/01_init.sql @@ -0,0 +1,27 @@ +CREATE TABLE IF NOT EXISTS chats ( + id INT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) DEFAULT 'New Chat', + mode ENUM('regular', 'coding', 'game', 'app') DEFAULT 'regular', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS messages ( + id INT AUTO_INCREMENT PRIMARY KEY, + chat_id INT NOT NULL, + role ENUM('user', 'assistant', 'system') NOT NULL, + content TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (chat_id) REFERENCES chats(id) ON DELETE CASCADE +); + +CREATE TABLE IF NOT EXISTS user_settings ( + id INT AUTO_INCREMENT PRIMARY KEY, + setting_key VARCHAR(50) UNIQUE NOT NULL, + setting_value TEXT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +); + +-- Default settings +INSERT IGNORE INTO user_settings (setting_key, setting_value) VALUES ('creativity', '0.7'); +INSERT IGNORE INTO user_settings (setting_key, setting_value) VALUES ('theme', 'dark-modern'); +INSERT IGNORE INTO user_settings (setting_key, setting_value) VALUES ('limits_off', '0'); diff --git a/index.php b/index.php index 7205f3d..7cb89f2 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,338 @@ query("SELECT setting_key, setting_value FROM user_settings"); + while ($row = $stmt->fetch()) { + $settings[$row['setting_key']] = $row['setting_value']; + } +} catch (Exception $e) { + // Fallback if table not ready +} + +$theme = $settings['theme'] ?? 'theme-dark-modern'; +$creativity = $settings['creativity'] ?? '0.7'; +$limitsOff = $settings['limits_off'] ?? '0'; ?> - - + + - - - New Style - - - - - - - - - - - - - - - - - - - + + + <?php echo htmlspecialchars($projectName); ?> + + + + + + + + + + + + + + + + + + + -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

+ +
+ + + + +
+
+
+ Regular +
+
+ +
+
+ +
+
+ +

How can I help you today?

+

Choose a mode from the sidebar to get started.

+
+
+ +
+
+ + +
+
+ AI can make mistakes. Check important info. +
+
+
+
+ + +
-
- Page updated: (UTC) -
+ + + + - + \ No newline at end of file