UI: Improve the hover menu looks

This commit is contained in:
oobabooga 2026-04-04 18:29:36 -07:00
parent 2eef90a323
commit 7fed60f90a
3 changed files with 92 additions and 45 deletions

View file

@ -735,7 +735,30 @@ audio {
.hover-element {
position: relative;
font-size: 24px;
padding-top: 4px;
}
#hover-element-button {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border-radius: 0.5rem;
cursor: pointer;
color: gray;
}
#hover-element-button:hover {
background-color: var(--background-fill-secondary);
}
#hover-element-button svg {
color: inherit;
}
.dark #hover-element-button:hover {
background-color: var(--selected-item-color-dark);
}
.hover-menu {
@ -743,27 +766,40 @@ audio {
position: absolute;
bottom: 100%;
left: 0;
box-shadow: 0 2px 12px rgb(0 0 0 / 15%);
border-radius: 0.5rem;
background: white;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 4px 16px rgb(0 0 0 / 12%), 0 1px 3px rgb(0 0 0 / 8%);
border-radius: 0.75rem;
z-index: 10000;
min-width: 330px;
flex-direction: column;
overflow: hidden;
padding: 4px;
}
.hover-menu::before {
content: '';
position: absolute;
top: 100%;
left: 0;
width: 100%;
height: 8px;
}
.hover-menu > * {
border: none !important;
box-shadow: none !important;
}
.hover-menu button {
width: 100%;
background: white !important;
border-radius: 0 !important;
background: transparent !important;
border: none !important;
border-radius: 0.5rem !important;
justify-content: space-between;
margin: 0 !important;
height: 36px;
border-color: transparent !important;
transition: background-color 0.15s ease;
}
.hover-menu button:not(#clear-history-confirm) {
border-bottom: 0 !important;
font-weight: 500;
box-shadow: none !important;
}
.hover-menu button:hover {
@ -775,19 +811,26 @@ audio {
}
#show-controls {
background-color: white;
border-color: transparent !important;
background-color: transparent;
border: none !important;
height: 36px;
border-radius: 0;
border-bottom: 0 !important;
border-radius: 0.5rem;
padding-top: 3px;
padding-left: 4px;
display: flex;
font-weight: normal;
}
#show-controls:hover {
background-color: #dbeafe;
}
.dark #show-controls {
background-color: var(--darker-gray);
background-color: transparent;
}
.dark #show-controls:hover {
background-color: var(--selected-item-color-dark);
}
#show-controls label {
@ -797,12 +840,12 @@ audio {
width: 100%;
padding-right: 12px;
gap: 10px;
font-weight: 600;
font-weight: 500;
color: var(--button-secondary-text-color);
}
#show-controls label input {
margin-top: 4px;
margin-top: 5px;
}
.transparent-substring {
@ -817,6 +860,7 @@ audio {
min-width: 0 !important;
display: flex;
flex-direction: column-reverse;
padding-left: 12px;
padding-right: 20px;
padding-bottom: 3px;
flex-grow: 0 !important;
@ -1208,9 +1252,14 @@ audio {
color: #9ca3af;
}
.dark .hover-menu {
background: var(--darker-gray);
border-color: transparent;
box-shadow: 0 4px 16px rgb(0 0 0 / 40%);
}
.dark .hover-menu button {
border-color: var(--border-color-primary);
background-color: var(--darker-gray) !important;
background-color: transparent !important;
}
.dark #chat-controls,

View file

@ -309,18 +309,19 @@ for (let i = 0; i < slimDropdownElements.length; i++) {
// https://github.com/SillyTavern/SillyTavern/blob/6c8bd06308c69d51e2eb174541792a870a83d2d6/public/script.js
//------------------------------------------------
var buttonsInChat = document.querySelectorAll("#chat-tab #chat-buttons button, #chat-tab #chat-buttons #show-controls");
var hoverContainer = document.getElementById("gr-hover-container");
var button = document.getElementById("hover-element-button");
var menu = document.getElementById("hover-menu");
var istouchscreen = (navigator.maxTouchPoints > 0) || "ontouchstart" in document.documentElement;
function showMenu() {
menu.style.display = "flex"; // Show the menu
menu.style.display = "flex";
}
function hideMenu() {
menu.style.display = "none"; // Hide the menu
menu.style.display = "none";
if (!istouchscreen) {
document.querySelector("#chat-input textarea").focus(); // Focus on the chat input
document.querySelector("#chat-input textarea").focus();
}
}
@ -329,7 +330,6 @@ if (buttonsInChat.length > 0) {
const thisButton = buttonsInChat[i];
menu.appendChild(thisButton);
// Only apply transformations to button elements
if (thisButton.tagName.toLowerCase() === "button") {
thisButton.addEventListener("click", () => {
hideMenu();
@ -339,7 +339,6 @@ if (buttonsInChat.length > 0) {
const matches = buttonText.match(/(\(.*?\))/);
if (matches && matches.length > 1) {
// Apply the transparent-substring class to the matched substring
const substring = matches[1];
const newText = buttonText.replace(substring, `&nbsp;<span class="transparent-substring">${substring.slice(1, -1)}</span>`);
thisButton.innerHTML = newText;
@ -348,16 +347,19 @@ if (buttonsInChat.length > 0) {
}
}
function isMouseOverButtonOrMenu() {
return menu.matches(":hover") || button.matches(":hover");
}
var menuInteracting = false;
button.addEventListener("mouseenter", function () {
hoverContainer.addEventListener("mouseenter", function () {
if (!istouchscreen) {
showMenu();
}
});
hoverContainer.addEventListener("mousedown", function () {
menuInteracting = true;
setTimeout(function () { menuInteracting = false; }, 300);
});
button.addEventListener("click", function () {
if (menu.style.display === "flex") {
hideMenu();
@ -367,24 +369,20 @@ button.addEventListener("click", function () {
}
});
// Delay to prevent menu hiding when the mouse leaves the button or menu
function delayedHideMenu() {
setTimeout(function () {
if (!isMouseOverButtonOrMenu()) {
hideMenu();
}
}, 100);
}
// Add event listener for mouseleave on the button
button.addEventListener("mouseleave", delayedHideMenu);
// Add event listener for mouseleave on the menu
menu.addEventListener("mouseleave", delayedHideMenu);
hoverContainer.addEventListener("mouseleave", function () {
if (!istouchscreen) {
setTimeout(function () {
if (!hoverContainer.matches(":hover") && !menu.matches(":hover")) {
hideMenu();
}
}, 50);
}
});
// Add event listener for click anywhere in the document
document.addEventListener("click", function (event) {
// Check if the click is outside the button/menu and the menu is visible
if (!isMouseOverButtonOrMenu() && menu.style.display === "flex") {
if (!menuInteracting && !event.target.closest("#gr-hover-container") && menu.style.display === "flex") {
hideMenu();
}

View file

@ -52,7 +52,7 @@ def create_ui():
shared.gradio['html_display'] = gr.HTML(value=chat_html_wrapper({'internal': [], 'visible': [], 'metadata': {}}, '', '', 'chat', 'cai-chat', '')['html'], visible=True)
with gr.Row(elem_id="chat-input-row"):
with gr.Column(scale=1, elem_id='gr-hover-container'):
gr.HTML(value='<div class="hover-element" onclick="void(0)"><span style="width: 100px; display: block" id="hover-element-button">&#9776;</span><div class="hover-menu" id="hover-menu"></div>', elem_id='gr-hover')
gr.HTML(value='<div class="hover-element" onclick="void(0)"><span id="hover-element-button"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="4" y1="6" x2="20" y2="6"></line><line x1="4" y1="12" x2="20" y2="12"></line><line x1="4" y1="18" x2="20" y2="18"></line></svg></span><div class="hover-menu" id="hover-menu"></div></div>', elem_id='gr-hover')
with gr.Column(scale=10, elem_id='chat-input-container'):
shared.gradio['textbox'] = gr.MultimodalTextbox(label='', placeholder='Send a message', file_types=['text', '.pdf', 'image'], file_count="multiple", elem_id='chat-input', elem_classes=['add_scrollbar'])