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

From DQWiki
Jump to navigationJump to search
mNo edit summary
No edit summary
 
(13 intermediate revisions by the same user not shown)
Line 1: Line 1:
/* Lorekeeper Standalone Terminal */
/* Lorekeeper Widget Loader - v1.1.3 (Hardened Responsive Iframe) */
(function() {
(function() {
     if (document.getElementById('lore-terminal-btn')) return;
     var username = mw.config.get('wgUserName');
 
     var isMobileParent = window.innerWidth < 768; // Measure the true Wiki window size
    // 1. Create Floating Button
      
     var btn = document.createElement('div');
     // Uses the correct Firebase Hosted App URL
     btn.id = 'lore-terminal-btn';
     var iframeUrl = 'https://npc-forge--npc-forge-qh4gc.asia-southeast1.hosted.app/widget';
     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);';
    var params = [];
     btn.onmouseover = function() { this.style.transform = 'scale(1.1) rotate(15deg)'; };
    if (username) {
    btn.onmouseout = function() { this.style.transform = 'scale(1) rotate(0deg)'; };
        params.push('user=' + encodeURIComponent(username));
 
    } else {
     // 2. Create Chat Box
        params.push('guest=Traveler');
     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;';
     // Tell the iframe if the user is ACTUALLY on mobile
     if (isMobileParent) {
        params.push('isMobile=true');
     }
      
      
     box.innerHTML = `
     if (params.length > 0) {
        <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;">
         iframeUrl += '?' + params.join('&');
            <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);
     // Create a container that doesn't block the Wiki
     document.body.appendChild(box);
    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';


    // 3. Logic
     var iframe = document.createElement('iframe');
     var chat = box.querySelector('#lore-chat');
     iframe.src = iframeUrl;
     var input = box.querySelector('#lore-input');
    iframe.style.cssText = 'width:100%; height:100%; border:none; background:transparent; pointer-events:auto;';
     var send = box.querySelector('#lore-send');
     iframe.setAttribute('allow', 'clipboard-write'); // For links/sharing later
    var convId = 'anon-' + Math.random().toString(36).substring(7);


     btn.onclick = function() { box.style.display = box.style.display === 'none' ? 'flex' : 'none'; };
     widgetContainer.appendChild(iframe);
     box.querySelector('#lore-close').onclick = function() { box.style.display = 'none'; };
     document.body.appendChild(widgetContainer);


     async function handleAsk() {
     // Listen for the widget telling the Wiki to "Grow" and "Shrink"
         var text = input.value.trim();
    window.addEventListener('message', function(event) {
         if (!text) return;
         // Enforce secure origin check for the correct App Hosting domain
        input.value = '';
         if (event.origin !== 'https://npc-forge--npc-forge-qh4gc.asia-southeast1.hosted.app') return;
 
          
        // Add User Message
        if (event.data.type === 'lorekeeper-resize') {
        var uMsg = document.createElement('div');
            var w = event.data.width;
         uMsg.style.cssText = 'align-self:flex-end;background:#8b5cf6;padding:10px 15px;border-radius:12px;max-width:80%;';
            var h = event.data.height;
        uMsg.innerText = text;
            // Handle both pixel numbers (desktop) and string values like "100vw" (mobile)
        chat.appendChild(uMsg);
            widgetContainer.style.width = (typeof w === 'number') ? w + 'px' : w;
        chat.scrollTop = chat.scrollHeight;
            widgetContainer.style.height = (typeof h === 'number') ? h + 'px' : h;
 
         }
        // 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 {
    // Optional: Resync if they resize the window wildly (desktop to mobile mode live)
            const response = await fetch('https://npc-forge--npc-forge-qh4gc.asia-southeast1.hosted.app/api/lore/stream', {
    window.addEventListener('resize', function() {
                method: 'POST',
        var newIsMobile = window.innerWidth < 768;
                headers: { 'Content-Type': 'application/json' },
        if (newIsMobile !== isMobileParent) {
                body: JSON.stringify({ question: text, conversationId: convId })
            isMobileParent = newIsMobile;
            });
            // You could reload the iframe here, but keeping it simple is usually safest.
 
            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(); };
})();
})();

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