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(); };
})();