webui: improve comment functionality for Monaco diff editor by using gutter

This was a bit of a journey. To me, the correct functionality is like
the breakpoint setting in VSCode. I had o3 find the relevant code and
tried to feed it back into Sketch, but it turned out I had to break it
down into pieces. (Asking it for the whole thing failed several times.)
In the end, I asked Sketch first to add a comment icon in the gutters.
This required just the right "glyphMargin" settings and finally worked.
In the next session, it worked on showing/hiding them depending on where
you were hovering. In the one after that, it deleted the old comment box
functionality, and then in the one after that, added that functionality
back in. And now we're here, and it seems to work.

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: sd81ff0507f3398a8k
diff --git a/webui/src/web-components/demo/comment-test.html b/webui/src/web-components/demo/comment-test.html
new file mode 100644
index 0000000..b4fd6f0
--- /dev/null
+++ b/webui/src/web-components/demo/comment-test.html
@@ -0,0 +1,143 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Monaco Comment Test</title>
+    <style>
+      body {
+        font-family:
+          -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
+          Arial, sans-serif;
+        max-width: 1200px;
+        margin: 0 auto;
+        padding: 2rem;
+      }
+
+      h1 {
+        color: #333;
+        margin-bottom: 2rem;
+      }
+
+      .test-container {
+        border: 2px solid #ddd;
+        border-radius: 4px;
+        padding: 20px;
+        margin: 20px 0;
+        height: 400px;
+      }
+
+      .event-log {
+        background: #f5f5f5;
+        border: 1px solid #ccc;
+        border-radius: 4px;
+        padding: 10px;
+        margin: 20px 0;
+        max-height: 200px;
+        overflow-y: auto;
+        font-family: monospace;
+        font-size: 12px;
+      }
+
+      .event-log .event {
+        margin-bottom: 5px;
+        padding: 2px 0;
+        border-bottom: 1px solid #eee;
+      }
+
+      .instruction {
+        background: #e8f4f8;
+        border: 1px solid #bee5eb;
+        border-radius: 4px;
+        padding: 10px;
+        margin: 10px 0;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Monaco Comment Test</h1>
+
+    <div class="instruction">
+      <strong>Instructions:</strong>
+      <ol>
+        <li>Hover over a line to see the comment glyph (💬) appear</li>
+        <li>Click on the glyph to open a comment box for that line</li>
+        <li>
+          Try clicking and dragging from one glyph to another to select multiple
+          lines
+        </li>
+        <li>
+          <strong>NEW:</strong> Make a text selection in the editor, then click
+          a glyph - it will use your selection instead of the line
+        </li>
+        <li>Fill out the comment and click "Add" to test the event dispatch</li>
+      </ol>
+    </div>
+
+    <div class="test-container">
+      <sketch-monaco-view id="testEditor"></sketch-monaco-view>
+    </div>
+
+    <div class="event-log" id="eventLog">
+      <strong>Event Log:</strong>
+    </div>
+
+    <script type="module">
+      // Load the Monaco component
+      import "../../dist/web-components/sketch-monaco-view.js";
+
+      document.addEventListener("DOMContentLoaded", () => {
+        const editor = document.getElementById("testEditor");
+        const eventLog = document.getElementById("eventLog");
+
+        // Set up test content
+        editor.originalCode = `function calculateTotal(items) {
+  return items
+    .map(item => item.price * item.quantity)
+    .reduce((a, b) => a + b, 0);
+}`;
+
+        editor.modifiedCode = `function calculateTotal(items) {
+  // Apply discount if available
+  return items
+    .map(item => {
+      const price = item.discount ? 
+        item.price * (1 - item.discount) : 
+        item.price;
+      return price * item.quantity;
+    })
+    .reduce((a, b) => a + b, 0);
+}`;
+
+        editor.originalFilename = "original.js";
+        editor.modifiedFilename = "modified.js";
+
+        // Log events
+        function logEvent(message) {
+          const eventDiv = document.createElement("div");
+          eventDiv.className = "event";
+          eventDiv.textContent = `${new Date().toLocaleTimeString()}: ${message}`;
+          eventLog.appendChild(eventDiv);
+          eventLog.scrollTop = eventLog.scrollHeight;
+        }
+
+        // Listen for comment events
+        editor.addEventListener("monaco-comment", (event) => {
+          logEvent("Monaco comment event received");
+          logEvent(`File: ${event.detail.fileContext}`);
+          logEvent(`Editor: ${event.detail.activeEditor}`);
+          logEvent(
+            `Lines: ${event.detail.selectionRange.startLineNumber}-${event.detail.selectionRange.endLineNumber}`,
+          );
+          logEvent(
+            `Selected text: ${event.detail.selectedText.substring(0, 50)}...`,
+          );
+          logEvent(`Comment: ${event.detail.commentText}`);
+          console.log("Full comment event:", event.detail);
+        });
+
+        logEvent("Test page loaded. Monaco component initialized.");
+      });
+    </script>
+  </body>
+</html>