incognitolm commited on
Commit
55c54a4
Β·
1 Parent(s): a2df94b

Message Versions

Browse files
Files changed (2) hide show
  1. public/css/chat.css +21 -16
  2. public/js/chat.js +25 -11
public/css/chat.css CHANGED
@@ -99,20 +99,13 @@
99
 
100
  /* Version navigator */
101
  .msg-version-nav {
102
- position: absolute;
103
- bottom: -4px;
104
- right: 0;
105
  display: flex;
106
  align-items: center;
107
  gap: 4px;
108
  font-size: 12px;
109
  color: var(--text-muted);
110
- opacity: 0;
111
- transition: opacity var(--transition);
112
  }
113
 
114
- .msg-group:hover .msg-version-nav { opacity: 1; }
115
-
116
  .msg-version-nav button {
117
  display: flex; align-items: center; justify-content: center;
118
  width: 20px; height: 20px; border-radius: 50%;
@@ -125,22 +118,34 @@
125
  .msg-actions {
126
  display: flex;
127
  gap: 3px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  opacity: 0;
129
  transition: opacity var(--transition);
130
  pointer-events: none;
131
- /* Default: left-aligned (assistant messages) */
132
- position: absolute;
133
- bottom: 4px;
134
- left: 0;
135
  }
136
 
137
- /* Right-aligned (user messages) */
138
- .msg-actions.msg-actions-right {
139
- left: auto;
140
- right: 0;
 
 
141
  }
142
 
143
- .msg-group:hover .msg-actions {
144
  opacity: 1;
145
  pointer-events: auto;
146
  }
 
99
 
100
  /* Version navigator */
101
  .msg-version-nav {
 
 
 
102
  display: flex;
103
  align-items: center;
104
  gap: 4px;
105
  font-size: 12px;
106
  color: var(--text-muted);
 
 
107
  }
108
 
 
 
109
  .msg-version-nav button {
110
  display: flex; align-items: center; justify-content: center;
111
  width: 20px; height: 20px; border-radius: 50%;
 
118
  .msg-actions {
119
  display: flex;
120
  gap: 3px;
121
+ }
122
+
123
+ .msg-actions.msg-actions-right {
124
+ justify-content: flex-end;
125
+ }
126
+
127
+ .msg-actions.msg-actions-left {
128
+ justify-content: flex-start;
129
+ }
130
+
131
+ .msg-controls {
132
+ display: flex;
133
+ flex-direction: column;
134
+ gap: 4px;
135
  opacity: 0;
136
  transition: opacity var(--transition);
137
  pointer-events: none;
 
 
 
 
138
  }
139
 
140
+ .msg-controls.msg-controls-right {
141
+ align-items: flex-end;
142
+ }
143
+
144
+ .msg-controls.msg-controls-left {
145
+ align-items: flex-start;
146
  }
147
 
148
+ .msg-group:hover .msg-controls {
149
  opacity: 1;
150
  pointer-events: auto;
151
  }
public/js/chat.js CHANGED
@@ -26,7 +26,19 @@ on('chat:aborted', (msg) => { if (msg.sessionId === activeSessionId) on
26
  on('chat:error', (msg) => { if (msg.sessionId === activeSessionId) onChatError(msg.error); });
27
  on('chat:asset', (msg) => { if (msg.sessionId === activeSessionId) appendAsset(msg.asset); });
28
  on('chat:toolCall', (msg) => { if (msg.sessionId === activeSessionId) handleLiveToolCall(msg.call); });
29
- on('chat:messageEdited', (msg) => { if (msg.sessionId === activeSessionId) renderHistory(msg.history); });
 
 
 
 
 
 
 
 
 
 
 
 
30
  on('chat:versionSelected', (msg) => { if (msg.sessionId === activeSessionId) renderHistory(msg.history); });
31
 
32
  // Reconnect: reload current session instead of resetting to welcome
@@ -121,13 +133,14 @@ function appendUserMsg(box, msg, index) {
121
 
122
  wrap.appendChild(bubble);
123
 
124
- // User actions appear on the RIGHT side
125
- wrap.appendChild(buildActions([
 
126
  { icon: 'πŸ“‹', title: 'Copy', fn: () => copyText(text) },
127
  { icon: '✏️', title: 'Edit', fn: () => startUserEdit(wrap, index, msg, text) },
128
  ], 'right'));
129
-
130
- if (msg.versions?.length > 1) wrap.appendChild(buildVersionNav(msg, index));
131
 
132
  box.appendChild(wrap);
133
  }
@@ -149,13 +162,14 @@ function appendAssistantMsg(box, msg, index) {
149
 
150
  wrap.appendChild(bubble);
151
 
152
- // Assistant actions appear on the LEFT side
153
- wrap.appendChild(buildActions([
 
154
  { icon: 'πŸ“‹', title: 'Copy', fn: () => copyText(msg.content || '') },
155
  { icon: '✏️', title: 'Edit', fn: () => startAssistantEdit(wrap, index, msg) },
156
  ], 'left'));
157
-
158
- if (msg.versions?.length > 1) wrap.appendChild(buildVersionNav(msg, index));
159
 
160
  box.appendChild(wrap);
161
  }
@@ -512,8 +526,8 @@ function appendAsset(asset) {
512
 
513
  // ── Submit ────────────────────────────────────────────────────────────────
514
 
515
- export function submitMessage(text, attachments = []) {
516
- if (!text.trim() && attachments.length === 0) return;
517
  if (isStreaming) { send({ type: 'chat:stop' }); return; }
518
  if (!activeSessionId) return;
519
 
 
26
  on('chat:error', (msg) => { if (msg.sessionId === activeSessionId) onChatError(msg.error); });
27
  on('chat:asset', (msg) => { if (msg.sessionId === activeSessionId) appendAsset(msg.asset); });
28
  on('chat:toolCall', (msg) => { if (msg.sessionId === activeSessionId) handleLiveToolCall(msg.call); });
29
+ on('chat:messageEdited', (msg) => {
30
+ if (msg.sessionId === activeSessionId) {
31
+ renderHistory(msg.history);
32
+ // Update the session history
33
+ const s = sessions.find(s => s.id === msg.sessionId);
34
+ if (s) s.history = msg.history;
35
+ // If edited message is user, regenerate the response
36
+ const editedMsg = msg.history[msg.messageIndex];
37
+ if (editedMsg && editedMsg.role === 'user') {
38
+ submitMessage('', [], true);
39
+ }
40
+ }
41
+ });
42
  on('chat:versionSelected', (msg) => { if (msg.sessionId === activeSessionId) renderHistory(msg.history); });
43
 
44
  // Reconnect: reload current session instead of resetting to welcome
 
133
 
134
  wrap.appendChild(bubble);
135
 
136
+ const controls = document.createElement('div');
137
+ controls.className = 'msg-controls msg-controls-right';
138
+ controls.appendChild(buildActions([
139
  { icon: 'πŸ“‹', title: 'Copy', fn: () => copyText(text) },
140
  { icon: '✏️', title: 'Edit', fn: () => startUserEdit(wrap, index, msg, text) },
141
  ], 'right'));
142
+ if (msg.versions?.length > 1) controls.appendChild(buildVersionNav(msg, index));
143
+ wrap.appendChild(controls);
144
 
145
  box.appendChild(wrap);
146
  }
 
162
 
163
  wrap.appendChild(bubble);
164
 
165
+ const controls = document.createElement('div');
166
+ controls.className = 'msg-controls msg-controls-left';
167
+ controls.appendChild(buildActions([
168
  { icon: 'πŸ“‹', title: 'Copy', fn: () => copyText(msg.content || '') },
169
  { icon: '✏️', title: 'Edit', fn: () => startAssistantEdit(wrap, index, msg) },
170
  ], 'left'));
171
+ if (msg.versions?.length > 1) controls.appendChild(buildVersionNav(msg, index));
172
+ wrap.appendChild(controls);
173
 
174
  box.appendChild(wrap);
175
  }
 
526
 
527
  // ── Submit ────────────────────────────────────────────────────────────────
528
 
529
+ export function submitMessage(text, attachments = [], regenerate = false) {
530
+ if (!text.trim() && attachments.length === 0 && !regenerate) return;
531
  if (isStreaming) { send({ type: 'chat:stop' }); return; }
532
  if (!activeSessionId) return;
533