Skip to content

Render interactive catalog resources in an in-app HTML viewer - #51

Open
soyalejolopez wants to merge 1 commit into
masterfrom
alejanl-microsoft-fantastic-invention
Open

Render interactive catalog resources in an in-app HTML viewer#51
soyalejolopez wants to merge 1 commit into
masterfrom
alejanl-microsoft-fantastic-invention

Conversation

@soyalejolopez

Copy link
Copy Markdown
Owner

Interactive catalog resources (Copilot Agents Guide, Agents Cost Calculator) now render their HTML page inside the app via a View button that opens a window-in-window modal with an Open-in-new-tab header link, instead of only linking to GitHub. Only index.html changed.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an interactive Resource Viewer Modal to index.html, allowing users to preview resources directly within an iframe. It includes the necessary CSS styling, HTML structure, and JavaScript logic to open and close the viewer, as well as handling the 'Escape' key and backdrop clicks. The review feedback suggests enhancing security by adding a sandbox attribute to the iframe, and improving accessibility by managing focus states and handling keydown events within same-origin iframe contexts.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread index.html
<button class="viewer-close" id="viewerClose" type="button" aria-label="Close viewer">&times;</button>
</div>
</div>
<iframe class="viewer-iframe" id="viewerFrame" title="Resource preview" loading="lazy" referrerpolicy="no-referrer"></iframe>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

To follow security best practices and enforce a strong security boundary, consider adding a sandbox attribute to the <iframe>. Since the embedded interactive resources are same-origin and require scripts, using allow-scripts allow-same-origin allow-popups allow-forms will ensure they function correctly while preventing them from navigating the top-level window (allow-top-navigation is omitted).

<iframe class="viewer-iframe" id="viewerFrame" title="Resource preview" loading="lazy" referrerpolicy="no-referrer" sandbox="allow-scripts allow-same-origin allow-popups allow-forms"></iframe>

Comment thread index.html
Comment on lines +2479 to +2496
function openViewer(name, url) {
const overlay = document.getElementById('viewerOverlay');
const frame = document.getElementById('viewerFrame');
document.getElementById('viewerTitle').textContent = name;
document.getElementById('viewerOpenTab').href = url;
frame.src = url;
overlay.classList.add('open');
document.body.style.overflow = 'hidden';
if (typeof window.clarity !== 'undefined') { window.clarity('event', 'resource_preview'); }
}

function closeViewer() {
const overlay = document.getElementById('viewerOverlay');
const frame = document.getElementById('viewerFrame');
overlay.classList.remove('open');
frame.src = 'about:blank';
document.body.style.overflow = '';
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve accessibility (A11y) and user experience, we should manage focus when opening and closing the modal. Specifically:

  1. Store the currently focused element before opening the modal, and restore focus to it when the modal is closed.
  2. Set focus to the close button when the modal opens so keyboard users can easily dismiss it.
  3. Bind an Escape key listener inside the same-origin iframe's document, as keydown events inside an iframe do not bubble up to the parent document.
    let activeElementBeforeModal = null;

    function openViewer(name, url) {
      activeElementBeforeModal = document.activeElement;
      const overlay = document.getElementById('viewerOverlay');
      const frame = document.getElementById('viewerFrame');
      document.getElementById('viewerTitle').textContent = name;
      document.getElementById('viewerOpenTab').href = url;
      frame.src = url;

      // Enable Escape key to close the viewer even when focus is inside the same-origin iframe
      frame.onload = () => {
        try {
          frame.contentDocument.addEventListener('keydown', (e) => {
            if (e.key === 'Escape') closeViewer();
          });
        } catch (err) {
          // Ignore cross-origin or loading errors
        }
      };

      overlay.classList.add('open');
      document.body.style.overflow = 'hidden';
      document.getElementById('viewerClose').focus();
      if (typeof window.clarity !== 'undefined') { window.clarity('event', 'resource_preview'); }
    }

    function closeViewer() {
      const overlay = document.getElementById('viewerOverlay');
      const frame = document.getElementById('viewerFrame');
      overlay.classList.remove('open');
      frame.src = 'about:blank';
      document.body.style.overflow = '';
      if (activeElementBeforeModal) {
        activeElementBeforeModal.focus();
      }
    }

Interactive resources (Copilot Agents Guide, Agents Cost Calculator) now
render their HTML page in an in-app modal (window-in-window) with a header
that links to the full page in a new tab, instead of only linking to GitHub.
The embed path is derived from each resource's source (README.md -> index.html),
so no catalog.json schema changes are required.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dad50700-e239-43cc-8994-b475682137c4
@soyalejolopez
soyalejolopez force-pushed the alejanl-microsoft-fantastic-invention branch from 4c27395 to dbf1bb8 Compare July 21, 2026 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants