File Manager Lite
Dir:
/home/codewavebd/public_html/resources/views/layouts
Upload
[..]
frontend.blade.php (35.94 KB)
Edit
Rename
Del
Edit: frontend.blade.php
<!DOCTYPE html> <html lang="en" data-theme="dark"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SEO Meta Fields --> <title>@yield('seo_title', \App\Models\Setting::get('seo_title', 'CodeWave BD | Custom Software & Web Solutions'))</title> <meta name="description" content="@yield('seo_description', \App\Models\Setting::get('seo_description', 'CodeWave BD builds premium custom software, ERP systems, retail POS apps, and web portals.'))"> <meta name="keywords" content="@yield('seo_keywords', \App\Models\Setting::get('seo_keywords', 'codewave bd, custom software development, erp bangladesh, pos software'))"> <link rel="canonical" href="{{ request()->url() }}"> <!-- Open Graph / Facebook --> <meta property="og:type" content="website"> <meta property="og:url" content="{{ request()->url() }}"> <meta property="og:title" content="@yield('seo_title', \App\Models\Setting::get('seo_title', 'CodeWave BD'))"> <meta property="og:description" content="@yield('seo_description', \App\Models\Setting::get('seo_description'))"> <meta property="og:image" content="@yield('seo_image', asset('assets/img/og_image.webp'))"> <!-- Twitter --> <meta property="twitter:card" content="summary_large_image"> <meta property="twitter:url" content="{{ request()->url() }}"> <meta property="twitter:title" content="@yield('seo_title', \App\Models\Setting::get('seo_title', 'CodeWave BD'))"> <meta property="twitter:description" content="@yield('seo_description', \App\Models\Setting::get('seo_description'))"> <meta property="twitter:image" content="@yield('seo_image', asset('assets/img/og_image.webp'))"> <!-- Favicon --> @if(\App\Models\Setting::get('site_favicon')) <link rel="icon" type="image/x-icon" href="{{ asset('uploads/' . \App\Models\Setting::get('site_favicon')) }}"> @else <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}"> @endif <!-- Bootstrap 5 CSS & Icons --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.2/font/bootstrap-icons.min.css"> <!-- Custom Premium Styles --> <link rel="stylesheet" href="{{ asset('assets/css/style.css') }}"> <!-- Organization & Website Schema --> <script type="application/ld+json"> { "@@context": "https://schema.org", "@type": "Organization", "name": "{{ \App\Models\Setting::get('site_name', 'CodeWave BD') }}", "url": "{{ url('/') }}", "logo": "{{ \App\Models\Setting::get('site_logo') ? asset('uploads/' . \App\Models\Setting::get('site_logo')) : asset('assets/img/logo.webp') }}", "contactPoint": { "@type": "ContactPoint", "telephone": "{{ \App\Models\Setting::get('contact_phone') }}", "contactType": "customer service", "areaServed": "BD", "availableLanguage": ["en", "bn"] }, "sameAs": [ "{{ \App\Models\Setting::get('facebook_url') }}", "{{ \App\Models\Setting::get('linkedin_url') }}", "{{ \App\Models\Setting::get('github_url') }}" ] } </script> <script type="application/ld+json"> { "@@context": "https://schema.org", "@type": "WebSite", "name": "{{ \App\Models\Setting::get('site_name', 'CodeWave BD') }}", "url": "{{ url('/') }}", "potentialAction": { "@type": "SearchAction", "target": "{{ url('/search') }}?query={search_term_string}", "query-input": "required name=search_term_string" } } </script> @yield('schemas') <!-- Inject Google Analytics, Tag Manager, and Search Console from settings --> {!! \App\Models\Setting::get('google_analytics_code') !!} {!! \App\Models\Setting::get('google_tag_manager_code') !!} {!! \App\Models\Setting::get('google_search_console_code') !!} </head> <body> <!-- Header Navigation --> <nav class="navbar navbar-expand-lg navbar-dark navbar-custom fixed-top"> <div class="container"> <a class="navbar-brand d-flex align-items-center gap-2" href="{{ route('home') }}"> @if(\App\Models\Setting::get('site_logo')) <img src="{{ asset('uploads/' . \App\Models\Setting::get('site_logo')) }}" alt="{{ \App\Models\Setting::get('site_name', 'CodeWave BD') }}" style="height: 38px; max-width: 180px; object-fit: contain;"> @else <i class="bi bi-wave-left"></i> CODE<span style="color: var(--accent-cyan)">WAVE</span><span class="fs-6 text-muted">.bd</span> @endif </a> <button class="navbar-toggler border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav ms-auto align-items-center"> <li class="nav-item"> <a class="nav-link {{ request()->routeIs('home') ? 'active' : '' }}" href="{{ route('home') }}">Home</a> </li> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" id="servicesDropdown" role="button" data-bs-toggle="dropdown"> Services </a> <ul class="dropdown-menu dropdown-menu-dark border-secondary bg-dark"> @foreach(\App\Models\Service::where('status', 'active')->orderBy('order')->get() as $navService) <li> <a class="dropdown-item py-2" href="{{ route('services.show', $navService->slug) }}"> <i class="bi {{ $navService->icon }} text-info me-2"></i> {{ $navService->title }} </a> </li> @endforeach </ul> </li> <li class="nav-item"> <a class="nav-link {{ request()->is('portfolio*') ? 'active' : '' }}" href="{{ route('home') }}#portfolio">Portfolio</a> </li> <li class="nav-item"> <a class="nav-link {{ request()->is('software*') ? 'active' : '' }}" href="{{ route('home') }}#software">Software Showcase</a> </li> <li class="nav-item"> <a class="nav-link {{ request()->routeIs('blog.index') ? 'active' : '' }}" href="{{ route('blog.index') }}">Blog</a> </li> <li class="nav-item ms-lg-3 my-2 my-lg-0"> <a class="btn btn-primary-glow" href="{{ route('home') }}#contact">Get A Quote</a> </li> <!-- Search Trigger --> <li class="nav-item ms-lg-3"> <button class="btn theme-toggle-btn border-0" data-bs-toggle="modal" data-bs-target="#searchModal" title="Search CodeWave"> <i class="bi bi-search"></i> </button> </li> <!-- Theme Toggle --> <li class="nav-item ms-lg-2"> <button class="theme-toggle-btn" id="themeToggler" title="Toggle Light/Dark Theme"> <i class="bi bi-sun-fill" id="themeIcon"></i> </button> </li> </ul> </div> </div> </nav> <!-- Main Content Injection --> <main> @yield('content') </main> <!-- Footer --> <footer class="py-5 bg-dark text-white border-top border-secondary mt-5" style="background-color: var(--bg-secondary) !important;"> <div class="container"> <div class="row"> <div class="col-lg-4 mb-4 mb-lg-0"> @if(\App\Models\Setting::get('site_logo')) <img src="{{ asset('uploads/' . \App\Models\Setting::get('site_logo')) }}" alt="{{ \App\Models\Setting::get('site_name', 'CodeWave BD') }}" class="mb-3" style="height: 38px; max-width: 180px; object-fit: contain;"> @else <h5 class="mb-3 font-heading fw-bold">CODE<span class="text-info">WAVE</span> BD</h5> @endif <p class="text-muted">Creating premium, enterprise-grade digital systems and business software. Elevate your brand online.</p> <div class="mt-3"> <a href="{{ \App\Models\Setting::get('facebook_url') }}" class="text-white me-3 fs-5" target="_blank"><i class="bi bi-facebook"></i></a> <a href="{{ \App\Models\Setting::get('linkedin_url') }}" class="text-white me-3 fs-5" target="_blank"><i class="bi bi-linkedin"></i></a> <a href="{{ \App\Models\Setting::get('github_url') }}" class="text-white fs-5" target="_blank"><i class="bi bi-github"></i></a> </div> </div> <div class="col-md-4 col-lg-2 mb-4 mb-md-0"> <h6 class="text-uppercase mb-3 font-heading fw-bold text-info">Company</h6> <ul class="list-unstyled text-muted"> <li><a href="{{ route('home') }}" class="text-decoration-none text-muted mb-2 d-block">About Us</a></li> <li><a href="{{ route('home') }}#services" class="text-decoration-none text-muted mb-2 d-block">Our Services</a></li> <li><a href="{{ route('home') }}#portfolio" class="text-decoration-none text-muted mb-2 d-block">Portfolio</a></li> <li><a href="{{ route('blog.index') }}" class="text-decoration-none text-muted mb-2 d-block">Blog News</a></li> </ul> </div> <div class="col-md-4 col-lg-3 mb-4 mb-md-0"> <h6 class="text-uppercase mb-3 font-heading fw-bold text-info">Featured Software</h6> <ul class="list-unstyled text-muted"> @foreach(\App\Models\SoftwareProduct::where('status', 'active')->take(3)->get() as $footProd) <li><a href="{{ route('software.show', $footProd->slug) }}" class="text-decoration-none text-muted mb-2 d-block">{{ $footProd->name }}</a></li> @endforeach </ul> </div> <div class="col-md-4 col-lg-3"> <h6 class="text-uppercase mb-3 font-heading fw-bold text-info">Contact Us</h6> <p class="text-muted mb-2"><i class="bi bi-geo-alt-fill text-info me-2"></i> {{ \App\Models\Setting::get('contact_address') }}</p> <p class="text-muted mb-2"><i class="bi bi-envelope-fill text-info me-2"></i> {{ \App\Models\Setting::get('contact_email') }}</p> <p class="text-muted mb-2"><i class="bi bi-phone-fill text-info me-2"></i> {{ \App\Models\Setting::get('contact_phone') }}</p> </div> </div> <hr class="border-secondary my-4"> <div class="row align-items-center"> <div class="col-md-6 text-center text-md-start"> <span class="text-muted small">© {{ date('Y') }} CodeWave BD. All Rights Reserved.</span> </div> <div class="col-md-6 text-center text-md-end mt-2 mt-md-0"> <a href="{{ route('login') }}" class="text-decoration-none text-muted small"><i class="bi bi-lock-fill me-1"></i>Admin Dashboard</a> </div> </div> </div> </footer> <!-- Dynamic Live Chat Integration --> @php $chatMode = \App\Models\Setting::get('live_chat_mode', 'native'); @endphp @if($chatMode === 'whatsapp') <!-- Floating WhatsApp CTA --> <a href="https://wa.me/{{ \App\Models\Setting::get('contact_whatsapp') }}?text=Hello%20CodeWave%20BD%2C%20I%20would%20like%20to%20request%20information%20about%20a%20project." class="whatsapp-float" target="_blank" title="Chat with Tanvir on WhatsApp"> <i class="bi bi-whatsapp"></i> </a> @elseif($chatMode === 'third_party') <!-- Third-Party Chat Script Code --> {!! \App\Models\Setting::get('live_chat_third_party_code') !!} @elseif($chatMode === 'native') <!-- CodeWave Native Live Chat Widget --> <div class="chat-widget-container"> <button class="chat-trigger-btn" id="chatTriggerBtn" title="Chat with Support"> <i class="bi bi-chat-dots-fill" id="chatTriggerIcon"></i> </button> <div class="chat-box-card" id="chatBoxCard"> <div class="chat-box-header text-white"> <div class="d-flex align-items-center gap-2"> <span class="chat-status-dot"></span> <div class="lh-sm"> <div class="fw-bold small">CodeWave Support</div> <div class="text-muted" style="font-size: 10px;">We are online</div> </div> </div> <button class="btn-close btn-close-white btn-sm" id="closeChatBtn"></button> </div> <!-- Chat Form (Initial state if no thread) --> <div class="chat-box-body" id="chatFormBody"> <div class="text-center py-3"> <i class="bi bi-chat-quote text-info fs-1"></i> <h6 class="text-white font-heading mt-2 mb-1">Start a Conversation</h6> <p class="small text-muted mb-0">Fill out your details to chat with a representative instantly.</p> </div> <form id="chatStartForm" class="chat-start-form"> <div class="mb-2"> <label class="small text-muted mb-1">Your Name</label> <input type="text" id="chatVisitorName" class="form-control form-control-sm bg-dark border-secondary text-white" placeholder="e.g. Rahat Chowdhury" required autocomplete="off"> </div> <div class="mb-2"> <label class="small text-muted mb-1">WhatsApp / Phone Number</label> <input type="text" id="chatVisitorPhone" class="form-control form-control-sm bg-dark border-secondary text-white" placeholder="e.g. 01712345678" required autocomplete="off"> </div> <div class="mb-2"> <label class="small text-muted mb-1">Email Address (Optional)</label> <input type="email" id="chatVisitorEmail" class="form-control form-control-sm bg-dark border-secondary text-white" placeholder="e.g. name@company.com" autocomplete="off"> </div> <div class="mb-3"> <label class="small text-muted mb-1">Your Message</label> <textarea id="chatVisitorFirstMsg" class="form-control form-control-sm bg-dark border-secondary text-white" rows="2" placeholder="How can we help you today?" required></textarea> </div> <button type="submit" class="btn btn-sm btn-info-glow w-100 py-2">Start Chatting</button> </form> </div> <!-- Chat Room (Messages state if thread active) --> <div class="chat-box-body" id="chatRoomBody" style="display: none;"> <div class="text-center py-2 border-bottom border-secondary mb-2"> <small class="text-muted">Chat session initiated.</small> </div> <div id="chatMessagesContainer" class="d-flex flex-column gap-2" style="overflow-y: auto; flex: 1;"> <!-- Messages populated dynamically --> </div> </div> <!-- Chat Footer (Input bar, hidden in form state) --> <div class="chat-box-footer" id="chatFooter" style="display: none;"> <input type="text" id="chatMessageInput" placeholder="Type a message..." autocomplete="off"> <button class="chat-send-btn" id="sendChatMsgBtn"> <i class="bi bi-send-fill"></i> </button> </div> </div> </div> <style> .chat-widget-container { position: fixed; bottom: 30px; right: 30px; z-index: 9999; } .chat-trigger-btn { width: 60px; height: 60px; border-radius: 50%; background: linear-gradient(135deg, var(--accent-indigo), var(--accent-cyan)); color: white; display: flex; justify-content: center; align-items: center; font-size: 26px; box-shadow: 0 4px 20px rgba(99, 102, 241, 0.4); cursor: pointer; transition: transform 0.3s ease, box-shadow 0.3s ease; border: none; outline: none; } .chat-trigger-btn:hover { transform: scale(1.1) rotate(5deg); box-shadow: 0 6px 25px rgba(99, 102, 241, 0.6); } .chat-box-card { position: absolute; bottom: 75px; right: 0; width: 360px; height: 480px; background: rgba(17, 24, 39, 0.95); backdrop-filter: blur(15px); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 16px; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); display: none; flex-direction: column; overflow: hidden; transition: opacity 0.3s ease, transform 0.3s ease; transform: translateY(20px) scale(0.95); opacity: 0; } .chat-box-card.active { display: flex; transform: translateY(0) scale(1); opacity: 1; } .chat-box-header { padding: 12px 18px; background: linear-gradient(90deg, rgba(99, 102, 241, 0.25), rgba(6, 182, 212, 0.25)); border-bottom: 1px solid rgba(255, 255, 255, 0.08); display: flex; align-items: center; justify-content: space-between; } .chat-status-dot { width: 8px; height: 8px; background-color: #10b981; border-radius: 50%; display: inline-block; box-shadow: 0 0 8px #10b981; animation: chat-pulse 2s infinite; } @keyframes chat-pulse { 0% { opacity: 0.5; } 50% { opacity: 1; } 100% { opacity: 0.5; } } .chat-box-body { flex: 1; padding: 15px; overflow-y: auto; display: flex; flex-direction: column; } .chat-start-form .form-control { font-size: 13px; border-radius: 8px; padding: 8px 12px; } .chat-msg-bubble { max-width: 80%; padding: 8px 12px; border-radius: 14px; font-size: 13.5px; line-height: 1.4; word-wrap: break-word; } .chat-msg-bubble.visitor { background-color: var(--accent-indigo) !important; color: white !important; align-self: flex-end; border-bottom-right-radius: 2px; } .chat-msg-bubble.admin { background-color: rgba(255, 255, 255, 0.08) !important; color: #e2e8f0 !important; align-self: flex-start; border-bottom-left-radius: 2px; border: 1px solid rgba(255, 255, 255, 0.05); } .chat-box-footer { padding: 10px 12px; border-top: 1px solid rgba(255, 255, 255, 0.08); display: flex; gap: 8px; align-items: center; } .chat-box-footer input { flex: 1; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 20px; padding: 6px 14px; color: white; font-size: 13px; outline: none; transition: border-color 0.2s; } .chat-box-footer input:focus { border-color: var(--accent-cyan); } .chat-send-btn { background: var(--accent-indigo); border: none; width: 32px; height: 32px; border-radius: 50%; color: white; display: flex; justify-content: center; align-items: center; cursor: pointer; transition: background 0.2s, transform 0.2s; } .chat-send-btn:hover { background: var(--accent-cyan); transform: scale(1.05); } </style> <script> document.addEventListener('DOMContentLoaded', () => { const triggerBtn = document.getElementById('chatTriggerBtn'); const triggerIcon = document.getElementById('chatTriggerIcon'); const chatCard = document.getElementById('chatBoxCard'); const closeBtn = document.getElementById('closeChatBtn'); const formBody = document.getElementById('chatFormBody'); const startForm = document.getElementById('chatStartForm'); const roomBody = document.getElementById('chatRoomBody'); const messagesContainer = document.getElementById('chatMessagesContainer'); const chatFooter = document.getElementById('chatFooter'); const messageInput = document.getElementById('chatMessageInput'); const sendBtn = document.getElementById('sendChatMsgBtn'); let threadActive = false; let chatOpen = false; let pollInterval = null; let lastMessageCount = 0; // 1. Toggle Chat Window if (triggerBtn) { triggerBtn.addEventListener('click', () => { chatOpen = !chatOpen; if (chatOpen) { chatCard.style.display = 'flex'; setTimeout(() => chatCard.classList.add('active'), 10); triggerIcon.className = 'bi bi-x-lg'; checkChatStatus(); } else { closeChatWindow(); } }); } if (closeBtn) { closeBtn.addEventListener('click', closeChatWindow); } function closeChatWindow() { chatOpen = false; chatCard.classList.remove('active'); setTimeout(() => chatCard.style.display = 'none', 300); triggerIcon.className = 'bi bi-chat-dots-fill'; stopPolling(); } // 2. Play synth chime sound function playPing() { try { const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); const osc = audioCtx.createOscillator(); const gain = audioCtx.createGain(); osc.connect(gain); gain.connect(audioCtx.destination); osc.type = 'sine'; osc.frequency.setValueAtTime(587.33, audioCtx.currentTime); // D5 osc.frequency.exponentialRampToValueAtTime(880, audioCtx.currentTime + 0.08); // A5 gain.gain.setValueAtTime(0.08, audioCtx.currentTime); gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.22); osc.start(audioCtx.currentTime); osc.stop(audioCtx.currentTime + 0.22); } catch(e) {} } // 3. Check session status on open function checkChatStatus() { fetch("{{ route('chat.messages') }}") .then(res => res.json()) .then(data => { if (data.success && data.messages.length > 0) { threadActive = true; formBody.style.display = 'none'; roomBody.style.display = 'flex'; chatFooter.style.display = 'flex'; renderMessages(data.messages); startPolling(); } else { threadActive = false; formBody.style.display = 'flex'; roomBody.style.display = 'none'; chatFooter.style.display = 'none'; } }); } // 4. Start Chat Form Submit if (startForm) { startForm.addEventListener('submit', (e) => { e.preventDefault(); const name = document.getElementById('chatVisitorName').value.trim(); const phone = document.getElementById('chatVisitorPhone').value.trim(); const email = document.getElementById('chatVisitorEmail').value.trim(); const msg = document.getElementById('chatVisitorFirstMsg').value.trim(); if (!name || !phone || !msg) return; fetch("{{ route('chat.start') }}", { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': '{{ csrf_token() }}' }, body: JSON.stringify({ name, phone, email, message: msg }) }) .then(res => res.json()) .then(data => { if (data.success) { threadActive = true; formBody.style.display = 'none'; roomBody.style.display = 'flex'; chatFooter.style.display = 'flex'; // Immediately load and show the first message checkChatStatus(); } }); }); } // 5. Send regular message function sendMsg() { const text = messageInput.value.trim(); if (!text) return; messageInput.value = ''; fetch("{{ route('chat.send') }}", { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': '{{ csrf_token() }}' }, body: JSON.stringify({ message: text }) }) .then(res => res.json()) .then(data => { if (data.success) { // Immediately update messages container fetchMessagesSilently(); } }); } if (sendBtn) { sendBtn.addEventListener('click', sendMsg); } if (messageInput) { messageInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') sendMsg(); }); } // 6. Fetch messages silently (for real-time update) function fetchMessagesSilently() { fetch("{{ route('chat.messages') }}") .then(res => res.json()) .then(data => { if (data.success && data.messages.length > 0) { renderMessages(data.messages); } }); } // 7. Render message bubbles function renderMessages(messages) { messagesContainer.innerHTML = ''; messages.forEach(msg => { const bubble = document.createElement('div'); bubble.className = `chat-msg-bubble ${msg.sender}`; bubble.innerText = msg.message; messagesContainer.appendChild(bubble); }); // Scroll to bottom messagesContainer.scrollTop = messagesContainer.scrollHeight; // Play chime if new message from admin if (messages.length > lastMessageCount) { const lastMsg = messages[messages.length - 1]; if (lastMsg.sender === 'admin' && lastMessageCount > 0) { playPing(); } lastMessageCount = messages.length; } } // 8. Polling Loop function startPolling() { stopPolling(); pollInterval = setInterval(fetchMessagesSilently, 3000); } function stopPolling() { if (pollInterval) { clearInterval(pollInterval); pollInterval = null; } } }); </script> @endif <!-- Global Live Search Modal --> <div class="modal fade search-modal-box" id="searchModal" tabindex="-1"> <div class="modal-dialog modal-lg modal-dialog-centered"> <div class="modal-content"> <div class="modal-header border-secondary"> <h5 class="modal-title font-heading text-info"><i class="bi bi-search me-2"></i>Live Search Platform</h5> <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button> </div> <div class="modal-body p-4"> <input type="text" id="liveSearchInput" class="form-control bg-dark border-secondary text-white py-3 fs-5" placeholder="Search for POS software, web development, ERP, case studies..." autocomplete="off"> <div class="mt-4" id="searchResultsContainer" style="display: none;"> <h6 class="text-uppercase text-info tracking-wider small mb-3">Search Results</h6> <div class="list-group list-group-flush border-top border-secondary" id="searchResultsList"> <!-- Populated dynamically --> </div> </div> </div> </div> </div> </div> <!-- Bootstrap 5 Bundle JS --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script> <!-- Theme Toggler and Live Search Script --> <script> // 1. Theme Toggle Management const htmlElement = document.documentElement; const themeToggler = document.getElementById('themeToggler'); const themeIcon = document.getElementById('themeIcon'); // Load saved theme or fall back to admin configured default const defaultTheme = "{{ \App\Models\Setting::get('default_theme', 'dark') }}"; const savedTheme = localStorage.getItem('codewave-theme') || defaultTheme; htmlElement.setAttribute('data-theme', savedTheme); updateThemeToggleUI(savedTheme); themeToggler.addEventListener('click', () => { const currentTheme = htmlElement.getAttribute('data-theme'); const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; htmlElement.setAttribute('data-theme', newTheme); localStorage.setItem('codewave-theme', newTheme); updateThemeToggleUI(newTheme); }); function updateThemeToggleUI(theme) { if (theme === 'dark') { themeIcon.className = 'bi bi-sun-fill text-warning'; } else { themeIcon.className = 'bi bi-moon-stars-fill text-primary'; } } // 2. AJAX Live Search const liveSearchInput = document.getElementById('liveSearchInput'); const searchResultsContainer = document.getElementById('searchResultsContainer'); const searchResultsList = document.getElementById('searchResultsList'); let searchTimeout = null; liveSearchInput.addEventListener('input', () => { clearTimeout(searchTimeout); const query = liveSearchInput.value.trim(); if (query.length < 2) { searchResultsContainer.style.display = 'none'; searchResultsList.innerHTML = ''; return; } searchTimeout = setTimeout(() => { fetch(`{{ route('search') }}?query=${encodeURIComponent(query)}`) .then(response => response.json()) .then(data => { searchResultsList.innerHTML = ''; if (data.results && data.results.length > 0) { data.results.forEach(result => { const item = document.createElement('a'); item.href = result.url; item.className = 'list-group-item list-group-item-action bg-transparent border-secondary text-white py-3 d-flex justify-content-between align-items-center'; item.innerHTML = ` <div> <h6 class="mb-0 text-white">${result.title}</h6> </div> <span class="badge bg-secondary rounded-pill small">${result.type}</span> `; searchResultsList.appendChild(item); }); searchResultsContainer.style.display = 'block'; } else { searchResultsList.innerHTML = '<div class="text-muted py-3">No results found for your query.</div>'; searchResultsContainer.style.display = 'block'; } }) .catch(err => console.error('Search request failed:', err)); }, 300); // 300ms debounce }); </script> </body> </html>
Simpan