@messenger-box/tailwind-ui-inbox 10.0.3-alpha.121 → 10.0.3-alpha.123

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.
Files changed (91) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/components/AIAgent/AIAgent.d.ts +2 -0
  3. package/lib/components/AIAgent/AIAgent.d.ts.map +1 -1
  4. package/lib/components/AIAgent/AIAgent.js +48 -29
  5. package/lib/components/AIAgent/AIAgent.js.map +1 -1
  6. package/lib/components/InboxMessage/InputComponent.d.ts +4 -1
  7. package/lib/components/InboxMessage/InputComponent.d.ts.map +1 -1
  8. package/lib/components/InboxMessage/InputComponent.js +20 -261
  9. package/lib/components/InboxMessage/InputComponent.js.map +1 -1
  10. package/lib/components/InboxMessage/UploadImageButton.js +2 -6
  11. package/lib/components/InboxMessage/UploadImageButton.js.map +1 -1
  12. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts +1 -0
  13. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts.map +1 -1
  14. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js +15 -5
  15. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js.map +1 -1
  16. package/lib/components/ModelConfigPanel.d.ts +10 -0
  17. package/lib/components/ModelConfigPanel.d.ts.map +1 -1
  18. package/lib/components/ModelConfigPanel.js +551 -2
  19. package/lib/components/ModelConfigPanel.js.map +1 -1
  20. package/lib/components/filler-components/RightSiderBar.d.ts +1 -0
  21. package/lib/components/filler-components/RightSiderBar.d.ts.map +1 -1
  22. package/lib/components/filler-components/RightSiderBar.js +173 -148
  23. package/lib/components/filler-components/RightSiderBar.js.map +1 -1
  24. package/lib/components/slot-fill/right-sidebar-filler.d.ts.map +1 -1
  25. package/lib/components/slot-fill/right-sidebar-filler.js.map +1 -1
  26. package/lib/config/env-config.d.ts +5 -0
  27. package/lib/config/env-config.d.ts.map +1 -1
  28. package/lib/config/env-config.js +16 -1
  29. package/lib/config/env-config.js.map +1 -1
  30. package/lib/container/AiLandingInput.d.ts.map +1 -1
  31. package/lib/container/AiLandingInput.js +19 -15
  32. package/lib/container/AiLandingInput.js.map +1 -1
  33. package/lib/container/Inbox.js +1 -1
  34. package/lib/container/Inbox.js.map +1 -1
  35. package/lib/container/InboxAiMessagesLoader.d.ts +1 -0
  36. package/lib/container/InboxAiMessagesLoader.d.ts.map +1 -1
  37. package/lib/container/InboxAiMessagesLoader.js +4 -1
  38. package/lib/container/InboxAiMessagesLoader.js.map +1 -1
  39. package/lib/container/InboxContainer.d.ts +1 -0
  40. package/lib/container/InboxContainer.d.ts.map +1 -1
  41. package/lib/container/InboxContainer.js +1 -6
  42. package/lib/container/InboxContainer.js.map +1 -1
  43. package/lib/container/InboxWithAiLoader.d.ts +1 -0
  44. package/lib/container/InboxWithAiLoader.d.ts.map +1 -1
  45. package/lib/container/InboxWithAiLoader.js +2 -1
  46. package/lib/container/InboxWithAiLoader.js.map +1 -1
  47. package/lib/container/ServiceInbox.js +1 -1
  48. package/lib/container/ServiceInbox.js.map +1 -1
  49. package/lib/container/ThreadMessages.js +1 -1
  50. package/lib/container/ThreadMessages.js.map +1 -1
  51. package/lib/container/ThreadMessagesInbox.js +1 -1
  52. package/lib/container/ThreadMessagesInbox.js.map +1 -1
  53. package/lib/container/Threads.js +1 -1
  54. package/lib/container/Threads.js.map +1 -1
  55. package/lib/hooks/usePersistentModelConfig.d.ts +5 -2
  56. package/lib/hooks/usePersistentModelConfig.d.ts.map +1 -1
  57. package/lib/hooks/usePersistentModelConfig.js +30 -10
  58. package/lib/hooks/usePersistentModelConfig.js.map +1 -1
  59. package/lib/module.js +1 -1
  60. package/lib/module.js.map +1 -1
  61. package/lib/templates/InboxWithAi.d.ts +1 -0
  62. package/lib/templates/InboxWithAi.d.ts.map +1 -1
  63. package/lib/templates/InboxWithAi.js +9 -6
  64. package/lib/templates/InboxWithAi.js.map +1 -1
  65. package/lib/templates/InboxWithAi.tsx +7 -3
  66. package/lib/xstate/index.d.ts +3 -0
  67. package/lib/xstate/index.d.ts.map +1 -0
  68. package/lib/xstate/rightSidebar.machine.d.ts +4 -0
  69. package/lib/xstate/rightSidebar.machine.d.ts.map +1 -0
  70. package/lib/xstate/rightSidebar.machine.js +174 -0
  71. package/lib/xstate/rightSidebar.machine.js.map +1 -0
  72. package/lib/xstate/rightSidebar.types.d.ts +52 -0
  73. package/lib/xstate/rightSidebar.types.d.ts.map +1 -0
  74. package/package.json +4 -4
  75. package/src/components/AIAgent/AIAgent.tsx +55 -28
  76. package/src/components/InboxMessage/InputComponent.tsx +23 -325
  77. package/src/components/InboxMessage/UploadImageButton.tsx +4 -4
  78. package/src/components/InboxMessage/message-widgets/ModernMessageGroup.tsx +17 -0
  79. package/src/components/ModelConfigPanel.tsx +666 -0
  80. package/src/components/filler-components/RightSiderBar.tsx +193 -146
  81. package/src/components/slot-fill/right-sidebar-filler.tsx +1 -0
  82. package/src/config/env-config.ts +6 -1
  83. package/src/container/AiLandingInput.tsx +32 -119
  84. package/src/container/InboxAiMessagesLoader.tsx +13 -2
  85. package/src/container/InboxContainer.tsx +2 -8
  86. package/src/container/InboxWithAiLoader.tsx +2 -0
  87. package/src/hooks/usePersistentModelConfig.ts +26 -13
  88. package/src/templates/InboxWithAi.tsx +7 -3
  89. package/src/xstate/index.ts +2 -0
  90. package/src/xstate/rightSidebar.machine.ts +139 -0
  91. package/src/xstate/rightSidebar.types.ts +55 -0
@@ -1,9 +1,8 @@
1
1
  import React, { useCallback, useMemo, useState, useRef, useEffect } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { config } from '../../config';
4
- import { UploadImageButton } from './UploadImageButton';
5
4
  import { FilesList } from '../inbox';
6
- import { ModelConfigPanel, modelOptions, templateOptions, getAllModels } from '../ModelConfigPanel';
5
+ import { ModelToolbar } from '../ModelConfigPanel';
7
6
  import { ModelConfig } from '../../hooks/usePersistentModelConfig';
8
7
 
9
8
  type MessageInputProps = {
@@ -12,6 +11,9 @@ type MessageInputProps = {
12
11
  placeholder?: string;
13
12
  modelConfig?: ModelConfig;
14
13
  onModelConfigChange?: (config: ModelConfig) => void;
14
+ textareaClassName?: string;
15
+ textareaStyles?: React.CSSProperties;
16
+ toolBarParentClassName?: string;
15
17
  };
16
18
 
17
19
  export const InputComponent = ({
@@ -19,6 +21,9 @@ export const InputComponent = ({
19
21
  placeholder,
20
22
  modelConfig,
21
23
  onModelConfigChange,
24
+ textareaClassName,
25
+ toolBarParentClassName,
26
+ textareaStyles,
22
27
  }: MessageInputProps) => {
23
28
  const [message, setMessage] = useState('');
24
29
  const [sending, setSending] = useState(false);
@@ -26,12 +31,7 @@ export const InputComponent = ({
26
31
  const [showToast, setShowToast] = useState(false);
27
32
  const [toastMessage, setToastMessage] = useState('');
28
33
  const [isFocused, setIsFocused] = useState(false);
29
- const [showModelDropdown, setShowModelDropdown] = useState(false);
30
- const [showTemplateDropdown, setShowTemplateDropdown] = useState(false);
31
- const [showSettingsModal, setShowSettingsModal] = useState(false);
32
34
  const textareaRef = useRef<HTMLTextAreaElement>(null);
33
- const modelDropdownRef = useRef<HTMLDivElement>(null);
34
- const templateDropdownRef = useRef<HTMLDivElement>(null);
35
35
  const { t } = useTranslation('translations');
36
36
 
37
37
  // Auto-focus the textarea when component mounts
@@ -48,19 +48,7 @@ export const InputComponent = ({
48
48
  }
49
49
  }, [modelConfig, onModelConfigChange]);
50
50
 
51
- // Handle click outside for dropdowns
52
- useEffect(() => {
53
- const handleClickOutside = (event: MouseEvent) => {
54
- if (modelDropdownRef.current && !modelDropdownRef.current.contains(event.target as Node)) {
55
- setShowModelDropdown(false);
56
- }
57
- if (templateDropdownRef.current && !templateDropdownRef.current.contains(event.target as Node)) {
58
- setShowTemplateDropdown(false);
59
- }
60
- };
61
- document.addEventListener('mousedown', handleClickOutside);
62
- return () => document.removeEventListener('mousedown', handleClickOutside);
63
- }, []);
51
+ // no dropdowns managed here; toolbar handles its own
64
52
 
65
53
  const showToastMessage = useCallback((message: string) => {
66
54
  setToastMessage(message);
@@ -126,38 +114,11 @@ export const InputComponent = ({
126
114
  const canSend = message.trim() || files.length > 0;
127
115
  const hasContent = message.trim().length > 0;
128
116
 
129
- // Get models and templates from ModelConfigPanel
130
- const allModelOptions = useMemo(() => {
131
- return getAllModels();
132
- }, []);
133
-
134
- const templateOptionsList = useMemo(() => {
135
- return templateOptions.map((t) => ({ value: t.value, label: t.label, icon: t.icon }));
136
- }, []);
137
-
138
- const handleModelSelect = useCallback(
139
- (modelValue: string) => {
140
- if (onModelConfigChange && modelConfig) {
141
- onModelConfigChange({ ...modelConfig, model: modelValue });
142
- }
143
- setShowModelDropdown(false);
144
- },
145
- [modelConfig, onModelConfigChange],
146
- );
147
-
148
- const handleTemplateSelect = useCallback(
149
- (templateValue: string) => {
150
- if (onModelConfigChange && modelConfig) {
151
- onModelConfigChange({ ...modelConfig, template: templateValue as any });
152
- }
153
- setShowTemplateDropdown(false);
154
- },
155
- [modelConfig, onModelConfigChange],
156
- );
117
+ // toolbar now owns model/template selections
157
118
 
158
119
  return (
159
120
  // <div className="bg-gray-50 border-t border-gray-200">
160
- <div className="bg-gray-50 border border-gray-200">
121
+ <div className="bg-white ">
161
122
  {/* Toast notification */}
162
123
  {showToast && (
163
124
  <div className="fixed top-4 right-4 z-50 bg-orange-50 border border-orange-200 text-orange-800 px-4 py-3 rounded-lg shadow-lg animate-bounce">
@@ -187,13 +148,14 @@ export const InputComponent = ({
187
148
  <div className="relative mb-3">
188
149
  <textarea
189
150
  ref={textareaRef}
190
- className={`w-full text-base bg-white border-2 rounded-2xl pl-4 pr-4 py-3 resize-none focus:outline-none placeholder-gray-500 transition-all duration-200 ${
191
- isFocused ? 'border-blue-500 ring-2 ring-blue-200' : 'border-gray-300'
192
- }`}
151
+ className={`w-full text-base bg-white border border-gray-300 rounded-2xl pl-4 pr-4 py-3 resize-none focus:border-gray-300 focus:outline-none placeholder-gray-500 transition-all duration-200 ${
152
+ isFocused ? 'border-gray-400 ring-2 ring-gray-300 focus:ring-gray-300' : 'border-gray-300'
153
+ } ${textareaClassName}`}
193
154
  style={{
194
155
  height: `${inputHeight}px`,
195
156
  minHeight: '120px',
196
157
  maxHeight: '200px',
158
+ ...textareaStyles,
197
159
  }}
198
160
  placeholder={placeholder || 'Message'}
199
161
  value={sending ? '' : message}
@@ -205,281 +167,17 @@ export const InputComponent = ({
205
167
  rows={1}
206
168
  />
207
169
  </div>
208
-
209
- {/* Simplified Toolbar - Only Template, Model, Upload, Send, and Settings */}
210
- <div className="flex items-center gap-2">
211
- <UploadImageButton onChange={onUploadImageChange}>
212
- <div className="flex items-center justify-center w-8 h-8 rounded-lg border border-gray-300 bg-white hover:bg-gray-50 transition-colors">
213
- <svg
214
- className="w-4 h-4 text-gray-600"
215
- fill="none"
216
- stroke="currentColor"
217
- viewBox="0 0 24 24"
218
- >
219
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
220
- </svg>
221
- </div>
222
- </UploadImageButton>
223
- {/* 1. Template Selection Dropdown */}
224
- <div className="relative" ref={templateDropdownRef}>
225
- <button
226
- onClick={() => setShowTemplateDropdown(!showTemplateDropdown)}
227
- className="flex items-center gap-2 px-3 py-1.5 text-sm rounded-lg border border-gray-300 bg-white hover:bg-gray-50 transition-colors min-w-[120px]"
228
- >
229
- {(() => {
230
- if (modelConfig && modelConfig.template) {
231
- const currentTemplate = templateOptionsList.find(
232
- (option) => option.value === modelConfig.template,
233
- );
234
- return currentTemplate ? (
235
- <>
236
- <span className="text-lg">{currentTemplate.icon}</span>
237
- <span className="text-gray-700">{currentTemplate.label}</span>
238
- </>
239
- ) : (
240
- <>
241
- <span className="text-lg">📝</span>
242
- <span className="text-gray-500">Template</span>
243
- </>
244
- );
245
- }
246
- return (
247
- <>
248
- <span className="text-lg">📝</span>
249
- <span className="text-gray-500">Template</span>
250
- </>
251
- );
252
- })()}
253
- <svg
254
- className="w-4 h-4 text-gray-500 ml-auto"
255
- fill="none"
256
- stroke="currentColor"
257
- viewBox="0 0 24 24"
258
- >
259
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
260
- </svg>
261
- </button>
262
-
263
- {showTemplateDropdown && (
264
- <div className="absolute bottom-full left-0 mb-2 w-48 bg-white border border-gray-200 rounded-lg shadow-lg z-50">
265
- <div className="py-1">
266
- {templateOptionsList.map((option) => (
267
- <button
268
- key={option.value}
269
- onClick={() => handleTemplateSelect(option.value)}
270
- className={`w-full px-3 py-2 text-left hover:bg-gray-50 transition-colors flex items-center gap-2 ${
271
- modelConfig?.template === option.value ? 'bg-blue-50' : ''
272
- }`}
273
- >
274
- <span className="text-lg">{option.icon}</span>
275
- <span className="font-medium text-gray-900">{option.label}</span>
276
- </button>
277
- ))}
278
- </div>
279
- </div>
280
- )}
281
- </div>
282
-
283
- {/* 2. Model Selection Dropdown */}
284
- <div className="relative" ref={modelDropdownRef}>
285
- <button
286
- onClick={() => setShowModelDropdown(!showModelDropdown)}
287
- className="flex items-center gap-2 px-3 py-1.5 text-sm rounded-lg border border-gray-300 bg-white hover:bg-gray-50 transition-colors min-w-[140px]"
288
- >
289
- {(() => {
290
- if (modelConfig && modelConfig.model) {
291
- const currentModel = allModelOptions.find(
292
- (option) => option.value === modelConfig.model,
293
- );
294
- return currentModel ? (
295
- <span className="text-gray-700">{currentModel.label}</span>
296
- ) : (
297
- <span className="text-gray-500">Model</span>
298
- );
299
- }
300
- return <span className="text-gray-500">Model</span>;
301
- })()}
302
- <svg
303
- className="w-4 h-4 text-gray-500 ml-auto"
304
- fill="none"
305
- stroke="currentColor"
306
- viewBox="0 0 24 24"
307
- >
308
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
309
- </svg>
310
- </button>
311
-
312
- {showModelDropdown && (
313
- <div className="absolute bottom-full left-0 mb-2 w-64 bg-white border border-gray-200 rounded-lg shadow-lg z-50 max-h-60 overflow-y-auto">
314
- <div className="py-1">
315
- {allModelOptions.map((option) => (
316
- <button
317
- key={option.value}
318
- onClick={() => handleModelSelect(option.value)}
319
- className={`w-full px-3 py-2 text-left hover:bg-gray-50 transition-colors ${
320
- modelConfig?.model === option.value ? 'bg-blue-50' : ''
321
- }`}
322
- >
323
- <div className="font-medium text-gray-900">{option.label}</div>
324
- </button>
325
- ))}
326
- </div>
327
- </div>
328
- )}
329
- </div>
330
-
331
- <div className="flex-1"></div>
332
-
333
- {/* 3. Upload Button */}
334
-
335
- {/* 4. Project Settings Button */}
336
- <button
337
- onClick={() => setShowSettingsModal(true)}
338
- className="flex items-center justify-center w-8 h-8 rounded-lg border border-gray-300 bg-white hover:bg-gray-50 transition-colors"
339
- >
340
- <svg className="w-4 h-4 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
341
- <path
342
- strokeLinecap="round"
343
- strokeLinejoin="round"
344
- strokeWidth={2}
345
- d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
346
- />
347
- <path
348
- strokeLinecap="round"
349
- strokeLinejoin="round"
350
- strokeWidth={2}
351
- d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
352
- />
353
- </svg>
354
- </button>
355
-
356
- {/* 5. Send Button */}
357
- <button
358
- className={`flex items-center justify-center w-8 h-8 rounded-lg border transition-colors ${
359
- canSend && !sending
360
- ? 'border-blue-500 bg-blue-500 hover:bg-blue-600 text-white'
361
- : 'border-gray-300 bg-gray-100 text-gray-400 cursor-not-allowed'
362
- }`}
363
- onClick={handleSend}
364
- disabled={!canSend || sending}
365
- type="button"
366
- >
367
- {sending ? (
368
- <svg className="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
369
- <circle
370
- className="opacity-25"
371
- cx="12"
372
- cy="12"
373
- r="10"
374
- stroke="currentColor"
375
- strokeWidth="4"
376
- ></circle>
377
- <path
378
- className="opacity-75"
379
- fill="currentColor"
380
- d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
381
- ></path>
382
- </svg>
383
- ) : (
384
- <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
385
- <path
386
- strokeLinecap="round"
387
- strokeLinejoin="round"
388
- strokeWidth={2}
389
- d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"
390
- />
391
- </svg>
392
- )}
393
- </button>
170
+ <div className={`${toolBarParentClassName}`}>
171
+ <ModelToolbar
172
+ modelConfig={modelConfig}
173
+ onModelConfigChange={onModelConfigChange}
174
+ sending={sending}
175
+ canSend={!!canSend}
176
+ onSend={handleSend}
177
+ onUploadImageChange={onUploadImageChange}
178
+ />
394
179
  </div>
395
180
  </div>
396
-
397
- {/* Simplified Settings Modal - Only API Key and Model */}
398
- {showSettingsModal && (
399
- <div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
400
- <div className="bg-white rounded-lg shadow-xl max-w-md w-full mx-4">
401
- <div className="p-6 mb-4">
402
- <div className="flex items-center justify-between mb-4">
403
- <h3 className="text-lg font-semibold text-gray-900">Project Settings</h3>
404
- <button
405
- onClick={() => setShowSettingsModal(false)}
406
- className="text-gray-400 hover:text-gray-600 transition-colors"
407
- >
408
- <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
409
- <path
410
- strokeLinecap="round"
411
- strokeLinejoin="round"
412
- strokeWidth={2}
413
- d="M6 18L18 6M6 6l12 12"
414
- />
415
- </svg>
416
- </button>
417
- </div>
418
-
419
- {modelConfig && onModelConfigChange && (
420
- <div className="space-y-4">
421
- {/* API Key Input */}
422
- <div>
423
- <label className="block text-sm font-medium text-gray-700 mb-2">API Key</label>
424
- <input
425
- type="password"
426
- value={modelConfig.apiKey}
427
- onChange={(e) =>
428
- onModelConfigChange({ ...modelConfig, apiKey: e.target.value })
429
- }
430
- className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
431
- placeholder="Enter your API key"
432
- />
433
- </div>
434
-
435
- {/* Extension ID Input */}
436
- <div>
437
- <label className="block text-sm font-medium text-gray-700 mb-2">
438
- Extension ID
439
- </label>
440
- <input
441
- type="text"
442
- value={modelConfig.extensionId || ''}
443
- onChange={(e) =>
444
- onModelConfigChange({ ...modelConfig, extensionId: e.target.value })
445
- }
446
- className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
447
- placeholder="Enter your extension ID"
448
- />
449
- </div>
450
-
451
- {/* Model Selection */}
452
- <div>
453
- <label className="block text-sm font-medium text-gray-700 mb-2">Model</label>
454
- <select
455
- value={modelConfig.model}
456
- onChange={(e) =>
457
- onModelConfigChange({ ...modelConfig, model: e.target.value })
458
- }
459
- className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
460
- >
461
- {allModelOptions.map((option) => (
462
- <option key={option.value} value={option.value}>
463
- {option.label}
464
- </option>
465
- ))}
466
- </select>
467
- </div>
468
- </div>
469
- )}
470
-
471
- {/* <div className="mt-6 flex justify-end">
472
- <button
473
- onClick={() => setShowSettingsModal(false)}
474
- className="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"
475
- >
476
- Save Settings
477
- </button>
478
- </div> */}
479
- </div>
480
- </div>
481
- </div>
482
- )}
483
181
  </div>
484
182
  );
485
183
  };
@@ -28,14 +28,14 @@ export const UploadImageButton = (props: IUploadImageButtonProps) => {
28
28
  onChange={props.onChange}
29
29
  />
30
30
  {/* Tooltip */}
31
- <div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-3 py-2 bg-gray-900 text-white text-xs rounded-lg shadow-lg opacity-0 group-hover:opacity-100 transition-all duration-200 pointer-events-none whitespace-nowrap z-20">
31
+ {/* <div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-3 py-2 bg-gray-900 text-white text-xs rounded-lg shadow-lg opacity-0 group-hover:opacity-100 transition-all duration-200 pointer-events-none whitespace-nowrap z-20">
32
32
  {t('tailwind_ui_inbox.upload_image')}
33
- {/* Tooltip arrow */}
33
+
34
34
  <div className="absolute top-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-l-4 border-r-4 border-t-4 border-l-transparent border-r-transparent border-t-gray-900"></div>
35
- </div>
35
+ </div> */}
36
36
  <button
37
37
  type="button"
38
- className="flex items-center justify-center w-8 h-8 bg-transparent hover:bg-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 transition-all duration-200 ease-in-out"
38
+ className="flex items-center justify-center w-8 h-8 bg-transparent hover:bg-gray-100 rounded-md focus:outline-none focus:ring-opacity-50 transition-all duration-200 ease-in-out"
39
39
  onClick={selectFile}
40
40
  aria-label={t('tailwind_ui_inbox.upload_image')}
41
41
  >
@@ -402,6 +402,7 @@ const useInjectStyles = () => {
402
402
  interface ModernMessageGroupProps {
403
403
  showAuthorName?: boolean;
404
404
  showAvatar?: boolean;
405
+ showTimestamp?: boolean;
405
406
  messages: IPost[];
406
407
  currentUser: IAuthUser;
407
408
  onOpen: (element?: any) => void;
@@ -417,6 +418,7 @@ interface ModernMessageGroupProps {
417
418
  interface MessageGroupProps {
418
419
  showAuthorName?: boolean;
419
420
  showAvatar?: boolean;
421
+ showTimestamp?: boolean;
420
422
  author: any;
421
423
  messages: IPost[];
422
424
  currentUser: IAuthUser;
@@ -919,6 +921,7 @@ const ModernMessageGroup: React.FC<MessageGroupProps> = ({
919
921
  currentUser,
920
922
  showAuthorName = false,
921
923
  showAvatar = false,
924
+ showTimestamp = false,
922
925
  onOpen,
923
926
  onMessageClick,
924
927
  isDesktopView = false,
@@ -977,6 +980,7 @@ const ModernMessageGroup: React.FC<MessageGroupProps> = ({
977
980
  formatTime={formatTime}
978
981
  showAuthorName={showAuthorName}
979
982
  showAvatar={showAvatar}
983
+ showTimestamp={showTimestamp}
980
984
  />
981
985
  ))}
982
986
  </div>
@@ -1034,6 +1038,7 @@ const ModernMessageGroup: React.FC<MessageGroupProps> = ({
1034
1038
  isLastInGroup={index === messages.length - 1}
1035
1039
  onMessageClick={onMessageClick}
1036
1040
  formatTime={formatTime}
1041
+ showTimestamp={showTimestamp}
1037
1042
  />
1038
1043
  ))}
1039
1044
  </div>
@@ -1046,6 +1051,7 @@ const ModernMessageGroup: React.FC<MessageGroupProps> = ({
1046
1051
  interface ModernMessageBubbleProps {
1047
1052
  showAuthorName?: boolean;
1048
1053
  showAvatar?: boolean;
1054
+ showTimestamp?: boolean;
1049
1055
  message: IPost;
1050
1056
  isOwnMessage: boolean;
1051
1057
  isSystemMessage: boolean;
@@ -1058,6 +1064,7 @@ interface ModernMessageBubbleProps {
1058
1064
  const ModernMessageBubble: React.FC<ModernMessageBubbleProps> = ({
1059
1065
  showAuthorName = false,
1060
1066
  showAvatar = false,
1067
+ showTimestamp = false,
1061
1068
  message,
1062
1069
  isOwnMessage,
1063
1070
  isSystemMessage,
@@ -1142,6 +1149,11 @@ const ModernMessageBubble: React.FC<ModernMessageBubbleProps> = ({
1142
1149
  <FilesList uploaded files={message.files.data} />
1143
1150
  </div>
1144
1151
  )}
1152
+ {showTimestamp ? (
1153
+ <div className="text-[10px] text-gray-500 mt-1 text-right">
1154
+ {formatTime(message.createdAt)}
1155
+ </div>
1156
+ ) : null}
1145
1157
  </div>
1146
1158
  </div>
1147
1159
 
@@ -1262,6 +1274,9 @@ const ModernMessageBubble: React.FC<ModernMessageBubbleProps> = ({
1262
1274
  </div>
1263
1275
  )} */}
1264
1276
  </div>
1277
+ {showTimestamp ? (
1278
+ <div className="text-[10px] text-gray-500 mt-1 text-right">{formatTime(message.createdAt)}</div>
1279
+ ) : null}
1265
1280
  </div>
1266
1281
  );
1267
1282
  };
@@ -1271,6 +1286,7 @@ export const ModernMessageGroupComponent: React.FC<ModernMessageGroupProps> = ({
1271
1286
  currentUser,
1272
1287
  showAuthorName = false,
1273
1288
  showAvatar = false,
1289
+ showTimestamp = false,
1274
1290
  onOpen,
1275
1291
  onMessageClick,
1276
1292
  isDesktopView = false,
@@ -1304,6 +1320,7 @@ export const ModernMessageGroupComponent: React.FC<ModernMessageGroupProps> = ({
1304
1320
  isSmallScreen={isSmallScreen}
1305
1321
  showAuthorName={showAuthorName}
1306
1322
  showAvatar={showAvatar}
1323
+ showTimestamp={showTimestamp}
1307
1324
  />
1308
1325
  );
1309
1326
  })}