OpenWebUI Fullscreen Chat Messages

Add fullscreen functionality to chat messages in Open Web-UI

// ==UserScript==
// @name         OpenWebUI Fullscreen Chat Messages
// @name:zh-CN   OpenWebUI多模型对话全屏查看
// @namespace    http://tampermonkey.net/
// @version      0.4
// @description  Add fullscreen functionality to chat messages in Open Web-UI
// @description:zh-CN 让Open WebUI的多模型对话能全屏展示
// @author       Van
// @match        https://ai.huzi-baozi.com/c/*  //注意修改为你自己的域名
// @grant        none
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  // Create and inject CSS for the fullscreen functionality
  const style = document.createElement('style');
  style.textContent = `
        .fullscreen-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.9);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 10000;
            opacity: 0;
            transform: scale(0.8);
            transition: all 0.3s ease;
        }

        @media (prefers-color-scheme: dark) {
            .fullscreen-overlay {
                background: rgba(0, 0, 0, 0.95);
            }
        }

        .fullscreen-overlay.active {
            opacity: 1;
            transform: scale(1);
        }

        .fullscreen-content {
            max-width: 90%;
            max-height: 90%;
            overflow: auto;
            background: white;
            border-radius: 10px;
            padding: 20px;
            box-shadow: 0 0 30px rgba(255, 255, 255, 0.2);
        }

        @media (prefers-color-scheme: dark) {
            .fullscreen-content {
                background: #1a1a1a;
                color: #ffffff;
                box-shadow: 0 0 30px rgba(0, 0, 0, 0.5);
            }
        }

        .fullscreen-content blockquote {
            border-left: 4px solid #ccc;
            margin: 1em 0;
            padding: 0.5em 1em;
            background: #f9f9f9;
            color: #666;
            font-style: italic;
        }

        @media (prefers-color-scheme: dark) {
            .fullscreen-content blockquote {
                border-left-color: #555;
                background: #2a2a2a;
                color: #aaa;
            }
        }

        .fullscreen-close {
            position: absolute;
            top: 20px;
            right: 20px;
            color: white;
            font-size: 30px;
            cursor: pointer;
            background: none;
            border: none;
            z-index: 10001;
        }

        @media (prefers-color-scheme: dark) {
            .fullscreen-close {
                color: #ddd;
            }
        }

        .fullscreen-icon {
            // position: absolute;
            top: 10px;
            right: 10px;
            cursor: pointer;
            z-index: 9999;
            // background: rgba(255, 255, 255, 0.8);
            border-radius: 50%;
            padding: 5px;
            transition: opacity 0.3s ease;
            opacity: 0;
        }

        .message-container:hover .fullscreen-icon {
            opacity: 1;
        }

        .fullscreen-icon svg {
            width: 20px;
            height: 20px;
        }
    `;
  document.head.appendChild(style);

  // Create fullscreen icon SVG
  function createFullscreenIcon() {
    const icon = document.createElement('div');
    icon.className = 'fullscreen-icon';
    icon.innerHTML = `
            <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5" />
            </svg>
        `;
    return icon;
  }

  // Create fullscreen overlay
  function createFullscreenOverlay(content) {
    // Create overlay
    const overlay = document.createElement('div');
    overlay.className = 'fullscreen-overlay markdown-prose';

    // Create close button
    const closeBtn = document.createElement('button');
    closeBtn.className = 'fullscreen-close';
    closeBtn.innerHTML = '&times;';
    closeBtn.addEventListener('click', () => {
      overlay.classList.remove('active');
      setTimeout(() => {
        document.body.removeChild(overlay);
      }, 300);
    });

    // Create content container
    const contentContainer = document.createElement('div');
    contentContainer.className = 'fullscreen-content';
    contentContainer.innerHTML = content;

    // Add elements to overlay
    overlay.appendChild(closeBtn);
    overlay.appendChild(contentContainer);

    // Add to document
    document.body.appendChild(overlay);

    // Trigger animation
    setTimeout(() => {
      overlay.classList.add('active');
    }, 10);

    // Close with ESC key
    const handleEsc = (e) => {
      if (e.key === 'Escape') {
        closeBtn.click();
        document.removeEventListener('keydown', handleEsc);
      }
    };
    document.addEventListener('keydown', handleEsc);

    return overlay;
  }

  // Add fullscreen icon to message containers
  function addFullscreenIcons() {
    // Select all message containers with IDs starting with "message-"
    const messageContainers = document.querySelectorAll('[id^="message-"]');

    messageContainers.forEach(container => {
      // Skip if icon already exists
      if (container.querySelector('.fullscreen-icon')) return;

      // Add class for styling
      container.classList.add('message-container');

      // Create and add icon
      const icon = createFullscreenIcon();
      container.appendChild(icon);

      // Add click event
      icon.addEventListener('click', (e) => {
        e.stopPropagation();

        // Get content to display fullscreen
        const contentContainer = container.querySelector('.chat-assistant');
        if (contentContainer) {
          createFullscreenOverlay(contentContainer.innerHTML);
        }
      });
    });
  }

  // Initialize the script
  function init() {
    // Add icons to existing messages
    addFullscreenIcons();

    // Watch for new messages and add icons to them
    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === 'childList') {
          mutation.addedNodes.forEach((node) => {
            if (node.nodeType === 1) { // Element node
              // Check if this is a message container or contains message containers
              if (node.id && node.id.startsWith('message-')) {
                // Add class for styling
                node.classList.add('message-container');

                // Add icon if not already present
                if (!node.querySelector('.fullscreen-icon')) {
                  const icon = createFullscreenIcon();
                  node.appendChild(icon);

                  icon.addEventListener('click', (e) => {
                    e.stopPropagation();
                    const contentContainer = node.querySelector('.chat-assistant');
                    if (contentContainer) {
                      createFullscreenOverlay(contentContainer.innerHTML);
                    }
                  });
                }
              }
            }
          });
        }
      });
    });

    // Start observing
    observer.observe(document.body, {
      childList: true,
      subtree: true
    });
  }

  // Run initialization when page is ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();