@nuraly/lumenui 0.3.4 → 0.3.6
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.
- package/dist/nuralyui.bundle.js +2581 -1483
- package/dist/nuralyui.bundle.js.gz +0 -0
- package/dist/src/components/button/bundle.js +130 -39
- package/dist/src/components/button/bundle.js.gz +0 -0
- package/dist/src/components/button/button.component.js +7 -4
- package/dist/src/components/button/button.style.js +92 -2
- package/dist/src/components/canvas/base-canvas.component.d.ts +8 -0
- package/dist/src/components/canvas/base-canvas.component.js +75 -3
- package/dist/src/components/canvas/bundle.js +2546 -1200
- package/dist/src/components/canvas/bundle.js.gz +0 -0
- package/dist/src/components/canvas/controllers/collaboration.controller.d.ts +24 -11
- package/dist/src/components/canvas/controllers/collaboration.controller.js +176 -120
- package/dist/src/components/canvas/controllers/selection.controller.js +20 -0
- package/dist/src/components/canvas/interfaces/collaboration.interface.d.ts +8 -0
- package/dist/src/components/canvas/templates/index.d.ts +1 -0
- package/dist/src/components/canvas/templates/index.js +2 -0
- package/dist/src/components/canvas/templates/lock-overlay.template.d.ts +20 -0
- package/dist/src/components/canvas/templates/lock-overlay.template.js +33 -0
- package/dist/src/components/canvas/workflow-canvas.component.js +52 -24
- package/dist/src/components/canvas/workflow-canvas.style.js +62 -1
- package/dist/src/components/canvas/workflow-canvas.types.js +50 -4
- package/dist/src/components/chat-panel/bundle.js +10 -10
- package/dist/src/components/chat-panel/bundle.js.gz +0 -0
- package/dist/src/components/chat-panel/chat-panel.component.js +8 -8
- package/dist/src/components/chatbot/bundle.js +454 -289
- package/dist/src/components/chatbot/bundle.js.gz +0 -0
- package/dist/src/components/chatbot/chatbot.style.js +162 -21
- package/dist/src/components/chatbot/chatbot.types.d.ts +1 -0
- package/dist/src/components/chatbot/core/chatbot-core.controller.js +13 -7
- package/dist/src/components/chatbot/providers/workflow-socket-provider.js +1 -2
- package/dist/src/components/chatbot/templates/input-box.template.js +58 -30
- package/dist/src/components/chatbot/templates/message.template.js +41 -31
- package/dist/src/components/chatbot/templates/thread-sidebar.template.js +38 -39
- package/dist/src/components/colorpicker/bundle.js +15 -10
- package/dist/src/components/colorpicker/bundle.js.gz +0 -0
- package/dist/src/components/colorpicker/color-picker.component.js +15 -10
- package/dist/src/components/datepicker/bundle.js +10 -10
- package/dist/src/components/datepicker/bundle.js.gz +0 -0
- package/dist/src/components/datepicker/datepicker.component.js +14 -22
- package/dist/src/components/dropdown/bundle.js +13 -12
- package/dist/src/components/dropdown/bundle.js.gz +0 -0
- package/dist/src/components/dropdown/dropdown.component.js +10 -9
- package/dist/src/components/file-upload/bundle.js +15 -14
- package/dist/src/components/file-upload/bundle.js.gz +0 -0
- package/dist/src/components/file-upload/file-upload.component.js +15 -14
- package/dist/src/components/icon/bundle.js +7 -7
- package/dist/src/components/icon/bundle.js.gz +0 -0
- package/dist/src/components/icon/icon-paths.js +15 -0
- package/dist/src/components/iconpicker/bundle.js +214 -122
- package/dist/src/components/iconpicker/bundle.js.gz +0 -0
- package/dist/src/components/iconpicker/icon-picker.component.js +4 -4
- package/dist/src/components/menu/bundle.js +5 -2
- package/dist/src/components/menu/bundle.js.gz +0 -0
- package/dist/src/components/menu/menu.component.js +5 -2
- package/dist/src/components/modal/bundle.js +16 -13
- package/dist/src/components/modal/bundle.js.gz +0 -0
- package/dist/src/components/modal/modal.component.js +16 -13
- package/dist/src/components/panel/bundle.js +28 -28
- package/dist/src/components/panel/bundle.js.gz +0 -0
- package/dist/src/components/popconfirm/bundle.js +135 -41
- package/dist/src/components/popconfirm/bundle.js.gz +0 -0
- package/dist/src/components/popconfirm/popconfirm.component.d.ts +15 -119
- package/dist/src/components/popconfirm/popconfirm.component.js +158 -162
- package/dist/src/components/popconfirm/popconfirm.style.js +94 -0
- package/dist/src/components/presence/bundle.js +2 -1
- package/dist/src/components/presence/bundle.js.gz +0 -0
- package/dist/src/components/presence/presence.component.js +2 -1
- package/dist/src/components/table/bundle.js +3 -2
- package/dist/src/components/table/bundle.js.gz +0 -0
- package/dist/src/components/table/table.component.js +3 -2
- package/dist/src/components/tabs/bundle.js +3 -3
- package/dist/src/components/tabs/bundle.js.gz +0 -0
- package/dist/src/components/timepicker/bundle.js +3 -3
- package/dist/src/components/timepicker/bundle.js.gz +0 -0
- package/package.json +1 -1
- package/packages/common/dist/VERSIONS.md +1 -1
- package/packages/common/dist/shared/controllers/dropdown.controller.d.ts +4 -0
- package/packages/common/dist/shared/controllers/dropdown.controller.d.ts.map +1 -1
- package/packages/common/dist/shared/controllers/dropdown.controller.js +29 -3
- package/packages/common/dist/shared/controllers/dropdown.controller.js.map +1 -1
|
Binary file
|
|
@@ -259,14 +259,13 @@ export default css `
|
|
|
259
259
|
}
|
|
260
260
|
|
|
261
261
|
.thread-item--active {
|
|
262
|
-
background-color: #
|
|
263
|
-
color: #
|
|
264
|
-
border-color:
|
|
262
|
+
background-color: #ededed;
|
|
263
|
+
color: #161616;
|
|
264
|
+
border-color: transparent;
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
.thread-item--active:hover {
|
|
268
|
-
background-color: #
|
|
269
|
-
opacity: 0.95;
|
|
268
|
+
background-color: #e5e5e5;
|
|
270
269
|
}
|
|
271
270
|
|
|
272
271
|
.thread-item__header {
|
|
@@ -288,14 +287,24 @@ export default css `
|
|
|
288
287
|
}
|
|
289
288
|
|
|
290
289
|
.thread-item__actions {
|
|
291
|
-
display:
|
|
290
|
+
display: flex;
|
|
292
291
|
align-items: center;
|
|
293
292
|
gap: 2px;
|
|
294
293
|
flex-shrink: 0;
|
|
295
294
|
}
|
|
296
295
|
|
|
297
|
-
.thread-
|
|
298
|
-
|
|
296
|
+
.thread-item__actions .thread-item__menu {
|
|
297
|
+
opacity: 0;
|
|
298
|
+
pointer-events: none;
|
|
299
|
+
transition: opacity 0.15s ease;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.thread-item:hover .thread-item__menu,
|
|
303
|
+
.thread-item--active .thread-item__menu,
|
|
304
|
+
.thread-item:focus-within .thread-item__menu,
|
|
305
|
+
.thread-item__actions nr-dropdown[open] .thread-item__menu {
|
|
306
|
+
opacity: 1;
|
|
307
|
+
pointer-events: auto;
|
|
299
308
|
}
|
|
300
309
|
|
|
301
310
|
.thread-item__action-btn {
|
|
@@ -323,27 +332,23 @@ export default css `
|
|
|
323
332
|
background-color: rgba(59, 130, 246, 0.1);
|
|
324
333
|
}
|
|
325
334
|
|
|
326
|
-
.thread-item__actions nr-popconfirm {
|
|
327
|
-
margin-top: 4px;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
335
|
.thread-item__delete:hover {
|
|
331
336
|
color: #ef4444;
|
|
332
337
|
background-color: rgba(239, 68, 68, 0.1);
|
|
333
338
|
}
|
|
334
339
|
|
|
335
340
|
.thread-item--active .thread-item__action-btn {
|
|
336
|
-
color: rgba(
|
|
341
|
+
color: rgba(22, 22, 22, 0.6);
|
|
337
342
|
}
|
|
338
343
|
|
|
339
344
|
.thread-item--active .thread-item__action-btn:hover {
|
|
340
|
-
color: #
|
|
341
|
-
background-color: rgba(
|
|
345
|
+
color: #161616;
|
|
346
|
+
background-color: rgba(0, 0, 0, 0.06);
|
|
342
347
|
}
|
|
343
348
|
|
|
344
349
|
.thread-item--active .thread-item__delete:hover {
|
|
345
350
|
color: #ef4444;
|
|
346
|
-
background-color: rgba(239, 68, 68, 0.
|
|
351
|
+
background-color: rgba(239, 68, 68, 0.1);
|
|
347
352
|
}
|
|
348
353
|
|
|
349
354
|
.thread-item__bookmark--active {
|
|
@@ -376,7 +381,7 @@ export default css `
|
|
|
376
381
|
}
|
|
377
382
|
|
|
378
383
|
.thread-item--active .thread-item__rename-input {
|
|
379
|
-
background:
|
|
384
|
+
background: #ffffff;
|
|
380
385
|
}
|
|
381
386
|
|
|
382
387
|
.thread-item__preview {
|
|
@@ -415,11 +420,13 @@ export default css `
|
|
|
415
420
|
.messages {
|
|
416
421
|
flex: 1;
|
|
417
422
|
overflow-y: auto;
|
|
423
|
+
overflow-x: hidden;
|
|
418
424
|
display: flex;
|
|
419
425
|
flex-direction: column;
|
|
420
426
|
gap: 0;
|
|
421
427
|
background-color: #ffffff;
|
|
422
|
-
padding: 8px
|
|
428
|
+
padding: 8px 1rem;
|
|
429
|
+
box-sizing: border-box;
|
|
423
430
|
justify-content: flex-start; /* Always align messages to top */
|
|
424
431
|
}
|
|
425
432
|
|
|
@@ -479,16 +486,22 @@ export default css `
|
|
|
479
486
|
border: 0 solid transparent;
|
|
480
487
|
}
|
|
481
488
|
|
|
482
|
-
/* Message attachments (file
|
|
489
|
+
/* Message attachments (file thumbs) */
|
|
483
490
|
.message__attachments {
|
|
484
491
|
display: flex;
|
|
485
492
|
flex-wrap: wrap;
|
|
486
|
-
gap: 0.
|
|
487
|
-
margin-top: 0.
|
|
493
|
+
gap: 0.375rem;
|
|
494
|
+
margin-top: 0.375rem;
|
|
488
495
|
position: relative;
|
|
489
496
|
z-index: 1;
|
|
490
497
|
}
|
|
491
498
|
|
|
499
|
+
.file-thumb--message {
|
|
500
|
+
width: 48px;
|
|
501
|
+
height: 48px;
|
|
502
|
+
border-radius: 8px;
|
|
503
|
+
}
|
|
504
|
+
|
|
492
505
|
.message-file-preview-dropdown {
|
|
493
506
|
display: inline-block;
|
|
494
507
|
position: relative;
|
|
@@ -986,6 +999,134 @@ export default css `
|
|
|
986
999
|
cursor: help;
|
|
987
1000
|
}
|
|
988
1001
|
|
|
1002
|
+
/* Claude-style upload thumbnail chip */
|
|
1003
|
+
.file-thumb {
|
|
1004
|
+
position: relative;
|
|
1005
|
+
display: inline-flex;
|
|
1006
|
+
align-items: center;
|
|
1007
|
+
justify-content: center;
|
|
1008
|
+
width: 56px;
|
|
1009
|
+
height: 56px;
|
|
1010
|
+
border-radius: 10px;
|
|
1011
|
+
overflow: hidden;
|
|
1012
|
+
background-color: #f3f4f6;
|
|
1013
|
+
border: 1px solid #e5e7eb;
|
|
1014
|
+
cursor: pointer;
|
|
1015
|
+
outline: none;
|
|
1016
|
+
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
1017
|
+
flex-shrink: 0;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
.file-thumb:hover,
|
|
1021
|
+
.file-thumb:focus-visible {
|
|
1022
|
+
border-color: #7c3aed;
|
|
1023
|
+
box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.15);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
.file-thumb__image {
|
|
1027
|
+
width: 100%;
|
|
1028
|
+
height: 100%;
|
|
1029
|
+
object-fit: cover;
|
|
1030
|
+
display: block;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
.file-thumb__ext {
|
|
1034
|
+
width: 100%;
|
|
1035
|
+
height: 100%;
|
|
1036
|
+
display: flex;
|
|
1037
|
+
align-items: center;
|
|
1038
|
+
justify-content: center;
|
|
1039
|
+
background: linear-gradient(135deg, #ede9fe, #ddd6fe);
|
|
1040
|
+
color: #5b21b6;
|
|
1041
|
+
font-weight: 600;
|
|
1042
|
+
font-size: 0.7rem;
|
|
1043
|
+
letter-spacing: 0.04em;
|
|
1044
|
+
text-transform: uppercase;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
.file-thumb__ext-label {
|
|
1048
|
+
padding: 0 4px;
|
|
1049
|
+
max-width: 100%;
|
|
1050
|
+
overflow: hidden;
|
|
1051
|
+
text-overflow: ellipsis;
|
|
1052
|
+
white-space: nowrap;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
.file-thumb__spinner {
|
|
1056
|
+
position: absolute;
|
|
1057
|
+
inset: 0;
|
|
1058
|
+
display: flex;
|
|
1059
|
+
align-items: center;
|
|
1060
|
+
justify-content: center;
|
|
1061
|
+
background-color: rgba(255, 255, 255, 0.55);
|
|
1062
|
+
backdrop-filter: blur(1px);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
.file-thumb__spinner-ring {
|
|
1066
|
+
width: 20px;
|
|
1067
|
+
height: 20px;
|
|
1068
|
+
border-radius: 50%;
|
|
1069
|
+
border: 2px solid rgba(124, 58, 237, 0.25);
|
|
1070
|
+
border-top-color: #7c3aed;
|
|
1071
|
+
animation: file-thumb-spin 0.8s linear infinite;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
.file-thumb--uploading {
|
|
1075
|
+
pointer-events: none;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
.file-thumb--uploading .file-thumb__remove {
|
|
1079
|
+
display: none;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
@keyframes file-thumb-spin {
|
|
1083
|
+
to { transform: rotate(360deg); }
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
.file-thumb__remove {
|
|
1087
|
+
position: absolute;
|
|
1088
|
+
top: 2px;
|
|
1089
|
+
right: 2px;
|
|
1090
|
+
width: 16px;
|
|
1091
|
+
height: 16px;
|
|
1092
|
+
padding: 0;
|
|
1093
|
+
border: none;
|
|
1094
|
+
border-radius: 50%;
|
|
1095
|
+
background-color: rgba(17, 24, 39, 0.7);
|
|
1096
|
+
color: #ffffff;
|
|
1097
|
+
display: inline-flex;
|
|
1098
|
+
align-items: center;
|
|
1099
|
+
justify-content: center;
|
|
1100
|
+
cursor: pointer;
|
|
1101
|
+
opacity: 0;
|
|
1102
|
+
transition: opacity 0.15s ease, background-color 0.15s ease;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
.file-thumb:hover .file-thumb__remove,
|
|
1106
|
+
.file-thumb:focus-within .file-thumb__remove {
|
|
1107
|
+
opacity: 1;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
.file-thumb__remove:hover {
|
|
1111
|
+
background-color: rgba(17, 24, 39, 0.9);
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
/* Dropdown preview extension tile (non-image files) */
|
|
1115
|
+
.file-preview-ext {
|
|
1116
|
+
width: 72px;
|
|
1117
|
+
height: 72px;
|
|
1118
|
+
display: flex;
|
|
1119
|
+
align-items: center;
|
|
1120
|
+
justify-content: center;
|
|
1121
|
+
border-radius: 10px;
|
|
1122
|
+
background: linear-gradient(135deg, #ede9fe, #ddd6fe);
|
|
1123
|
+
color: #5b21b6;
|
|
1124
|
+
font-weight: 600;
|
|
1125
|
+
font-size: 0.875rem;
|
|
1126
|
+
letter-spacing: 0.04em;
|
|
1127
|
+
text-transform: uppercase;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
989
1130
|
/* File preview dropdown content */
|
|
990
1131
|
.file-preview-content {
|
|
991
1132
|
display: flex;
|
|
@@ -348,14 +348,20 @@ export class ChatbotCoreController {
|
|
|
348
348
|
continue;
|
|
349
349
|
}
|
|
350
350
|
const chatbotFile = yield this.fileHandler.createChatbotFile(file);
|
|
351
|
-
const uploaded = yield this.providerService.uploadFileToProvider(file);
|
|
352
|
-
if (uploaded) {
|
|
353
|
-
Object.assign(chatbotFile, uploaded);
|
|
354
|
-
}
|
|
355
|
-
uploadedFiles.push(chatbotFile);
|
|
356
351
|
this.fileHandler.addFile(chatbotFile);
|
|
357
|
-
|
|
358
|
-
this.
|
|
352
|
+
try {
|
|
353
|
+
const uploaded = yield this.providerService.uploadFileToProvider(file);
|
|
354
|
+
const finalUpdates = Object.assign({ isUploading: false, uploadProgress: 100 }, (uploaded || {}));
|
|
355
|
+
this.fileHandler.updateFile(chatbotFile.id, finalUpdates);
|
|
356
|
+
Object.assign(chatbotFile, finalUpdates);
|
|
357
|
+
uploadedFiles.push(chatbotFile);
|
|
358
|
+
if (this.ui.showFilePreview) {
|
|
359
|
+
this.ui.showFilePreview(chatbotFile);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
catch (uploadError) {
|
|
363
|
+
this.fileHandler.removeFile(chatbotFile.id);
|
|
364
|
+
throw uploadError;
|
|
359
365
|
}
|
|
360
366
|
}
|
|
361
367
|
catch (error) {
|
|
@@ -88,7 +88,6 @@ export class WorkflowSocketProvider {
|
|
|
88
88
|
this.socket = io(socketNs, {
|
|
89
89
|
path: this.config.socketPath,
|
|
90
90
|
query: { __params: JSON.stringify({ workflowId: this.config.workflowId }) },
|
|
91
|
-
transports: ['websocket', 'polling'],
|
|
92
91
|
autoConnect: true,
|
|
93
92
|
reconnection: true,
|
|
94
93
|
reconnectionAttempts: 5
|
|
@@ -96,7 +95,7 @@ export class WorkflowSocketProvider {
|
|
|
96
95
|
return new Promise((resolve, reject) => {
|
|
97
96
|
const timeout = setTimeout(() => {
|
|
98
97
|
reject(new Error('Socket connection timeout'));
|
|
99
|
-
},
|
|
98
|
+
}, 30000);
|
|
100
99
|
this.socket.on('connect', () => {
|
|
101
100
|
clearTimeout(timeout);
|
|
102
101
|
this.connected = true;
|
|
@@ -8,7 +8,9 @@ import { repeat } from 'lit/directives/repeat.js';
|
|
|
8
8
|
import { styleMap } from 'lit/directives/style-map.js';
|
|
9
9
|
import { msg } from '@lit/localize';
|
|
10
10
|
/**
|
|
11
|
-
* Renders
|
|
11
|
+
* Renders thumbnail chips for uploaded files (image thumb for images,
|
|
12
|
+
* extension badge for other file types). While a file is uploading, a
|
|
13
|
+
* spinner overlay is shown on top of the thumbnail.
|
|
12
14
|
*/
|
|
13
15
|
function renderContextTags(files, onRemove, onFileClick) {
|
|
14
16
|
const formatFileSize = (bytes) => {
|
|
@@ -19,57 +21,83 @@ function renderContextTags(files, onRemove, onFileClick) {
|
|
|
19
21
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
20
22
|
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
|
|
21
23
|
};
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (mimeType
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return 'file';
|
|
24
|
+
const getExtension = (name, mimeType) => {
|
|
25
|
+
const dot = name.lastIndexOf('.');
|
|
26
|
+
if (dot >= 0 && dot < name.length - 1) {
|
|
27
|
+
return name.slice(dot + 1).toUpperCase().slice(0, 4);
|
|
28
|
+
}
|
|
29
|
+
if (mimeType) {
|
|
30
|
+
const slash = mimeType.indexOf('/');
|
|
31
|
+
if (slash >= 0)
|
|
32
|
+
return mimeType.slice(slash + 1).toUpperCase().slice(0, 4);
|
|
33
|
+
}
|
|
34
|
+
return 'FILE';
|
|
34
35
|
};
|
|
35
36
|
const isImage = (mimeType) => mimeType.startsWith('image/');
|
|
36
37
|
return html `
|
|
37
38
|
<div class="context-tags-row" part="context-tags">
|
|
38
39
|
${repeat(files, f => f.id, f => html `
|
|
39
|
-
<nr-dropdown
|
|
40
|
-
trigger="hover"
|
|
40
|
+
<nr-dropdown
|
|
41
|
+
trigger="hover"
|
|
41
42
|
placement="top"
|
|
42
43
|
size="small"
|
|
43
44
|
class="file-preview-dropdown"
|
|
44
45
|
>
|
|
45
|
-
<
|
|
46
|
+
<div
|
|
46
47
|
slot="trigger"
|
|
47
|
-
class="
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
class="file-thumb ${f.isUploading ? 'file-thumb--uploading' : ''}"
|
|
49
|
+
role="button"
|
|
50
|
+
tabindex="0"
|
|
51
|
+
title="${f.name}"
|
|
50
52
|
@click=${() => onFileClick === null || onFileClick === void 0 ? void 0 : onFileClick(f)}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
>
|
|
54
|
+
${isImage(f.mimeType) && (f.previewUrl || f.url) ? html `
|
|
55
|
+
<img
|
|
56
|
+
class="file-thumb__image"
|
|
57
|
+
src="${f.previewUrl || f.url}"
|
|
58
|
+
alt="${f.name}"
|
|
59
|
+
/>
|
|
60
|
+
` : html `
|
|
61
|
+
<div class="file-thumb__ext" data-ext="${getExtension(f.name, f.mimeType)}">
|
|
62
|
+
<span class="file-thumb__ext-label">${getExtension(f.name, f.mimeType)}</span>
|
|
63
|
+
</div>
|
|
64
|
+
`}
|
|
65
|
+
${f.isUploading ? html `
|
|
66
|
+
<div class="file-thumb__spinner" aria-label="${msg('Uploading')}">
|
|
67
|
+
<span class="file-thumb__spinner-ring"></span>
|
|
68
|
+
</div>
|
|
69
|
+
` : ''}
|
|
70
|
+
<button
|
|
71
|
+
type="button"
|
|
72
|
+
class="file-thumb__remove"
|
|
73
|
+
aria-label="${msg('Remove file')}"
|
|
74
|
+
title="${msg('Remove file')}"
|
|
75
|
+
@click=${(e) => { e.stopPropagation(); onRemove(f.id); }}
|
|
76
|
+
>
|
|
77
|
+
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round">
|
|
78
|
+
<line x1="6" y1="6" x2="18" y2="18"/>
|
|
79
|
+
<line x1="6" y1="18" x2="18" y2="6"/>
|
|
80
|
+
</svg>
|
|
81
|
+
</button>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
55
84
|
<div slot="content" class="file-preview-content">
|
|
56
85
|
${isImage(f.mimeType) && (f.url || f.previewUrl) ? html `
|
|
57
|
-
<img
|
|
58
|
-
src="${f.previewUrl || f.url}"
|
|
86
|
+
<img
|
|
87
|
+
src="${f.previewUrl || f.url}"
|
|
59
88
|
alt="${f.name}"
|
|
60
89
|
class="file-preview-image"
|
|
61
90
|
/>
|
|
62
91
|
` : html `
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
class="file-preview-icon"
|
|
67
|
-
></nr-icon>
|
|
92
|
+
<div class="file-preview-ext" data-ext="${getExtension(f.name, f.mimeType)}">
|
|
93
|
+
${getExtension(f.name, f.mimeType)}
|
|
94
|
+
</div>
|
|
68
95
|
`}
|
|
69
96
|
<div class="file-preview-info">
|
|
70
97
|
<div class="file-preview-name" title="${f.name}">${f.name}</div>
|
|
71
98
|
<div class="file-preview-details">
|
|
72
99
|
<span>${formatFileSize(f.size)}</span>
|
|
100
|
+
${f.isUploading ? html `<span> · ${msg('Uploading…')}</span>` : ''}
|
|
73
101
|
</div>
|
|
74
102
|
</div>
|
|
75
103
|
</div>
|
|
@@ -37,28 +37,27 @@ function formatFileSize(bytes) {
|
|
|
37
37
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
38
38
|
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Get icon name based on MIME type
|
|
42
|
-
*/
|
|
43
|
-
function getFileIcon(mimeType) {
|
|
44
|
-
if (mimeType.startsWith('image/'))
|
|
45
|
-
return 'image';
|
|
46
|
-
if (mimeType.startsWith('video/'))
|
|
47
|
-
return 'video';
|
|
48
|
-
if (mimeType.startsWith('audio/'))
|
|
49
|
-
return 'music';
|
|
50
|
-
if (mimeType === 'application/pdf')
|
|
51
|
-
return 'file-pdf';
|
|
52
|
-
if (mimeType.startsWith('text/'))
|
|
53
|
-
return 'file-text';
|
|
54
|
-
return 'file';
|
|
55
|
-
}
|
|
56
40
|
/**
|
|
57
41
|
* Check if file is an image
|
|
58
42
|
*/
|
|
59
43
|
function isImageFile(mimeType) {
|
|
60
44
|
return mimeType.startsWith('image/');
|
|
61
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Derive a short extension label for non-image thumbnails
|
|
48
|
+
*/
|
|
49
|
+
function getFileExtension(name, mimeType) {
|
|
50
|
+
const dot = name.lastIndexOf('.');
|
|
51
|
+
if (dot >= 0 && dot < name.length - 1) {
|
|
52
|
+
return name.slice(dot + 1).toUpperCase().slice(0, 4);
|
|
53
|
+
}
|
|
54
|
+
if (mimeType) {
|
|
55
|
+
const slash = mimeType.indexOf('/');
|
|
56
|
+
if (slash >= 0)
|
|
57
|
+
return mimeType.slice(slash + 1).toUpperCase().slice(0, 4);
|
|
58
|
+
}
|
|
59
|
+
return 'FILE';
|
|
60
|
+
}
|
|
62
61
|
/**
|
|
63
62
|
* Renders a single message
|
|
64
63
|
*/
|
|
@@ -87,33 +86,44 @@ export function renderMessage(message, handlers) {
|
|
|
87
86
|
${message.files && message.files.length > 0 ? html `
|
|
88
87
|
<div class="message__attachments" part="message-attachments" role="list" aria-label="${msg('Attached files')}">
|
|
89
88
|
${message.files.map((f) => html `
|
|
90
|
-
<nr-dropdown
|
|
91
|
-
trigger="hover"
|
|
89
|
+
<nr-dropdown
|
|
90
|
+
trigger="hover"
|
|
92
91
|
placement="top-end"
|
|
93
92
|
size="small"
|
|
94
93
|
class="message-file-preview-dropdown"
|
|
95
94
|
>
|
|
96
|
-
<
|
|
95
|
+
<div
|
|
97
96
|
slot="trigger"
|
|
98
|
-
class="
|
|
99
|
-
|
|
97
|
+
class="file-thumb file-thumb--message"
|
|
98
|
+
role="button"
|
|
99
|
+
tabindex="0"
|
|
100
|
+
title="${f.name}"
|
|
100
101
|
@click=${() => { var _a; return (_a = handlers.onFileClick) === null || _a === void 0 ? void 0 : _a.call(handlers, f); }}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
>
|
|
103
|
+
${isImageFile(f.mimeType) && (f.url || f.previewUrl) ? html `
|
|
104
|
+
<img
|
|
105
|
+
class="file-thumb__image"
|
|
106
|
+
src="${f.previewUrl || f.url}"
|
|
107
|
+
alt="${f.name}"
|
|
108
|
+
/>
|
|
109
|
+
` : html `
|
|
110
|
+
<div class="file-thumb__ext" data-ext="${getFileExtension(f.name, f.mimeType)}">
|
|
111
|
+
<span class="file-thumb__ext-label">${getFileExtension(f.name, f.mimeType)}</span>
|
|
112
|
+
</div>
|
|
113
|
+
`}
|
|
114
|
+
</div>
|
|
115
|
+
|
|
104
116
|
<div slot="content" class="message-file-preview-content">
|
|
105
117
|
${isImageFile(f.mimeType) && (f.url || f.previewUrl) ? html `
|
|
106
|
-
<img
|
|
107
|
-
src="${f.previewUrl || f.url}"
|
|
118
|
+
<img
|
|
119
|
+
src="${f.previewUrl || f.url}"
|
|
108
120
|
alt="${f.name}"
|
|
109
121
|
class="message-file-preview-image"
|
|
110
122
|
/>
|
|
111
123
|
` : html `
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
class="message-file-preview-icon"
|
|
116
|
-
></nr-icon>
|
|
124
|
+
<div class="file-preview-ext" data-ext="${getFileExtension(f.name, f.mimeType)}">
|
|
125
|
+
${getFileExtension(f.name, f.mimeType)}
|
|
126
|
+
</div>
|
|
117
127
|
`}
|
|
118
128
|
<div class="message-file-preview-info">
|
|
119
129
|
<div class="message-file-preview-name" title="${f.name}">${f.name}</div>
|
|
@@ -56,60 +56,59 @@ function renderThreadItem(thread, data, handlers) {
|
|
|
56
56
|
<div class="thread-item__title">${thread.title || msg('New Chat')}</div>
|
|
57
57
|
`}
|
|
58
58
|
<div class="thread-item__actions">
|
|
59
|
-
${handlers.
|
|
59
|
+
${handlers.onBookmarkThread && thread.bookmarked ? html `
|
|
60
60
|
<button
|
|
61
|
-
class="thread-item__action-btn"
|
|
62
|
-
title="${msg('
|
|
63
|
-
@click=${(e) => {
|
|
64
|
-
e.stopPropagation();
|
|
65
|
-
e.target.dispatchEvent(new CustomEvent('nr-thread-edit', {
|
|
66
|
-
bubbles: true,
|
|
67
|
-
composed: true,
|
|
68
|
-
detail: { threadId: thread.id }
|
|
69
|
-
}));
|
|
70
|
-
}}
|
|
71
|
-
part="thread-rename"
|
|
72
|
-
>
|
|
73
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
|
|
74
|
-
</button>
|
|
75
|
-
` : ''}
|
|
76
|
-
${handlers.onBookmarkThread ? html `
|
|
77
|
-
<button
|
|
78
|
-
class="thread-item__action-btn ${thread.bookmarked ? 'thread-item__bookmark--active' : ''}"
|
|
79
|
-
title="${thread.bookmarked ? msg('Remove bookmark') : msg('Bookmark conversation')}"
|
|
61
|
+
class="thread-item__action-btn thread-item__bookmark--active"
|
|
62
|
+
title="${msg('Remove bookmark')}"
|
|
80
63
|
@click=${(e) => {
|
|
81
64
|
e.stopPropagation();
|
|
82
65
|
handlers.onBookmarkThread(thread.id);
|
|
83
66
|
}}
|
|
84
67
|
part="thread-bookmark"
|
|
85
68
|
>
|
|
86
|
-
|
|
87
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>
|
|
88
|
-
` : html `
|
|
89
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>
|
|
90
|
-
`}
|
|
69
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>
|
|
91
70
|
</button>
|
|
92
71
|
` : ''}
|
|
93
|
-
${handlers.onDeleteThread ? html `
|
|
94
|
-
<nr-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
ok-type="danger"
|
|
100
|
-
placement="right"
|
|
72
|
+
${data.editingThreadId !== thread.id && (handlers.onRenameThread || handlers.onBookmarkThread || handlers.onDeleteThread) ? html `
|
|
73
|
+
<nr-dropdown
|
|
74
|
+
trigger="click"
|
|
75
|
+
placement="bottom-end"
|
|
76
|
+
size="small"
|
|
77
|
+
auto-close
|
|
101
78
|
@click=${(e) => e.stopPropagation()}
|
|
102
|
-
@nr-
|
|
79
|
+
@nr-dropdown-item-click=${(e) => {
|
|
80
|
+
var _a, _b;
|
|
81
|
+
const id = (_b = (_a = e.detail) === null || _a === void 0 ? void 0 : _a.item) === null || _b === void 0 ? void 0 : _b.id;
|
|
82
|
+
if (id === 'rename' && handlers.onRenameThread) {
|
|
83
|
+
e.target.dispatchEvent(new CustomEvent('nr-thread-edit', {
|
|
84
|
+
bubbles: true,
|
|
85
|
+
composed: true,
|
|
86
|
+
detail: { threadId: thread.id }
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
else if (id === 'bookmark' && handlers.onBookmarkThread) {
|
|
90
|
+
handlers.onBookmarkThread(thread.id);
|
|
91
|
+
}
|
|
92
|
+
else if (id === 'delete' && handlers.onDeleteThread) {
|
|
93
|
+
handlers.onDeleteThread(thread.id);
|
|
94
|
+
}
|
|
95
|
+
}}
|
|
96
|
+
.items=${[
|
|
97
|
+
...(handlers.onRenameThread ? [{ id: 'rename', label: msg('Rename') }] : []),
|
|
98
|
+
...(handlers.onBookmarkThread ? [{ id: 'bookmark', label: thread.bookmarked ? msg('Remove bookmark') : msg('Bookmark') }] : []),
|
|
99
|
+
...(handlers.onDeleteThread ? [{ id: 'delete', label: msg('Delete') }] : []),
|
|
100
|
+
]}
|
|
103
101
|
>
|
|
104
102
|
<button
|
|
105
103
|
slot="trigger"
|
|
106
|
-
class="thread-item__action-btn thread-
|
|
107
|
-
title="${msg('
|
|
108
|
-
part="thread-
|
|
104
|
+
class="thread-item__action-btn thread-item__menu"
|
|
105
|
+
title="${msg('More options')}"
|
|
106
|
+
part="thread-menu"
|
|
107
|
+
aria-label="${msg('More options')}"
|
|
109
108
|
>
|
|
110
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="
|
|
109
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" stroke="none"><circle cx="5" cy="12" r="1.8"/><circle cx="12" cy="12" r="1.8"/><circle cx="19" cy="12" r="1.8"/></svg>
|
|
111
110
|
</button>
|
|
112
|
-
</nr-
|
|
111
|
+
</nr-dropdown>
|
|
113
112
|
` : ''}
|
|
114
113
|
</div>
|
|
115
114
|
</div>
|