38751-vm/assets/js/main.js
Flatlogic Bot 3d02f25bbd V baru
2026-02-25 22:06:24 +00:00

215 lines
8.0 KiB
JavaScript

document.addEventListener('DOMContentLoaded', () => {
// Basic interaction for toasts
try {
const toasts = document.querySelectorAll('.toast');
toasts.forEach(toastEl => {
if (window.bootstrap && bootstrap.Toast) {
const toast = new bootstrap.Toast(toastEl, { delay: 5000 });
toast.show();
}
});
} catch (e) {
console.error('Toast error:', e);
}
const html = document.documentElement;
const updateIcons = (theme) => {
// Update all theme toggle icons
const icons = document.querySelectorAll('#theme-toggle i, #theme-toggle-mobile i');
icons.forEach(icon => {
if (theme === 'dark') {
icon.className = 'fa-solid fa-sun';
} else {
icon.className = 'fa-solid fa-moon';
}
});
// Update all theme status texts
const textLabels = document.querySelectorAll('.theme-status-text');
textLabels.forEach(label => {
label.textContent = theme === 'dark' ? 'Dark Mode' : 'Light Mode';
});
};
// Theme Toggle Logic
const initThemeToggle = (btnId) => {
const themeToggle = document.getElementById(btnId);
if (!themeToggle) return;
themeToggle.addEventListener('click', () => {
const currentTheme = html.getAttribute('data-theme') || 'light';
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
// Update UI
html.setAttribute('data-theme', newTheme);
// Update All Icons and Labels
updateIcons(newTheme);
// Save preference
document.cookie = `theme=${newTheme}; path=/; max-age=${365 * 24 * 60 * 60}`;
localStorage.setItem('theme', newTheme);
});
};
// AJAX Category Filtering
const initCategoryAjax = () => {
const filters = document.querySelectorAll('.category-filter');
const gridContainer = document.getElementById('apk-grid-container');
const dropdownBtn = document.getElementById('category-dropdown-btn');
const latestTitle = document.getElementById('latest-title');
if (!gridContainer || filters.length === 0) return;
filters.forEach(filter => {
filter.addEventListener('click', (e) => {
e.preventDefault();
const category = filter.getAttribute('data-category');
const url = filter.getAttribute('href');
const categoryName = filter.textContent;
// Update UI state
gridContainer.style.opacity = '0.5';
gridContainer.style.pointerEvents = 'none';
// Fetch data
fetch(url, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.text())
.then(data => {
gridContainer.innerHTML = data;
gridContainer.style.opacity = '1';
gridContainer.style.pointerEvents = 'all';
// Update dropdown button text
if (dropdownBtn) {
dropdownBtn.innerHTML = `${categoryName} <i class="bi bi-chevron-down ms-1 small"></i>`;
}
// Update URL without refreshing
window.history.pushState({ category: category }, '', url);
})
.catch(err => {
console.error('Fetch error:', err);
gridContainer.style.opacity = '1';
gridContainer.style.pointerEvents = 'all';
});
});
});
// Handle browser back/forward
window.addEventListener('popstate', (e) => {
window.location.reload(); // Simple solution for now
});
};
// AI Chat Assistant Logic
const initAIChat = () => {
const toggleBtn = document.getElementById('toggle-ai-chat');
const closeBtn = document.getElementById('close-ai-chat');
const chatWindow = document.getElementById('ai-chat-window');
const chatInput = document.getElementById('ai-chat-input');
const sendBtn = document.getElementById('send-ai-chat');
const messagesContainer = document.getElementById('ai-chat-messages');
if (!toggleBtn || !chatWindow) return;
toggleBtn.addEventListener('click', () => {
chatWindow.classList.toggle('d-none');
if (!chatWindow.classList.contains('d-none')) {
chatInput.focus();
}
});
closeBtn.addEventListener('click', () => {
chatWindow.classList.add('d-none');
});
const appendMessage = (message, isUser = false) => {
const div = document.createElement('div');
div.className = 'mb-3 d-flex ' + (isUser ? 'justify-content-end' : '');
const content = document.createElement('div');
content.className = (isUser ? 'bg-success text-white' : 'bg-white') + ' p-3 rounded-4 shadow-sm small';
content.style.maxWidth = '85%';
if (isUser) {
content.style.borderBottomRightRadius = '0';
} else {
content.style.borderBottomLeftRadius = '0';
}
content.textContent = message;
div.appendChild(content);
messagesContainer.appendChild(div);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
};
const sendMessage = () => {
const message = chatInput.value.trim();
if (!message) return;
appendMessage(message, true);
chatInput.value = '';
// Loading state
const loadingDiv = document.createElement('div');
loadingDiv.className = 'mb-3 d-flex';
loadingDiv.innerHTML = '<div class="bg-white p-3 rounded-4 shadow-sm small" style="border-bottom-left-radius: 0 !important;"><div class="spinner-border spinner-border-sm text-success" role="status"></div> Thinking...</div>';
messagesContainer.appendChild(loadingDiv);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
fetch('/api/ai/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message: message })
})
.then(response => response.json())
.then(data => {
messagesContainer.removeChild(loadingDiv);
if (data.reply) {
appendMessage(data.reply);
} else {
appendMessage(data.error || 'Sorry, something went wrong.');
}
})
.catch(err => {
messagesContainer.removeChild(loadingDiv);
appendMessage('Error connecting to AI assistant.');
console.error(err);
});
};
sendBtn.addEventListener('click', sendMessage);
chatInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendMessage();
});
};
// Initial Sync
const currentTheme = html.getAttribute('data-theme') || 'light';
updateIcons(currentTheme);
// Sync theme from localStorage if cookie is missing but localStorage has it
const savedTheme = localStorage.getItem('theme');
const currentCookie = document.cookie.split('; ').find(row => row.startsWith('theme='))?.split('=')[1];
if (savedTheme && !currentCookie) {
html.setAttribute('data-theme', savedTheme);
updateIcons(savedTheme);
document.cookie = `theme=${savedTheme}; path=/; max-age=${365 * 24 * 60 * 60}`;
}
initThemeToggle('theme-toggle');
initThemeToggle('theme-toggle-mobile');
initCategoryAjax();
initAIChat();
console.log('ApkNusa ready.');
});