feat: add copy buttons and user message delete, remove confirmation dialogs
This commit is contained in:
parent
f55e7e3ac4
commit
7063e382a9
1 changed files with 301 additions and 17 deletions
318
src/ui.js
318
src/ui.js
|
|
@ -909,6 +909,41 @@ async function openUncloseaiEmbeddedModalNew() {
|
|||
|
||||
const actions = [
|
||||
{ text: "🔄 Refresh Models", action: loadModels },
|
||||
{ text: "📋 Full Raw", action: async () => {
|
||||
try {
|
||||
const history = getChatHistory();
|
||||
let rawContent = '';
|
||||
history.forEach(msg => {
|
||||
if (msg.role === 'user') {
|
||||
rawContent += `**You:** ${msg.content}\n\n`;
|
||||
} else if (msg.role === 'assistant') {
|
||||
rawContent += `**AI:** ${msg.content}\n\n`;
|
||||
}
|
||||
});
|
||||
await navigator.clipboard.writeText(rawContent);
|
||||
alert("Full chat copied as raw markdown!");
|
||||
} catch (error) {
|
||||
alert("Failed to copy: " + error.message);
|
||||
}
|
||||
}},
|
||||
{ text: "📄 Full HTML", action: async () => {
|
||||
try {
|
||||
const history = getChatHistory();
|
||||
let htmlContent = '<div style="font-family: system-ui, -apple-system, sans-serif;">';
|
||||
history.forEach(msg => {
|
||||
if (msg.role === 'user') {
|
||||
htmlContent += `<div style="margin-bottom: 16px;"><strong>You:</strong><br>${marked.parse(msg.content)}</div>`;
|
||||
} else if (msg.role === 'assistant') {
|
||||
htmlContent += `<div style="margin-bottom: 16px;"><strong>AI:</strong><br>${marked.parse(msg.content)}</div>`;
|
||||
}
|
||||
});
|
||||
htmlContent += '</div>';
|
||||
await navigator.clipboard.writeText(htmlContent);
|
||||
alert("Full chat copied as HTML!");
|
||||
} catch (error) {
|
||||
alert("Failed to copy: " + error.message);
|
||||
}
|
||||
}},
|
||||
{ text: "🗑️ Clear Chat", action: async () => {
|
||||
if (confirm("Clear all conversation history?")) {
|
||||
chatBox.innerHTML = '';
|
||||
|
|
@ -1099,8 +1134,48 @@ async function openUncloseaiEmbeddedModalNew() {
|
|||
border-radius: 18px 18px 4px 18px;
|
||||
max-width: 80%;
|
||||
word-wrap: break-word;
|
||||
position: relative;
|
||||
`;
|
||||
userMsg.textContent = message;
|
||||
|
||||
// Add delete button to user message
|
||||
const userDeleteBtn = document.createElement("button");
|
||||
userDeleteBtn.textContent = "×";
|
||||
userDeleteBtn.style.cssText = `
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 0, 0, 0.8);
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
display: none;
|
||||
transition: all 0.2s;
|
||||
`;
|
||||
userDeleteBtn.onclick = (e) => {
|
||||
e.stopPropagation();
|
||||
// Remove from chat history
|
||||
const currentHistory = getChatHistory();
|
||||
const updatedHistory = currentHistory.filter(msg => !(msg.role === 'user' && msg.content === message));
|
||||
updateChatHistory(updatedHistory);
|
||||
saveConversationHistory(updatedHistory);
|
||||
|
||||
userMsg.remove();
|
||||
};
|
||||
|
||||
// Show delete button on hover
|
||||
userMsg.onmouseenter = () => {
|
||||
userDeleteBtn.style.display = 'block';
|
||||
};
|
||||
userMsg.onmouseleave = () => {
|
||||
userDeleteBtn.style.display = 'none';
|
||||
};
|
||||
|
||||
userMsg.appendChild(userDeleteBtn);
|
||||
chatBox.appendChild(userMsg);
|
||||
|
||||
// Add AI response placeholder
|
||||
|
|
@ -1241,13 +1316,66 @@ async function openUncloseaiEmbeddedModalNew() {
|
|||
transition: all 0.2s;
|
||||
`;
|
||||
deleteBtn.onclick = () => {
|
||||
if (confirm("Delete this message?")) {
|
||||
userMsg.remove();
|
||||
aiMsg.remove();
|
||||
userMsg.remove();
|
||||
aiMsg.remove();
|
||||
};
|
||||
|
||||
// Copy Raw (Markdown) button
|
||||
const copyRawBtn = document.createElement("button");
|
||||
copyRawBtn.textContent = "📋";
|
||||
copyRawBtn.title = "Copy raw (Markdown)";
|
||||
copyRawBtn.style.cssText = `
|
||||
background: none;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s;
|
||||
`;
|
||||
copyRawBtn.onclick = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(response);
|
||||
const originalText = copyRawBtn.textContent;
|
||||
copyRawBtn.textContent = "✓";
|
||||
setTimeout(() => {
|
||||
copyRawBtn.textContent = originalText;
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
alert("Failed to copy: " + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
// Copy HTML button
|
||||
const copyHtmlBtn = document.createElement("button");
|
||||
copyHtmlBtn.textContent = "📄";
|
||||
copyHtmlBtn.title = "Copy HTML";
|
||||
copyHtmlBtn.style.cssText = `
|
||||
background: none;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s;
|
||||
`;
|
||||
copyHtmlBtn.onclick = async () => {
|
||||
try {
|
||||
const htmlContent = marked.parse(response);
|
||||
await navigator.clipboard.writeText(htmlContent);
|
||||
const originalText = copyHtmlBtn.textContent;
|
||||
copyHtmlBtn.textContent = "✓";
|
||||
setTimeout(() => {
|
||||
copyHtmlBtn.textContent = originalText;
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
alert("Failed to copy: " + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
messageActions.appendChild(ttsBtn);
|
||||
messageActions.appendChild(copyRawBtn);
|
||||
messageActions.appendChild(copyHtmlBtn);
|
||||
messageActions.appendChild(deleteBtn);
|
||||
aiMsg.appendChild(messageActions);
|
||||
|
||||
|
|
@ -1337,8 +1465,57 @@ You have complete knowledge of this page content and can reference any details,
|
|||
border-radius: 18px 18px 4px 18px;
|
||||
max-width: 80%;
|
||||
word-wrap: break-word;
|
||||
position: relative;
|
||||
`;
|
||||
userMsg.textContent = msg.content;
|
||||
|
||||
// Add delete button to historical user message
|
||||
const userDeleteBtn = document.createElement("button");
|
||||
userDeleteBtn.textContent = "×";
|
||||
userDeleteBtn.style.cssText = `
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 0, 0, 0.8);
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
display: none;
|
||||
transition: all 0.2s;
|
||||
`;
|
||||
userDeleteBtn.onclick = (e) => {
|
||||
e.stopPropagation();
|
||||
// Remove from chat history by index
|
||||
const currentHistory = loadConversationHistory();
|
||||
if (index >= 0 && index < currentHistory.length) {
|
||||
currentHistory.splice(index, 1);
|
||||
saveConversationHistory(currentHistory);
|
||||
|
||||
// Update the chat.js module history
|
||||
const systemMsg = currentHistory.find(msg => msg.role === 'system');
|
||||
const newHistory = [
|
||||
{ role: 'system', content: getSystemMessage() },
|
||||
...currentHistory
|
||||
];
|
||||
updateChatHistory(newHistory);
|
||||
}
|
||||
|
||||
userMsg.remove();
|
||||
};
|
||||
|
||||
// Show delete button on hover
|
||||
userMsg.onmouseenter = () => {
|
||||
userDeleteBtn.style.display = 'block';
|
||||
};
|
||||
userMsg.onmouseleave = () => {
|
||||
userDeleteBtn.style.display = 'none';
|
||||
};
|
||||
|
||||
userMsg.appendChild(userDeleteBtn);
|
||||
chatBox.appendChild(userMsg);
|
||||
console.log("Added user message to chatBox");
|
||||
} else if (msg.role === 'assistant') {
|
||||
|
|
@ -1455,7 +1632,62 @@ You have complete knowledge of this page content and can reference any details,
|
|||
// TODO: Remove from chat history
|
||||
};
|
||||
|
||||
// Copy Raw (Markdown) button
|
||||
const copyRawBtn = document.createElement("button");
|
||||
copyRawBtn.textContent = "📋";
|
||||
copyRawBtn.title = "Copy raw (Markdown)";
|
||||
copyRawBtn.style.cssText = `
|
||||
background: none;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s;
|
||||
`;
|
||||
copyRawBtn.onclick = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(msg.content);
|
||||
const originalText = copyRawBtn.textContent;
|
||||
copyRawBtn.textContent = "✓";
|
||||
setTimeout(() => {
|
||||
copyRawBtn.textContent = originalText;
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
alert("Failed to copy: " + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
// Copy HTML button
|
||||
const copyHtmlBtn = document.createElement("button");
|
||||
copyHtmlBtn.textContent = "📄";
|
||||
copyHtmlBtn.title = "Copy HTML";
|
||||
copyHtmlBtn.style.cssText = `
|
||||
background: none;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s;
|
||||
`;
|
||||
copyHtmlBtn.onclick = async () => {
|
||||
try {
|
||||
const htmlContent = marked.parse(msg.content);
|
||||
await navigator.clipboard.writeText(htmlContent);
|
||||
const originalText = copyHtmlBtn.textContent;
|
||||
copyHtmlBtn.textContent = "✓";
|
||||
setTimeout(() => {
|
||||
copyHtmlBtn.textContent = originalText;
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
alert("Failed to copy: " + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
messageActions.appendChild(ttsBtn);
|
||||
messageActions.appendChild(copyRawBtn);
|
||||
messageActions.appendChild(copyHtmlBtn);
|
||||
messageActions.appendChild(deleteBtn);
|
||||
aiMsg.appendChild(messageActions);
|
||||
|
||||
|
|
@ -1657,7 +1889,62 @@ You have complete knowledge of this page content and can reference any details,
|
|||
introMsg.remove();
|
||||
};
|
||||
|
||||
// Copy Raw (Markdown) button
|
||||
const copyRawBtn = document.createElement("button");
|
||||
copyRawBtn.textContent = "📋";
|
||||
copyRawBtn.title = "Copy raw (Markdown)";
|
||||
copyRawBtn.style.cssText = `
|
||||
background: none;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s;
|
||||
`;
|
||||
copyRawBtn.onclick = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(response);
|
||||
const originalText = copyRawBtn.textContent;
|
||||
copyRawBtn.textContent = "✓";
|
||||
setTimeout(() => {
|
||||
copyRawBtn.textContent = originalText;
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
alert("Failed to copy: " + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
// Copy HTML button
|
||||
const copyHtmlBtn = document.createElement("button");
|
||||
copyHtmlBtn.textContent = "📄";
|
||||
copyHtmlBtn.title = "Copy HTML";
|
||||
copyHtmlBtn.style.cssText = `
|
||||
background: none;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s;
|
||||
`;
|
||||
copyHtmlBtn.onclick = async () => {
|
||||
try {
|
||||
const htmlContent = marked.parse(response);
|
||||
await navigator.clipboard.writeText(htmlContent);
|
||||
const originalText = copyHtmlBtn.textContent;
|
||||
copyHtmlBtn.textContent = "✓";
|
||||
setTimeout(() => {
|
||||
copyHtmlBtn.textContent = originalText;
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
alert("Failed to copy: " + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
messageActions.appendChild(ttsBtn);
|
||||
messageActions.appendChild(copyRawBtn);
|
||||
messageActions.appendChild(copyHtmlBtn);
|
||||
messageActions.appendChild(deleteBtn);
|
||||
introMsg.appendChild(messageActions);
|
||||
|
||||
|
|
@ -2165,15 +2452,14 @@ export async function openUncloseaiEmbeddedModal() {
|
|||
"position: absolute; top: 2px; right: 2px; width: 20px; height: 20px; font-size: 12px; background: rgba(255,0,0,0.7); color: white; border: none; border-radius: 50%; cursor: pointer;";
|
||||
deleteBtn.onclick = ((messageIndex) => {
|
||||
return () => {
|
||||
if (confirm("Delete this message?")) {
|
||||
const savedHistory = loadConversationHistory();
|
||||
if (messageIndex >= 0 && messageIndex < savedHistory.length) {
|
||||
savedHistory.splice(messageIndex, 1);
|
||||
localStorage.setItem(
|
||||
getPageSpecificKey("hermes-conversation-history"),
|
||||
JSON.stringify(savedHistory),
|
||||
);
|
||||
// Update global chat history
|
||||
const savedHistory = loadConversationHistory();
|
||||
if (messageIndex >= 0 && messageIndex < savedHistory.length) {
|
||||
savedHistory.splice(messageIndex, 1);
|
||||
localStorage.setItem(
|
||||
getPageSpecificKey("hermes-conversation-history"),
|
||||
JSON.stringify(savedHistory),
|
||||
);
|
||||
// Update global chat history
|
||||
chatHistory = [
|
||||
{
|
||||
role: "system",
|
||||
|
|
@ -2513,11 +2799,9 @@ Format: Start with "Greetings! I'm Hermes..." and make it sound natural and enga
|
|||
deleteBtn.style.cssText =
|
||||
"position: absolute; top: 2px; right: 2px; width: 20px; height: 20px; font-size: 12px; background: rgba(255,0,0,0.7); color: white; border: none; border-radius: 50%; cursor: pointer;";
|
||||
deleteBtn.onclick = () => {
|
||||
if (confirm("Delete this message?")) {
|
||||
div.remove();
|
||||
// Update stored history
|
||||
restoreConversationHistory();
|
||||
}
|
||||
div.remove();
|
||||
// Update stored history
|
||||
restoreConversationHistory();
|
||||
};
|
||||
div.appendChild(deleteBtn);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue