Review-Nachrichten: konsistentes Styling in History, Chat und Shared-Links
- renderMarkdown: [Review: Agent], [Review-Feedback ...], [APPROVED] Tags parsen → styled HTML-Header bzw. ausgeblendet (zentral für alle Views) - history.js: Review-Messages als .review-bubble rendern statt .assistant/.user Review-Messages vom Merging ausgenommen - shared-page.js: Review-Messages erkennen → .review-bubble Klasse Merge-Logik schützt Review-Messages vor Zusammenführung - addReviewBubbleStatic(): Neue Funktion für History-Rendering mit allen Buttons (Reply, Delete, Mark, Share) - chat.css: .review-inline-header, .review-inline-feedback Styles
This commit is contained in:
1 parent
5fe3f8ac87
commit
6369f7f09c
4 files changed
+94
-14
No files matched your search
@@ -987,6 +987,19 @@
|
||||
gap: var(--badge-spacing);
|
||||
}
|
||||
|
||||
.review-inline-header {
|
||||
color: var(--secondary);
|
||||
margin-right: .3em;
|
||||
}
|
||||
|
||||
.review-inline-feedback {
|
||||
color: var(--warning);
|
||||
margin-bottom: .4em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--badge-spacing);
|
||||
}
|
||||
|
||||
.review-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
+34
-8
@@ -157,8 +157,10 @@ function _mergeConsecutiveAssistantTexts(msgs) {
|
||||
for (const msg of msgs) {
|
||||
if (msg.type === 'text' && msg.role === 'assistant') {
|
||||
const prev = result[result.length - 1];
|
||||
const isReview = msg.content && msg.content.startsWith('[Review:');
|
||||
const prevIsReview = prev && prev.content && prev.content.startsWith('[Review:');
|
||||
if (prev && prev.type === 'text' && prev.role === 'assistant'
|
||||
&& prev.iteration === msg.iteration) {
|
||||
&& prev.iteration === msg.iteration && !isReview && !prevIsReview) {
|
||||
// Gleiche Iteration: nahtlos zusammenfügen (Web-Search-Fragmente etc.)
|
||||
prev.content = (prev.content || '') + ' ' + (msg.content || '');
|
||||
// IDs/Timestamps: letztes behalten (für Mark-Button etc.)
|
||||
@@ -178,8 +180,9 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds) {
|
||||
for (const msg of msgs) {
|
||||
const div = document.createElement('div');
|
||||
switch (msg.type) {
|
||||
case 'text':
|
||||
if (msg.role === 'user') {
|
||||
case 'text': {
|
||||
const isReviewMsg = msg.content && (msg.content.startsWith('[Review:') || msg.content.startsWith('[Review-Feedback'));
|
||||
if (msg.role === 'user' && !isReviewMsg) {
|
||||
div.className = 'msg user markdown' + (msg.isMarked ? ' marked' : '');
|
||||
if (msg.deletedOn) div.classList.add(isDeletedVisible() ? 'msg-deleted' : 'msg-deleted-hidden');
|
||||
div.dataset.role = 'user';
|
||||
@@ -208,6 +211,20 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds) {
|
||||
ind.addEventListener('click', () => loadAndShowAttachments(msg.id, ind));
|
||||
div.appendChild(ind);
|
||||
}
|
||||
} else if (isReviewMsg) {
|
||||
div.className = 'msg review-bubble markdown' + (msg.isMarked ? ' marked' : '');
|
||||
if (msg.deletedOn) div.classList.add(isDeletedVisible() ? 'msg-deleted' : 'msg-deleted-hidden');
|
||||
div.dataset.role = msg.role;
|
||||
div.dataset.timestamp = msg.createdAt || '';
|
||||
if (msg.id) div.dataset.messageId = msg.id;
|
||||
div.innerHTML = renderMarkdown(msg.content);
|
||||
parseFluentEmojis(div);
|
||||
_addTimestamp(div, msg.createdAt);
|
||||
_addReplyButton(div);
|
||||
_addDeleteButton(div, msg.id, msg.deletedOn);
|
||||
_addMarkButton(div, msg.id, msg.isMarked);
|
||||
_addShareButton(div, msg.id);
|
||||
fragment.appendChild(div);
|
||||
} else if (msg.role === 'assistant') {
|
||||
div.className = 'msg assistant markdown' + (msg.isMarked ? ' marked' : '');
|
||||
if (msg.deletedOn) div.classList.add(isDeletedVisible() ? 'msg-deleted' : 'msg-deleted-hidden');
|
||||
@@ -224,6 +241,7 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds) {
|
||||
fragment.appendChild(div);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'tool_use':
|
||||
if (!isToolVisible(msg.toolName)) continue;
|
||||
div.className = 'tool-box';
|
||||
@@ -262,13 +280,21 @@ function renderMessages(msgs, addToConversation) {
|
||||
switch (msg.type) {
|
||||
case 'text':
|
||||
if (msg.role === 'user') {
|
||||
addUserBubble(msg.content, false, msg.createdAt, msg.id, msg.isMarked, msg.deletedOn);
|
||||
if (msg.attachmentCount > 0) {
|
||||
_autoLoadImageAttachments(msg.id);
|
||||
addAttachmentIndicator(msg.id, msg.attachmentCount, msg.attachmentNames);
|
||||
if (msg.content && msg.content.startsWith('[Review-Feedback')) {
|
||||
addReviewBubbleStatic(msg.content, msg.createdAt, msg.id, msg.isMarked, msg.deletedOn);
|
||||
} else {
|
||||
addUserBubble(msg.content, false, msg.createdAt, msg.id, msg.isMarked, msg.deletedOn);
|
||||
if (msg.attachmentCount > 0) {
|
||||
_autoLoadImageAttachments(msg.id);
|
||||
addAttachmentIndicator(msg.id, msg.attachmentCount, msg.attachmentNames);
|
||||
}
|
||||
}
|
||||
} else if (msg.role === 'assistant') {
|
||||
addAssistantBubble(msg.content, msg.createdAt, msg.id, msg.isMarked, msg.deletedOn);
|
||||
if (msg.content && msg.content.startsWith('[Review:')) {
|
||||
addReviewBubbleStatic(msg.content, msg.createdAt, msg.id, msg.isMarked, msg.deletedOn);
|
||||
} else {
|
||||
addAssistantBubble(msg.content, msg.createdAt, msg.id, msg.isMarked, msg.deletedOn);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -25,12 +25,18 @@ registerPage('shared', {
|
||||
messages = _mergeConsecutiveTexts(messages);
|
||||
|
||||
for (const msg of messages) {
|
||||
const c = msg.content || '';
|
||||
const isReview = c.startsWith('[Review:') || c.startsWith('[Review-Feedback');
|
||||
const div = document.createElement('div');
|
||||
div.className = 'msg ' + (msg.role === 'user' ? 'user' : 'assistant') + ' markdown';
|
||||
if (msg.role === 'user') {
|
||||
if (isReview) {
|
||||
div.className = 'msg review-bubble markdown';
|
||||
} else {
|
||||
div.className = 'msg ' + (msg.role === 'user' ? 'user' : 'assistant') + ' markdown';
|
||||
}
|
||||
if (!isReview && msg.role === 'user') {
|
||||
renderUserContent(div, msg.content);
|
||||
} else {
|
||||
div.innerHTML = renderMarkdown(msg.content);
|
||||
div.innerHTML = renderMarkdown(c);
|
||||
parseFluentEmojis(div);
|
||||
wrapKreaGalleries(div);
|
||||
}
|
||||
@@ -56,11 +62,14 @@ registerPage('shared', {
|
||||
function _mergeConsecutiveTexts(msgs) {
|
||||
const result = [];
|
||||
for (const msg of msgs) {
|
||||
if (msg.role === 'assistant') {
|
||||
const c = msg.content || '';
|
||||
const isReview = c.startsWith('[Review:') || c.startsWith('[Review-Feedback');
|
||||
if (msg.role === 'assistant' && !isReview) {
|
||||
const prev = result[result.length - 1];
|
||||
if (prev && prev.role === 'assistant'
|
||||
&& !(prev.content || '').startsWith('[Review:')
|
||||
&& prev.iteration === msg.iteration) {
|
||||
prev.content = (prev.content || '') + ' ' + (msg.content || '');
|
||||
prev.content = (prev.content || '') + ' ' + c;
|
||||
if (msg.createdAt) prev.createdAt = msg.createdAt;
|
||||
continue;
|
||||
}
|
||||
|
||||
+33
-1
@@ -167,7 +167,20 @@ function renderMarkdown(text) {
|
||||
return '%%CODE' + (codeBlocks.length - 1) + '%%';
|
||||
});
|
||||
|
||||
// 4) [Krea: dateiname.png] → Inline-Thumbnail mit Klick für Vollbild
|
||||
// 4a) [Review: AgentName] prefix → Review-Header
|
||||
html = html.replace(/\[Review:\s*([^\]]+)\]\s*/g, function(match, agentName) {
|
||||
return '<span class="review-inline-header"><i class="fa fa-check-circle-o"></i> <strong>' + esc(agentName.trim()) + '</strong></span> ';
|
||||
});
|
||||
|
||||
// 4b) [Review-Feedback von AgentName (Runde X/Y)]: → Review-Feedback-Header
|
||||
html = html.replace(/\[Review-Feedback von\s+([^\(]+)\(Runde\s+(\d+)\/(\d+)\)\]:\s*/g, function(match, agentName, round, maxRounds) {
|
||||
return '<div class="review-inline-feedback"><i class="fa fa-repeat"></i> <strong>Feedback von ' + esc(agentName.trim()) + '</strong> <span class="review-round">Runde ' + esc(round) + '/' + esc(maxRounds) + '</span></div>';
|
||||
});
|
||||
|
||||
// 4c) [APPROVED] ausblenden
|
||||
html = html.replace(/\[APPROVED\]/g, '');
|
||||
|
||||
// 4d) [Krea: dateiname.png] → Inline-Thumbnail mit Klick für Vollbild
|
||||
html = html.replace(/\[Krea:\s*([^\]]+)\]/g, function(match, filename) {
|
||||
var fn = filename.trim();
|
||||
var safeFn = esc(fn);
|
||||
@@ -640,6 +653,25 @@ function addWarningBubble(text, streamed = false) {
|
||||
|
||||
// ── Review Bubbles ──
|
||||
|
||||
function addReviewBubbleStatic(text, timestamp, messageId, isMarked, deletedOn) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'msg review-bubble markdown' + (isMarked ? ' marked' : '');
|
||||
if (deletedOn) div.classList.add(isDeletedVisible() ? 'msg-deleted' : 'msg-deleted-hidden');
|
||||
div.dataset.role = 'assistant';
|
||||
div.dataset.timestamp = timestamp || '';
|
||||
if (messageId) div.dataset.messageId = messageId;
|
||||
div.innerHTML = renderMarkdown(text);
|
||||
parseFluentEmojis(div);
|
||||
_addTimestamp(div, timestamp);
|
||||
_addReplyButton(div);
|
||||
_addDeleteButton(div, messageId, deletedOn);
|
||||
_addMarkButton(div, messageId, isMarked);
|
||||
_addShareButton(div, messageId);
|
||||
chatEl().appendChild(div);
|
||||
scrollDown();
|
||||
return div;
|
||||
}
|
||||
|
||||
let _reviewBubble = null;
|
||||
let _reviewTextEl = null;
|
||||
let _reviewText = '';
|
||||
|
||||
Reference in new issue
Block a user