37686-vm/assets/js/main.js
Flatlogic Bot 0d950dd749 random AI
2026-01-22 03:41:29 +00:00

214 lines
8.0 KiB
JavaScript

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');
// 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;
// If switching modes, start a new chat for that mode
startNewChat();
});
});
function startNewChat() {
currentChatId = null;
chatWindow.innerHTML = `
<div class="text-center my-auto">
<i class="bi bi-stars fs-1 text-primary opacity-50"></i>
<h4 class="mt-3">New ${currentMode} Chat</h4>
<p class="text-muted">How can I help you in this mode?</p>
</div>
`;
}
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 {
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 `<pre class="bg-dark text-white p-3 rounded my-2 overflow-auto" style="font-size: 0.85rem; border: 1px solid var(--border-color);"><code>${escapeHtml(code.trim())}</code></pre>`;
});
}
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('<html') || codeToLaunch.toLowerCase().includes('<!doctype') || codeToLaunch.toLowerCase().includes('<body')) {
const btn = document.createElement('button');
btn.className = 'btn btn-sm btn-success mt-2 d-inline-flex align-items-center gap-2';
btn.innerHTML = '<i class="bi bi-rocket-takeoff"></i> Launch Application';
btn.onclick = () => {
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 = '<span class="spinner-border spinner-border-sm" role="status"></span>';
} else {
sendBtn.innerHTML = '<i class="bi bi-arrow-up-circle-fill"></i>';
}
}
sendBtn.addEventListener('click', sendMessage);
chatInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
// 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');
});