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: absolute;
 
 
 
6
  top: 0.3em;
7
- right: 0;
 
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
- transition: background-color var(--transition-speed) ease-in-out;
 
 
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-background);
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
- if (element.classList.contains("kvps-row")) {
7
- return element.querySelector(".kvps-val")?.innerText || "";
8
- } else if (element.classList.contains("message-text")) {
9
- return (
10
- element.querySelector("pre")?.innerText ||
11
- element.querySelector("span")?.innerText ||
12
- ""
13
- );
14
- } else {
15
- return element.querySelector("span")?.innerText || "";
 
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
- element.appendChild(container);
 
 
 
 
 
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: #171717;
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(contentDiv);
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(preElement);
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(row);
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) {