@nuraly/lumenui 0.3.5 → 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 +2575 -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 +2525 -1185
- 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 +401 -242
- package/dist/src/components/chatbot/bundle.js.gz +0 -0
- package/dist/src/components/chatbot/chatbot.style.js +156 -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 {
|
|
@@ -292,14 +291,18 @@ export default css `
|
|
|
292
291
|
align-items: center;
|
|
293
292
|
gap: 2px;
|
|
294
293
|
flex-shrink: 0;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.thread-item__actions .thread-item__menu {
|
|
295
297
|
opacity: 0;
|
|
296
298
|
pointer-events: none;
|
|
297
299
|
transition: opacity 0.15s ease;
|
|
298
300
|
}
|
|
299
301
|
|
|
300
|
-
.thread-item:hover .thread-
|
|
301
|
-
.thread-item--active .thread-
|
|
302
|
-
.thread-item:focus-within .thread-
|
|
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 {
|
|
303
306
|
opacity: 1;
|
|
304
307
|
pointer-events: auto;
|
|
305
308
|
}
|
|
@@ -329,27 +332,23 @@ export default css `
|
|
|
329
332
|
background-color: rgba(59, 130, 246, 0.1);
|
|
330
333
|
}
|
|
331
334
|
|
|
332
|
-
.thread-item__actions nr-popconfirm {
|
|
333
|
-
margin-top: 4px;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
335
|
.thread-item__delete:hover {
|
|
337
336
|
color: #ef4444;
|
|
338
337
|
background-color: rgba(239, 68, 68, 0.1);
|
|
339
338
|
}
|
|
340
339
|
|
|
341
340
|
.thread-item--active .thread-item__action-btn {
|
|
342
|
-
color: rgba(
|
|
341
|
+
color: rgba(22, 22, 22, 0.6);
|
|
343
342
|
}
|
|
344
343
|
|
|
345
344
|
.thread-item--active .thread-item__action-btn:hover {
|
|
346
|
-
color: #
|
|
347
|
-
background-color: rgba(
|
|
345
|
+
color: #161616;
|
|
346
|
+
background-color: rgba(0, 0, 0, 0.06);
|
|
348
347
|
}
|
|
349
348
|
|
|
350
349
|
.thread-item--active .thread-item__delete:hover {
|
|
351
350
|
color: #ef4444;
|
|
352
|
-
background-color: rgba(239, 68, 68, 0.
|
|
351
|
+
background-color: rgba(239, 68, 68, 0.1);
|
|
353
352
|
}
|
|
354
353
|
|
|
355
354
|
.thread-item__bookmark--active {
|
|
@@ -382,7 +381,7 @@ export default css `
|
|
|
382
381
|
}
|
|
383
382
|
|
|
384
383
|
.thread-item--active .thread-item__rename-input {
|
|
385
|
-
background:
|
|
384
|
+
background: #ffffff;
|
|
386
385
|
}
|
|
387
386
|
|
|
388
387
|
.thread-item__preview {
|
|
@@ -421,11 +420,13 @@ export default css `
|
|
|
421
420
|
.messages {
|
|
422
421
|
flex: 1;
|
|
423
422
|
overflow-y: auto;
|
|
423
|
+
overflow-x: hidden;
|
|
424
424
|
display: flex;
|
|
425
425
|
flex-direction: column;
|
|
426
426
|
gap: 0;
|
|
427
427
|
background-color: #ffffff;
|
|
428
|
-
padding: 8px
|
|
428
|
+
padding: 8px 1rem;
|
|
429
|
+
box-sizing: border-box;
|
|
429
430
|
justify-content: flex-start; /* Always align messages to top */
|
|
430
431
|
}
|
|
431
432
|
|
|
@@ -485,16 +486,22 @@ export default css `
|
|
|
485
486
|
border: 0 solid transparent;
|
|
486
487
|
}
|
|
487
488
|
|
|
488
|
-
/* Message attachments (file
|
|
489
|
+
/* Message attachments (file thumbs) */
|
|
489
490
|
.message__attachments {
|
|
490
491
|
display: flex;
|
|
491
492
|
flex-wrap: wrap;
|
|
492
|
-
gap: 0.
|
|
493
|
-
margin-top: 0.
|
|
493
|
+
gap: 0.375rem;
|
|
494
|
+
margin-top: 0.375rem;
|
|
494
495
|
position: relative;
|
|
495
496
|
z-index: 1;
|
|
496
497
|
}
|
|
497
498
|
|
|
499
|
+
.file-thumb--message {
|
|
500
|
+
width: 48px;
|
|
501
|
+
height: 48px;
|
|
502
|
+
border-radius: 8px;
|
|
503
|
+
}
|
|
504
|
+
|
|
498
505
|
.message-file-preview-dropdown {
|
|
499
506
|
display: inline-block;
|
|
500
507
|
position: relative;
|
|
@@ -992,6 +999,134 @@ export default css `
|
|
|
992
999
|
cursor: help;
|
|
993
1000
|
}
|
|
994
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
|
+
|
|
995
1130
|
/* File preview dropdown content */
|
|
996
1131
|
.file-preview-content {
|
|
997
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>
|