main
html 457 lines 12.6 KB
Raw
1 <html>
2
3 <head>
4 <script type="module">
5 import { store as fullScreenStore } from "/components/modals/full-screen-input/full-screen-store.js";
6 import { store as messageQueueStore } from "/components/chat/message-queue/message-queue-store.js";
7 import { store as chatInputStore } from "/components/chat/input/input-store.js";
8 </script>
9 </head>
10
11 <body>
12 <div x-data>
13 <x-extension id="chat-input-box-start"></x-extension>
14 <div class="input-row">
15 <!-- More actions (+): opens upward; content lives in bottom-actions.html -->
16 <div class="attachment-wrapper chat-more-dropdown" @click.outside="$store.chatInput.closeChatMoreMenu()"
17 @keydown.escape.window="$store.chatInput.closeChatMoreMenu()">
18 <button type="button" class="chat-more-trigger" @click.stop="$store.chatInput.toggleChatMoreMenu()"
19 :aria-expanded="$store.chatInput.chatMoreMenuOpen.toString()" aria-label="More actions">
20 <x-icon aria-hidden="true" name="add"></x-icon>
21 </button>
22 <div class="chat-more-panel" x-show="$store.chatInput.chatMoreMenuOpen" x-transition style="display: none;">
23 <x-component path="chat/input/bottom-actions.html"></x-component>
24 </div>
25 </div>
26
27 <!-- Container for composer and expand button -->
28 <div id="chat-input-container">
29 <div id="chat-input" role="textbox" aria-label="Message" aria-multiline="true" contenteditable="true"
30 spellcheck="true" :data-placeholder="$store.chatInput.inputPlaceholder"
31 @keydown="$store.chatInput.handleKeydown($event)"
32 @input="$store.chatInput.handleInput($event)"
33 @paste="$store.chatInput.handlePaste($event)"
34 :class="{ 'progress-active': $store.chatInput.progressActive, 'is-empty': !$store.chatInput.message }"
35 x-create="$store.chatInput.mountEditor($el)"
36 x-destroy="$store.chatInput.unmountEditor($el)"></div>
37 <div id="chat-input-progress-placeholder" x-show="$store.chatInput.showProgressPlaceholder"
38 x-html="$store.chatInput.progressPlaceholderHtml"
39 :class="{ 'progress-active': $store.chatInput.progressActive }" aria-hidden="true" style="display: none;">
40 </div>
41 <button id="expand-button" @click="$store.fullScreenInputModal.openModal()" aria-label="Expand input">
42 <x-icon aria-hidden="true" name="fullscreen"></x-icon>
43 </button>
44 </div>
45
46 <div id="chat-buttons-wrapper">
47 <!-- Send button -->
48 <button class="chat-button" id="send-button" @click="$store.chatInput.activateSendButton()"
49 :class="$store.chatInput.sendButtonClass" :title="$store.chatInput.sendButtonTitle"
50 :aria-label="$store.chatInput.sendButtonTitle">
51 <x-icon :name="$store.chatInput.sendButtonIcon"></x-icon>
52 </button>
53 </div>
54 </div>
55
56 <!-- Full Screen Input Modal -->
57 <x-component path="modals/full-screen-input/full-screen-input.html"></x-component>
58 <x-extension id="chat-input-box-end"></x-extension>
59 </div>
60
61
62 <style>
63 /* Layout rows */
64 .input-row {
65 display: flex;
66 align-items: center;
67 gap: 0.72rem;
68 width: 100%;
69 min-height: 4.25rem;
70 padding: 0.42rem 0.52rem 0.42rem 0.72rem;
71 border: 1px solid color-mix(in srgb, var(--color-border) 72%, transparent);
72 border-radius: 8px;
73 background: color-mix(in srgb, var(--color-panel) 72%, var(--color-background) 28%);
74 box-shadow:
75 inset 0 1px 0 rgba(255, 255, 255, 0.035),
76 0 18px 46px rgba(0, 0, 0, 0.18);
77 white-space: nowrap;
78 transition: border-color 0.16s ease, background-color 0.16s ease, box-shadow 0.16s ease;
79 }
80
81 .input-row:focus-within {
82 border-color: color-mix(in srgb, var(--color-border) 88%, var(--color-text) 12%);
83 box-shadow:
84 inset 0 1px 0 rgba(255, 255, 255, 0.045),
85 0 22px 54px rgba(0, 0, 0, 0.22);
86 }
87
88 .attachment-wrapper {
89 position: relative;
90 flex-shrink: 0;
91 }
92
93 /* Composer + menu: custom panel (edit here; not shared with file-browser dropdown) */
94 .chat-more-dropdown {
95 z-index: 1;
96 }
97
98 .chat-more-trigger {
99 cursor: pointer;
100 color: var(--color-text);
101 opacity: 0.82;
102 transition: opacity 0.16s ease, background-color 0.16s ease, color 0.16s ease;
103 display: flex;
104 align-items: center;
105 justify-content: center;
106 width: 2.5rem;
107 height: 2.5rem;
108 padding: 0;
109 border: none;
110 border-radius: 10px;
111 background: transparent;
112 }
113
114 .chat-more-trigger:hover {
115 opacity: 1;
116 background: color-mix(in srgb, var(--color-border) 36%, transparent);
117 }
118
119 .chat-more-trigger:active {
120 opacity: 0.5;
121 }
122
123 .chat-more-trigger .material-symbols-outlined {
124 font-size: 1.7rem;
125 line-height: 1;
126 }
127
128 .chat-more-panel {
129 position: absolute;
130 left: 0;
131 bottom: 100%;
132 margin-bottom: 0.25rem;
133 min-width: 11rem;
134 max-width: min(18rem, 92vw);
135 max-height: min(70vh, 20rem);
136 overflow-x: hidden;
137 overflow-y: auto;
138 background-color: color-mix(in srgb, var(--color-panel) 90%, black 10%);
139 border: 1px solid var(--color-border);
140 border-radius: 12px;
141 box-shadow: 0 16px 38px rgba(0, 0, 0, 0.3);
142 z-index: 1050;
143 padding: 0.3rem;
144 }
145
146 .light-mode .chat-more-panel {
147 box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12);
148 }
149
150 /* Text input */
151 #chat-input-container {
152 position: relative;
153 width: 100%;
154 min-width: 0;
155 display: flex;
156 align-items: center;
157 align-self: stretch;
158 }
159
160 #chat-input {
161 background-color: transparent;
162 border: 0;
163 border-radius: 0;
164 color: var(--color-text);
165 flex-grow: 1;
166 font-family: var(--font-family-main, "Rubik", Arial, Helvetica, sans-serif);
167 font-optical-sizing: auto;
168 -webkit-font-optical-sizing: auto;
169 font-size: 1rem;
170 line-height: 1.45;
171 max-height: 30vh;
172 min-height: 2.8rem;
173 width: 100%;
174 padding: 0.68rem 2.2rem 0.68rem 0.1rem;
175 margin: 0;
176 overflow-y: auto;
177 white-space: pre-wrap;
178 word-break: break-word;
179 scroll-behavior: smooth;
180 resize: none;
181 align-content: center;
182 background-clip: border-box;
183 outline: none;
184 transition: color 0.16s ease, background-color 0.16s ease;
185 -webkit-transition: color 0.16s ease, background-color 0.16s ease;
186 }
187
188 #chat-input.is-empty::before {
189 content: attr(data-placeholder);
190 color: color-mix(in srgb, var(--color-text) 62%, transparent);
191 opacity: 0.78;
192 pointer-events: none;
193 }
194
195 #chat-input .composer-code-block {
196 display: block;
197 margin: 0.48rem 0;
198 padding: 0.56rem 0.7rem;
199 border-radius: 6px;
200 background: color-mix(in srgb, var(--color-border) 28%, transparent);
201 }
202
203 #chat-input .composer-code-content {
204 min-height: 1.35rem;
205 margin: 0;
206 outline: none;
207 white-space: pre-wrap;
208 word-break: break-word;
209 font-family: var(--font-family-code, "Roboto Mono", monospace);
210 font-size: 0.94rem;
211 line-height: 1.45;
212 }
213
214 #chat-input::-webkit-scrollbar {
215 width: 6px;
216 height: 6px;
217 }
218
219 #chat-input::-webkit-scrollbar-track {
220 background: transparent;
221 margin: 4px 0;
222 border-radius: 6px;
223 }
224
225 #chat-input::-webkit-scrollbar-thumb {
226 background-color: rgba(155, 155, 155, 0.5);
227 border-radius: 6px;
228 -webkit-transition: background-color 0.2s ease;
229 transition: background-color 0.2s ease;
230 }
231
232 #chat-input::-webkit-scrollbar-thumb:hover {
233 background-color: rgba(155, 155, 155, 0.7);
234 }
235
236 #chat-input:focus {
237 outline: none;
238 background-color: transparent;
239 }
240
241 /* Progress ghost text animation — gentle pulse on placeholder */
242 #chat-input.progress-active.is-empty::before {
243 animation: placeholder-pulse 2s ease-in-out infinite;
244 }
245
246 @keyframes placeholder-pulse {
247
248 0%,
249 100% {
250 opacity: 0.45;
251 }
252
253 50% {
254 opacity: 0.85;
255 }
256 }
257
258 #chat-input.progress-active {
259 border-color: color-mix(in srgb, var(--color-highlight) 20%, transparent);
260 outline-color: color-mix(in srgb, var(--color-highlight) 15%, transparent);
261 }
262
263 #chat-input-progress-placeholder {
264 position: absolute;
265 top: 0;
266 bottom: 0;
267 left: 0.12rem;
268 right: 2rem;
269 color: var(--color-text-muted);
270 opacity: 0.7;
271 font-family: var(--font-family-code, "Roboto Mono", monospace);
272 font-size: 0.9rem;
273 line-height: 1.25;
274 white-space: nowrap;
275 overflow: hidden;
276 text-overflow: ellipsis;
277 pointer-events: none;
278 display: flex;
279 align-items: center;
280 gap: 0.35rem;
281 }
282
283 #chat-input-progress-placeholder.progress-active {
284 animation: placeholder-pulse 2s ease-in-out infinite;
285 }
286
287 #chat-input-progress-placeholder .chat-input-progress-icon {
288 display: inline-flex;
289 align-items: center;
290 justify-content: center;
291 font-size: 1.15rem;
292 line-height: 1;
293 color: var(--color-highlight);
294 }
295
296 #expand-button {
297 position: absolute;
298 top: 50%;
299 right: 0;
300 width: 2rem;
301 height: 2rem;
302 background: transparent;
303 border: none;
304 cursor: pointer;
305 transform: translateY(-50%) scale(0.8);
306 transform-origin: center;
307 font-size: 1.2rem;
308 color: var(--color-text);
309 opacity: 0.2;
310 transition: opacity 0.2s;
311 display: flex;
312 align-items: center;
313 justify-content: center;
314 padding: 0;
315 }
316
317 #expand-button:hover {
318 opacity: 0.7;
319 }
320
321 #expand-button:active {
322 opacity: 1;
323 }
324
325 #expand-button .material-symbols-outlined {
326 display: block;
327 font-size: 1.3rem;
328 line-height: 1;
329 }
330
331 /* Chat buttons (Send/Mic) */
332 #chat-buttons-wrapper {
333 gap: 0.58rem;
334 padding-left: 0;
335 line-height: 1;
336 display: -webkit-flex;
337 display: flex;
338 align-items: center;
339 }
340
341 .chat-button {
342 border: 1px solid transparent;
343 border-radius: 50%;
344 color: #fff;
345 cursor: pointer;
346 font-size: var(--font-size-normal);
347 height: 3.15rem;
348 width: 3.15rem;
349 margin: 0;
350 display: -webkit-flex;
351 display: flex;
352 align-items: center;
353 justify-content: center;
354 flex-shrink: 0;
355 flex-grow: 0;
356 min-width: 3.15rem;
357 -webkit-transition: background-color var(--transition-speed), border-color 0.16s ease, box-shadow 0.16s ease, filter 0.12s ease-in-out, transform 0.12s ease;
358 transition: background-color var(--transition-speed), border-color 0.16s ease, box-shadow 0.16s ease, filter 0.12s ease-in-out, transform 0.12s ease;
359 }
360
361 #send-button {
362 order: 2;
363 border-radius: 12px;
364 background-color: #4248f1;
365 box-shadow: none;
366 }
367
368 #send-button.send-queue {
369 background-color: #e67e22;
370 box-shadow: none;
371 }
372
373 #send-button.stop {
374 background-color: var(--color-error-text);
375 box-shadow: none;
376 }
377
378 #send-button:hover {
379 background-color: #353bc5;
380 filter: none;
381 box-shadow: none;
382 }
383
384 #send-button.send-queue:hover {
385 background-color: #d35400;
386 filter: none;
387 }
388
389 #send-button.stop:hover {
390 background-color: color-mix(in srgb, var(--color-error-text) 82%, black);
391 filter: none;
392 }
393
394 #send-button:active {
395 background-color: #2b309c;
396 transform: translateY(1px) scale(0.98);
397 filter: brightness(0.96);
398 }
399
400 #send-button.stop:active {
401 background-color: color-mix(in srgb, var(--color-error-text) 68%, black);
402 }
403
404 .chat-button svg {
405 width: 1.5rem;
406 height: 1.5rem;
407 }
408
409 #send-button .material-symbols-outlined {
410 font-size: 1.78rem;
411 }
412
413 /* Responsive tweaks */
414 @media (max-width: 640px) {
415 #chat-input {
416 align-content: center;
417 }
418
419 #chat-buttons-wrapper {
420 display: flex;
421 gap: 0.42rem;
422 padding: 0 !important;
423 width: auto;
424 flex-wrap: nowrap;
425 -webkit-transition: all 0.3s ease;
426 transition: all 0.3s ease;
427 }
428
429 .input-row {
430 gap: 0.42rem;
431 min-height: 4rem;
432 padding: 0.36rem 0.42rem 0.36rem 0.48rem;
433 }
434
435 .chat-more-trigger {
436 width: 2.15rem;
437 height: 2.15rem;
438 }
439
440 .chat-button {
441 width: 2.75rem;
442 height: 2.75rem;
443 min-width: 2.75rem;
444 }
445 }
446
447 @media (min-width: 768px) {
448 #chat-buttons-wrapper {
449 flex-wrap: nowrap;
450 -webkit-flex-wrap: nowrap;
451 flex-wrap: nowrap;
452 }
453 }
454 </style>
455 </body>
456
457 </html>