@messenger-box/tailwind-ui-inbox 10.0.3-alpha.70 → 10.0.3-alpha.72

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 (155) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/components/AIAgent/AIAgent.d.ts +14 -0
  3. package/lib/components/AIAgent/AIAgent.d.ts.map +1 -0
  4. package/lib/components/AIAgent/AIAgent.js +1148 -0
  5. package/lib/components/AIAgent/AIAgent.js.map +1 -0
  6. package/lib/components/AIAgent/index.d.ts +2 -0
  7. package/lib/components/AIAgent/index.d.ts.map +1 -0
  8. package/lib/components/InboxMessage/InputComponent.d.ts +9 -0
  9. package/lib/components/InboxMessage/InputComponent.d.ts.map +1 -0
  10. package/lib/components/InboxMessage/InputComponent.js +210 -0
  11. package/lib/components/InboxMessage/InputComponent.js.map +1 -0
  12. package/lib/components/InboxMessage/LeftSidebar.d.ts +2 -0
  13. package/lib/components/InboxMessage/LeftSidebar.d.ts.map +1 -1
  14. package/lib/components/InboxMessage/LeftSidebar.js +16 -5
  15. package/lib/components/InboxMessage/LeftSidebar.js.map +1 -1
  16. package/lib/components/InboxMessage/MessageInput.d.ts.map +1 -1
  17. package/lib/components/InboxMessage/MessageInput.js +14 -10
  18. package/lib/components/InboxMessage/MessageInput.js.map +1 -1
  19. package/lib/components/InboxMessage/MessageInputComponent.d.ts +9 -0
  20. package/lib/components/InboxMessage/MessageInputComponent.d.ts.map +1 -0
  21. package/lib/components/InboxMessage/MessageInputComponent.js +173 -0
  22. package/lib/components/InboxMessage/MessageInputComponent.js.map +1 -0
  23. package/lib/components/InboxMessage/Messages.d.ts +3 -1
  24. package/lib/components/InboxMessage/Messages.d.ts.map +1 -1
  25. package/lib/components/InboxMessage/Messages.js +16 -60
  26. package/lib/components/InboxMessage/Messages.js.map +1 -1
  27. package/lib/components/InboxMessage/MessagesBuilderUi.d.ts +17 -0
  28. package/lib/components/InboxMessage/MessagesBuilderUi.d.ts.map +1 -0
  29. package/lib/components/InboxMessage/MessagesBuilderUi.js +162 -0
  30. package/lib/components/InboxMessage/MessagesBuilderUi.js.map +1 -0
  31. package/lib/components/InboxMessage/UploadImageButton.d.ts +1 -0
  32. package/lib/components/InboxMessage/UploadImageButton.d.ts.map +1 -1
  33. package/lib/components/InboxMessage/UploadImageButton.js +3 -3
  34. package/lib/components/InboxMessage/UploadImageButton.js.map +1 -1
  35. package/lib/components/InboxMessage/index.d.ts +3 -0
  36. package/lib/components/InboxMessage/index.d.ts.map +1 -1
  37. package/lib/components/InboxMessage/message-widgets/CommonMessage.d.ts.map +1 -1
  38. package/lib/components/InboxMessage/message-widgets/CommonMessage.js +11 -6
  39. package/lib/components/InboxMessage/message-widgets/CommonMessage.js.map +1 -1
  40. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts +14 -0
  41. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts.map +1 -0
  42. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js +1525 -0
  43. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js.map +1 -0
  44. package/lib/components/InboxMessage/message-widgets/PlainMessage.d.ts.map +1 -1
  45. package/lib/components/InboxMessage/message-widgets/PlainMessage.js +6 -3
  46. package/lib/components/InboxMessage/message-widgets/PlainMessage.js.map +1 -1
  47. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.d.ts +2 -0
  48. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.d.ts.map +1 -1
  49. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js +225 -26
  50. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js.map +1 -1
  51. package/lib/components/InboxMessage/message-widgets/index.d.ts +1 -0
  52. package/lib/components/InboxMessage/message-widgets/index.d.ts.map +1 -1
  53. package/lib/components/index.d.ts +2 -1
  54. package/lib/components/index.d.ts.map +1 -1
  55. package/lib/compute.d.ts.map +1 -1
  56. package/lib/compute.js +79 -3
  57. package/lib/compute.js.map +1 -1
  58. package/lib/config/env-config.d.ts +6 -0
  59. package/lib/config/env-config.d.ts.map +1 -1
  60. package/lib/config/env-config.js +19 -1
  61. package/lib/config/env-config.js.map +1 -1
  62. package/lib/container/AiInbox.d.ts +15 -0
  63. package/lib/container/AiInbox.d.ts.map +1 -0
  64. package/lib/container/AiInbox.js +1520 -0
  65. package/lib/container/AiInbox.js.map +1 -0
  66. package/lib/container/AiInboxWithLoader.d.ts +36 -0
  67. package/lib/container/AiInboxWithLoader.d.ts.map +1 -0
  68. package/lib/container/AiInboxWithLoader.js +300 -0
  69. package/lib/container/AiInboxWithLoader.js.map +1 -0
  70. package/lib/container/AiLandingInput.d.ts +4 -0
  71. package/lib/container/AiLandingInput.d.ts.map +1 -0
  72. package/lib/container/AiLandingInput.js +164 -0
  73. package/lib/container/AiLandingInput.js.map +1 -0
  74. package/lib/container/Inbox.d.ts.map +1 -1
  75. package/lib/container/Inbox.js +177 -58
  76. package/lib/container/Inbox.js.map +1 -1
  77. package/lib/container/InboxAiMessagesLoader.d.ts +36 -0
  78. package/lib/container/InboxAiMessagesLoader.d.ts.map +1 -0
  79. package/lib/container/InboxAiMessagesLoader.js +47 -0
  80. package/lib/container/InboxAiMessagesLoader.js.map +1 -0
  81. package/lib/container/InboxContainer.d.ts +12 -0
  82. package/lib/container/InboxContainer.d.ts.map +1 -0
  83. package/lib/container/InboxContainer.js +31 -0
  84. package/lib/container/InboxContainer.js.map +1 -0
  85. package/lib/container/InboxTemplate1.d.ts +15 -0
  86. package/lib/container/InboxTemplate1.d.ts.map +1 -0
  87. package/lib/container/InboxTemplate1.js +1375 -0
  88. package/lib/container/InboxTemplate1.js.map +1 -0
  89. package/lib/container/InboxTemplate1WithLoader.d.ts +36 -0
  90. package/lib/container/InboxTemplate1WithLoader.d.ts.map +1 -0
  91. package/lib/container/InboxTemplate2.d.ts +15 -0
  92. package/lib/container/InboxTemplate2.d.ts.map +1 -0
  93. package/lib/container/InboxTemplate2.js +1426 -0
  94. package/lib/container/InboxTemplate2.js.map +1 -0
  95. package/lib/container/InboxWithAiLoader.d.ts +15 -0
  96. package/lib/container/InboxWithAiLoader.d.ts.map +1 -0
  97. package/lib/container/InboxWithAiLoader.js +56 -0
  98. package/lib/container/InboxWithAiLoader.js.map +1 -0
  99. package/lib/container/ServiceInbox.js +1 -1
  100. package/lib/container/ServiceInbox.js.map +1 -1
  101. package/lib/container/ThreadMessages.js +1 -1
  102. package/lib/container/ThreadMessages.js.map +1 -1
  103. package/lib/container/ThreadMessagesInbox.js +1 -1
  104. package/lib/container/ThreadMessagesInbox.js.map +1 -1
  105. package/lib/container/Threads.js +1 -1
  106. package/lib/container/Threads.js.map +1 -1
  107. package/lib/container/index.d.ts +4 -1
  108. package/lib/container/index.d.ts.map +1 -1
  109. package/lib/index.js +1 -1
  110. package/lib/machines/aiAgentMachine.d.ts +3 -0
  111. package/lib/machines/aiAgentMachine.d.ts.map +1 -0
  112. package/lib/machines/aiAgentMachine.js +1040 -0
  113. package/lib/machines/aiAgentMachine.js.map +1 -0
  114. package/lib/machines/types.d.ts +77 -0
  115. package/lib/machines/types.d.ts.map +1 -0
  116. package/lib/routes.json +40 -0
  117. package/lib/templates/InboxWithAi.d.ts +15 -0
  118. package/lib/templates/InboxWithAi.d.ts.map +1 -0
  119. package/lib/templates/InboxWithAi.js +405 -0
  120. package/lib/templates/InboxWithAi.js.map +1 -0
  121. package/lib/templates/InboxWithAi.tsx +502 -0
  122. package/package.json +7 -5
  123. package/src/components/AIAgent/AIAgent.tsx +1351 -0
  124. package/src/components/AIAgent/README.md +82 -0
  125. package/src/components/AIAgent/index.ts +1 -0
  126. package/src/components/InboxMessage/InputComponent.tsx +263 -0
  127. package/src/components/InboxMessage/LeftSidebar.tsx +14 -4
  128. package/src/components/InboxMessage/MessageInput.tsx +73 -66
  129. package/src/components/InboxMessage/MessageInputComponent.tsx +245 -0
  130. package/src/components/InboxMessage/Messages.tsx +24 -68
  131. package/src/components/InboxMessage/MessagesBuilderUi.tsx +205 -0
  132. package/src/components/InboxMessage/UploadImageButton.tsx +3 -2
  133. package/src/components/InboxMessage/index.ts +3 -0
  134. package/src/components/InboxMessage/message-widgets/CommonMessage.tsx +39 -21
  135. package/src/components/InboxMessage/message-widgets/ModernMessageGroup.tsx +1968 -0
  136. package/src/components/InboxMessage/message-widgets/PlainMessage.tsx +6 -2
  137. package/src/components/InboxMessage/message-widgets/SlackLikeMessageGroup.tsx +337 -53
  138. package/src/components/InboxMessage/message-widgets/index.ts +1 -0
  139. package/src/components/index.ts +4 -0
  140. package/src/compute.ts +83 -2
  141. package/src/config/env-config.ts +6 -0
  142. package/src/container/AiInbox.tsx +1796 -0
  143. package/src/container/AiInboxWithLoader.tsx +356 -0
  144. package/src/container/AiLandingInput.tsx +168 -0
  145. package/src/container/Inbox.tsx +280 -130
  146. package/src/container/InboxAiMessagesLoader.tsx +68 -0
  147. package/src/container/InboxContainer.tsx +35 -0
  148. package/src/container/InboxTemplate1.tsx +1542 -0
  149. package/src/container/InboxTemplate1WithLoader.tsx +338 -0
  150. package/src/container/InboxTemplate2.tsx +1606 -0
  151. package/src/container/InboxWithAiLoader.tsx +76 -0
  152. package/src/container/index.ts +15 -1
  153. package/src/machines/aiAgentMachine.ts +1248 -0
  154. package/src/machines/types.ts +59 -0
  155. package/src/templates/InboxWithAi.tsx +502 -0
@@ -1,14 +1,18 @@
1
1
  import React from 'react';
2
2
 
3
3
  interface IPlainMessageProps {
4
- message: string;
4
+ message: string; // may contain HTML
5
5
  index: number;
6
6
  }
7
7
 
8
8
  export const PlainMessage = ({ message, index }: IPlainMessageProps) => {
9
9
  return (
10
10
  <div className="w-full flex justify-center mb-7" key={`msgList_${index}`}>
11
- <p className="text-sm font-bold">{message}</p>
11
+ {/* <p className="text-sm font-bold">{message}</p> */}
12
+ <div
13
+ className="text-sm font-bold whitespace-pre-wrap prose prose-sm max-w-none"
14
+ dangerouslySetInnerHTML={{ __html: message }}
15
+ />
12
16
  </div>
13
17
  );
14
18
  };
@@ -8,6 +8,8 @@ interface SlackLikeMessageGroupProps {
8
8
  currentUser: IAuthUser;
9
9
  onOpen: (element?: any) => void;
10
10
  onMessageClick: (msg: IPost) => void;
11
+ isDesktopView?: boolean;
12
+ isSmallScreen?: boolean;
11
13
  }
12
14
 
13
15
  interface MessageGroupProps {
@@ -16,6 +18,8 @@ interface MessageGroupProps {
16
18
  currentUser: IAuthUser;
17
19
  onOpen: (element?: any) => void;
18
20
  onMessageClick: (msg: IPost) => void;
21
+ isDesktopView?: boolean;
22
+ isSmallScreen?: boolean;
19
23
  }
20
24
 
21
25
  // Utility function to group messages by user and time
@@ -53,7 +57,238 @@ export const groupMessagesByUserAndTime = (messages: IPost[], timeThresholdMinut
53
57
  return groups;
54
58
  };
55
59
 
56
- const MessageGroup: React.FC<MessageGroupProps> = ({ author, messages, currentUser, onOpen, onMessageClick }) => {
60
+ // Detect if a string likely contains HTML
61
+ const isProbablyHTML = (value: string): boolean => {
62
+ if (!value) return false;
63
+ return /<\/?[a-z][\s\S]*>/i.test(value.trim());
64
+ };
65
+
66
+ // Minimal sanitizer without extra deps
67
+ const sanitizeHtml = (html: string): string => {
68
+ try {
69
+ if (typeof window === 'undefined' || typeof window.DOMParser === 'undefined') {
70
+ return html
71
+ .replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, '')
72
+ .replace(/<style[\s\S]*?>[\s\S]*?<\/style>/gi, '')
73
+ .replace(/on\w+\s*=\s*"[^"]*"/gi, '')
74
+ .replace(/on\w+\s*=\s*'[^']*'/gi, '')
75
+ .replace(/on\w+\s*=\s*[^\s>]+/gi, '')
76
+ .replace(/javascript:/gi, '');
77
+ }
78
+
79
+ const parser = new window.DOMParser();
80
+ const doc = parser.parseFromString(html, 'text/html');
81
+
82
+ const dangerousTags = ['script', 'style', 'iframe', 'object', 'embed', 'link', 'meta'];
83
+ dangerousTags.forEach((tag) => {
84
+ doc.querySelectorAll(tag).forEach((el) => el.remove());
85
+ });
86
+
87
+ const walker = doc.createTreeWalker(doc.body, (NodeFilter as any).SHOW_ELEMENT);
88
+ let node = walker.nextNode() as Element | null;
89
+ while (node) {
90
+ Array.from(node.attributes).forEach((attr) => {
91
+ const name = attr.name.toLowerCase();
92
+ const value = (attr.value || '').toLowerCase();
93
+ if (name.startsWith('on') || value.startsWith('javascript:')) {
94
+ node?.removeAttribute(attr.name);
95
+ }
96
+ if ((name === 'src' || name === 'href') && !/^https?:|^\/.*/.test(attr.value)) {
97
+ node?.removeAttribute(attr.name);
98
+ }
99
+ });
100
+ node = walker.nextNode() as Element | null;
101
+ }
102
+
103
+ return doc.body.innerHTML;
104
+ } catch (e) {
105
+ return html.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, '');
106
+ }
107
+ };
108
+
109
+ // Render markdown-like content with fenced code blocks
110
+ const FormattedMessageContent: React.FC<{ content: string }> = ({ content }) => {
111
+ if (!content) return null;
112
+ // Normalize escaped fences (\``` -> ```)
113
+ // Unescape any backslash-escaped backticks so Markdown fences work
114
+ const normalized = content.replace(/\\`/g, '`');
115
+ const blocks = normalized.split('\n\n').filter((b) => b.trim());
116
+ return (
117
+ <div className="space-y-3">
118
+ {blocks.map((block, index) => {
119
+ const trimmed = block.trim();
120
+
121
+ // Fenced code anywhere in block
122
+ if (trimmed.includes('```')) {
123
+ const parts: React.ReactNode[] = [];
124
+ const pushText = (t: string, key: string) => {
125
+ const txt = (t || '').trim();
126
+ if (!txt) return;
127
+ if (txt.startsWith('# ')) {
128
+ parts.push(
129
+ <h1 key={key} className="text-xl font-semibold text-gray-900">
130
+ {txt.substring(2)}
131
+ </h1>,
132
+ );
133
+ return;
134
+ }
135
+ if (txt.startsWith('## ')) {
136
+ parts.push(
137
+ <h2 key={key} className="text-base font-semibold text-gray-800">
138
+ {txt.substring(3)}
139
+ </h2>,
140
+ );
141
+ return;
142
+ }
143
+ if (txt.startsWith('### ')) {
144
+ parts.push(
145
+ <h3 key={key} className="text-sm font-medium text-gray-700">
146
+ {txt.substring(4)}
147
+ </h3>,
148
+ );
149
+ return;
150
+ }
151
+ if (txt.startsWith('- ') || txt.startsWith('• ')) {
152
+ const items = txt.split('\n').filter((l) => l.trim());
153
+ parts.push(
154
+ <ul key={key} className="list-disc pl-5 space-y-1">
155
+ {items.map((it, i) => (
156
+ <li key={`${key}-li-${i}`} className="text-gray-700">
157
+ {it.replace(/^[\u2212\-•]\s*/, '')}
158
+ </li>
159
+ ))}
160
+ </ul>,
161
+ );
162
+ return;
163
+ }
164
+ if (txt.includes('**') || txt.includes('`')) {
165
+ const formatted = txt
166
+ .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
167
+ .replace(/`([^`]+)`/g, '<code class="bg-gray-100 px-1 rounded">$1</code>');
168
+ parts.push(
169
+ <div
170
+ key={key}
171
+ className="text-gray-700"
172
+ dangerouslySetInnerHTML={{ __html: sanitizeHtml(formatted) }}
173
+ />,
174
+ );
175
+ return;
176
+ }
177
+ parts.push(
178
+ <p key={key} className="text-gray-700 whitespace-pre-wrap">
179
+ {txt}
180
+ </p>,
181
+ );
182
+ };
183
+
184
+ const codeRegex = /```([\w-]*)\n?([\s\S]*?)```/g;
185
+ let lastIndex = 0;
186
+ let m: RegExpExecArray | null;
187
+ while ((m = codeRegex.exec(trimmed)) !== null) {
188
+ const [full, lang, code] = m;
189
+ const before = trimmed.slice(lastIndex, m.index);
190
+ pushText(before, `${index}-before-${lastIndex}`);
191
+ const language = (lang || '').trim() || 'code';
192
+ parts.push(
193
+ <div
194
+ key={`${index}-code-${m.index}`}
195
+ className="border border-gray-200 rounded overflow-hidden"
196
+ >
197
+ <div className="px-3 py-1.5 text-[10px] font-semibold uppercase tracking-wide bg-gray-100 text-gray-600">
198
+ {language}
199
+ </div>
200
+ <div className="bg-gray-900 p-3 overflow-x-auto">
201
+ <pre className="text-xs text-gray-100 font-mono leading-relaxed not-prose">
202
+ <code>{code}</code>
203
+ </pre>
204
+ </div>
205
+ </div>,
206
+ );
207
+ lastIndex = m.index + full.length;
208
+ }
209
+ const after = trimmed.slice(lastIndex);
210
+ pushText(after, `${index}-after`);
211
+ return (
212
+ <div key={index} className="space-y-2">
213
+ {parts}
214
+ </div>
215
+ );
216
+ }
217
+
218
+ if (isProbablyHTML(trimmed)) {
219
+ return (
220
+ <div
221
+ key={index}
222
+ className="prose prose-sm max-w-none"
223
+ dangerouslySetInnerHTML={{ __html: sanitizeHtml(trimmed) }}
224
+ />
225
+ );
226
+ }
227
+
228
+ if (trimmed.startsWith('### '))
229
+ return (
230
+ <h3 key={index} className="text-sm font-medium text-gray-700">
231
+ {trimmed.substring(4)}
232
+ </h3>
233
+ );
234
+ if (trimmed.startsWith('## '))
235
+ return (
236
+ <h2 key={index} className="text-base font-semibold text-gray-800">
237
+ {trimmed.substring(3)}
238
+ </h2>
239
+ );
240
+ if (trimmed.startsWith('# '))
241
+ return (
242
+ <h1 key={index} className="text-xl font-semibold text-gray-900">
243
+ {trimmed.substring(2)}
244
+ </h1>
245
+ );
246
+
247
+ if (trimmed.startsWith('- ') || trimmed.startsWith('• ')) {
248
+ const items = trimmed.split('\n').filter((l) => l.trim());
249
+ return (
250
+ <ul key={index} className="list-disc pl-5 space-y-1">
251
+ {items.map((it, i) => (
252
+ <li key={`${index}-li-${i}`} className="text-gray-700">
253
+ {it.replace(/^[\u2212\-•]\s*/, '')}
254
+ </li>
255
+ ))}
256
+ </ul>
257
+ );
258
+ }
259
+
260
+ if (trimmed.includes('**') || trimmed.includes('`')) {
261
+ const formatted = trimmed
262
+ .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
263
+ .replace(/`([^`]+)`/g, '<code class="bg-gray-100 px-1 rounded">$1</code>');
264
+ return (
265
+ <div
266
+ key={index}
267
+ className="text-gray-700"
268
+ dangerouslySetInnerHTML={{ __html: sanitizeHtml(formatted) }}
269
+ />
270
+ );
271
+ }
272
+
273
+ return (
274
+ <p key={index} className="text-gray-700 whitespace-pre-wrap">
275
+ {trimmed}
276
+ </p>
277
+ );
278
+ })}
279
+ </div>
280
+ );
281
+ };
282
+
283
+ const MessageGroup: React.FC<MessageGroupProps> = ({
284
+ author,
285
+ messages,
286
+ currentUser,
287
+ onOpen,
288
+ onMessageClick,
289
+ isDesktopView = false,
290
+ isSmallScreen = false,
291
+ }) => {
57
292
  const isOwnMessage = author?.id === currentUser?.id;
58
293
  const authorName =
59
294
  author?.givenName && author?.familyName
@@ -66,37 +301,60 @@ const MessageGroup: React.FC<MessageGroupProps> = ({ author, messages, currentUs
66
301
  return format(date, 'h:mm a');
67
302
  };
68
303
 
69
- return (
70
- <div className="mb-1 group hover:bg-white hover:bg-opacity-60 -mx-4 px-4 py-1 rounded transition-colors">
71
- <div className="flex items-start space-x-2">
72
- {/* Avatar - show for all messages */}
73
- <div className="flex-shrink-0 mt-0.5">
74
- <img
75
- className="w-9 h-9 rounded-lg cursor-pointer hover:opacity-80 transition-opacity"
76
- src={author?.picture || '/default-avatar.svg'}
77
- alt={authorName}
78
- onClick={() => onOpen(firstMessage)}
79
- onError={(e) => {
80
- e.currentTarget.src = '/default-avatar.svg';
81
- }}
82
- />
83
- </div>
304
+ // Determine if this is an AI/system message for special styling
305
+ const isSystemMessage =
306
+ author?.username?.toLowerCase().includes('ai') ||
307
+ author?.username?.toLowerCase().includes('assistant') ||
308
+ author?.username?.toLowerCase().includes('system');
84
309
 
85
- <div className="flex-1 min-w-0">
86
- {/* Author name and timestamp - show for all messages */}
87
- <div className="flex items-center space-x-2 mb-1">
88
- <span className="text-sm font-bold text-gray-900">{authorName}</span>
89
- <span className="text-xs text-gray-500">{formatTime(firstMessage.createdAt)}</span>
90
- {isOwnMessage && <span className="text-xs text-gray-400 italic">(you)</span>}
310
+ return (
311
+ <div
312
+ className={`group hover:bg-white hover:bg-opacity-60 rounded transition-colors ${
313
+ isDesktopView ? 'mb-8 -mx-6 px-6 py-4' : isSmallScreen ? 'mb-4 -mx-2 px-2 py-2' : 'mb-6 -mx-4 px-4 py-3'
314
+ }`}
315
+ >
316
+ <div
317
+ className={`flex items-start ${
318
+ isDesktopView ? 'space-x-4' : isSmallScreen ? 'space-x-2' : 'space-x-3'
319
+ }`}
320
+ >
321
+ {/* Avatar - Only show for non-system messages */}
322
+ {!isSystemMessage && (
323
+ <div className="flex-shrink-0 mt-0.5">
324
+ <img
325
+ className={`rounded-lg cursor-pointer hover:opacity-80 transition-opacity ${
326
+ isDesktopView ? 'w-12 h-12' : isSmallScreen ? 'w-8 h-8' : 'w-10 h-10'
327
+ }`}
328
+ src={author?.picture || '/default-avatar.svg'}
329
+ alt={authorName}
330
+ onClick={() => onOpen(firstMessage)}
331
+ onError={(e) => {
332
+ e.currentTarget.src = '/default-avatar.svg';
333
+ }}
334
+ />
91
335
  </div>
336
+ )}
337
+
338
+ <div className="flex-1 min-w-0 overflow-hidden">
339
+ {/* Author name and timestamp - Only show for non-system messages */}
340
+ {!isSystemMessage && (
341
+ <div className="flex items-center space-x-2 mb-1">
342
+ <span className="text-sm font-semibold text-gray-900 truncate">{authorName}</span>
343
+ <span className="text-xs text-gray-500 flex-shrink-0">
344
+ {formatTime(firstMessage.createdAt)}
345
+ </span>
346
+ {isOwnMessage && <span className="text-xs text-gray-400 italic flex-shrink-0">(you)</span>}
347
+ </div>
348
+ )}
92
349
 
93
350
  {/* Messages in the group - single line for each message */}
94
- <div className="space-y-1">
351
+ <div className="space-y-0.5">
95
352
  {messages.map((message, index) => (
96
353
  <MessageBubble
97
354
  key={message.id}
98
355
  message={message}
99
356
  isOwnMessage={isOwnMessage}
357
+ isSystemMessage={isSystemMessage}
100
358
  isFirstInGroup={index === 0}
101
359
  isLastInGroup={index === messages.length - 1}
102
360
  showTimestamp={isOwnMessage && index === 0}
@@ -123,11 +381,13 @@ interface MessageBubbleProps {
123
381
  totalInGroup: number;
124
382
  authorName: string;
125
383
  formatTime: (timestamp: string) => string;
384
+ isSystemMessage: boolean;
126
385
  }
127
386
 
128
387
  const MessageBubble: React.FC<MessageBubbleProps> = ({
129
388
  message,
130
389
  isOwnMessage,
390
+ isSystemMessage,
131
391
  isFirstInGroup,
132
392
  isLastInGroup,
133
393
  showTimestamp,
@@ -137,41 +397,61 @@ const MessageBubble: React.FC<MessageBubbleProps> = ({
137
397
  formatTime,
138
398
  }) => {
139
399
  const handleClick = () => {
140
- onMessageClick?.(message);
400
+ if (!isSystemMessage) {
401
+ onMessageClick?.(message);
402
+ }
141
403
  };
142
404
 
143
405
  // All messages use the same format (Slack style - left aligned)
144
406
  return (
145
- <div className="py-0.5 hover:bg-gray-50 hover:bg-opacity-50 rounded px-1 -mx-1 group">
146
- <div className="text-sm text-gray-900 cursor-pointer hover:bg-gray-100 px-1 rounded" onClick={handleClick}>
147
- {/* Show timestamp on hover */}
148
- <span className="text-xs text-gray-500 opacity-0 group-hover:opacity-100 transition-opacity float-right ml-2">
149
- {formatTime(message.createdAt)}
150
- </span>
151
-
152
- {message.message && (
153
- <span className="whitespace-pre-wrap break-words leading-relaxed">{message.message}</span>
154
- )}
407
+ <div
408
+ className={`py-1 hover:bg-gray-50 hover:bg-opacity-50 rounded px-1 sm:px-2 -mx-1 sm:-mx-2 group ${
409
+ isSystemMessage ? '' : 'cursor-pointer'
410
+ }`}
411
+ >
412
+ <div className="flex items-start justify-between gap-2">
413
+ <div
414
+ className={`text-sm hover:bg-gray-100 px-1 sm:px-2 py-1 rounded flex-1 ${
415
+ isSystemMessage ? 'text-gray-800' : 'text-gray-900 cursor-pointer'
416
+ }`}
417
+ onClick={handleClick}
418
+ >
419
+ {message.message && (
420
+ <div className="break-words leading-relaxed">
421
+ {message.message.includes('```') ? (
422
+ <FormattedMessageContent content={message.message} />
423
+ ) : isProbablyHTML(message.message) ? (
424
+ <div
425
+ className="prose prose-sm max-w-none"
426
+ dangerouslySetInnerHTML={{ __html: sanitizeHtml(message.message) }}
427
+ />
428
+ ) : (
429
+ <FormattedMessageContent content={message.message} />
430
+ )}
431
+ </div>
432
+ )}
155
433
 
156
- {message.files?.totalCount > 0 && (
157
- <div className="mt-1 clear-both">
158
- <FilesList uploaded files={message.files.data} />
159
- </div>
160
- )}
161
- <div className={`${navigator.userAgent.includes('Firefox') ? 'mt-1' : ''} clear-both`}></div>
162
-
163
- {/* Show delivery status for own messages */}
164
- {/* {isOwnMessage && message.isDelivered !== undefined && (
165
- <div className="text-xs text-gray-400 mt-1 clear-both">
166
- {message.isDelivered
167
- ? message.isRead
168
- ? '✓✓ Read'
169
- : '✓✓ Delivered'
170
- : '✓ Sent'
171
- }
172
- </div>
173
- )} */}
434
+ {message.files?.totalCount > 0 && (
435
+ <div className="mt-2">
436
+ <FilesList uploaded files={message.files.data} />
437
+ </div>
438
+ )}
439
+ </div>
440
+
441
+ {/* Show timestamp to the right of message */}
442
+ <span className="text-xs text-gray-500 flex-shrink-0 mt-1">{formatTime(message.createdAt)}</span>
174
443
  </div>
444
+
445
+ {/* Show delivery status for own messages */}
446
+ {/* {isOwnMessage && message.isDelivered !== undefined && (
447
+ <div className="text-xs text-gray-400 mt-1 clear-both">
448
+ {message.isDelivered
449
+ ? message.isRead
450
+ ? '✓✓ Read'
451
+ : '✓✓ Delivered'
452
+ : '✓ Sent'}
453
+ </div>
454
+ )} */}
175
455
  </div>
176
456
  );
177
457
  };
@@ -181,6 +461,8 @@ export const SlackLikeMessageGroup: React.FC<SlackLikeMessageGroupProps> = ({
181
461
  currentUser,
182
462
  onOpen,
183
463
  onMessageClick,
464
+ isDesktopView = false,
465
+ isSmallScreen = false,
184
466
  }) => {
185
467
  // Filter out non-message items (like date strings)
186
468
  const actualMessages = messages.filter((msg) => typeof msg !== 'string') as IPost[];
@@ -189,7 +471,7 @@ export const SlackLikeMessageGroup: React.FC<SlackLikeMessageGroupProps> = ({
189
471
  const messageGroups = groupMessagesByUserAndTime(actualMessages);
190
472
 
191
473
  return (
192
- <div className="space-y-2">
474
+ <div className={`min-h-fit ${isDesktopView ? 'space-y-8' : isSmallScreen ? 'space-y-4' : 'space-y-6'}`}>
193
475
  {messageGroups.map((group, groupIndex) => {
194
476
  const author = group[0]?.author;
195
477
  return (
@@ -200,6 +482,8 @@ export const SlackLikeMessageGroup: React.FC<SlackLikeMessageGroupProps> = ({
200
482
  currentUser={currentUser}
201
483
  onOpen={onOpen}
202
484
  onMessageClick={onMessageClick}
485
+ isDesktopView={isDesktopView}
486
+ isSmallScreen={isSmallScreen}
203
487
  />
204
488
  );
205
489
  })}
@@ -1,2 +1,3 @@
1
1
  export { MessageSliceRenderer } from './MessageSliceRenderer';
2
2
  export { SlackLikeMessageGroup } from './SlackLikeMessageGroup';
3
+ export { ModernMessageGroupComponent } from './ModernMessageGroup';
@@ -3,6 +3,8 @@ export {
3
3
  LeftSidebar,
4
4
  RightSidebar,
5
5
  MessageInput,
6
+ MessageInputComponent,
7
+ InputComponent,
6
8
  Messages,
7
9
  CommonMessage,
8
10
  MessageSliceRenderer,
@@ -11,5 +13,7 @@ export {
11
13
  UploadImageButton,
12
14
  UserModalContent,
13
15
  ServiceInboxItem,
16
+ MessagesBuilderUi,
14
17
  } from './InboxMessage';
15
18
  export { ChatMessageFiller, ChatMessageFill2 } from './slot-fill';
19
+ export { AIAgent } from './AIAgent';
package/src/compute.ts CHANGED
@@ -25,7 +25,7 @@ export const messengerPageStore: IRouteModule[] | { [key: string]: any } = [
25
25
  component: () => import('./container/InboxWithLoader'),
26
26
  tab: 'Chat App',
27
27
  position: IMenuPosition.Middle,
28
- // authority: [PreDefineAccountPermissions.secureUser],
28
+ //authority: [PreDefineAccountPermissions.secureUser],
29
29
  name: 'Inbox',
30
30
  path: '/o/:orgName/inbox',
31
31
  },
@@ -41,10 +41,91 @@ export const messengerPageStore: IRouteModule[] | { [key: string]: any } = [
41
41
  path: '//o/:orgName/direct-message/:id?/:postId?',
42
42
  // path: '/o/:orgName/inbox',
43
43
  },
44
+ // {
45
+ // exact: false,
46
+ // icon: 'AiOutlineInbox',
47
+ // key: 'ai-messenger',
48
+ // component: () => import('./container/AiInboxWithLoader'),
49
+ // tab: 'DM',
50
+ // position: IMenuPosition.Middle,
51
+ // // authority: [PreDefineAccountPermissions.secureUser],
52
+ // name: 'AiMessenger',
53
+ // path: '//o/:orgName/ai-messenger/:id?/:postId?',
54
+ // // path: '/o/:orgName/inbox',
55
+ // },
56
+ {
57
+ exact: false,
58
+ icon: 'AiOutlineInbox',
59
+ key: 'ai-messenger',
60
+ component: () => import('./container/InboxWithAiLoader'),
61
+ tab: 'Ai Messenger',
62
+ position: IMenuPosition.Middle,
63
+ name: 'AiMessenger',
64
+ path: '/ai-messenger',
65
+ },
66
+ {
67
+ exact: false,
68
+ icon: 'AiOutlineInbox',
69
+ key: 'ai-messenger-with-org-name',
70
+ component: () => import('./container/InboxWithAiLoader'),
71
+ tab: 'Ai Messenger',
72
+ position: IMenuPosition.Middle,
73
+ name: 'AiMessengerWithOrgName',
74
+ path: '//o/:orgName/ai-messenger',
75
+ },
76
+ // {
77
+ // exact: false,
78
+ // icon: 'AiOutlineInbox',
79
+ // key: 'ai-messenger-with-channel-id',
80
+ // component: () => import('./templates/InboxWithAi'),
81
+ // tab: 'Ai Messenger',
82
+ // position: IMenuPosition.Middle,
83
+ // name: 'AiMessengerWithChannelId',
84
+ // path: '//o?/:orgName?/ai-messenger/:id',
85
+ // },
86
+
87
+ // {
88
+ // exact: false,
89
+ // icon: 'AiOutlineInbox',
90
+ // key: 'messenger-ai',
91
+ // component: () => import('./container/InboxAiLoader'),
92
+ // tab: 'Ai Messenger',
93
+ // position: IMenuPosition.Middle,
94
+ // name: 'MessengerAi',
95
+ // path: '/messenger-ai',
96
+ // },
97
+ {
98
+ exact: false,
99
+ icon: 'AiOutlineInbox',
100
+ key: 'ai-messenger-with-message-app',
101
+ component: () => import('./container/InboxAiMessagesLoader'),
102
+ tab: 'Ai Messenger',
103
+ position: IMenuPosition.Middle,
104
+ name: 'AiMessengerWithMessageApp',
105
+ path: '/ai-messenger/app',
106
+ },
107
+ // {
108
+ // exact: false,
109
+ // icon: 'AiOutlineInbox',
110
+ // key: 'ai-messenger-with-preview',
111
+ // component: () => import('./container/InboxWithAiLoader'),
112
+ // tab: 'Ai Messenger',
113
+ // position: IMenuPosition.Middle,
114
+ // name: 'AiMessengerWithPreview',
115
+ // path: '//o?/:orgName?/ai-messenger/app/:id/preview',
116
+ // },
44
117
  ];
45
118
 
46
119
  // get only selected Routes to work
47
- const selectedRoutes = ['inbox', 'direct-message'];
120
+ const selectedRoutes = [
121
+ 'inbox',
122
+ 'direct-message',
123
+ 'ai-messenger',
124
+ 'ai-messenger-with-org-name',
125
+ 'ai-messenger-with-channel-id',
126
+ 'ai-messenger-with-message-app',
127
+ 'ai-messenger-with-preview',
128
+ ];
48
129
 
49
130
  const filteredRoutes = getFilteredRoutes(messengerPageStore, selectedRoutes);
50
131
 
@@ -4,8 +4,14 @@ import { getEnvironment } from '@common-stack/core';
4
4
  const env = getEnvironment();
5
5
 
6
6
  export const config = cleanEnv(env, {
7
+ CLIENT_URL: str({ default: 'http://localhost:3011' }),
7
8
  WEB_INBOX_MESSEGE_PATH: str({ default: 'inbox' }),
8
9
  WEB_THREAD_MESSEGE_PATH: str({ default: 'thread' }),
9
10
  MESSAGES_PER_PAGE: num({ devDefault: 10, default: 10 }),
10
11
  FILES_PER_MESSAGE: num({ default: 10 }),
12
+ VITE_OPENAI_API_KEY: str({ default: '' }),
13
+ VITE_ANTHROPIC_API_KEY: str({ default: '' }),
14
+ ANTHROPIC_API_KEY: str({ default: '' }),
15
+ NEWS_API_KEY: str({ default: '' }),
16
+ OPENAI_API_KEY: str({ default: '' }),
11
17
  });