diff --git a/css/main.css b/css/main.css index 8e57db89..c5460eb7 100644 --- a/css/main.css +++ b/css/main.css @@ -1570,3 +1570,56 @@ button:focus { .svelte-sa48pu.stretch:has(> .hidden:only-child) { display: none; } + +.delete-container { + position: absolute; + right: 8px; + display: flex; + gap: 6px; + opacity: 0; + transition: opacity 0.2s; + margin-left: 0; +} + +.chat-label-with-delete { + position: relative; + padding-right: 60px; +} + +.trash-btn { + border: none; + background: none; + cursor: pointer; + padding: 2px; + opacity: 0.7; +} + +.cancel-btn { + border: none; + background: #ef4444; + color: white; + cursor: pointer; + width: 20px; + height: 20px; + border-radius: 2px; + font-family: monospace; + font-size: 12px; + align-items: center; + justify-content: center; + display: none; +} + +.confirm-btn { + border: none; + background: #22c55e; + color: white; + cursor: pointer; + width: 20px; + height: 20px; + border-radius: 2px; + font-family: monospace; + font-size: 12px; + align-items: center; + justify-content: center; + display: none; +} diff --git a/js/main.js b/js/main.js index 70afabe3..e9ca5a0b 100644 --- a/js/main.js +++ b/js/main.js @@ -917,3 +917,73 @@ document.querySelector("#chat-input .upload-button").title = "Upload text files, // Activate web search document.getElementById("web-search").title = "Search the internet with DuckDuckGo"; + +//------------------------------------------------ +// Inline icons for deleting past chats +//------------------------------------------------ + +function addMiniDeletes() { + document.querySelectorAll("#past-chats label:not(.has-delete)").forEach(label => { + const container = document.createElement("span"); + container.className = "delete-container"; + + label.classList.add("chat-label-with-delete"); + + const trashBtn = document.createElement("button"); + trashBtn.innerHTML = "🗑️"; + trashBtn.className = "trash-btn"; + + const cancelBtn = document.createElement("button"); + cancelBtn.innerHTML = "✕"; + cancelBtn.className = "cancel-btn"; + + const confirmBtn = document.createElement("button"); + confirmBtn.innerHTML = "✓"; + confirmBtn.className = "confirm-btn"; + + label.addEventListener("mouseenter", () => { + container.style.opacity = "1"; + }); + + label.addEventListener("mouseleave", () => { + container.style.opacity = "0"; + }); + + trashBtn.onclick = (e) => { + e.stopPropagation(); + label.querySelector("input").click(); + document.querySelector("#delete_chat").click(); + trashBtn.style.display = "none"; + cancelBtn.style.display = "flex"; + confirmBtn.style.display = "flex"; + }; + + cancelBtn.onclick = (e) => { + e.stopPropagation(); + document.querySelector("#delete_chat-cancel").click(); + resetButtons(); + }; + + confirmBtn.onclick = (e) => { + e.stopPropagation(); + document.querySelector("#delete_chat-confirm").click(); + resetButtons(); + }; + + function resetButtons() { + trashBtn.style.display = "inline"; + cancelBtn.style.display = "none"; + confirmBtn.style.display = "none"; + } + + container.append(trashBtn, cancelBtn, confirmBtn); + label.appendChild(container); + label.classList.add("has-delete"); + }); +} + +new MutationObserver(() => addMiniDeletes()).observe( + document.querySelector("#past-chats"), + {childList: true, subtree: true} +); +addMiniDeletes(); diff --git a/modules/chat.py b/modules/chat.py index 49511af1..ad5045e0 100644 --- a/modules/chat.py +++ b/modules/chat.py @@ -1562,7 +1562,6 @@ def handle_delete_chat_confirm_click(state): unique_id, gr.update(visible=False), gr.update(visible=True), - gr.update(visible=False) ] diff --git a/modules/ui_chat.py b/modules/ui_chat.py index d7a5ec69..428b64c9 100644 --- a/modules/ui_chat.py +++ b/modules/ui_chat.py @@ -26,15 +26,15 @@ def create_ui(): with gr.Row(elem_id='past-chats-buttons'): shared.gradio['branch_chat'] = gr.Button('Branch', elem_classes=['refresh-button', 'refresh-button-medium'], elem_id='Branch', interactive=not mu) shared.gradio['rename_chat'] = gr.Button('Rename', elem_classes=['refresh-button', 'refresh-button-medium'], interactive=not mu) - shared.gradio['delete_chat'] = gr.Button('🗑️', elem_classes='refresh-button', interactive=not mu) + shared.gradio['delete_chat'] = gr.Button('🗑️', visible=False, elem_classes='refresh-button', interactive=not mu, elem_id='delete_chat') shared.gradio['Start new chat'] = gr.Button('New chat', elem_classes=['refresh-button', 'refresh-button-medium', 'focus-on-chat-input']) shared.gradio['branch_index'] = gr.Number(value=-1, precision=0, visible=False, elem_id="Branch-index", interactive=True) shared.gradio['search_chat'] = gr.Textbox(placeholder='Search chats...', max_lines=1, elem_id='search_chat') with gr.Row(elem_id='delete-chat-row', visible=False) as shared.gradio['delete-chat-row']: - shared.gradio['delete_chat-cancel'] = gr.Button('Cancel', elem_classes=['refresh-button', 'focus-on-chat-input']) - shared.gradio['delete_chat-confirm'] = gr.Button('Confirm', variant='stop', elem_classes=['refresh-button', 'focus-on-chat-input']) + shared.gradio['delete_chat-cancel'] = gr.Button('Cancel', elem_classes=['refresh-button', 'focus-on-chat-input'], elem_id='delete_chat-cancel') + shared.gradio['delete_chat-confirm'] = gr.Button('Confirm', variant='stop', elem_classes=['refresh-button', 'focus-on-chat-input'], elem_id='delete_chat-confirm') with gr.Row(elem_id='rename-row', visible=False) as shared.gradio['rename-row']: shared.gradio['rename_to'] = gr.Textbox(label='Rename to:', placeholder='New name', elem_classes=['no-background']) @@ -261,11 +261,9 @@ def create_event_handlers(): ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( chat.handle_start_new_chat_click, gradio('interface_state'), gradio('history', 'display', 'unique_id'), show_progress=False) - shared.gradio['delete_chat'].click(lambda: gr.update(visible=True), None, gradio('delete-chat-row')) - shared.gradio['delete_chat-cancel'].click(lambda: gr.update(visible=False), None, gradio('delete-chat-row')) shared.gradio['delete_chat-confirm'].click( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( - chat.handle_delete_chat_confirm_click, gradio('interface_state'), gradio('history', 'display', 'unique_id', 'delete-chat-row'), show_progress=False) + chat.handle_delete_chat_confirm_click, gradio('interface_state'), gradio('history', 'display', 'unique_id'), show_progress=False) shared.gradio['branch_chat'].click( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then(