Spaces:
Paused
Paused
frdel
commited on
Commit
·
3bcc6f4
1
Parent(s):
e93554b
action buttons sticky
Browse files
webui/components/messages/action-buttons/simple-action-buttons.css
CHANGED
|
@@ -2,87 +2,88 @@
|
|
| 2 |
|
| 3 |
/* Main action buttons container - precise positioning */
|
| 4 |
.action-buttons {
|
| 5 |
-
position:
|
|
|
|
|
|
|
|
|
|
| 6 |
top: 0.3em;
|
| 7 |
-
right:
|
|
|
|
| 8 |
display: none;
|
| 9 |
flex-direction: row;
|
| 10 |
gap: 0;
|
| 11 |
-
background: var(--color-panel);
|
| 12 |
-
border: 1px solid var(--color-border);
|
| 13 |
border-radius: 6px;
|
| 14 |
transition: opacity var(--transition-speed) ease-in-out;
|
| 15 |
z-index: 10;
|
| 16 |
-
overflow: hidden;
|
| 17 |
}
|
| 18 |
|
| 19 |
/* Individual action button - precise hit area */
|
| 20 |
-
.action-button {
|
| 21 |
display: flex;
|
| 22 |
align-items: center;
|
| 23 |
justify-content: center;
|
| 24 |
width: 26px;
|
| 25 |
height: 26px;
|
| 26 |
-
background: transparent;
|
| 27 |
-
border: none;
|
| 28 |
cursor: pointer;
|
| 29 |
-
|
|
|
|
|
|
|
| 30 |
color: var(--color-text);
|
| 31 |
padding: 0;
|
| 32 |
font-size: 14px;
|
| 33 |
-
opacity: 0.7;
|
| 34 |
margin: 0;
|
| 35 |
}
|
| 36 |
|
| 37 |
-
.action-button:first-child {
|
| 38 |
border-radius: 5px 0 0 5px;
|
| 39 |
}
|
| 40 |
|
| 41 |
-
.action-button:last-child {
|
| 42 |
border-radius: 0 5px 5px 0;
|
| 43 |
}
|
| 44 |
|
| 45 |
-
.action-button:hover {
|
| 46 |
opacity: 1;
|
| 47 |
-
background: var(--color-
|
| 48 |
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
|
| 49 |
}
|
| 50 |
|
| 51 |
-
.action-button:active {
|
| 52 |
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
| 53 |
}
|
| 54 |
|
| 55 |
/* Material icons - same as original */
|
| 56 |
-
.action-button .material-symbols-outlined {
|
| 57 |
font-size: 16px;
|
| 58 |
line-height: 1;
|
| 59 |
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 20;
|
| 60 |
}
|
| 61 |
|
| 62 |
/* Success state - same as original */
|
| 63 |
-
.action-button.success {
|
| 64 |
background: #4CAF50;
|
| 65 |
border-color: #4CAF50;
|
| 66 |
color: white;
|
| 67 |
}
|
| 68 |
|
| 69 |
-
.action-button.success .material-symbols-outlined {
|
| 70 |
font-variation-settings: 'FILL' 1, 'wght' 500, 'GRAD' 0, 'opsz' 20;
|
| 71 |
}
|
| 72 |
|
| 73 |
/* Error state - same as original */
|
| 74 |
-
.action-button.error {
|
| 75 |
background: var(--color-accent);
|
| 76 |
border-color: var(--color-accent);
|
| 77 |
color: white;
|
| 78 |
}
|
| 79 |
|
| 80 |
-
.action-button.error .material-symbols-outlined {
|
| 81 |
font-variation-settings: 'FILL' 1, 'wght' 500, 'GRAD' 0, 'opsz' 20;
|
| 82 |
}
|
| 83 |
|
| 84 |
/* Speaking state - same as original */
|
| 85 |
-
.action-button.speaking {
|
| 86 |
background: var(--color-primary);
|
| 87 |
border-color: var(--color-primary);
|
| 88 |
color: white;
|
|
@@ -97,8 +98,10 @@
|
|
| 97 |
|
| 98 |
/* Show action buttons on hover - simplified, no device detection needed */
|
| 99 |
.msg-content:hover .action-buttons,
|
| 100 |
-
.kvps-row:hover .action-buttons,
|
| 101 |
-
.message-text:hover .action-buttons
|
|
|
|
|
|
|
| 102 |
display: flex;
|
| 103 |
animation: fadeInAfterDelay 0.3s ease-in-out;
|
| 104 |
animation-delay: 0.3s;
|
|
|
|
| 2 |
|
| 3 |
/* Main action buttons container - precise positioning */
|
| 4 |
.action-buttons {
|
| 5 |
+
position: sticky;
|
| 6 |
+
height:0;
|
| 7 |
+
width:fit-content;
|
| 8 |
+
overflow: visible;
|
| 9 |
top: 0.3em;
|
| 10 |
+
margin-right:0.1em;
|
| 11 |
+
margin-left: auto;
|
| 12 |
display: none;
|
| 13 |
flex-direction: row;
|
| 14 |
gap: 0;
|
|
|
|
|
|
|
| 15 |
border-radius: 6px;
|
| 16 |
transition: opacity var(--transition-speed) ease-in-out;
|
| 17 |
z-index: 10;
|
|
|
|
| 18 |
}
|
| 19 |
|
| 20 |
/* Individual action button - precise hit area */
|
| 21 |
+
.action-buttons .action-button {
|
| 22 |
display: flex;
|
| 23 |
align-items: center;
|
| 24 |
justify-content: center;
|
| 25 |
width: 26px;
|
| 26 |
height: 26px;
|
|
|
|
|
|
|
| 27 |
cursor: pointer;
|
| 28 |
+
background-color: var(--color-background);
|
| 29 |
+
/* border: 1px solid var(--color-border); */
|
| 30 |
+
/* transition: background-color var(--transition-speed) ease-in-out; */
|
| 31 |
color: var(--color-text);
|
| 32 |
padding: 0;
|
| 33 |
font-size: 14px;
|
| 34 |
+
/* opacity: 0.7; */
|
| 35 |
margin: 0;
|
| 36 |
}
|
| 37 |
|
| 38 |
+
.action-buttons .action-button:first-child {
|
| 39 |
border-radius: 5px 0 0 5px;
|
| 40 |
}
|
| 41 |
|
| 42 |
+
.action-buttons .action-button:last-child {
|
| 43 |
border-radius: 0 5px 5px 0;
|
| 44 |
}
|
| 45 |
|
| 46 |
+
.action-buttons .action-button:hover {
|
| 47 |
opacity: 1;
|
| 48 |
+
background: var(--color-panel);
|
| 49 |
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
|
| 50 |
}
|
| 51 |
|
| 52 |
+
.action-buttons .action-button:active {
|
| 53 |
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
| 54 |
}
|
| 55 |
|
| 56 |
/* Material icons - same as original */
|
| 57 |
+
.action-buttons .action-button .material-symbols-outlined {
|
| 58 |
font-size: 16px;
|
| 59 |
line-height: 1;
|
| 60 |
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 20;
|
| 61 |
}
|
| 62 |
|
| 63 |
/* Success state - same as original */
|
| 64 |
+
.action-buttons .action-button.success {
|
| 65 |
background: #4CAF50;
|
| 66 |
border-color: #4CAF50;
|
| 67 |
color: white;
|
| 68 |
}
|
| 69 |
|
| 70 |
+
.action-buttons .action-button.success .material-symbols-outlined {
|
| 71 |
font-variation-settings: 'FILL' 1, 'wght' 500, 'GRAD' 0, 'opsz' 20;
|
| 72 |
}
|
| 73 |
|
| 74 |
/* Error state - same as original */
|
| 75 |
+
.action-buttons .action-button.error {
|
| 76 |
background: var(--color-accent);
|
| 77 |
border-color: var(--color-accent);
|
| 78 |
color: white;
|
| 79 |
}
|
| 80 |
|
| 81 |
+
.action-buttons .action-button.error .material-symbols-outlined {
|
| 82 |
font-variation-settings: 'FILL' 1, 'wght' 500, 'GRAD' 0, 'opsz' 20;
|
| 83 |
}
|
| 84 |
|
| 85 |
/* Speaking state - same as original */
|
| 86 |
+
.action-buttons .action-button.speaking {
|
| 87 |
background: var(--color-primary);
|
| 88 |
border-color: var(--color-primary);
|
| 89 |
color: white;
|
|
|
|
| 98 |
|
| 99 |
/* Show action buttons on hover - simplified, no device detection needed */
|
| 100 |
.msg-content:hover .action-buttons,
|
| 101 |
+
/* .kvps-row:hover .action-buttons, */
|
| 102 |
+
.message-text:hover .action-buttons,
|
| 103 |
+
.kvps-val:hover .action-buttons,
|
| 104 |
+
.message-body:hover > .action-buttons {
|
| 105 |
display: flex;
|
| 106 |
animation: fadeInAfterDelay 0.3s ease-in-out;
|
| 107 |
animation-delay: 0.3s;
|
webui/components/messages/action-buttons/simple-action-buttons.js
CHANGED
|
@@ -3,19 +3,23 @@ import { store as speechStore } from "/components/chat/speech/speech-store.js";
|
|
| 3 |
|
| 4 |
// Extract text content from different message types
|
| 5 |
function getTextContent(element) {
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
|
|
|
| 16 |
}
|
|
|
|
|
|
|
| 17 |
}
|
| 18 |
|
|
|
|
| 19 |
// Create and add action buttons to element
|
| 20 |
export function addActionButtonsToElement(element) {
|
| 21 |
// Skip if buttons already exist
|
|
@@ -116,5 +120,10 @@ export function addActionButtonsToElement(element) {
|
|
| 116 |
};
|
| 117 |
|
| 118 |
container.append(copyBtn, speakBtn);
|
| 119 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
}
|
|
|
|
| 3 |
|
| 4 |
// Extract text content from different message types
|
| 5 |
function getTextContent(element) {
|
| 6 |
+
// Get all children except action buttons
|
| 7 |
+
const textParts = [];
|
| 8 |
+
// Loop through all child elements
|
| 9 |
+
for (const child of element.children) {
|
| 10 |
+
// Skip action buttons
|
| 11 |
+
if (child.classList.contains("action-buttons")) continue;
|
| 12 |
+
// Get text content from the child
|
| 13 |
+
const text = child.innerText || "";
|
| 14 |
+
if (text.trim()) {
|
| 15 |
+
textParts.push(text.trim());
|
| 16 |
+
}
|
| 17 |
}
|
| 18 |
+
// Join all text parts with double newlines
|
| 19 |
+
return textParts.join("\n\n");
|
| 20 |
}
|
| 21 |
|
| 22 |
+
|
| 23 |
// Create and add action buttons to element
|
| 24 |
export function addActionButtonsToElement(element) {
|
| 25 |
// Skip if buttons already exist
|
|
|
|
| 120 |
};
|
| 121 |
|
| 122 |
container.append(copyBtn, speakBtn);
|
| 123 |
+
// Add container as the first child instead of appending it
|
| 124 |
+
if (element.firstChild) {
|
| 125 |
+
element.insertBefore(container, element.firstChild);
|
| 126 |
+
} else {
|
| 127 |
+
element.appendChild(container);
|
| 128 |
+
}
|
| 129 |
}
|
webui/css/messages.css
CHANGED
|
@@ -318,7 +318,7 @@
|
|
| 318 |
}
|
| 319 |
|
| 320 |
.kvps-val {
|
| 321 |
-
margin: 0.65rem 0 0.65rem 0.4rem;
|
| 322 |
white-space: pre-wrap;
|
| 323 |
}
|
| 324 |
|
|
|
|
| 318 |
}
|
| 319 |
|
| 320 |
.kvps-val {
|
| 321 |
+
/* margin: 0.65rem 0 0.65rem 0.4rem; */
|
| 322 |
white-space: pre-wrap;
|
| 323 |
}
|
| 324 |
|
webui/index.css
CHANGED
|
@@ -16,7 +16,7 @@
|
|
| 16 |
--color-accent-dark: #cf6679;
|
| 17 |
--color-message-bg-dark: #2d2d2d;
|
| 18 |
--color-message-text-dark: #e0e0e0;
|
| 19 |
-
--color-panel-dark: #
|
| 20 |
--color-border-dark: #444444a8;
|
| 21 |
--color-input-dark: #131313;
|
| 22 |
--color-input-focus-dark: #101010;
|
|
|
|
| 16 |
--color-accent-dark: #cf6679;
|
| 17 |
--color-message-bg-dark: #2d2d2d;
|
| 18 |
--color-message-text-dark: #e0e0e0;
|
| 19 |
+
--color-panel-dark: #1a1a1a;
|
| 20 |
--color-border-dark: #444444a8;
|
| 21 |
--color-input-dark: #131313;
|
| 22 |
--color-input-focus-dark: #101010;
|
webui/js/messages.js
CHANGED
|
@@ -219,7 +219,7 @@ export function _drawMessage(
|
|
| 219 |
}
|
| 220 |
|
| 221 |
// Ensure action buttons exist
|
| 222 |
-
addActionButtonsToElement(
|
| 223 |
adjustMarkdownRender(contentDiv);
|
| 224 |
|
| 225 |
} else {
|
|
@@ -244,7 +244,7 @@ export function _drawMessage(
|
|
| 244 |
spanElement.innerHTML = convertHTML(content);
|
| 245 |
|
| 246 |
// Ensure action buttons exist
|
| 247 |
-
addActionButtonsToElement(
|
| 248 |
|
| 249 |
}
|
| 250 |
} else {
|
|
@@ -693,6 +693,8 @@ function drawKvps(container, kvps, latex) {
|
|
| 693 |
addValue(value);
|
| 694 |
}
|
| 695 |
|
|
|
|
|
|
|
| 696 |
// autoscroll the KVP value if needed
|
| 697 |
// if (getAutoScroll()) #TODO needs a better redraw system
|
| 698 |
setTimeout(() => {
|
|
@@ -720,7 +722,6 @@ function drawKvps(container, kvps, latex) {
|
|
| 720 |
span.innerHTML = convertHTML(value);
|
| 721 |
pre.appendChild(span);
|
| 722 |
tdiv.appendChild(pre);
|
| 723 |
-
addActionButtonsToElement(row);
|
| 724 |
|
| 725 |
// KaTeX rendering for markdown
|
| 726 |
if (latex) {
|
|
@@ -794,6 +795,8 @@ function drawKvpsIncremental(container, kvps, latex) {
|
|
| 794 |
// Clear and rebuild content (for now - could be optimized further)
|
| 795 |
tdiv.innerHTML = "";
|
| 796 |
|
|
|
|
|
|
|
| 797 |
if (Array.isArray(value)) {
|
| 798 |
for (const item of value) {
|
| 799 |
addValue(item, tdiv);
|
|
@@ -836,10 +839,10 @@ function drawKvpsIncremental(container, kvps, latex) {
|
|
| 836 |
tdiv.appendChild(pre);
|
| 837 |
|
| 838 |
// Add action buttons to the row
|
| 839 |
-
const row = tdiv.closest(".kvps-row");
|
| 840 |
-
if (row) {
|
| 841 |
-
addActionButtonsToElement(
|
| 842 |
-
}
|
| 843 |
|
| 844 |
// KaTeX rendering for markdown
|
| 845 |
if (latex) {
|
|
|
|
| 219 |
}
|
| 220 |
|
| 221 |
// Ensure action buttons exist
|
| 222 |
+
addActionButtonsToElement(bodyDiv);
|
| 223 |
adjustMarkdownRender(contentDiv);
|
| 224 |
|
| 225 |
} else {
|
|
|
|
| 244 |
spanElement.innerHTML = convertHTML(content);
|
| 245 |
|
| 246 |
// Ensure action buttons exist
|
| 247 |
+
addActionButtonsToElement(bodyDiv);
|
| 248 |
|
| 249 |
}
|
| 250 |
} else {
|
|
|
|
| 693 |
addValue(value);
|
| 694 |
}
|
| 695 |
|
| 696 |
+
addActionButtonsToElement(tdiv);
|
| 697 |
+
|
| 698 |
// autoscroll the KVP value if needed
|
| 699 |
// if (getAutoScroll()) #TODO needs a better redraw system
|
| 700 |
setTimeout(() => {
|
|
|
|
| 722 |
span.innerHTML = convertHTML(value);
|
| 723 |
pre.appendChild(span);
|
| 724 |
tdiv.appendChild(pre);
|
|
|
|
| 725 |
|
| 726 |
// KaTeX rendering for markdown
|
| 727 |
if (latex) {
|
|
|
|
| 795 |
// Clear and rebuild content (for now - could be optimized further)
|
| 796 |
tdiv.innerHTML = "";
|
| 797 |
|
| 798 |
+
addActionButtonsToElement(tdiv);
|
| 799 |
+
|
| 800 |
if (Array.isArray(value)) {
|
| 801 |
for (const item of value) {
|
| 802 |
addValue(item, tdiv);
|
|
|
|
| 839 |
tdiv.appendChild(pre);
|
| 840 |
|
| 841 |
// Add action buttons to the row
|
| 842 |
+
// const row = tdiv.closest(".kvps-row");
|
| 843 |
+
// if (row) {
|
| 844 |
+
// addActionButtonsToElement(pre);
|
| 845 |
+
// }
|
| 846 |
|
| 847 |
// KaTeX rendering for markdown
|
| 848 |
if (latex) {
|