clay-server 2.17.0 → 2.18.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,226 @@
1
+ /* ==========================================================================
2
+ @Mention Autocomplete Dropdown
3
+ ========================================================================== */
4
+
5
+ #mention-menu {
6
+ display: none;
7
+ position: absolute;
8
+ bottom: 100%;
9
+ left: 0;
10
+ right: 0;
11
+ max-height: 240px;
12
+ overflow-y: auto;
13
+ background: var(--bg-alt);
14
+ border: 1px solid var(--border);
15
+ border-radius: 14px;
16
+ margin-bottom: 8px;
17
+ box-shadow: 0 -4px 24px rgba(var(--shadow-rgb), 0.4);
18
+ z-index: 10;
19
+ }
20
+
21
+ #mention-menu.visible { display: block; }
22
+
23
+ .mention-item {
24
+ display: flex;
25
+ align-items: center;
26
+ padding: 10px 16px;
27
+ cursor: pointer;
28
+ gap: 10px;
29
+ border-bottom: 1px solid var(--border-subtle);
30
+ }
31
+
32
+ .mention-item:last-child { border-bottom: none; }
33
+
34
+ .mention-item:hover,
35
+ .mention-item.active {
36
+ background: rgba(var(--overlay-rgb), 0.05);
37
+ }
38
+
39
+ .mention-item-avatar {
40
+ width: 24px;
41
+ height: 24px;
42
+ border-radius: 50%;
43
+ flex-shrink: 0;
44
+ }
45
+
46
+ .mention-item-name {
47
+ font-size: 14px;
48
+ font-weight: 600;
49
+ color: var(--text);
50
+ flex: 1;
51
+ }
52
+
53
+ .mention-item-dot {
54
+ width: 8px;
55
+ height: 8px;
56
+ border-radius: 50%;
57
+ flex-shrink: 0;
58
+ }
59
+
60
+ /* ==========================================================================
61
+ @Mention Chip (in user bubble)
62
+ ========================================================================== */
63
+
64
+ .mention-chip {
65
+ display: inline;
66
+ color: var(--accent);
67
+ font-weight: 600;
68
+ background: rgba(var(--accent-rgb, 124, 58, 237), 0.12);
69
+ padding: 1px 5px;
70
+ border-radius: 4px;
71
+ font-size: inherit;
72
+ }
73
+
74
+ /* ==========================================================================
75
+ @Mention Chip (in input area)
76
+ ========================================================================== */
77
+
78
+ #input-mention-chip {
79
+ display: inline-flex;
80
+ align-items: center;
81
+ gap: 5px;
82
+ padding: 3px 6px 3px 4px;
83
+ margin: 0 0 4px 0;
84
+ border-radius: 6px;
85
+ background: color-mix(in srgb, var(--chip-color, #6c5ce7) 12%, transparent);
86
+ border: 1px solid color-mix(in srgb, var(--chip-color, #6c5ce7) 25%, transparent);
87
+ cursor: default;
88
+ flex-shrink: 0;
89
+ width: fit-content;
90
+ animation: chip-in 0.15s ease-out;
91
+ }
92
+
93
+ @keyframes chip-in {
94
+ from { opacity: 0; transform: scale(0.9); }
95
+ to { opacity: 1; transform: scale(1); }
96
+ }
97
+
98
+ .input-mention-chip-avatar {
99
+ width: 18px;
100
+ height: 18px;
101
+ border-radius: 50%;
102
+ flex-shrink: 0;
103
+ }
104
+
105
+ .input-mention-chip-name {
106
+ font-size: 13px;
107
+ font-weight: 600;
108
+ white-space: nowrap;
109
+ }
110
+
111
+ .input-mention-chip-remove {
112
+ background: none;
113
+ border: none;
114
+ padding: 0 2px;
115
+ margin: 0;
116
+ cursor: pointer;
117
+ font-size: 15px;
118
+ line-height: 1;
119
+ color: var(--text-dimmer);
120
+ opacity: 0.6;
121
+ transition: opacity 0.1s;
122
+ }
123
+
124
+ .input-mention-chip-remove:hover {
125
+ opacity: 1;
126
+ }
127
+
128
+ /* ==========================================================================
129
+ @Mention Response Block
130
+ ========================================================================== */
131
+
132
+ .msg-mention {
133
+ position: relative;
134
+ max-width: var(--content-width);
135
+ margin: 0 auto 24px;
136
+ padding: 4px 20px;
137
+ border-radius: 12px;
138
+ background: color-mix(in srgb, var(--mention-color, #6c5ce7) 6%, transparent);
139
+ transition: background 0.15s;
140
+ }
141
+
142
+ .msg-mention:hover {
143
+ background: color-mix(in srgb, var(--mention-color, #6c5ce7) 10%, transparent);
144
+ }
145
+
146
+ .mention-header {
147
+ display: flex;
148
+ align-items: center;
149
+ gap: 6px;
150
+ margin-bottom: 4px;
151
+ }
152
+
153
+ .mention-avatar {
154
+ width: 22px;
155
+ height: 22px;
156
+ border-radius: 50%;
157
+ flex-shrink: 0;
158
+ }
159
+
160
+ .mention-name {
161
+ font-size: 13px;
162
+ font-weight: 700;
163
+ color: var(--mention-color, #6c5ce7);
164
+ }
165
+
166
+ .mention-content {
167
+ font-size: 15px;
168
+ line-height: 1.7;
169
+ word-break: break-word;
170
+ color: var(--text);
171
+ }
172
+
173
+ /* Activity bar inside mention block */
174
+ .msg-mention .mention-activity-bar {
175
+ margin: 4px 0;
176
+ padding: 0;
177
+ }
178
+
179
+ /* Copy hint ("Click to grab this") for mention blocks in project chat */
180
+ .msg-mention:hover .msg-copy-hint { opacity: 1; }
181
+ .msg-mention.copy-primed .msg-copy-hint { opacity: 1; color: var(--accent); }
182
+ .msg-mention.copy-done .msg-copy-hint { opacity: 1; color: var(--success); }
183
+
184
+ /* ==========================================================================
185
+ @Mention in Mate DM (DM-style layout)
186
+ ========================================================================== */
187
+
188
+ /* Badge next to mate name */
189
+ .mention-badge {
190
+ font-size: 10px;
191
+ font-weight: 700;
192
+ letter-spacing: 0.5px;
193
+ color: var(--text-dimmer);
194
+ background: rgba(var(--overlay-rgb), 0.08);
195
+ padding: 1px 5px;
196
+ border-radius: 4px;
197
+ }
198
+
199
+ /* DM-style mention: override the DM mate avatar so it uses the mentioned mate's avatar */
200
+ .msg-mention-dm .dm-bubble-avatar-mate {
201
+ /* Inherits dm-bubble-avatar styling from mates.css */
202
+ }
203
+
204
+ /* Activity bar inside DM-style mention */
205
+ .msg-mention-dm .mention-activity-bar {
206
+ margin: 4px 0;
207
+ padding: 0;
208
+ }
209
+
210
+ /* Error state */
211
+ .mention-error {
212
+ color: var(--danger, #e74c3c);
213
+ font-size: 13px;
214
+ font-style: italic;
215
+ }
216
+
217
+ /* ==========================================================================
218
+ Mobile adjustments
219
+ ========================================================================== */
220
+
221
+ @media (max-width: 768px) {
222
+ .msg-mention {
223
+ max-width: 100%;
224
+ padding: 4px 12px;
225
+ }
226
+ }
@@ -1041,6 +1041,13 @@
1041
1041
  #layout.sidebar-collapsed #user-island .user-island-actions {
1042
1042
  display: none;
1043
1043
  }
1044
+ /* Keep user island expanded in mate DM mode regardless of sidebar state */
1045
+ body.mate-dm-active #layout.sidebar-collapsed #user-island .user-island-info {
1046
+ display: block;
1047
+ }
1048
+ body.mate-dm-active #layout.sidebar-collapsed #user-island .user-island-actions {
1049
+ display: flex;
1050
+ }
1044
1051
 
1045
1052
 
1046
1053
 
@@ -384,6 +384,7 @@
384
384
  <button id="new-msg-btn" class="hidden" aria-label="Scroll to bottom"></button>
385
385
  <div id="input-area">
386
386
  <div id="input-wrapper">
387
+ <div id="mention-menu"></div>
387
388
  <div id="slash-menu"></div>
388
389
  <div id="suggestion-chips" class="hidden"></div>
389
390
  <div id="input-row">
@@ -1,5 +1,6 @@
1
1
  import { iconHtml, refreshIcons } from './icons.js';
2
2
  import { setRewindMode, isRewindMode } from './rewind.js';
3
+ import { checkForMention, showMentionMenu, hideMentionMenu, isMentionMenuVisible, mentionMenuKeydown, setMentionAtIdx, parseMentionFromInput, clearMentionState, sendMention, renderMentionUser, removeMentionChip } from './mention.js';
3
4
 
4
5
  var ctx;
5
6
 
@@ -86,6 +87,24 @@ export function sendMessage() {
86
87
  return;
87
88
  }
88
89
 
90
+ // Check for @mention: if a mate was selected, route to mention handler
91
+ var mention = parseMentionFromInput(text);
92
+ if (mention) {
93
+ hideMentionMenu();
94
+ if (ctx.hideSuggestionChips) ctx.hideSuggestionChips();
95
+ var mentionPastes = pendingPastes.map(function (p) { return p.text; });
96
+ // Render user message with mention chip (same as history replay)
97
+ renderMentionUser({ mateName: mention.mateName, text: mention.text });
98
+ sendMention(mention.mateId, mention.text, mentionPastes);
99
+ clearMentionState();
100
+ ctx.inputEl.value = "";
101
+ sendInputSync();
102
+ clearPendingImages();
103
+ autoResize();
104
+ ctx.inputEl.focus();
105
+ return;
106
+ }
107
+
89
108
  // Prepend file paths to text
90
109
  var files = pendingFiles.slice();
91
110
  if (files.length > 0) {
@@ -603,10 +622,20 @@ export function initInput(_ctx) {
603
622
  var val = ctx.inputEl.value;
604
623
  if (val.startsWith("/") && !val.includes(" ") && val.length > 1) {
605
624
  showSlashMenu(val.substring(1));
625
+ hideMentionMenu();
606
626
  } else if (val === "/") {
607
627
  showSlashMenu("");
628
+ hideMentionMenu();
608
629
  } else {
609
630
  hideSlashMenu();
631
+ // Check for @mention
632
+ var mentionCheck = checkForMention(val, ctx.inputEl.selectionStart);
633
+ if (mentionCheck.active) {
634
+ setMentionAtIdx(mentionCheck.startIdx);
635
+ showMentionMenu(mentionCheck.query);
636
+ } else {
637
+ hideMentionMenu();
638
+ }
610
639
  }
611
640
  // Toggle send/stop button based on input content during processing
612
641
  if (ctx.processing && ctx.setSendBtnMode) {
@@ -618,6 +647,11 @@ export function initInput(_ctx) {
618
647
  ctx.inputEl.addEventListener("compositionend", function () { isComposing = false; });
619
648
 
620
649
  ctx.inputEl.addEventListener("keydown", function (e) {
650
+ // @Mention menu keyboard navigation
651
+ if (isMentionMenuVisible()) {
652
+ if (mentionMenuKeydown(e)) return;
653
+ }
654
+
621
655
  if (slashFiltered.length > 0 && ctx.slashMenu.classList.contains("visible")) {
622
656
  if (e.key === "ArrowDown") {
623
657
  e.preventDefault();
@@ -643,6 +677,13 @@ export function initInput(_ctx) {
643
677
  }
644
678
  }
645
679
 
680
+ // Backspace on empty input: remove mention chip if present
681
+ if (e.key === "Backspace" && ctx.inputEl.value === "" && document.getElementById("input-mention-chip")) {
682
+ e.preventDefault();
683
+ removeMentionChip();
684
+ return;
685
+ }
686
+
646
687
  // Ctrl+J: insert newline (like Claude CLI)
647
688
  if (e.key === "j" && e.ctrlKey && !e.metaKey) {
648
689
  e.preventDefault();