User:Jono Bean/common.js: Difference between revisions
From DQWiki
Jump to navigationJump to search
No edit summary |
mNo edit summary |
(No difference)
| |
Revision as of 07:52, 25 February 2026
/* Lorekeeper Standalone Terminal */
(function() {
if (document.getElementById('lore-terminal-btn')) return;
// 1. Create Floating Button
var btn = document.createElement('div');
btn.id = 'lore-terminal-btn';
btn.innerHTML = '?';
btn.style.cssText = 'position:fixed;bottom:30px;right:30px;width:60px;height:60px;background:#8b5cf6;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:30px;cursor:pointer;box-shadow:0 10px 25px rgba(139,92,246,0.5);transition:0.3s;z-index:999999;border:2px solid rgba(255,255,255,0.2);';
btn.onmouseover = function() { this.style.transform = 'scale(1.1) rotate(15deg)'; };
btn.onmouseout = function() { this.style.transform = 'scale(1) rotate(0deg)'; };
// 2. Create Chat Box
var box = document.createElement('div');
box.id = 'lore-terminal-box';
box.style.cssText = 'position:fixed;bottom:100px;right:30px;width:400px;height:550px;background:rgba(15,15,20,0.95);backdrop-filter:blur(15px);border:1px solid rgba(139,92,246,0.3);border-radius:24px;display:none;flex-direction:column;box-shadow:0 25px 50px rgba(0,0,0,0.5);overflow:hidden;z-index:999999;color:#fff;font-family:system-ui,-apple-system,sans-serif;';
box.innerHTML = `
<div style="padding:20px;background:rgba(139,92,246,0.1);border-bottom:1px solid rgba(139,92,246,0.2);display:flex;justify-content:space-between;align-items:center;">
<div style="font-weight:bold;color:#a78bfa;">Archives of the Western Kingdom</div>
<div id="lore-close" style="cursor:pointer;opacity:0.6;">?</div>
</div>
<div id="lore-chat" style="flex:1;overflow-y:auto;padding:20px;display:flex;flex-direction:column;gap:15px;font-size:14px;scroll-behavior:smooth;">
<div style="background:rgba(255,255,255,0.05);padding:12px;border-radius:12px;border-left:3px solid #8b5cf6;">Greetings, Traveler. What secrets of the archives do you seek?</div>
</div>
<div style="padding:20px;border-top:1px solid rgba(255,255,255,0.1);display:flex;gap:10px;">
<input id="lore-input" placeholder="Ask about the Iron Guild..." style="flex:1;background:rgba(255,255,255,0.05);border:1px solid rgba(139,92,246,0.2);padding:10px 15px;border-radius:12px;color:#fff;outline:none;">
<button id="lore-send" style="background:#8b5cf6;border:none;color:#fff;padding:0 15px;border-radius:10px;cursor:pointer;font-weight:bold;">Ask</button>
</div>
`;
document.body.appendChild(btn);
document.body.appendChild(box);
// 3. Logic
var chat = box.querySelector('#lore-chat');
var input = box.querySelector('#lore-input');
var send = box.querySelector('#lore-send');
var convId = 'anon-' + Math.random().toString(36).substring(7);
btn.onclick = function() { box.style.display = box.style.display === 'none' ? 'flex' : 'none'; };
box.querySelector('#lore-close').onclick = function() { box.style.display = 'none'; };
async function handleAsk() {
var text = input.value.trim();
if (!text) return;
input.value = '';
// Add User Message
var uMsg = document.createElement('div');
uMsg.style.cssText = 'align-self:flex-end;background:#8b5cf6;padding:10px 15px;border-radius:12px;max-width:80%;';
uMsg.innerText = text;
chat.appendChild(uMsg);
chat.scrollTop = chat.scrollHeight;
// Add AI Message Placeholder
var aMsg = document.createElement('div');
aMsg.style.cssText = 'background:rgba(255,255,255,0.05);padding:12px;border-radius:12px;max-width:90%;border-left:3px solid #8b5cf6;';
aMsg.innerHTML = '<i>The scribe is searching...</i>';
chat.appendChild(aMsg);
try {
const response = await fetch('https://npc-forge--npc-forge-qh4gc.asia-southeast1.hosted.app/api/lore/stream', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ question: text, conversationId: convId })
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
aMsg.innerHTML = '';
var fullContent = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
fullContent += chunk;
aMsg.innerText = fullContent; // Typewriter effect
chat.scrollTop = chat.scrollHeight;
}
} catch (err) {
aMsg.innerHTML = '<span style="color:#ef4444;">The archives are unreachable at the moment.</span>';
}
}
send.onclick = handleAsk;
input.onkeypress = function(e) { if (e.key === 'Enter') handleAsk(); };
})();