User:Jono Bean/common.js: Difference between revisions
From DQWiki
Jump to navigationJump to search
No edit summary |
No edit summary |
||
| Line 1: | Line 1: | ||
/* Lorekeeper | /* Lorekeeper Standalone Terminal */ | ||
(function() { | (function() { | ||
if (document.getElementById('lore-terminal-btn')) return; | |||
if (document.getElementById(' | |||
var | // 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( | 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(); }; | |||
})(); | })(); | ||
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(); };
})();