Gemini Test

This commit is contained in:
Michael Schimmel
2026-01-09 12:04:00 +01:00
parent f35dafeac2
commit 1387131f57
+67 -32
View File
@@ -14,12 +14,9 @@ uses
type
TBlockType = (btMarkdown, btRawText, btHtml);
/// <summary>
/// Manages an incremental Markdown/HTML stream within a TWebBrowser.
/// Supports block-based rendering and collapsible raw text sections.
/// </summary>
// Manages an incremental Markdown/HTML stream within a TWebBrowser.
// Supports block-based rendering and collapsible raw text sections.
IMarkdownStream = interface
['{A1B2C3D4-E5F6-4788-9900-112233445566}']
procedure InitializeBrowser(const Browser: TWebBrowser);
procedure BeginBlock(const AType: TBlockType; const ATitle: string = '');
procedure Append(const Content: string);
@@ -202,6 +199,7 @@ begin
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/delphi.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css">
<style>
@@ -219,56 +217,56 @@ begin
color: #0078d4; border-bottom: 1px solid #f0f0f0; margin-bottom: 6px;
}
/* Raw Text Blocks */
.raw-wrapper {
background-color: #f3f2f1;
border: 1px solid #edebe9;
border-radius: 4px;
margin: 4px 0;
display: flex;
flex-direction: column;
display: flex; flex-direction: column;
}
.raw-header {
padding: 6px 10px;
font-size: 11px;
font-weight: bold;
color: #323130;
background: #faf9f8;
display: flex;
align-items: center;
border-bottom: 1px solid transparent;
cursor: pointer;
user-select: none;
padding: 6px 10px; font-size: 11px; font-weight: bold; color: #323130;
background: #faf9f8; display: flex; align-items: center;
border-bottom: 1px solid transparent; cursor: pointer; user-select: none;
}
.raw-header:hover { background: #f0f0f0; color: #0078d4; }
.icon-svg {
width: 14px; height: 14px; margin-right: 8px;
fill: none; stroke: currentColor; stroke-width: 2;
stroke-linecap: round; stroke-linejoin: round;
transition: transform 0.2s;
}
.raw-content {
font-family: "Cascadia Code", "Consolas", monospace;
font-size: 12.5px; white-space: pre-wrap;
padding: 10px; margin: 0; overflow: hidden; color: #201f1e;
}
/* Collapsed Logic */
.collapsed .raw-content {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
.collapsed .raw-content { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; }
.collapsed .icon-svg { transform: rotate(-90deg); }
.expanded .icon-svg { transform: rotate(0deg); }
.expanded .raw-header { border-bottom-color: #edebe9; }
/* Markdown Specifics */
blockquote { border-left: 4px solid #0078d4; padding-left: 12px; color: #605e5c; }
pre { background: #f6f8fa; padding: 12px; border: 1px solid #d0d7de; border-radius: 6px; }
/* Code Blocks & Copy Button */
.code-wrapper { position: relative; margin: 1em 0; }
pre { background: #f6f8fa; padding: 12px; border: 1px solid #d0d7de; border-radius: 6px; overflow-x: auto; margin: 0; }
code { font-family: "Cascadia Code", Consolas, monospace; font-size: 90%; }
.copy-btn {
position: sticky; top: 10px; float: right; z-index: 10;
margin-top: 10px; margin-bottom: -42px; margin-right: 10px;
display: flex; align-items: center; justify-content: center;
width: 32px; height: 32px;
background-color: rgba(255, 255, 255, 0.8); backdrop-filter: blur(2px);
border: 1px solid #d0d7de; border-radius: 6px;
cursor: pointer; color: #57606a; transition: all 0.2s;
}
.copy-btn:hover { background-color: #ffffff; color: #0969da; border-color: #0969da; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.copy-btn:active { background-color: #edeff2; transform: translateY(1px); }
.copy-btn svg { fill: currentColor; }
</style>
</head>
<body>
@@ -282,8 +280,10 @@ begin
let currentTitle = "";
let currentBuffer = "";
// Inline SVG für das Icon
// Icons
const chevronSvg = '<svg class="icon-svg" viewBox="0 0 24 24"><polyline points="6 9 12 15 18 9"></polyline></svg>';
const iconCopy = '<svg viewBox="0 0 16 16" width="16" height="16"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg>';
const iconCheck = '<svg viewBox="0 0 16 16" width="16" height="16" style="color: #2da44e"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path></svg>';
function toggleBlock(header) {
const wrapper = header.closest('.raw-wrapper');
@@ -294,6 +294,35 @@ begin
}
}
function addCopyButtons(container) {
const pres = container.querySelectorAll("pre");
pres.forEach(function(preBlock) {
if (preBlock.parentNode.classList.contains("code-wrapper")) return;
const wrapper = document.createElement("div");
wrapper.className = "code-wrapper";
preBlock.parentNode.insertBefore(wrapper, preBlock);
wrapper.appendChild(preBlock);
const button = document.createElement("button");
button.className = "copy-btn";
button.innerHTML = iconCopy;
button.title = "Copy to Clipboard";
button.addEventListener("click", function() {
const code = preBlock.querySelector("code");
if (!code) return;
const text = code.innerText;
navigator.clipboard.writeText(text).then(function() {
button.innerHTML = iconCheck;
setTimeout(function() { button.innerHTML = iconCopy; }, 2000);
}, function(err) { console.error("Clipboard failed", err); });
});
wrapper.insertBefore(button, preBlock);
});
}
function renderTo(target, content, mode, title, isFinal) {
target.innerHTML = "";
if (mode === "markdown") {
@@ -306,6 +335,13 @@ begin
const c = document.createElement("div");
c.innerHTML = (typeof marked !== "undefined") ? marked.parse(content) : content;
target.appendChild(c);
// Highlight and add Copy Buttons
if (typeof hljs !== "undefined") {
c.querySelectorAll("pre code").forEach((block) => { hljs.highlightElement(block); });
}
addCopyButtons(c);
} else if (mode === "text") {
const wrapper = document.createElement("div");
wrapper.className = "raw-wrapper " + (isFinal ? "collapsed" : "expanded");
@@ -313,7 +349,6 @@ begin
const header = document.createElement("div");
header.className = "raw-header";
header.onclick = function() { toggleBlock(this); };
header.innerHTML = chevronSvg + '<span>' + (title || "Raw Output") + '</span>';
const code = document.createElement("pre");