diff --git a/src/ui.js b/src/ui.js index 25d6096..87e7cfc 100644 --- a/src/ui.js +++ b/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 = '
'; + history.forEach(msg => { + if (msg.role === 'user') { + htmlContent += `
You:
${marked.parse(msg.content)}
`; + } else if (msg.role === 'assistant') { + htmlContent += `
AI:
${marked.parse(msg.content)}
`; + } + }); + htmlContent += '
'; + 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);