@nuraly/lumenui 0.3.9 → 0.6.0
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 +676 -668
- package/dist/nuralyui.bundle.js.gz +0 -0
- package/dist/src/components/canvas/bundle.js +452 -444
- package/dist/src/components/canvas/bundle.js.gz +0 -0
- package/dist/src/components/chatbot/bundle.js +189 -181
- package/dist/src/components/chatbot/bundle.js.gz +0 -0
- package/dist/src/components/chatbot/chatbot.component.d.ts +14 -1
- package/dist/src/components/chatbot/chatbot.component.js +165 -8
- package/dist/src/components/chatbot/chatbot.style.js +6 -9
- package/dist/src/components/chatbot/chatbot.types.d.ts +94 -0
- package/dist/src/components/chatbot/templates/artifact-panel.template.d.ts +2 -1
- package/dist/src/components/chatbot/templates/artifact-panel.template.js +17 -18
- package/dist/src/components/chatbot/templates/chatbot-main.template.d.ts +3 -1
- package/dist/src/components/chatbot/templates/chatbot-main.template.js +15 -10
- package/dist/src/components/chatbot/templates/file-upload-area.template.d.ts +5 -6
- package/dist/src/components/chatbot/templates/file-upload-area.template.js +6 -13
- package/dist/src/components/chatbot/templates/input-box.template.d.ts +2 -1
- package/dist/src/components/chatbot/templates/input-box.template.js +45 -39
- package/dist/src/components/chatbot/templates/message.template.d.ts +4 -4
- package/dist/src/components/chatbot/templates/message.template.js +17 -17
- package/dist/src/components/chatbot/templates/suggestion.template.d.ts +3 -9
- package/dist/src/components/chatbot/templates/suggestion.template.js +6 -13
- package/dist/src/components/chatbot/templates/thread-sidebar.template.d.ts +2 -1
- package/dist/src/components/chatbot/templates/thread-sidebar.template.js +19 -19
- package/dist/src/components/chatbot/templates/url-modal.template.d.ts +2 -3
- package/dist/src/components/chatbot/templates/url-modal.template.js +24 -28
- package/dist/src/components/icon/bundle.js +10 -10
- package/dist/src/components/icon/bundle.js.gz +0 -0
- package/dist/src/components/icon/icon-paths.js +1 -0
- package/dist/src/components/iconpicker/bundle.js +1 -1
- package/dist/src/components/iconpicker/bundle.js.gz +0 -0
- package/dist/src/components/panel/bundle.js +1 -1
- package/dist/src/components/panel/bundle.js.gz +0 -0
- package/dist/src/components/tabs/bundle.js +1 -1
- package/dist/src/components/tabs/bundle.js.gz +0 -0
- package/package.json +1 -1
- package/packages/common/dist/VERSIONS.md +1 -1
|
@@ -4,23 +4,16 @@
|
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
import { html } from 'lit';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Renders file upload drag-and-drop area
|
|
10
|
-
*/
|
|
11
|
-
export function renderFileUploadArea(data, handlers) {
|
|
7
|
+
export function renderFileUploadArea(data) {
|
|
12
8
|
return html `
|
|
13
|
-
<div
|
|
9
|
+
<div
|
|
14
10
|
class="file-upload-area ${data.isDragging ? 'file-upload-area--dragging' : ''}"
|
|
15
11
|
part="file-upload-area"
|
|
16
|
-
@drop=${handlers.onDrop}
|
|
17
|
-
@dragover=${handlers.onDragOver}
|
|
18
|
-
@dragleave=${handlers.onDragLeave}
|
|
19
12
|
>
|
|
20
|
-
<div class="file-upload-area__content">
|
|
21
|
-
<
|
|
22
|
-
<div class="file-upload-area__text">
|
|
23
|
-
${
|
|
13
|
+
<div class="file-upload-area__content" part="file-upload-area-content">
|
|
14
|
+
<nr-icon name="upload" size="xlarge" part="file-upload-area-icon"></nr-icon>
|
|
15
|
+
<div class="file-upload-area__text" part="file-upload-area-text">
|
|
16
|
+
${data.label}
|
|
24
17
|
</div>
|
|
25
18
|
</div>
|
|
26
19
|
</div>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
import { TemplateResult } from 'lit';
|
|
7
|
-
import { ChatbotFile } from '../chatbot.types.js';
|
|
7
|
+
import { ChatbotFile, ChatbotI18n } from '../chatbot.types.js';
|
|
8
8
|
import type { AudioRecordingState } from '../chatbot-audio.controller.js';
|
|
9
9
|
import { DropdownItem } from '../../dropdown/dropdown.types.js';
|
|
10
10
|
import { SelectOption } from '../../select/select.types.js';
|
|
@@ -41,6 +41,7 @@ export interface InputBoxTemplateData {
|
|
|
41
41
|
showAudioButton: boolean;
|
|
42
42
|
audioRecording: AudioRecordingState;
|
|
43
43
|
audioMode: 'transcribe' | 'message';
|
|
44
|
+
i18n: ChatbotI18n;
|
|
44
45
|
}
|
|
45
46
|
/**
|
|
46
47
|
* Renders the complete input box
|
|
@@ -6,13 +6,12 @@
|
|
|
6
6
|
import { html, nothing } from 'lit';
|
|
7
7
|
import { repeat } from 'lit/directives/repeat.js';
|
|
8
8
|
import { styleMap } from 'lit/directives/style-map.js';
|
|
9
|
-
import { msg } from '@lit/localize';
|
|
10
9
|
/**
|
|
11
10
|
* Renders thumbnail chips for uploaded files (image thumb for images,
|
|
12
11
|
* extension badge for other file types). While a file is uploading, a
|
|
13
12
|
* spinner overlay is shown on top of the thumbnail.
|
|
14
13
|
*/
|
|
15
|
-
function renderContextTags(files, onRemove, onFileClick) {
|
|
14
|
+
function renderContextTags(files, onRemove, i18n, onFileClick) {
|
|
16
15
|
const formatFileSize = (bytes) => {
|
|
17
16
|
if (bytes === 0)
|
|
18
17
|
return '0 Bytes';
|
|
@@ -46,6 +45,7 @@ function renderContextTags(files, onRemove, onFileClick) {
|
|
|
46
45
|
<div
|
|
47
46
|
slot="trigger"
|
|
48
47
|
class="file-thumb ${f.isUploading ? 'file-thumb--uploading' : ''}"
|
|
48
|
+
part="file-thumb"
|
|
49
49
|
role="button"
|
|
50
50
|
tabindex="0"
|
|
51
51
|
title="${f.name}"
|
|
@@ -54,24 +54,26 @@ function renderContextTags(files, onRemove, onFileClick) {
|
|
|
54
54
|
${isImage(f.mimeType) && (f.previewUrl || f.url) ? html `
|
|
55
55
|
<img
|
|
56
56
|
class="file-thumb__image"
|
|
57
|
+
part="file-thumb-image"
|
|
57
58
|
src="${f.previewUrl || f.url}"
|
|
58
59
|
alt="${f.name}"
|
|
59
60
|
/>
|
|
60
61
|
` : 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>
|
|
62
|
+
<div class="file-thumb__ext" part="file-thumb-ext" data-ext="${getExtension(f.name, f.mimeType)}">
|
|
63
|
+
<span class="file-thumb__ext-label" part="file-thumb-ext-label">${getExtension(f.name, f.mimeType)}</span>
|
|
63
64
|
</div>
|
|
64
65
|
`}
|
|
65
66
|
${f.isUploading ? html `
|
|
66
|
-
<div class="file-thumb__spinner" aria-label="${
|
|
67
|
+
<div class="file-thumb__spinner" part="file-thumb-spinner" aria-label="${i18n.input.uploadingLabel}">
|
|
67
68
|
<span class="file-thumb__spinner-ring"></span>
|
|
68
69
|
</div>
|
|
69
70
|
` : ''}
|
|
70
71
|
<button
|
|
71
72
|
type="button"
|
|
72
73
|
class="file-thumb__remove"
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
part="file-thumb-remove"
|
|
75
|
+
aria-label="${i18n.input.removeFileLabel}"
|
|
76
|
+
title="${i18n.input.removeFileLabel}"
|
|
75
77
|
@click=${(e) => { e.stopPropagation(); onRemove(f.id); }}
|
|
76
78
|
>
|
|
77
79
|
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round">
|
|
@@ -97,7 +99,7 @@ function renderContextTags(files, onRemove, onFileClick) {
|
|
|
97
99
|
<div class="file-preview-name" title="${f.name}">${f.name}</div>
|
|
98
100
|
<div class="file-preview-details">
|
|
99
101
|
<span>${formatFileSize(f.size)}</span>
|
|
100
|
-
${f.isUploading ? html `<span> · ${
|
|
102
|
+
${f.isUploading ? html `<span> · ${i18n.input.uploadingProgress}</span>` : ''}
|
|
101
103
|
</div>
|
|
102
104
|
</div>
|
|
103
105
|
</div>
|
|
@@ -120,17 +122,17 @@ function renderFileUploadButton(data, handlers) {
|
|
|
120
122
|
?disabled=${data.disabled}
|
|
121
123
|
@nr-dropdown-item-click=${handlers.onFileDropdownClick}
|
|
122
124
|
>
|
|
123
|
-
<nr-button
|
|
125
|
+
<nr-button
|
|
124
126
|
slot="trigger"
|
|
125
127
|
part="file-button"
|
|
126
128
|
type="default"
|
|
127
129
|
size="small"
|
|
128
|
-
.icon=${["
|
|
130
|
+
.icon=${["paperclip"]}
|
|
129
131
|
?disabled=${data.disabled}
|
|
130
|
-
aria-label="${
|
|
131
|
-
title="${
|
|
132
|
+
aria-label="${data.i18n.input.attachFilesAriaLabel}"
|
|
133
|
+
title="${data.i18n.input.attachFilesAriaLabel}"
|
|
132
134
|
>
|
|
133
|
-
|
|
135
|
+
${data.i18n.input.attachButton}
|
|
134
136
|
</nr-button>
|
|
135
137
|
</nr-dropdown>
|
|
136
138
|
`;
|
|
@@ -148,12 +150,12 @@ function renderModuleSelector(data, handlers) {
|
|
|
148
150
|
size="small"
|
|
149
151
|
?disabled=${data.disabled}
|
|
150
152
|
searchable
|
|
151
|
-
search-placeholder="${
|
|
153
|
+
search-placeholder="${data.i18n.modules.moduleSearchPlaceholder}"
|
|
152
154
|
use-custom-selected-display
|
|
153
155
|
part="module-select"
|
|
154
156
|
class="module-select"
|
|
155
157
|
@nr-change=${handlers.onModuleChange}
|
|
156
|
-
aria-label="${
|
|
158
|
+
aria-label="${data.i18n.modules.moduleSelectAriaLabel}"
|
|
157
159
|
>
|
|
158
160
|
<span slot="selected-display">
|
|
159
161
|
${data.renderModuleDisplay()}
|
|
@@ -174,10 +176,10 @@ function renderSendButton(data, handlers) {
|
|
|
174
176
|
.iconRight=${data.isQueryRunning ? 'square' : 'arrow-up'}
|
|
175
177
|
@click=${data.isQueryRunning ? handlers.onStop : handlers.onSend}
|
|
176
178
|
@keydown=${handlers.onSendKeydown}
|
|
177
|
-
aria-label="${data.isQueryRunning ?
|
|
178
|
-
title="${data.isQueryRunning ?
|
|
179
|
+
aria-label="${data.isQueryRunning ? data.i18n.send.stopQueryLabel : data.i18n.send.sendMessageLabel}"
|
|
180
|
+
title="${data.isQueryRunning ? data.i18n.send.stopQueryLabel : data.i18n.send.sendMessageLabel}"
|
|
179
181
|
>
|
|
180
|
-
${data.isQueryRunning ?
|
|
182
|
+
${data.isQueryRunning ? data.i18n.send.stopButton : data.i18n.send.sendButton}
|
|
181
183
|
</nr-button>
|
|
182
184
|
`;
|
|
183
185
|
}
|
|
@@ -190,7 +192,7 @@ function renderSendButton(data, handlers) {
|
|
|
190
192
|
function renderRecordingBar(data, handlers) {
|
|
191
193
|
const { duration, bars } = data.audioRecording;
|
|
192
194
|
const isTranscribe = data.audioMode === 'transcribe';
|
|
193
|
-
const sendTitle = isTranscribe ?
|
|
195
|
+
const sendTitle = isTranscribe ? data.i18n.audio.convertToTextLabel : data.i18n.audio.sendAsVoiceMessageLabel;
|
|
194
196
|
const sendIcon = isTranscribe
|
|
195
197
|
? html `<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
196
198
|
<rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/>
|
|
@@ -200,12 +202,13 @@ function renderRecordingBar(data, handlers) {
|
|
|
200
202
|
<path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/>
|
|
201
203
|
</svg>`;
|
|
202
204
|
return html `
|
|
203
|
-
<div class="audio-recording-bar">
|
|
205
|
+
<div class="audio-recording-bar" part="audio-recording-bar">
|
|
204
206
|
<button
|
|
205
207
|
class="audio-rec-cancel"
|
|
206
|
-
|
|
208
|
+
part="audio-cancel-button"
|
|
209
|
+
title="${data.i18n.audio.cancelRecordingLabel}"
|
|
207
210
|
@click=${handlers.onAudioCancel}
|
|
208
|
-
aria-label="${
|
|
211
|
+
aria-label="${data.i18n.audio.cancelRecordingLabel}"
|
|
209
212
|
>
|
|
210
213
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
211
214
|
<polyline points="3 6 5 6 21 6"/>
|
|
@@ -214,22 +217,23 @@ function renderRecordingBar(data, handlers) {
|
|
|
214
217
|
</svg>
|
|
215
218
|
</button>
|
|
216
219
|
|
|
217
|
-
<div class="audio-rec-indicator">
|
|
218
|
-
<span class="audio-rec-dot"></span>
|
|
219
|
-
<div class="audio-rec-wave">
|
|
220
|
+
<div class="audio-rec-indicator" part="audio-indicator">
|
|
221
|
+
<span class="audio-rec-dot" part="audio-dot"></span>
|
|
222
|
+
<div class="audio-rec-wave" part="audio-wave">
|
|
220
223
|
${bars.map(v => html `
|
|
221
|
-
<div class="audio-rec-bar" style=${styleMap({ height: `${Math.round(v * 24)}px` })}></div>
|
|
224
|
+
<div class="audio-rec-bar" part="audio-bar" style=${styleMap({ height: `${Math.round(v * 24)}px` })}></div>
|
|
222
225
|
`)}
|
|
223
226
|
</div>
|
|
224
|
-
<span class="audio-rec-time">${duration}</span>
|
|
227
|
+
<span class="audio-rec-time" part="audio-time">${duration}</span>
|
|
225
228
|
</div>
|
|
226
229
|
|
|
227
|
-
<span class="audio-rec-mode-label">
|
|
228
|
-
${isTranscribe ?
|
|
230
|
+
<span class="audio-rec-mode-label" part="audio-mode-label">
|
|
231
|
+
${isTranscribe ? data.i18n.audio.speechToTextLabel : data.i18n.audio.voiceMessageLabel}
|
|
229
232
|
</span>
|
|
230
233
|
|
|
231
234
|
<button
|
|
232
235
|
class="audio-rec-send ${isTranscribe ? 'audio-rec-send--transcribe' : ''}"
|
|
236
|
+
part="audio-send-button"
|
|
233
237
|
title="${sendTitle}"
|
|
234
238
|
@click=${handlers.onAudioSend}
|
|
235
239
|
aria-label="${sendTitle}"
|
|
@@ -244,23 +248,24 @@ function renderRecordingBar(data, handlers) {
|
|
|
244
248
|
*/
|
|
245
249
|
function renderActionButtons(data, handlers) {
|
|
246
250
|
return html `
|
|
247
|
-
<div class="action-buttons-row">
|
|
248
|
-
<div class="action-buttons-left">
|
|
251
|
+
<div class="action-buttons-row" part="actions">
|
|
252
|
+
<div class="action-buttons-left" part="actions-left">
|
|
249
253
|
${data.enableFileUpload ? renderFileUploadButton(data, handlers) : nothing}
|
|
250
254
|
${data.enableModuleSelection && data.moduleOptions.length > 0
|
|
251
255
|
? renderModuleSelector(data, handlers)
|
|
252
256
|
: nothing}
|
|
253
257
|
</div>
|
|
254
258
|
|
|
255
|
-
<div class="action-buttons-right">
|
|
259
|
+
<div class="action-buttons-right" part="actions-right">
|
|
256
260
|
${data.showAudioButton && !data.isQueryRunning ? html `
|
|
257
261
|
<!-- Speech-to-text: mic + keyboard indicator -->
|
|
258
262
|
<button
|
|
259
263
|
class="audio-mic-btn"
|
|
260
|
-
|
|
264
|
+
part="audio-mic-button audio-mic-transcribe"
|
|
265
|
+
title="${data.i18n.audio.recordSpeechLabel}"
|
|
261
266
|
?disabled=${data.disabled}
|
|
262
267
|
@click=${() => { var _a; return (_a = handlers.onAudioStart) === null || _a === void 0 ? void 0 : _a.call(handlers, 'transcribe'); }}
|
|
263
|
-
aria-label="${
|
|
268
|
+
aria-label="${data.i18n.audio.recordSpeechLabel}"
|
|
264
269
|
>
|
|
265
270
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
266
271
|
<path d="M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z"/>
|
|
@@ -275,10 +280,11 @@ function renderActionButtons(data, handlers) {
|
|
|
275
280
|
<!-- Voice message: mic + waveform indicator -->
|
|
276
281
|
<button
|
|
277
282
|
class="audio-mic-btn"
|
|
278
|
-
|
|
283
|
+
part="audio-mic-button audio-mic-voice"
|
|
284
|
+
title="${data.i18n.audio.sendVoiceMessageLabel}"
|
|
279
285
|
?disabled=${data.disabled}
|
|
280
286
|
@click=${() => { var _a; return (_a = handlers.onAudioStart) === null || _a === void 0 ? void 0 : _a.call(handlers, 'message'); }}
|
|
281
|
-
aria-label="${
|
|
287
|
+
aria-label="${data.i18n.audio.sendVoiceMessageLabel}"
|
|
282
288
|
>
|
|
283
289
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
284
290
|
<path d="M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z"/>
|
|
@@ -316,18 +322,18 @@ export function renderInputBox(data, handlers) {
|
|
|
316
322
|
<div class="input-container" part="input-container">
|
|
317
323
|
<!-- Context tags -->
|
|
318
324
|
${data.uploadedFiles.length > 0
|
|
319
|
-
? renderContextTags(data.uploadedFiles, handlers.onFileRemove, handlers.onFileClick)
|
|
325
|
+
? renderContextTags(data.uploadedFiles, handlers.onFileRemove, data.i18n, handlers.onFileClick)
|
|
320
326
|
: nothing}
|
|
321
327
|
|
|
322
328
|
<!-- Input area -->
|
|
323
|
-
<div class="input-row">
|
|
329
|
+
<div class="input-row" part="input-row">
|
|
324
330
|
<div
|
|
325
331
|
class="input-box__input"
|
|
326
332
|
part="input"
|
|
327
333
|
contenteditable="true"
|
|
328
334
|
role="textbox"
|
|
329
335
|
aria-multiline="true"
|
|
330
|
-
aria-label="${
|
|
336
|
+
aria-label="${data.i18n.input.chatInputAriaLabel}"
|
|
331
337
|
data-placeholder="${data.placeholder}"
|
|
332
338
|
@input=${handlers.onInput}
|
|
333
339
|
@keydown=${handlers.onKeydown}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
import { TemplateResult, nothing } from 'lit';
|
|
7
|
-
import { ChatbotMessage, ChatbotLoadingType } from '../chatbot.types.js';
|
|
7
|
+
import { ChatbotMessage, ChatbotLoadingType, ChatbotI18n } from '../chatbot.types.js';
|
|
8
8
|
export interface MessageTemplateHandlers {
|
|
9
9
|
onRetry: (message: ChatbotMessage) => void;
|
|
10
10
|
onRetryKeydown: (e: KeyboardEvent) => void;
|
|
@@ -15,7 +15,7 @@ export interface MessageTemplateHandlers {
|
|
|
15
15
|
/**
|
|
16
16
|
* Renders a single message
|
|
17
17
|
*/
|
|
18
|
-
export declare function renderMessage(message: ChatbotMessage, handlers: MessageTemplateHandlers): TemplateResult;
|
|
18
|
+
export declare function renderMessage(message: ChatbotMessage, handlers: MessageTemplateHandlers, i18n: ChatbotI18n): TemplateResult;
|
|
19
19
|
/**
|
|
20
20
|
* Renders bot typing indicator
|
|
21
21
|
*/
|
|
@@ -23,9 +23,9 @@ export declare function renderBotTypingIndicator(isTyping: boolean, loadingIndic
|
|
|
23
23
|
/**
|
|
24
24
|
* Renders empty state
|
|
25
25
|
*/
|
|
26
|
-
export declare function renderEmptyState(): TemplateResult;
|
|
26
|
+
export declare function renderEmptyState(i18n: ChatbotI18n): TemplateResult;
|
|
27
27
|
/**
|
|
28
28
|
* Renders messages container with all messages
|
|
29
29
|
*/
|
|
30
|
-
export declare function renderMessages(messages: ChatbotMessage[], suggestions: TemplateResult | typeof nothing, typingIndicator: TemplateResult | typeof nothing, messageHandlers: MessageTemplateHandlers): TemplateResult;
|
|
30
|
+
export declare function renderMessages(messages: ChatbotMessage[], suggestions: TemplateResult | typeof nothing, typingIndicator: TemplateResult | typeof nothing, messageHandlers: MessageTemplateHandlers, i18n: ChatbotI18n): TemplateResult;
|
|
31
31
|
//# sourceMappingURL=message.template.d.ts.map
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import { html, nothing } from 'lit';
|
|
7
7
|
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
8
8
|
import { classMap } from 'lit/directives/class-map.js';
|
|
9
|
-
import { msg } from '@lit/localize';
|
|
10
9
|
import { ChatbotLoadingType } from '../chatbot.types.js';
|
|
11
10
|
import { formatTimestamp } from '../utils/format.js';
|
|
12
11
|
/**
|
|
@@ -61,7 +60,7 @@ function getFileExtension(name, mimeType) {
|
|
|
61
60
|
/**
|
|
62
61
|
* Renders a single message
|
|
63
62
|
*/
|
|
64
|
-
export function renderMessage(message, handlers) {
|
|
63
|
+
export function renderMessage(message, handlers, i18n) {
|
|
65
64
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
66
65
|
const isError = (_a = message.text) === null || _a === void 0 ? void 0 : _a.includes('[ERROR_START]');
|
|
67
66
|
const messageClasses = {
|
|
@@ -84,7 +83,7 @@ export function renderMessage(message, handlers) {
|
|
|
84
83
|
: unsafeHTML(((_h = (_g = message.text) === null || _g === void 0 ? void 0 : _g.trim()) !== null && _h !== void 0 ? _h : '').replaceAll('\n', '<br>'))}
|
|
85
84
|
</div>
|
|
86
85
|
${message.files && message.files.length > 0 ? html `
|
|
87
|
-
<div class="message__attachments" part="message-attachments" role="list" aria-label="${
|
|
86
|
+
<div class="message__attachments" part="message-attachments" role="list" aria-label="${i18n.messages.attachedFilesLabel}">
|
|
88
87
|
${message.files.map((f) => html `
|
|
89
88
|
<nr-dropdown
|
|
90
89
|
trigger="hover"
|
|
@@ -145,10 +144,11 @@ export function renderMessage(message, handlers) {
|
|
|
145
144
|
size="small"
|
|
146
145
|
color="#9ca3af"
|
|
147
146
|
class="message__copy"
|
|
147
|
+
part="message-copy"
|
|
148
148
|
@click=${() => handlers.onCopy(message)}
|
|
149
149
|
@keydown=${(e) => handlers.onCopyKeydown(e, message)}
|
|
150
|
-
title="${
|
|
151
|
-
aria-label="${
|
|
150
|
+
title="${i18n.messages.copyMessageLabel}"
|
|
151
|
+
aria-label="${i18n.messages.copyMessageLabel}"
|
|
152
152
|
role="button"
|
|
153
153
|
tabindex="0"
|
|
154
154
|
></nr-icon>
|
|
@@ -162,9 +162,9 @@ export function renderMessage(message, handlers) {
|
|
|
162
162
|
part="retry-button"
|
|
163
163
|
@click=${() => handlers.onRetry(message)}
|
|
164
164
|
@keydown=${handlers.onRetryKeydown}
|
|
165
|
-
aria-label="${
|
|
165
|
+
aria-label="${i18n.messages.retryMessageLabel}"
|
|
166
166
|
>
|
|
167
|
-
${
|
|
167
|
+
${i18n.messages.retryButton}
|
|
168
168
|
</nr-button>`
|
|
169
169
|
: nothing}
|
|
170
170
|
</div>
|
|
@@ -178,18 +178,18 @@ export function renderBotTypingIndicator(isTyping, loadingIndicator, loadingText
|
|
|
178
178
|
return nothing;
|
|
179
179
|
const indicatorContent = loadingIndicator === ChatbotLoadingType.Dots
|
|
180
180
|
? html `
|
|
181
|
-
<div class="dots">
|
|
181
|
+
<div class="dots" part="typing-dots">
|
|
182
182
|
<span></span>
|
|
183
183
|
<span></span>
|
|
184
184
|
<span></span>
|
|
185
185
|
</div>
|
|
186
186
|
`
|
|
187
|
-
: html `<div class="spinner"></div>`;
|
|
187
|
+
: html `<div class="spinner" part="typing-spinner"></div>`;
|
|
188
188
|
return html `
|
|
189
189
|
<div class="message bot loading" part="typing-indicator">
|
|
190
|
-
<div class="message__content">
|
|
190
|
+
<div class="message__content" part="typing-content">
|
|
191
191
|
${indicatorContent}
|
|
192
|
-
${loadingText ? html `<span class="loading-text">${loadingText.split('').map((char, i) => html `<span class="loading-text__char" style="animation-delay:${i * 0.04}s">${char === ' ' ? '\u00A0' : char}</span>`)}</span>` : nothing}
|
|
192
|
+
${loadingText ? html `<span class="loading-text" part="typing-text">${loadingText.split('').map((char, i) => html `<span class="loading-text__char" style="animation-delay:${i * 0.04}s">${char === ' ' ? '\u00A0' : char}</span>`)}</span>` : nothing}
|
|
193
193
|
</div>
|
|
194
194
|
</div>
|
|
195
195
|
`;
|
|
@@ -197,12 +197,12 @@ export function renderBotTypingIndicator(isTyping, loadingIndicator, loadingText
|
|
|
197
197
|
/**
|
|
198
198
|
* Renders empty state
|
|
199
199
|
*/
|
|
200
|
-
export function renderEmptyState() {
|
|
200
|
+
export function renderEmptyState(i18n) {
|
|
201
201
|
return html `
|
|
202
202
|
<div class="empty-state" part="empty-state">
|
|
203
203
|
<slot name="empty-state">
|
|
204
|
-
<div class="empty-state__content">
|
|
205
|
-
${
|
|
204
|
+
<div class="empty-state__content" part="empty-state-content">
|
|
205
|
+
${i18n.messages.startConversationLabel}
|
|
206
206
|
</div>
|
|
207
207
|
</slot>
|
|
208
208
|
</div>
|
|
@@ -211,11 +211,11 @@ export function renderEmptyState() {
|
|
|
211
211
|
/**
|
|
212
212
|
* Renders messages container with all messages
|
|
213
213
|
*/
|
|
214
|
-
export function renderMessages(messages, suggestions, typingIndicator, messageHandlers) {
|
|
214
|
+
export function renderMessages(messages, suggestions, typingIndicator, messageHandlers, i18n) {
|
|
215
215
|
return html `
|
|
216
216
|
<div class="messages" part="messages">
|
|
217
|
-
${messages.length === 0 ? renderEmptyState() : nothing}
|
|
218
|
-
${messages.map((message) => renderMessage(message, messageHandlers))}
|
|
217
|
+
${messages.length === 0 ? renderEmptyState(i18n) : nothing}
|
|
218
|
+
${messages.map((message) => renderMessage(message, messageHandlers, i18n))}
|
|
219
219
|
${suggestions}
|
|
220
220
|
${typingIndicator}
|
|
221
221
|
</div>
|
|
@@ -4,17 +4,11 @@
|
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
import { TemplateResult, nothing } from 'lit';
|
|
7
|
-
import { ChatbotSuggestion } from '../chatbot.types.js';
|
|
7
|
+
import { ChatbotSuggestion, ChatbotI18n } from '../chatbot.types.js';
|
|
8
8
|
export interface SuggestionTemplateHandlers {
|
|
9
9
|
onClick: (suggestion: ChatbotSuggestion) => void;
|
|
10
10
|
onKeydown: (e: KeyboardEvent) => void;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*/
|
|
15
|
-
export declare function renderSuggestion(suggestion: ChatbotSuggestion, handlers: SuggestionTemplateHandlers): TemplateResult;
|
|
16
|
-
/**
|
|
17
|
-
* Renders suggestions container
|
|
18
|
-
*/
|
|
19
|
-
export declare function renderSuggestions(_chatStarted: boolean, suggestions: ChatbotSuggestion[], handlers: SuggestionTemplateHandlers): TemplateResult | typeof nothing;
|
|
12
|
+
export declare function renderSuggestion(suggestion: ChatbotSuggestion, handlers: SuggestionTemplateHandlers, i18n: ChatbotI18n): TemplateResult;
|
|
13
|
+
export declare function renderSuggestions(_chatStarted: boolean, suggestions: ChatbotSuggestion[], handlers: SuggestionTemplateHandlers, i18n: ChatbotI18n): TemplateResult | typeof nothing;
|
|
20
14
|
//# sourceMappingURL=suggestion.template.d.ts.map
|
|
@@ -5,34 +5,27 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { html, nothing } from 'lit';
|
|
7
7
|
import { classMap } from 'lit/directives/class-map.js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Renders a single suggestion
|
|
11
|
-
*/
|
|
12
|
-
export function renderSuggestion(suggestion, handlers) {
|
|
8
|
+
export function renderSuggestion(suggestion, handlers, i18n) {
|
|
13
9
|
return html `
|
|
14
|
-
<div
|
|
15
|
-
class="suggestion ${classMap({ 'suggestion--disabled': suggestion.enabled === false })}"
|
|
10
|
+
<div
|
|
11
|
+
class="suggestion ${classMap({ 'suggestion--disabled': suggestion.enabled === false })}"
|
|
16
12
|
part="suggestion"
|
|
17
13
|
role="button"
|
|
18
14
|
tabindex="0"
|
|
19
15
|
@click=${() => handlers.onClick(suggestion)}
|
|
20
16
|
@keydown=${handlers.onKeydown}
|
|
21
17
|
data-id="${suggestion.id}"
|
|
22
|
-
aria-label="${
|
|
18
|
+
aria-label="${i18n.messages.suggestionPrefix}${suggestion.text}"
|
|
23
19
|
>
|
|
24
20
|
${suggestion.text}
|
|
25
21
|
</div>
|
|
26
22
|
`;
|
|
27
23
|
}
|
|
28
|
-
|
|
29
|
-
* Renders suggestions container
|
|
30
|
-
*/
|
|
31
|
-
export function renderSuggestions(_chatStarted, suggestions, handlers) {
|
|
24
|
+
export function renderSuggestions(_chatStarted, suggestions, handlers, i18n) {
|
|
32
25
|
return suggestions.length > 0
|
|
33
26
|
? html `
|
|
34
27
|
<div class="suggestion-container" part="suggestions">
|
|
35
|
-
${suggestions.map((suggestion) => renderSuggestion(suggestion, handlers))}
|
|
28
|
+
${suggestions.map((suggestion) => renderSuggestion(suggestion, handlers, i18n))}
|
|
36
29
|
</div>
|
|
37
30
|
`
|
|
38
31
|
: nothing;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
import { TemplateResult } from 'lit';
|
|
7
|
-
import { ChatbotThread } from '../chatbot.types.js';
|
|
7
|
+
import { ChatbotThread, ChatbotI18n } from '../chatbot.types.js';
|
|
8
8
|
export interface ThreadSidebarTemplateHandlers {
|
|
9
9
|
onCreateNew: () => void;
|
|
10
10
|
onSelectThread: (threadId: string) => void;
|
|
@@ -16,6 +16,7 @@ export interface ThreadSidebarTemplateData {
|
|
|
16
16
|
threads: ChatbotThread[];
|
|
17
17
|
activeThreadId?: string;
|
|
18
18
|
editingThreadId?: string;
|
|
19
|
+
i18n: ChatbotI18n;
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
22
|
* Renders thread sidebar
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import { html, nothing } from 'lit';
|
|
7
7
|
import { repeat } from 'lit/directives/repeat.js';
|
|
8
8
|
import { classMap } from 'lit/directives/class-map.js';
|
|
9
|
-
import { msg } from '@lit/localize';
|
|
10
9
|
import { formatTimestamp } from '../utils/format.js';
|
|
11
10
|
function renderThreadItem(thread, data, handlers) {
|
|
12
11
|
const lastMessage = thread.messages.length > 0
|
|
@@ -27,6 +26,7 @@ function renderThreadItem(thread, data, handlers) {
|
|
|
27
26
|
${data.editingThreadId === thread.id && handlers.onRenameThread ? html `
|
|
28
27
|
<input
|
|
29
28
|
class="thread-item__rename-input"
|
|
29
|
+
part="thread-rename-input"
|
|
30
30
|
type="text"
|
|
31
31
|
.value=${thread.title || ''}
|
|
32
32
|
@click=${(e) => e.stopPropagation()}
|
|
@@ -53,13 +53,13 @@ function renderThreadItem(thread, data, handlers) {
|
|
|
53
53
|
}}
|
|
54
54
|
/>
|
|
55
55
|
` : html `
|
|
56
|
-
<div class="thread-item__title">${thread.title ||
|
|
56
|
+
<div class="thread-item__title" part="thread-title">${thread.title || data.i18n.threads.newChatTitle}</div>
|
|
57
57
|
`}
|
|
58
|
-
<div class="thread-item__actions">
|
|
58
|
+
<div class="thread-item__actions" part="thread-actions">
|
|
59
59
|
${handlers.onBookmarkThread && thread.bookmarked ? html `
|
|
60
60
|
<button
|
|
61
61
|
class="thread-item__action-btn thread-item__bookmark--active"
|
|
62
|
-
title="${
|
|
62
|
+
title="${data.i18n.threads.removeBookmarkLabel}"
|
|
63
63
|
@click=${(e) => {
|
|
64
64
|
e.stopPropagation();
|
|
65
65
|
handlers.onBookmarkThread(thread.id);
|
|
@@ -94,17 +94,17 @@ function renderThreadItem(thread, data, handlers) {
|
|
|
94
94
|
}
|
|
95
95
|
}}
|
|
96
96
|
.items=${[
|
|
97
|
-
...(handlers.onRenameThread ? [{ id: 'rename', label:
|
|
98
|
-
...(handlers.onBookmarkThread ? [{ id: 'bookmark', label: thread.bookmarked ?
|
|
99
|
-
...(handlers.onDeleteThread ? [{ id: 'delete', label:
|
|
97
|
+
...(handlers.onRenameThread ? [{ id: 'rename', label: data.i18n.threads.renameLabel }] : []),
|
|
98
|
+
...(handlers.onBookmarkThread ? [{ id: 'bookmark', label: thread.bookmarked ? data.i18n.threads.removeBookmarkLabel : data.i18n.threads.bookmarkLabel }] : []),
|
|
99
|
+
...(handlers.onDeleteThread ? [{ id: 'delete', label: data.i18n.threads.deleteLabel }] : []),
|
|
100
100
|
]}
|
|
101
101
|
>
|
|
102
102
|
<button
|
|
103
103
|
slot="trigger"
|
|
104
104
|
class="thread-item__action-btn thread-item__menu"
|
|
105
|
-
title="${
|
|
105
|
+
title="${data.i18n.threads.moreOptionsLabel}"
|
|
106
106
|
part="thread-menu"
|
|
107
|
-
aria-label="${
|
|
107
|
+
aria-label="${data.i18n.threads.moreOptionsLabel}"
|
|
108
108
|
>
|
|
109
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>
|
|
110
110
|
</button>
|
|
@@ -112,10 +112,10 @@ function renderThreadItem(thread, data, handlers) {
|
|
|
112
112
|
` : ''}
|
|
113
113
|
</div>
|
|
114
114
|
</div>
|
|
115
|
-
<div class="thread-item__preview">
|
|
115
|
+
<div class="thread-item__preview" part="thread-preview">
|
|
116
116
|
${previewText}
|
|
117
117
|
</div>
|
|
118
|
-
<div class="thread-item__timestamp">${formatTimestamp(thread.updatedAt)}</div>
|
|
118
|
+
<div class="thread-item__timestamp" part="thread-timestamp">${formatTimestamp(thread.updatedAt)}</div>
|
|
119
119
|
</div>
|
|
120
120
|
`;
|
|
121
121
|
}
|
|
@@ -127,27 +127,27 @@ export function renderThreadSidebar(data, handlers) {
|
|
|
127
127
|
const regularThreads = data.threads.filter(t => !t.bookmarked);
|
|
128
128
|
return html `
|
|
129
129
|
<div class="thread-sidebar" part="thread-sidebar">
|
|
130
|
-
<div class="thread-sidebar__header">
|
|
131
|
-
<h3>${
|
|
130
|
+
<div class="thread-sidebar__header" part="thread-sidebar-header">
|
|
131
|
+
<h3 part="thread-sidebar-title">${data.i18n.threads.conversationsTitle}</h3>
|
|
132
132
|
</div>
|
|
133
133
|
|
|
134
|
-
<div class="thread-list">
|
|
134
|
+
<div class="thread-list" part="thread-list">
|
|
135
135
|
${bookmarkedThreads.length > 0 ? html `
|
|
136
|
-
<div class="thread-section" part="thread-section-bookmarks">
|
|
137
|
-
<div class="thread-section__label">
|
|
136
|
+
<div class="thread-section" part="thread-section thread-section-bookmarks">
|
|
137
|
+
<div class="thread-section__label" part="thread-section-label">
|
|
138
138
|
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" 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>
|
|
139
|
-
${
|
|
139
|
+
${data.i18n.threads.bookmarksLabel}
|
|
140
140
|
</div>
|
|
141
141
|
${repeat(bookmarkedThreads, t => t.id, t => renderThreadItem(t, data, handlers))}
|
|
142
142
|
</div>
|
|
143
143
|
` : nothing}
|
|
144
144
|
${regularThreads.length > 0 || bookmarkedThreads.length === 0 ? html `
|
|
145
145
|
${bookmarkedThreads.length > 0 ? html `
|
|
146
|
-
<div class="thread-section__label">${
|
|
146
|
+
<div class="thread-section__label" part="thread-section-label">${data.i18n.threads.allConversationsLabel}</div>
|
|
147
147
|
` : nothing}
|
|
148
148
|
${repeat(regularThreads, t => t.id, t => renderThreadItem(t, data, handlers))}
|
|
149
149
|
${regularThreads.length === 0 && bookmarkedThreads.length === 0 ? html `
|
|
150
|
-
<p class="empty-msg">${
|
|
150
|
+
<p class="empty-msg" part="thread-empty">${data.i18n.threads.noConversationsLabel}</p>
|
|
151
151
|
` : nothing}
|
|
152
152
|
` : nothing}
|
|
153
153
|
</div>
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
import { TemplateResult } from 'lit';
|
|
7
|
+
import { ChatbotI18n } from '../chatbot.types.js';
|
|
7
8
|
export interface UrlModalTemplateHandlers {
|
|
8
9
|
onClose: () => void;
|
|
9
10
|
onUrlInputChange: (e: Event) => void;
|
|
@@ -17,9 +18,7 @@ export interface UrlModalTemplateData {
|
|
|
17
18
|
isLoading?: boolean;
|
|
18
19
|
error?: string;
|
|
19
20
|
selectedFileName?: string;
|
|
21
|
+
i18n: ChatbotI18n;
|
|
20
22
|
}
|
|
21
|
-
/**
|
|
22
|
-
* Renders URL attachment modal
|
|
23
|
-
*/
|
|
24
23
|
export declare function renderUrlModal(data: UrlModalTemplateData, handlers: UrlModalTemplateHandlers): TemplateResult;
|
|
25
24
|
//# sourceMappingURL=url-modal.template.d.ts.map
|