User:Jono Bean/common.js: Difference between revisions

From DQWiki
Jump to navigationJump to search
mNo edit summary
No edit summary
 
(11 intermediate revisions by the same user not shown)
Line 1: Line 1:
/* Lorekeeper Standalone Terminal v2 */
/* Lorekeeper Widget Loader - v1.1.3 (Hardened Responsive Iframe) */
(function() {
(function() {
     function initLorekeeper() {
     var username = mw.config.get('wgUserName');
         if (document.getElementById('lore-terminal-btn')) return;
    var isMobileParent = window.innerWidth < 768; // Measure the true Wiki window size
   
    // Uses the correct Firebase Hosted App URL
    var iframeUrl = 'https://npc-forge--npc-forge-qh4gc.asia-southeast1.hosted.app/widget';
   
    var params = [];
    if (username) {
         params.push('user=' + encodeURIComponent(username));
    } else {
        params.push('guest=Traveler');
    }
   
    // Tell the iframe if the user is ACTUALLY on mobile
    if (isMobileParent) {
        params.push('isMobile=true');
    }
   
    if (params.length > 0) {
        iframeUrl += '?' + params.join('&');
    }


        // 1. Create Floating Button
    // Create a container that doesn't block the Wiki
        var btn = document.createElement('div');
    var widgetContainer = document.createElement('div');
        btn.id = 'lore-terminal-btn';
    widgetContainer.id = 'lorekeeper-widget-container';
        btn.innerHTML = '?';
    widgetContainer.style.cssText = 'position:fixed; bottom:0; right:0; z-index:99999; pointer-events:none; transition: width 0.3s ease, height 0.3s ease;';
        btn.style.cssText = 'position:fixed !important; bottom:30px !important; right:30px !important; 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.6); z-index:9999999 !important; border:2px solid rgba(255,255,255,0.3); transition: transform 0.2s ease;';
    widgetContainer.style.width = isMobileParent ? '80px' : '300px';  
       
    widgetContainer.style.height = isMobileParent ? '80px' : '120px';
        // 2. Create Chat Box
        var box = document.createElement('div');
        box.id = 'lore-terminal-box';
        box.style.cssText = 'position:fixed !important; bottom:100px !important; right:30px !important; width:400px; height:600px; background:rgb(15,15,20); border:1px solid rgba(139,92,246,0.5); border-radius:24px; display:none; flex-direction:column; box-shadow:0 25px 60px rgba(0,0,0,0.8); overflow:hidden; z-index:9999999 !important; color:#ffffff; font-family: sans-serif;';
       
        box.innerHTML =
            '<div style="padding:15px 20px; background:rgba(139,92,246,0.15); border-bottom:1px solid rgba(139,92,246,0.3); display:flex; justify-content:space-between; align-items:center;">' +
                '<div style="font-weight:bold; color:#a78bfa; font-size:16px;">Archives of the Western Kingdom</div>' +
                '<div id="lore-close" style="cursor:pointer; font-size:20px; color:#fff; padding:5px;">?</div>' +
            '</div>' +
            '<div id="lore-chat" style="flex:1; overflow-y:auto; padding:20px; display:flex; flex-direction:column; gap:12px; font-size:14px; line-height:1.5;">' +
                '<div style="background:rgba(255,255,255,0.08); padding:12px 16px; border-radius:12px; border-left:4px solid #8b5cf6;">Greetings, Scribe. What knowledge do you seek from the archives?</div>' +
            '</div>' +
            '<div style="padding:15px; background:rgba(0,0,0,0.3); 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.3); padding:10px 14px; border-radius:10px; color:#fff; outline:none; font-size:14px;">' +
                '<button id="lore-send" style="background:#8b5cf6; border:none; color:#fff; padding:0 18px; border-radius:10px; cursor:pointer; font-weight:bold; font-size:14px;">Ask</button>' +
            '</div>';


        document.body.appendChild(btn);
    var iframe = document.createElement('iframe');
        document.body.appendChild(box);
    iframe.src = iframeUrl;
    iframe.style.cssText = 'width:100%; height:100%; border:none; background:transparent; pointer-events:auto;';
    iframe.setAttribute('allow', 'clipboard-write'); // For links/sharing later


        // Events
    widgetContainer.appendChild(iframe);
        var chat = document.getElementById('lore-chat');
    document.body.appendChild(widgetContainer);
        var input = document.getElementById('lore-input');
        var send = document.getElementById('lore-send');
        var convId = 'anon-' + Math.random().toString(36).substring(7);


        btn.onclick = function() {
    // Listen for the widget telling the Wiki to "Grow" and "Shrink"
            box.style.display = (box.style.display === 'none' || box.style.display === '') ? 'flex' : 'none';
    window.addEventListener('message', function(event) {
         };
        // Enforce secure origin check for the correct App Hosting domain
         document.getElementById('lore-close').onclick = function() { box.style.display = 'none'; };
        if (event.origin !== 'https://npc-forge--npc-forge-qh4gc.asia-southeast1.hosted.app') return;
 
          
        async function handleAsk() {
         if (event.data.type === 'lorekeeper-resize') {
             var text = input.value.trim();
             var w = event.data.width;
             if (!text) return;
             var h = event.data.height;
            input.value = '';
             // Handle both pixel numbers (desktop) and string values like "100vw" (mobile)
 
             widgetContainer.style.width = (typeof w === 'number') ? w + 'px' : w;
             // User UI
             widgetContainer.style.height = (typeof h === 'number') ? h + 'px' : h;
             var uDiv = document.createElement('div');
        }
             uDiv.style.cssText = 'align-self:flex-end; background:#8b5cf6; padding:10px 14px; border-radius:12px; max-width:85%; font-weight:500;';
    });
            uDiv.textContent = text;
            chat.appendChild(uDiv);
            chat.scrollTop = chat.scrollHeight;


            // AI UI Placeholder
    // Optional: Resync if they resize the window wildly (desktop to mobile mode live)
            var aDiv = document.createElement('div');
    window.addEventListener('resize', function() {
            aDiv.style.cssText = 'background:rgba(255,255,255,0.05); padding:12px 16px; border-radius:12px; max-width:92%; border-left:4px solid #8b5cf6; white-space: pre-wrap;';
        var newIsMobile = window.innerWidth < 768;
            aDiv.innerHTML = '<i>Searching the archives...</i>';
        if (newIsMobile !== isMobileParent) {
            chat.appendChild(aDiv);
            isMobileParent = newIsMobile;
 
            // You could reload the iframe here, but keeping it simple is usually safest.
            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();
                aDiv.textContent = '';
                var content = '';
 
                while (true) {
                    const { done, value } = await reader.read();
                    if (done) break;
                    content += decoder.decode(value);
                    aDiv.textContent = content; // Typewriter
                    chat.scrollTop = chat.scrollHeight;
                }
            } catch (e) {
                aDiv.innerHTML = '<span style="color:#f87171;">Connection to archives lost.</span>';
            }
         }
         }
 
     });
        send.onclick = handleAsk;
        input.onkeydown = function(e) { if (e.key === 'Enter') handleAsk(); };
    }
 
    // Wait for the document to be ready
    if (document.readyState === "complete" || document.readyState === "interactive") {
        initLorekeeper();
     } else {
        window.addEventListener("DOMContentLoaded", initLorekeeper);
    }
})();
})();

Latest revision as of 08:07, 1 March 2026

/* Lorekeeper Widget Loader - v1.1.3 (Hardened Responsive Iframe) */
(function() {
    var username = mw.config.get('wgUserName');
    var isMobileParent = window.innerWidth < 768; // Measure the true Wiki window size
    
    // Uses the correct Firebase Hosted App URL
    var iframeUrl = 'https://npc-forge--npc-forge-qh4gc.asia-southeast1.hosted.app/widget';
    
    var params = [];
    if (username) {
        params.push('user=' + encodeURIComponent(username));
    } else {
        params.push('guest=Traveler');
    }
    
    // Tell the iframe if the user is ACTUALLY on mobile
    if (isMobileParent) {
        params.push('isMobile=true');
    }
    
    if (params.length > 0) {
        iframeUrl += '?' + params.join('&');
    }

    // Create a container that doesn't block the Wiki
    var widgetContainer = document.createElement('div');
    widgetContainer.id = 'lorekeeper-widget-container';
    widgetContainer.style.cssText = 'position:fixed; bottom:0; right:0; z-index:99999; pointer-events:none; transition: width 0.3s ease, height 0.3s ease;';
    widgetContainer.style.width = isMobileParent ? '80px' : '300px'; 
    widgetContainer.style.height = isMobileParent ? '80px' : '120px';

    var iframe = document.createElement('iframe');
    iframe.src = iframeUrl;
    iframe.style.cssText = 'width:100%; height:100%; border:none; background:transparent; pointer-events:auto;';
    iframe.setAttribute('allow', 'clipboard-write'); // For links/sharing later

    widgetContainer.appendChild(iframe);
    document.body.appendChild(widgetContainer);

    // Listen for the widget telling the Wiki to "Grow" and "Shrink"
    window.addEventListener('message', function(event) {
        // Enforce secure origin check for the correct App Hosting domain
        if (event.origin !== 'https://npc-forge--npc-forge-qh4gc.asia-southeast1.hosted.app') return;
        
        if (event.data.type === 'lorekeeper-resize') {
            var w = event.data.width;
            var h = event.data.height;
            // Handle both pixel numbers (desktop) and string values like "100vw" (mobile)
            widgetContainer.style.width = (typeof w === 'number') ? w + 'px' : w;
            widgetContainer.style.height = (typeof h === 'number') ? h + 'px' : h;
        }
    });

    // Optional: Resync if they resize the window wildly (desktop to mobile mode live)
    window.addEventListener('resize', function() {
        var newIsMobile = window.innerWidth < 768;
        if (newIsMobile !== isMobileParent) {
            isMobileParent = newIsMobile;
            // You could reload the iframe here, but keeping it simple is usually safest.
        }
    });
})();