mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 19:05:11 +00:00
Fix export-html styling and behavior
- Fix UTF-8 decoding with TextDecoder for base64 session data - Use toolOutput color for expand hints (not borderAccent) - Remove '- click to expand' text to match TUI - Ctrl+O toggles expanded state (not visibility) on tool outputs - Edit diffs always visible (not affected by Ctrl+O) - Remove Ctrl+F override to allow browser search - Replace tabs with 3 spaces in all tool outputs - Fix syntax highlighting default color to use --text - Add more hljs token selectors (property, punctuation, operator) - Compaction uses customMessageBg/Label/Text colors - Model change uses dim color without background - Scroll to end on initial load - Pointer cursor on expandable elements
This commit is contained in:
parent
55fd8d9fed
commit
fcb700701e
1 changed files with 112 additions and 68 deletions
|
|
@ -214,6 +214,14 @@
|
|||
max-width: 800px;
|
||||
}
|
||||
|
||||
/* Help bar */
|
||||
.help-bar {
|
||||
font-size: 11px;
|
||||
color: var(--dim);
|
||||
margin-bottom: 16px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.header {
|
||||
background: var(--container-bg);
|
||||
|
|
@ -278,6 +286,10 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.assistant-message > .message-timestamp {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.assistant-text {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
|
@ -289,6 +301,13 @@
|
|||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.thinking-collapsed {
|
||||
display: none;
|
||||
padding: 12px 16px;
|
||||
color: var(--thinkingText);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Tool execution */
|
||||
.tool-execution {
|
||||
padding: 12px 16px;
|
||||
|
|
@ -305,7 +324,7 @@
|
|||
}
|
||||
|
||||
.tool-path {
|
||||
color: var(--borderAccent);
|
||||
color: var(--accent);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
|
|
@ -353,6 +372,7 @@
|
|||
.tool-output code {
|
||||
padding: 0;
|
||||
background: none;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.tool-output.expandable {
|
||||
|
|
@ -387,9 +407,7 @@
|
|||
}
|
||||
|
||||
.expand-hint {
|
||||
color: var(--borderAccent);
|
||||
font-style: italic;
|
||||
margin-top: 4px;
|
||||
color: var(--toolOutput);
|
||||
}
|
||||
|
||||
/* Diff */
|
||||
|
|
@ -397,6 +415,7 @@
|
|||
margin-top: 12px;
|
||||
font-size: 11px;
|
||||
overflow-x: auto;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.diff-added { color: var(--toolDiffAdded); }
|
||||
|
|
@ -406,8 +425,6 @@
|
|||
/* Model change */
|
||||
.model-change {
|
||||
padding: 8px 16px;
|
||||
background: var(--info-bg);
|
||||
border-radius: 4px;
|
||||
color: var(--dim);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
|
@ -417,59 +434,41 @@
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Compaction */
|
||||
/* Compaction / Branch Summary - matches customMessage colors from TUI */
|
||||
.compaction {
|
||||
background: var(--info-bg);
|
||||
background: var(--customMessageBg);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.compaction-header {
|
||||
padding: 12px 16px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.compaction-header:hover {
|
||||
background: var(--selectedBg);
|
||||
}
|
||||
|
||||
.compaction-toggle {
|
||||
color: var(--borderAccent);
|
||||
font-size: 10px;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.compaction.expanded .compaction-toggle {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.compaction-title {
|
||||
color: var(--text);
|
||||
.compaction-label {
|
||||
color: var(--customMessageLabel);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.compaction-collapsed {
|
||||
color: var(--customMessageText);
|
||||
}
|
||||
|
||||
.compaction-content {
|
||||
display: none;
|
||||
padding: 0 16px 16px;
|
||||
color: var(--customMessageText);
|
||||
white-space: pre-wrap;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.compaction.expanded .compaction-collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.compaction.expanded .compaction-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.compaction-summary {
|
||||
background: var(--selectedBg);
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* System prompt */
|
||||
.system-prompt {
|
||||
background: var(--info-bg);
|
||||
background: var(--customMessageBg);
|
||||
padding: 12px 16px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 16px;
|
||||
|
|
@ -477,12 +476,12 @@
|
|||
|
||||
.system-prompt-header {
|
||||
font-weight: bold;
|
||||
color: var(--warning);
|
||||
color: var(--customMessageLabel);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.system-prompt-content {
|
||||
color: var(--dim);
|
||||
color: var(--customMessageText);
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
font-size: 11px;
|
||||
|
|
@ -656,15 +655,17 @@
|
|||
}
|
||||
|
||||
/* Syntax highlighting */
|
||||
.hljs { background: transparent; }
|
||||
.hljs { background: transparent; color: var(--text); }
|
||||
.hljs-comment, .hljs-quote { color: var(--syntaxComment); }
|
||||
.hljs-keyword, .hljs-selector-tag { color: var(--syntaxKeyword); }
|
||||
.hljs-number, .hljs-literal { color: var(--syntaxNumber); }
|
||||
.hljs-string, .hljs-doctag { color: var(--syntaxString); }
|
||||
.hljs-title, .hljs-section, .hljs-name { color: var(--syntaxFunction); }
|
||||
.hljs-type, .hljs-class, .hljs-built_in { color: var(--syntaxType); }
|
||||
.hljs-attr, .hljs-variable, .hljs-params { color: var(--syntaxVariable); }
|
||||
.hljs-attr, .hljs-variable, .hljs-params, .hljs-property { color: var(--syntaxVariable); }
|
||||
.hljs-meta { color: var(--syntaxKeyword); }
|
||||
.hljs-punctuation, .hljs-operator { color: var(--syntaxOperator); }
|
||||
.hljs-subst { color: var(--text); }
|
||||
|
||||
/* Footer */
|
||||
.footer {
|
||||
|
|
@ -783,6 +784,7 @@
|
|||
</aside>
|
||||
<main id="content">
|
||||
<div id="header-container"></div>
|
||||
<div class="help-bar">Ctrl+T toggle thinking · Ctrl+O toggle tools · Esc reset</div>
|
||||
<div id="messages"></div>
|
||||
<div class="footer">
|
||||
Generated by {{APP_NAME}} on {{GENERATED_DATE}}
|
||||
|
|
@ -801,7 +803,14 @@
|
|||
(function() {
|
||||
'use strict';
|
||||
|
||||
const data = JSON.parse(atob(document.getElementById('session-data').textContent));
|
||||
// Decode base64 with proper UTF-8 handling
|
||||
const base64 = document.getElementById('session-data').textContent;
|
||||
const binary = atob(base64);
|
||||
const bytes = new Uint8Array(binary.length);
|
||||
for (let i = 0; i < binary.length; i++) {
|
||||
bytes[i] = binary.charCodeAt(i);
|
||||
}
|
||||
const data = JSON.parse(new TextDecoder('utf-8').decode(bytes));
|
||||
const { header, entries, leafId, systemPrompt, tools } = data;
|
||||
|
||||
// Build entry index
|
||||
|
|
@ -1328,6 +1337,8 @@
|
|||
|
||||
// Format expandable output (matches old export-html.ts exactly)
|
||||
function formatExpandableOutput(text, maxLines, lang) {
|
||||
// Replace tabs with spaces first
|
||||
text = replaceTabs(text);
|
||||
const lines = text.split('\n');
|
||||
const displayLines = lines.slice(0, maxLines);
|
||||
const remaining = lines.length - maxLines;
|
||||
|
|
@ -1353,7 +1364,7 @@
|
|||
|
||||
let out = '<div class="tool-output expandable" onclick="this.classList.toggle(\'expanded\')">';
|
||||
out += `<div class="output-preview"><pre><code class="hljs">${previewHighlighted}</code></pre>`;
|
||||
out += `<div class="expand-hint">... (${remaining} more lines) - click to expand</div>`;
|
||||
out += `<div class="expand-hint">... (${remaining} more lines)</div>`;
|
||||
out += '</div>';
|
||||
out += `<div class="output-full"><pre><code class="hljs">${highlighted}</code></pre></div></div>`;
|
||||
return out;
|
||||
|
|
@ -1369,7 +1380,7 @@
|
|||
for (const line of displayLines) {
|
||||
out += `<div>${escapeHtml(replaceTabs(line))}</div>`;
|
||||
}
|
||||
out += `<div class="expand-hint">... (${remaining} more lines) - click to expand</div>`;
|
||||
out += `<div class="expand-hint">... (${remaining} more lines)</div>`;
|
||||
out += '</div>';
|
||||
out += '<div class="output-full">';
|
||||
for (const line of lines) {
|
||||
|
|
@ -1493,13 +1504,8 @@
|
|||
const diffLines = result.details.diff.split('\n');
|
||||
html += '<div class="tool-diff">';
|
||||
for (const line of diffLines) {
|
||||
if (line.startsWith('+')) {
|
||||
html += `<div class="diff-added">${escapeHtml(line)}</div>`;
|
||||
} else if (line.startsWith('-')) {
|
||||
html += `<div class="diff-removed">${escapeHtml(line)}</div>`;
|
||||
} else {
|
||||
html += `<div class="diff-context">${escapeHtml(line)}</div>`;
|
||||
}
|
||||
const cls = line.match(/^\+/) ? 'diff-added' : line.match(/^-/) ? 'diff-removed' : 'diff-context';
|
||||
html += `<div class="${cls}">${escapeHtml(replaceTabs(line))}</div>`;
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
|
@ -1570,7 +1576,10 @@
|
|||
if (block.type === 'text' && block.text.trim()) {
|
||||
html += `<div class="assistant-text markdown-content">${renderMarkdown(block.text)}</div>`;
|
||||
} else if (block.type === 'thinking' && block.thinking.trim()) {
|
||||
html += `<div class="thinking-block">`;
|
||||
html += `<div class="thinking-text">${escapeHtml(block.thinking)}</div>`;
|
||||
html += `<div class="thinking-collapsed">Thinking ...</div>`;
|
||||
html += `</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1617,14 +1626,10 @@
|
|||
}
|
||||
|
||||
if (entry.type === 'compaction') {
|
||||
return `<div class="compaction" id="${entryId}">
|
||||
<div class="compaction-header" onclick="this.parentElement.classList.toggle('expanded')">
|
||||
<span class="compaction-toggle">▶</span>
|
||||
<span class="compaction-title">Context compacted from ${entry.tokensBefore.toLocaleString()} tokens</span>
|
||||
</div>
|
||||
<div class="compaction-content">
|
||||
<div class="compaction-summary">${escapeHtml(entry.summary)}</div>
|
||||
</div>
|
||||
return `<div class="compaction" id="${entryId}" onclick="this.classList.toggle('expanded')">
|
||||
<div class="compaction-label">[compaction]</div>
|
||||
<div class="compaction-collapsed">Compacted from ${entry.tokensBefore.toLocaleString()} tokens (ctrl+o to expand)</div>
|
||||
<div class="compaction-content"><strong>Compacted from ${entry.tokensBefore.toLocaleString()} tokens</strong>\n\n${escapeHtml(entry.summary)}</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
|
|
@ -1738,7 +1743,8 @@
|
|||
if (scrollToTarget) {
|
||||
const targetEl = document.getElementById(`entry-${targetId}`);
|
||||
if (targetEl) {
|
||||
targetEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
// Use 'end' to ensure we scroll far enough to see the target
|
||||
targetEl.scrollIntoView({ behavior: 'smooth', block: 'end' });
|
||||
// Brief highlight
|
||||
targetEl.style.outline = '2px solid var(--accent)';
|
||||
setTimeout(() => { targetEl.style.outline = ''; }, 1500);
|
||||
|
|
@ -1791,18 +1797,56 @@
|
|||
// Close sidebar when clicking close button
|
||||
document.getElementById('sidebar-close').addEventListener('click', closeSidebar);
|
||||
|
||||
// Keyboard shortcut: Escape to reset to leaf
|
||||
// Track toggle states
|
||||
let thinkingExpanded = true;
|
||||
let toolOutputsExpanded = true;
|
||||
|
||||
const toggleThinking = () => {
|
||||
thinkingExpanded = !thinkingExpanded;
|
||||
document.querySelectorAll('.thinking-text').forEach(el => {
|
||||
el.style.display = thinkingExpanded ? '' : 'none';
|
||||
});
|
||||
document.querySelectorAll('.thinking-collapsed').forEach(el => {
|
||||
el.style.display = thinkingExpanded ? 'none' : '';
|
||||
});
|
||||
};
|
||||
|
||||
const toggleToolOutputs = () => {
|
||||
toolOutputsExpanded = !toolOutputsExpanded;
|
||||
// Toggle expanded state on expandable tool outputs
|
||||
document.querySelectorAll('.tool-output.expandable').forEach(el => {
|
||||
if (toolOutputsExpanded) {
|
||||
el.classList.add('expanded');
|
||||
} else {
|
||||
el.classList.remove('expanded');
|
||||
}
|
||||
});
|
||||
// Toggle compaction/branch-summary expanded state
|
||||
document.querySelectorAll('.compaction').forEach(el => {
|
||||
if (toolOutputsExpanded) {
|
||||
el.classList.add('expanded');
|
||||
} else {
|
||||
el.classList.remove('expanded');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Keyboard shortcuts
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
searchInput.value = '';
|
||||
searchQuery = '';
|
||||
navigateTo(leafId);
|
||||
}
|
||||
// Focus search on Ctrl/Cmd+F
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'f') {
|
||||
// Toggle thinking blocks on Ctrl+T
|
||||
if (e.ctrlKey && e.key === 't') {
|
||||
e.preventDefault();
|
||||
searchInput.focus();
|
||||
searchInput.select();
|
||||
toggleThinking();
|
||||
}
|
||||
// Toggle tool outputs on Ctrl+O
|
||||
if (e.ctrlKey && e.key === 'o') {
|
||||
e.preventDefault();
|
||||
toggleToolOutputs();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue