diff --git a/admin.php b/admin.php new file mode 100644 index 0000000..70bd43b --- /dev/null +++ b/admin.php @@ -0,0 +1,111 @@ +prepare("INSERT INTO faqs (keywords, answer) VALUES (?, ?)"); + $stmt->execute([$keywords, $answer]); + } + } elseif (isset($_POST['action']) && $_POST['action'] === 'delete') { + $id = $_POST['id'] ?? 0; + if ($id) { + $stmt = db()->prepare("DELETE FROM faqs WHERE id = ?"); + $stmt->execute([$id]); + } + } + header("Location: admin.php"); + exit; +} + +$faqs = db()->query("SELECT * FROM faqs ORDER BY created_at DESC")->fetchAll(); +?> + + + + + + Admin - FAQ Manager + + + + + + +
+
+
+
+
+
+
+

FAQ Manager

+ Back to Chat +
+ +
+

Add New FAQ

+
+ +
+ + +
+
+ + +
+ +
+
+ +

Existing FAQs

+ + + + + + + + + + + + + + + + + +
KeywordsAnswerActions
+
+ + + +
+
+
+ + + diff --git a/api/chat.php b/api/chat.php new file mode 100644 index 0000000..c3bc6ba --- /dev/null +++ b/api/chat.php @@ -0,0 +1,35 @@ + "I didn't catch that. Could you repeat?"]); + exit; +} + +$faqs = db()->query("SELECT keywords, answer FROM faqs")->fetchAll(); + +$bestMatch = null; +$maxOverlap = 0; + +$userWords = preg_split('/\W+/', strtolower($message), -1, PREG_SPLIT_NO_EMPTY); + +foreach ($faqs as $faq) { + $keywords = preg_split('/[\s,]+/', strtolower($faq['keywords']), -1, PREG_SPLIT_NO_EMPTY); + $overlap = count(array_intersect($userWords, $keywords)); + + if ($overlap > $maxOverlap) { + $maxOverlap = $overlap; + $bestMatch = $faq['answer']; + } +} + +if ($bestMatch) { + echo json_encode(['reply' => $bestMatch]); +} else { + // Default fallback + echo json_encode(['reply' => "I'm sorry, I don't have an answer for that yet. You can try asking about 'pricing' or 'support'."]); +} diff --git a/assets/css/custom.css b/assets/css/custom.css index 65a1626..50e0502 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -1,346 +1,302 @@ -: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; -} - body { - font-family: var(--font-body); - background-color: var(--color-bg); - color: var(--color-text); - overflow-x: hidden; -} - -h1, h2, h3, h4, h5, h6, .navbar-brand { - font-family: var(--font-heading); - letter-spacing: -0.03em; -} - -/* 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; -} - -.navbar.scrolled { - border-bottom-color: #000; - padding-top: 0.5rem; - padding-bottom: 0.5rem; -} - -.brand-text { - font-size: 1.5rem; - font-weight: 800; -} - -.nav-link { - font-weight: 500; - color: var(--color-text); - margin-left: 1rem; - position: relative; -} - -.nav-link:hover, .nav-link.active { - color: var(--color-primary); -} - -/* 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); -} - -.btn:hover { - transform: translate(-2px, -2px); - box-shadow: var(--shadow-hover); -} - -.btn:active { - transform: translate(2px, 2px); - box-shadow: 0 0 0 #000; -} - -.btn-primary { - background-color: var(--color-primary); - border-color: #000; - color: #fff; -} - -.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 { + background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab); + background-size: 400% 400%; + animation: gradient 15s ease infinite; + color: #212529; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + font-size: 14px; + margin: 0; 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; +.main-wrapper { 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; + min-height: 100vh; width: 100%; + padding: 20px; + box-sizing: border-box; + position: relative; + z-index: 1; } -.stack-card { - position: absolute; - width: 80%; +@keyframes gradient { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} + +.chat-container { + width: 100%; + max-width: 600px; + background: rgba(255, 255, 255, 0.85); + border: 1px solid rgba(255, 255, 255, 0.3); + border-radius: 20px; + display: flex; + flex-direction: column; + height: 85vh; + box-shadow: 0 20px 40px rgba(0,0,0,0.2); + backdrop-filter: blur(15px); + -webkit-backdrop-filter: blur(15px); + overflow: hidden; +} + +.chat-header { + padding: 1.5rem; + border-bottom: 1px solid rgba(0, 0, 0, 0.05); + background: rgba(255, 255, 255, 0.5); + font-weight: 700; + font-size: 1.1rem; + display: flex; + justify-content: space-between; + align-items: center; +} + +.chat-messages { + flex: 1; + overflow-y: auto; + padding: 1.5rem; + display: flex; + flex-direction: column; + gap: 1.25rem; +} + +/* Custom Scrollbar */ +::-webkit-scrollbar { + width: 6px; +} + +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.3); + border-radius: 10px; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.5); +} + +.message { + max-width: 85%; + padding: 0.85rem 1.1rem; + border-radius: 16px; + line-height: 1.5; + font-size: 0.95rem; + box-shadow: 0 4px 15px rgba(0,0,0,0.05); + animation: fadeIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(20px) scale(0.95); } + to { opacity: 1; transform: translateY(0) scale(1); } +} + +.message.visitor { + align-self: flex-end; + background: linear-gradient(135deg, #212529 0%, #343a40 100%); + color: #fff; + border-bottom-right-radius: 4px; +} + +.message.bot { + align-self: flex-start; + background: #ffffff; + color: #212529; + border-bottom-left-radius: 4px; +} + +.chat-input-area { + padding: 1.25rem; + background: rgba(255, 255, 255, 0.5); + border-top: 1px solid rgba(0, 0, 0, 0.05); +} + +.chat-input-area form { + display: flex; + gap: 0.75rem; +} + +.chat-input-area input { + flex: 1; + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 12px; + padding: 0.75rem 1rem; + outline: none; + background: rgba(255, 255, 255, 0.9); + transition: all 0.3s ease; +} + +.chat-input-area input:focus { + border-color: #23a6d5; + box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.2); +} + +.chat-input-area button { + background: #212529; + color: #fff; + border: none; + padding: 0.75rem 1.5rem; + border-radius: 12px; + cursor: pointer; + font-weight: 600; + transition: all 0.3s ease; +} + +.chat-input-area button:hover { + background: #000; + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(0,0,0,0.2); +} + +/* Background Animations */ +.bg-animations { + position: fixed; + top: 0; + left: 0; + width: 100%; height: 100%; - border-radius: var(--radius-card); - border: 2px solid #000; - box-shadow: var(--shadow-hard); - left: 10%; - transform: rotate(-3deg); - background-size: cover; + z-index: 0; + overflow: hidden; + pointer-events: none; } -/* Forms */ -.form-control { - border: 2px solid #000; - border-radius: 0.5rem; +.blob { + position: absolute; + width: 500px; + height: 500px; + background: rgba(255, 255, 255, 0.2); + border-radius: 50%; + filter: blur(80px); + animation: move 20s infinite alternate cubic-bezier(0.45, 0, 0.55, 1); +} + +.blob-1 { + top: -10%; + left: -10%; + background: rgba(238, 119, 82, 0.4); +} + +.blob-2 { + bottom: -10%; + right: -10%; + background: rgba(35, 166, 213, 0.4); + animation-delay: -7s; + width: 600px; + height: 600px; +} + +.blob-3 { + top: 40%; + left: 30%; + background: rgba(231, 60, 126, 0.3); + animation-delay: -14s; + width: 450px; + height: 450px; +} + +@keyframes move { + 0% { transform: translate(0, 0) rotate(0deg) scale(1); } + 33% { transform: translate(150px, 100px) rotate(120deg) scale(1.1); } + 66% { transform: translate(-50px, 200px) rotate(240deg) scale(0.9); } + 100% { transform: translate(0, 0) rotate(360deg) scale(1); } +} + +.admin-link { + font-size: 14px; + color: #fff; + text-decoration: none; + background: rgba(0, 0, 0, 0.2); + padding: 0.5rem 1rem; + border-radius: 8px; + transition: all 0.3s ease; +} + +.admin-link:hover { + background: rgba(0, 0, 0, 0.4); + text-decoration: none; +} + +/* Admin Styles */ +.admin-container { + max-width: 900px; + margin: 3rem auto; + padding: 2.5rem; + background: rgba(255, 255, 255, 0.85); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border-radius: 24px; + box-shadow: 0 20px 50px rgba(0,0,0,0.15); + border: 1px solid rgba(255, 255, 255, 0.4); + position: relative; + z-index: 1; +} + +.admin-container h1 { + margin-top: 0; + color: #212529; + font-weight: 800; +} + +.table { + width: 100%; + border-collapse: separate; + border-spacing: 0 8px; + margin-top: 1.5rem; +} + +.table th { + background: transparent; + border: none; padding: 1rem; - font-weight: 500; - background: #f8f9fa; + color: #6c757d; + font-weight: 600; + text-transform: uppercase; + font-size: 0.75rem; + letter-spacing: 1px; +} + +.table td { + background: #fff; + padding: 1rem; + border: none; +} + +.table tr td:first-child { border-radius: 12px 0 0 12px; } +.table tr td:last-child { border-radius: 0 12px 12px 0; } + +.form-group { + margin-bottom: 1.25rem; +} + +.form-group label { + display: block; + margin-bottom: 0.5rem; + font-weight: 600; + font-size: 0.9rem; +} + +.form-control { + width: 100%; + padding: 0.75rem 1rem; + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 12px; + background: #fff; + transition: all 0.3s ease; + box-sizing: border-box; } .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%; } -} + outline: none; + border-color: #23a6d5; + box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.1); +} \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js index fdf2cfd..d349598 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1,73 +1,39 @@ document.addEventListener('DOMContentLoaded', () => { - - // 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; - - 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(); - } + const chatForm = document.getElementById('chat-form'); + const chatInput = document.getElementById('chat-input'); + const chatMessages = document.getElementById('chat-messages'); - // Scroll with offset - const offset = 80; - const elementPosition = targetElement.getBoundingClientRect().top; - const offsetPosition = elementPosition + window.pageYOffset - offset; - - window.scrollTo({ - top: offsetPosition, - behavior: "smooth" - }); - } - }); - }); - - // 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'); - } else { - navbar.classList.remove('scrolled', 'shadow-sm', 'bg-white'); - navbar.classList.add('bg-transparent'); - } - }); - - // Intersection Observer for fade-up animations - const observerOptions = { - threshold: 0.1, - rootMargin: "0px 0px -50px 0px" + const appendMessage = (text, sender) => { + const msgDiv = document.createElement('div'); + msgDiv.classList.add('message', sender); + msgDiv.textContent = text; + chatMessages.appendChild(msgDiv); + chatMessages.scrollTop = chatMessages.scrollHeight; }; - 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); + chatForm.addEventListener('submit', async (e) => { + e.preventDefault(); + const message = chatInput.value.trim(); + if (!message) return; - // 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); + appendMessage(message, 'visitor'); + chatInput.value = ''; + + try { + const response = await fetch('api/chat.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ message }) + }); + const data = await response.json(); + + // Artificial delay for realism + setTimeout(() => { + appendMessage(data.reply, 'bot'); + }, 500); + } catch (error) { + console.error('Error:', error); + appendMessage("Sorry, something went wrong. Please try again.", 'bot'); + } }); - -}); \ No newline at end of file +}); diff --git a/index.php b/index.php index 7205f3d..9416a71 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,52 @@ - - - New Style - - - - - - - - - - - - - - - - - - - + + + Chat Assistant + + + + + + + + + + + -
-
-

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

+
+
+
+
+
+
+
+
+ Chat Assistant + Admin +
+
+
+ Hello! I'm your assistant. How can I help you today? +
+
+
+
+ + +
+
-
- + + + - + \ No newline at end of file diff --git a/opencode.json b/opencode.json new file mode 100644 index 0000000..d13dbc3 --- /dev/null +++ b/opencode.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://opencode.ai/config.json", + "provider": { + "openai": { + "options": { + "apiKey": "{env:OPENAI_API_KEY}" + } + }, + "google": { + "options": { + "apiKey": "{env:GOOGLE_API_KEY}" + } + } + } +}