@stack-spot/ai-chat-widget 1.20.2-beta.0 → 1.20.2-beta.10

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 (76) hide show
  1. package/dist/app-metadata.json +6 -6
  2. package/dist/components/ProgressBar.d.ts +5 -1
  3. package/dist/components/ProgressBar.d.ts.map +1 -1
  4. package/dist/components/ProgressBar.js +8 -8
  5. package/dist/components/ProgressBar.js.map +1 -1
  6. package/dist/components/Selector/index.d.ts +1 -1
  7. package/dist/components/Selector/index.d.ts.map +1 -1
  8. package/dist/components/Selector/index.js +4 -4
  9. package/dist/components/Selector/index.js.map +1 -1
  10. package/dist/layout.css +2 -1
  11. package/dist/views/Agents/AgentDescription.d.ts +2 -2
  12. package/dist/views/Agents/AgentDescription.d.ts.map +1 -1
  13. package/dist/views/Agents/AgentDescription.js +1 -3
  14. package/dist/views/Agents/AgentDescription.js.map +1 -1
  15. package/dist/views/Agents/AgentsPanel.d.ts.map +1 -1
  16. package/dist/views/Agents/AgentsPanel.js +2 -2
  17. package/dist/views/Agents/AgentsPanel.js.map +1 -1
  18. package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
  19. package/dist/views/Agents/AgentsTab.js +5 -16
  20. package/dist/views/Agents/AgentsTab.js.map +1 -1
  21. package/dist/views/Agents/useAgentFavorites.d.ts +1 -1
  22. package/dist/views/Agents/useAgentFavorites.js +3 -3
  23. package/dist/views/Agents/useAgentFavorites.js.map +1 -1
  24. package/dist/views/Chat/ChatMessage.d.ts +2 -2
  25. package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
  26. package/dist/views/Chat/ChatMessage.js +14 -10
  27. package/dist/views/Chat/ChatMessage.js.map +1 -1
  28. package/dist/views/Chat/styled.d.ts.map +1 -1
  29. package/dist/views/Chat/styled.js +10 -4
  30. package/dist/views/Chat/styled.js.map +1 -1
  31. package/dist/views/ChatHistory/utils.d.ts.map +1 -1
  32. package/dist/views/ChatHistory/utils.js +3 -13
  33. package/dist/views/ChatHistory/utils.js.map +1 -1
  34. package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
  35. package/dist/views/MessageInput/AgentSelector.js +11 -19
  36. package/dist/views/MessageInput/AgentSelector.js.map +1 -1
  37. package/dist/views/MessageInput/ButtonAgent.d.ts.map +1 -1
  38. package/dist/views/MessageInput/ButtonAgent.js +3 -4
  39. package/dist/views/MessageInput/ButtonAgent.js.map +1 -1
  40. package/dist/views/MessageInput/ButtonBar.d.ts +17 -0
  41. package/dist/views/MessageInput/ButtonBar.d.ts.map +1 -0
  42. package/dist/views/MessageInput/ButtonBar.js +16 -0
  43. package/dist/views/MessageInput/ButtonBar.js.map +1 -0
  44. package/dist/views/MessageInput/InfoBar.d.ts.map +1 -1
  45. package/dist/views/MessageInput/InfoBar.js +2 -2
  46. package/dist/views/MessageInput/InfoBar.js.map +1 -1
  47. package/dist/views/MessageInput/SelectContent.d.ts +2 -0
  48. package/dist/views/MessageInput/SelectContent.d.ts.map +1 -0
  49. package/dist/views/MessageInput/SelectContent.js +48 -0
  50. package/dist/views/MessageInput/SelectContent.js.map +1 -0
  51. package/dist/views/MessageInput/dictionary.js +2 -2
  52. package/dist/views/MessageInput/dictionary.js.map +1 -1
  53. package/dist/views/MessageInput/index.d.ts.map +1 -1
  54. package/dist/views/MessageInput/index.js +4 -8
  55. package/dist/views/MessageInput/index.js.map +1 -1
  56. package/dist/views/MessageInput/styled.d.ts +6 -1
  57. package/dist/views/MessageInput/styled.d.ts.map +1 -1
  58. package/dist/views/MessageInput/styled.js +60 -22
  59. package/dist/views/MessageInput/styled.js.map +1 -1
  60. package/package.json +1 -1
  61. package/src/app-metadata.json +2 -2
  62. package/src/components/ProgressBar.tsx +3 -3
  63. package/src/layout.css +2 -1
  64. package/src/views/Chat/ChatMessage.tsx +45 -16
  65. package/src/views/Chat/styled.ts +10 -4
  66. package/src/views/MessageInput/ButtonBar.tsx +2 -2
  67. package/src/views/MessageInput/SelectContent.tsx +45 -12
  68. package/src/views/MessageInput/styled.ts +19 -21
  69. package/dist/utils/agent.d.ts +0 -2
  70. package/dist/utils/agent.d.ts.map +0 -1
  71. package/dist/utils/agent.js +0 -2
  72. package/dist/utils/agent.js.map +0 -1
  73. package/dist/views/MessageInput/ButtonGroup.d.ts +0 -29
  74. package/dist/views/MessageInput/ButtonGroup.d.ts.map +0 -1
  75. package/dist/views/MessageInput/ButtonGroup.js +0 -34
  76. package/dist/views/MessageInput/ButtonGroup.js.map +0 -1
@@ -1,17 +1,58 @@
1
1
  import { IconButton } from '@citric/ui';
2
2
  import { theme } from '@stack-spot/portal-theme';
3
3
  import { styled } from 'styled-components';
4
- const INFO_BAR_HEIGHT = 42;
4
+ const INFO_BAR_HEIGHT = 38;
5
5
  const INFO_BAR_DISPLACEMENT = 4;
6
6
  export const MAX_INPUT_HEIGHT = 300;
7
7
  export const MIN_INPUT_HEIGHT = 24;
8
+ export const SelectionBarWrapper = styled.div `
9
+ display: inline-flex;
10
+ justify-content: space-between;
11
+ position: relative;
12
+ padding: 8px;
13
+ background-color: ${theme.color.light[500]};
14
+ border-bottom-left-radius: 4px;
15
+ border-bottom-right-radius: 4px;
16
+ border: 2px solid ${({ $inputFocused }) => theme.color.light[$inputFocused ? 600 : 500]};
17
+ border-top: none;
18
+
19
+ .selection-list {
20
+ opacity: 0;
21
+ transition: height 0.4s, opacity 0.3s;
22
+ }
23
+ .visible {
24
+ opacity: 1;
25
+ }
26
+
27
+ .selection-list-content {
28
+ background-color: ${theme.color.light[500]};
29
+ }
30
+
31
+ ul {
32
+ list-style: none;
33
+ padding: 0;
34
+ margin: 12px;
35
+ min-width: 225px;
36
+ }
37
+ li {
38
+ cursor: pointer;
39
+ svg {
40
+ width: 16px;
41
+ height: 16px;
42
+ }
43
+ &:hover {
44
+ background-color: ${theme.color.light[600]}
45
+ }
46
+ a:hover {
47
+ background-color: ${theme.color.light[600]}
48
+ }
49
+ }
50
+ `;
8
51
  export const MessageInputBox = styled.div `
9
52
  display: flex;
10
53
  flex-direction: column;
11
54
 
12
55
  > .info-bar {
13
- margin-top: 8px;
14
- margin-bottom: -3px;
15
56
  position: relative;
16
57
  overflow: hidden;
17
58
 
@@ -31,14 +72,14 @@ export const MessageInputBox = styled.div `
31
72
  top: 0;
32
73
  left: 0;
33
74
  right: 0;
34
- border-top-left-radius: 10px;
35
- border-top-right-radius: 10px;
36
75
  height: ${INFO_BAR_HEIGHT}px;
37
- padding: 6px 4px 0;
76
+ padding-top: 8px;
38
77
  background-color: ${theme.color.light[500]};
39
78
  display: flex;
40
79
  flex-direction: row;
41
- gap: 6px;
80
+ gap: 4px;
81
+ border-right: 2px solid ${({ $inputFocused }) => theme.color.light[$inputFocused ? 600 : 500]};
82
+ border-left: 2px solid ${({ $inputFocused }) => theme.color.light[$inputFocused ? 600 : 500]};
42
83
 
43
84
  .list-overflow {
44
85
  max-width: calc(100% - 30px); // close button + gap
@@ -91,16 +132,19 @@ export const MessageInputBox = styled.div `
91
132
  flex-direction: row;
92
133
  gap: 8px;
93
134
  align-items: end;
94
- border-radius: 4px;
95
- border: 1px solid ${theme.color.light[500]};
96
- background-color: ${theme.color.light[300]};
135
+ border-top-left-radius: 4px;
136
+ border-top-right-radius: 4px;
137
+ border: 2px solid ${theme.color.light[500]};
138
+
139
+ background-color: ${theme.color.light[500]};
97
140
  padding: 10px 8px;
98
141
  transition: border-color 0.3s, background-color 0.3s;
99
142
 
100
143
  &.focused {
101
- border-color: ${theme.color.primary[500]};
144
+ border: 2px solid ${theme.color.light[600]};
102
145
  }
103
146
 
147
+
104
148
  &.disabled {
105
149
  background-color: ${theme.color.light[500]};
106
150
  }
@@ -119,18 +163,12 @@ export const MessageInputBox = styled.div `
119
163
  button {
120
164
  border: none;
121
165
  border-radius: 2px;
122
- opacity: 0.6;
166
+ /* opacity: 0.6; */
123
167
  transition: background-color 0.2s, opacity 0.2s;
124
- background-color: transparent;
168
+ /* background-color: transparent; */
125
169
  padding: 0;
126
170
 
127
- svg {
128
- fill: ${theme.color.light[700]};
129
- width: 16px;
130
- height: 16px;
131
- }
132
-
133
- &:hover {
171
+ /* &:hover {
134
172
  background-color: ${theme.color.light[500]};
135
173
  }
136
174
 
@@ -141,7 +179,7 @@ export const MessageInputBox = styled.div `
141
179
  }
142
180
  svg {
143
181
  fill: ${theme.color.inverse.contrastText};
144
- }
182
+ }
145
183
  }
146
184
 
147
185
  &.expand {
@@ -154,7 +192,7 @@ export const MessageInputBox = styled.div `
154
192
  svg {
155
193
  transform: rotate(180deg);
156
194
  }
157
- }
195
+ } */
158
196
 
159
197
  &.agent {
160
198
  border-radius: 50%;
@@ -1 +1 @@
1
- {"version":3,"file":"styled.js","sourceRoot":"","sources":["../../../src/views/MessageInput/styled.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE1C,MAAM,eAAe,GAAG,EAAE,CAAA;AAC1B,MAAM,qBAAqB,GAAG,CAAC,CAAA;AAC/B,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAA;AACnC,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAA;AAElC,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;kBAYvB,eAAe,GAAG,qBAAqB;;;;;;;;;;;;;;;;gBAgBzC,eAAe;;0BAEL,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA+BtC,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;0BA0BM,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;0BACtB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;wBAKxB,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;;;;4BAIpB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;gBAuBlC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;4BAMV,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;4BAItB,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;;;;;kBAKlC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAuD5C,UAAU;;;;;;;;;;;;;;8BAcc,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;8BACtB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;gCAQpB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;oBAOlC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;cAoBpC,gBAAgB;;;;;;;;CAQ7B,CAAA"}
1
+ {"version":3,"file":"styled.js","sourceRoot":"","sources":["../../../src/views/MessageInput/styled.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE1C,MAAM,eAAe,GAAG,EAAE,CAAA;AAC1B,MAAM,qBAAqB,GAAG,CAAC,CAAA;AAC/B,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAA;AACnC,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAA;AAElC,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAA2B;;;;;sBAKlD,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;sBAGtB,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;;;;;;;;;;;;wBAYjE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;0BAgBpB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;0BAGtB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;CAG/C,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAA2B;;;;;;;;;;kBAUlD,eAAe,GAAG,qBAAqB;;;;;;;;;;;;;;gBAczC,eAAe;;0BAEL,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;gCAIhB,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;+BACpE,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4BxF,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;0BA2BM,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;0BAEtB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;4BAKpB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;4BAKtB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;4BAuBtB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;4BAItB,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;;;;;kBAKlC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAuD5C,UAAU;;;;;;;;;;;;;;8BAcc,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;8BACtB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;gCAQpB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;oBAOlC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;cAoBpC,gBAAgB;;;;;;;;CAQ7B,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stack-spot/ai-chat-widget",
3
- "version": "1.20.2-beta.0",
3
+ "version": "1.20.2-beta.10",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stack-spot/ai-chat-widget",
3
- "version": "1.20.2",
4
- "date": "Wed May 14 2025 11:51:55 GMT-0300 (Horário Padrão de Brasília)",
3
+ "version": "1.20.2-beta.10",
4
+ "date": "Mon May 19 2025 15:28:06 GMT-0300 (Horário Padrão de Brasília)",
5
5
  "dependencies": [
6
6
  {
7
7
  "name": "@stack-spot/app-metadata",
@@ -129,15 +129,15 @@ const Styled = styled.div<{ $bg: string[], $fg: string[], $shimmer: string[], $a
129
129
  &:before {
130
130
  content: '';
131
131
  display: block;
132
- width: 33%;
132
+ width: 100%;
133
133
  height: 100%;
134
134
  background: ${({ $fg, $animate, $bg }) => $animate ? gradientFromColorArray($fg) : $bg};
135
- animation: ${({ $animate }) => $animate ? 'slide 1.5s infinite forwards' : 'none'};
135
+ animation: ${({ $animate }) => $animate ? 'slide .5s infinite forwards' : 'none'};
136
136
  }
137
137
 
138
138
  @keyframes slide {
139
139
  from {
140
- margin-left: -33%;
140
+ margin-left: -100%;
141
141
  }
142
142
  to {
143
143
  margin-left: 100%;
package/src/layout.css CHANGED
@@ -31,7 +31,6 @@
31
31
  background-color: var(--light-400);
32
32
  border-radius: 4px;
33
33
  position: relative;
34
- overflow: hidden;
35
34
  width: 100%;
36
35
  height: 100%;
37
36
 
@@ -104,11 +103,13 @@
104
103
  }
105
104
 
106
105
  .chat-content {
106
+ padding-bottom: 16px;
107
107
  display: flex;
108
108
  flex-direction: column;
109
109
  flex: 1;
110
110
  flex-basis: 0;
111
111
  overflow: auto;
112
+ padding-right: 12px;
112
113
  }
113
114
 
114
115
  .chat-right-panel {
@@ -1,6 +1,6 @@
1
1
  import { Box, Button, Checkbox, Flex, IconBox, Input, Label, Radio, Text } from '@citric/core'
2
2
  import { Cog, Copy, Dislike, DislikeFill, Like, LikeFill, TimesCircle } from '@citric/icons'
3
- import { Avatar, Badge, IconButton } from '@citric/ui'
3
+ import { Badge, IconButton } from '@citric/ui'
4
4
  import { agentClient } from '@stack-spot/portal-network'
5
5
  import { listToClass } from '@stack-spot/portal-theme'
6
6
  import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
@@ -37,7 +37,7 @@ interface Props extends CustomMessage {
37
37
  /**
38
38
  * The name of the user currently logged in (will be used if the agent type of the message is "user").
39
39
  */
40
- username: string,
40
+ username?: string,
41
41
  /**
42
42
  * Whether or not this is the last message in the chat. This is important for disabling action buttons in messages that are no longer
43
43
  * relevant.
@@ -169,14 +169,15 @@ const RenderInputsEntry = ({ isLast, entry, value, setValue, labels, setLabels }
169
169
  /**
170
170
  * Renders a message (ChatEntry) in the chat.
171
171
  */
172
- export const ChatMessage = ({ message, username, isLast, beforeMessage, afterMessage }: Props) => {
172
+ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Props) => {
173
173
  const t = useTranslate(dictionary)
174
174
  const [liked, setLiked] = useState<boolean | undefined>()
175
175
  const [value, setValue] = useState<string[]>(message.getValue()?.initialValue ?? [])
176
176
  const [labels, setLabels] = useState<string[]>(message.getValue()?.initialValue ?? [])
177
177
  const entry = useChatEntry(message)
178
178
  const dateFormatter = useDateFormatter()
179
- const userInfo = entry.agentType === 'user' ? <Avatar size="xs">{username}</Avatar> : <AgentInfo agent={entry.agent} />
179
+ // const userInfo = entry.agentType === 'user' ? <Avatar size="xs">{username}</Avatar> : <AgentInfo agent={entry.agent} />
180
+ const userInfo = entry.agentType === 'user' ? <></> : <AgentInfo agent={entry.agent} />
180
181
  const date = new Date(entry.updated ?? '')
181
182
  const shouldShowFooter = entry.updated && !isNaN(date.getTime())
182
183
  const ref = useRef<HTMLLIElement>(null)
@@ -185,7 +186,8 @@ export const ChatMessage = ({ message, username, isLast, beforeMessage, afterMes
185
186
  const chat = useCurrentChat()
186
187
  const agentId = entry.agent?.id ?? ''
187
188
  const [agent] = agentClient.agentById.useStatefulQuery({ agentId, builtIn: !!entry?.agent?.builtIn }, { enabled: !!agentId })
188
-
189
+ const [copied, setCopied] = useState(false)
190
+
189
191
  useChatScrollToBottomEffect(ref, [entry])
190
192
 
191
193
  const detailKS = useCallback(({ name, slug, documentScore, documentId }: Required<TextChatEntry>['knowledgeSources'][number]) => {
@@ -250,6 +252,12 @@ export const ChatMessage = ({ message, username, isLast, beforeMessage, afterMes
250
252
  )}
251
253
  </>, [entry, isLast, runAction])
252
254
 
255
+ const handleCopy = () => {
256
+ onCopyAll(entry, chat)
257
+ setCopied(true)
258
+ setTimeout(() => setCopied(false), 1000)
259
+ }
260
+
253
261
  const renderContent = () => {
254
262
  if (entry.type === 'md') {
255
263
  return <>
@@ -257,13 +265,7 @@ export const ChatMessage = ({ message, username, isLast, beforeMessage, afterMes
257
265
  {renderActions()}
258
266
  </>
259
267
  }
260
- if (entry.type === 'text') {
261
- return <>
262
- <p className="plain-text">{entry.content}</p>
263
- {renderActions()}
264
- </>
265
- }
266
-
268
+
267
269
  return <form>
268
270
  <RenderInputsEntry entry={entry} isLast={isLast} value={value} setValue={setValue} setLabels={setLabels} labels={labels} />
269
271
  <Box mt="4">
@@ -322,22 +324,47 @@ export const ChatMessage = ({ message, username, isLast, beforeMessage, afterMes
322
324
  {shouldShowFooter && <div className="message-footer">
323
325
  {entry.agentType === 'bot' && !entry.error && <div className="message-actions">
324
326
  {entry.type === 'md' && (
325
- <IconButton title={t.copy} aria-label={t.copy} onClick={() => onCopyAll(entry, chat)}>
327
+ <IconButton appearance="square" color="light" title={t.copy} aria-label={t.copy} onClick={handleCopy}>
326
328
  <Copy />
329
+ {copied && (
330
+ <div style={{ fontSize: 12, marginLeft: 4 }}>
331
+ <Text appearance="microtext1" colorScheme="light.700">{t.copied}</Text>
332
+ </div>
333
+ )}
327
334
  </IconButton>
328
335
  )}
329
336
  {entry.messageId && (
330
337
  <>
331
- <IconButton title={t.like} aria-label={t.like} onClick={like}>
338
+ <IconButton appearance="square" color="light" title={t.like} aria-label={t.like} onClick={like}>
332
339
  {liked === true ? <LikeFill /> : <Like />}
333
340
  </IconButton>
334
- <IconButton title={t.dislike} aria-label={t.dislike} onClick={dislike}>
341
+ <IconButton appearance="square" color="light" title={t.dislike} aria-label={t.dislike} onClick={dislike}>
335
342
  {liked === false ? <DislikeFill /> : <Dislike />}
336
343
  </IconButton>
337
344
  </>
338
345
  )}
339
346
  </div>}
340
- <Text appearance="microtext1" className="chat-date">
347
+
348
+ {entry.agentType === 'user' && (
349
+ <div className="message-actions">
350
+ <IconButton
351
+ appearance="square"
352
+ color="light"
353
+ title={t.copy}
354
+ aria-label={t.copy}
355
+ onClick={handleCopy}
356
+ size="sm"
357
+ >
358
+ <Copy />
359
+ {copied && (
360
+ <div style={{ fontSize: 12, marginLeft: 4 }}>
361
+ <Text appearance="microtext1" colorScheme="light.700">{t.copied}</Text>
362
+ </div>
363
+ )}
364
+ </IconButton>
365
+ </div>
366
+ )}
367
+ <Text as="label" appearance="microtext1" className="chat-date">
341
368
  {dateFormatter.formatForChatMessage(date)}
342
369
  </Text>
343
370
  </div>}
@@ -352,6 +379,7 @@ const dictionary = {
352
379
  dislike: 'Dislike',
353
380
  tools: 'Tools',
354
381
  openToolsPanel: 'Open the tools panel to see more details.',
382
+ copied: 'Copied',
355
383
  },
356
384
  pt: {
357
385
  copy: 'Copiar',
@@ -359,5 +387,6 @@ const dictionary = {
359
387
  dislike: 'Não gostei',
360
388
  tools: 'Ferramentas',
361
389
  openToolsPanel: 'Abrir o painel de ferramentas para ver mais detalhes.',
390
+ copied: 'Copiado',
362
391
  },
363
392
  } satisfies Dictionary
@@ -11,7 +11,8 @@ export const ChatList: IStyledComponentBase<
11
11
  flex-direction: column;
12
12
  justify-content: end;
13
13
  gap: 20px;
14
- margin: 0 5px;
14
+ /* margin: 0 5px; */
15
+ margin: 0;
15
16
  padding: 0;
16
17
  flex: 1;
17
18
 
@@ -61,14 +62,18 @@ export const ChatList: IStyledComponentBase<
61
62
  .message-footer {
62
63
  display: flex;
63
64
  flex-direction: row;
65
+ align-items: center;
66
+ gap: 8px;
64
67
 
65
68
  .message-actions {
66
69
  display: flex;
67
70
  flex-direction: row;
68
- gap: 8px;
71
+ gap: 4px;
69
72
  }
70
73
 
71
74
  .chat-date {
75
+ display: inline-block;
76
+ align-content: flex-end;
72
77
  opacity: 0.6;
73
78
  margin-left: auto;
74
79
  }
@@ -145,9 +150,10 @@ export const ChatList: IStyledComponentBase<
145
150
  gap: 8px;
146
151
 
147
152
  .message-content {
148
- padding: 10px;
153
+ padding: 16px;
154
+ border-radius: 24px;
155
+ border-top-right-radius: 0;
149
156
  background-color: ${theme.color.light[500]};
150
- border-radius: 4px;
151
157
 
152
158
  .markdown > p:first-child {
153
159
  margin-top: 0;
@@ -28,8 +28,8 @@ export const ButtonBar = ({ onSend, isLoading, focused }: SelectionBarProps) =>
28
28
  const features = useCurrentChatState('features')
29
29
 
30
30
  return (
31
- <SelectionBarWrapper $inputFocused={focused}>
32
- <Flex>
31
+ <SelectionBarWrapper className="button-group" $inputFocused={focused}>
32
+ <Flex sx={{ gap: '4px' }}>
33
33
  <SelectContent />
34
34
  {features.editor && (
35
35
  <IconButton color="light" appearance="square" aria-label={t.code} title={t.code} onClick={() => widget.set('panel', 'editor')}>
@@ -1,13 +1,52 @@
1
1
  import { Clip, KnowledgeSource, Spaces, Stack } from '@citric/icons'
2
2
  import { IconButton } from '@citric/ui'
3
3
  import { SelectionList } from '@stack-spot/portal-components/SelectionList'
4
- import { useState } from 'react'
5
- import { useWidget } from '../../context/hooks'
4
+ import { useMemo, useState } from 'react'
5
+ import { useCurrentChatState, useWidget } from '../../context/hooks'
6
+
7
+ type chatFeatures = 'workspace' | 'knowledgeSource' | 'stack'
8
+ type chatPanel = 'ks' | 'workspace' | 'stack'
6
9
 
7
10
  export const SelectContent = () => {
8
11
  const widget = useWidget()
9
12
  const [visibleMenu, setVisibleMenu] = useState(false)
10
-
13
+ const features = useCurrentChatState('features')
14
+ const hasFeatureButtons = features.workspace || features.knowledgeSource || features.stack
15
+
16
+ const itemConfigs = [
17
+ {
18
+ key: 'knowledgeSource',
19
+ label: 'Knowledge Sources',
20
+ icon: <KnowledgeSource />,
21
+ panel: 'ks',
22
+ },
23
+ {
24
+ key: 'stack',
25
+ label: 'Stacks AI',
26
+ icon: <Stack />,
27
+ panel: 'stack',
28
+ },
29
+ {
30
+ key: 'workspace',
31
+ label: 'Spots',
32
+ icon: <Spaces />,
33
+ panel: 'workspace',
34
+ },
35
+ ]
36
+
37
+ const listItems = useMemo(() =>
38
+ itemConfigs.filter(chatFeatures => features[chatFeatures.key as chatFeatures])
39
+ .map(chatFeatures => ({
40
+ label: chatFeatures.label,
41
+ icon: chatFeatures.icon,
42
+ onClick: () => {
43
+ widget.set('panel', chatFeatures.panel as chatPanel)
44
+ setVisibleMenu(false)
45
+ },
46
+ })), [features, widget])
47
+
48
+ if (!hasFeatureButtons) return null
49
+
11
50
  return (
12
51
  <>
13
52
  <IconButton
@@ -17,24 +56,18 @@ export const SelectContent = () => {
17
56
  title="title"
18
57
  data-test-hint="button-hint"
19
58
  aria-label="aria-label"
20
- onClick={() => setVisibleMenu(state => !state)} >
59
+ onClick={() => setVisibleMenu(state => !state)}>
21
60
  <Clip />
22
61
  </IconButton>
23
62
  <SelectionList
24
63
  style={{
25
64
  position: 'absolute',
26
- top: '-150px',
65
+ top: '-140px',
27
66
  }}
28
67
  id="teste"
29
68
  visible={visibleMenu}
30
69
  onHide={() => setVisibleMenu(false)}
31
- items={
32
- [
33
- { label: 'Knowledge Sources', icon: <KnowledgeSource />, onClick: () => widget.set('panel', 'ks') },
34
- { label: 'Stacks AI', icon: <Stack />, onClick: () => widget.set('panel', 'stack') },
35
- { label: 'Spots', icon: <Spaces />, onClick: () => widget.set('panel', 'workspace') },
36
- ]
37
- }
70
+ items={listItems}
38
71
  />
39
72
  </>
40
73
  )
@@ -2,7 +2,7 @@ import { IconButton } from '@citric/ui'
2
2
  import { theme } from '@stack-spot/portal-theme'
3
3
  import { styled } from 'styled-components'
4
4
 
5
- const INFO_BAR_HEIGHT = 42
5
+ const INFO_BAR_HEIGHT = 38
6
6
  const INFO_BAR_DISPLACEMENT = 4
7
7
  export const MAX_INPUT_HEIGHT = 300
8
8
  export const MIN_INPUT_HEIGHT = 24
@@ -12,15 +12,24 @@ export const SelectionBarWrapper = styled.div<{$inputFocused?: boolean}>`
12
12
  justify-content: space-between;
13
13
  position: relative;
14
14
  padding: 8px;
15
- padding-top: 6px;
16
15
  background-color: ${theme.color.light[500]};
17
16
  border-bottom-left-radius: 4px;
18
17
  border-bottom-right-radius: 4px;
19
18
  border: 2px solid ${({ $inputFocused }) => theme.color.light[$inputFocused ? 600 : 500]};
20
19
  border-top: none;
20
+
21
+ .selection-list {
22
+ opacity: 0;
23
+ transition: height 0.4s, opacity 0.3s;
24
+ }
25
+ .visible {
26
+ opacity: 1;
27
+ }
28
+
21
29
  .selection-list-content {
22
- background-color: ${theme.color.light[500]}
30
+ background-color: ${theme.color.light[500]};
23
31
  }
32
+
24
33
  ul {
25
34
  list-style: none;
26
35
  padding: 0;
@@ -45,11 +54,8 @@ export const SelectionBarWrapper = styled.div<{$inputFocused?: boolean}>`
45
54
  export const MessageInputBox = styled.div<{$inputFocused?: boolean}>`
46
55
  display: flex;
47
56
  flex-direction: column;
48
- margin-top: 8px;
49
57
 
50
58
  > .info-bar {
51
- padding-top: 8px;
52
- /* padding-bottom: -3px; */
53
59
  position: relative;
54
60
  overflow: hidden;
55
61
 
@@ -69,14 +75,12 @@ export const MessageInputBox = styled.div<{$inputFocused?: boolean}>`
69
75
  top: 0;
70
76
  left: 0;
71
77
  right: 0;
72
- /* border-top-left-radius: 10px;
73
- border-top-right-radius: 10px; */
74
78
  height: ${INFO_BAR_HEIGHT}px;
75
- padding: 6px 8px 0;
79
+ padding-top: 8px;
76
80
  background-color: ${theme.color.light[500]};
77
81
  display: flex;
78
82
  flex-direction: row;
79
- gap: 6px;
83
+ gap: 4px;
80
84
  border-right: 2px solid ${({ $inputFocused }) => theme.color.light[$inputFocused ? 600 : 500]};
81
85
  border-left: 2px solid ${({ $inputFocused }) => theme.color.light[$inputFocused ? 600 : 500]};
82
86
 
@@ -162,18 +166,12 @@ export const MessageInputBox = styled.div<{$inputFocused?: boolean}>`
162
166
  button {
163
167
  border: none;
164
168
  border-radius: 2px;
165
- opacity: 0.6;
169
+ /* opacity: 0.6; */
166
170
  transition: background-color 0.2s, opacity 0.2s;
167
- background-color: transparent;
171
+ /* background-color: transparent; */
168
172
  padding: 0;
169
173
 
170
- svg {
171
- fill: ${theme.color.light[700]};
172
- width: 16px;
173
- height: 16px;
174
- }
175
-
176
- &:hover {
174
+ /* &:hover {
177
175
  background-color: ${theme.color.light[500]};
178
176
  }
179
177
 
@@ -184,7 +182,7 @@ export const MessageInputBox = styled.div<{$inputFocused?: boolean}>`
184
182
  }
185
183
  svg {
186
184
  fill: ${theme.color.inverse.contrastText};
187
- }
185
+ }
188
186
  }
189
187
 
190
188
  &.expand {
@@ -197,7 +195,7 @@ export const MessageInputBox = styled.div<{$inputFocused?: boolean}>`
197
195
  svg {
198
196
  transform: rotate(180deg);
199
197
  }
200
- }
198
+ } */
201
199
 
202
200
  &.agent {
203
201
  border-radius: 50%;
@@ -1,2 +0,0 @@
1
- export declare const isAgentDefault: (agentSlug?: string) => agentSlug is "stk_code_buddy";
2
- //# sourceMappingURL=agent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/utils/agent.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,eAAgB,MAAM,kCAAmC,CAAA"}
@@ -1,2 +0,0 @@
1
- export const isAgentDefault = (agentSlug) => agentSlug === 'stk_code_buddy';
2
- //# sourceMappingURL=agent.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/utils/agent.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,SAAkB,EAAE,EAAE,CAAC,SAAS,KAAK,gBAAgB,CAAA"}
@@ -1,29 +0,0 @@
1
- interface ButtonGroupProps {
2
- /**
3
- * Whether or not the button group is expanded.
4
- */
5
- expanded: boolean;
6
- /**
7
- * A function to set the button group as expanded or collapsed.
8
- */
9
- setExpanded: React.Dispatch<React.SetStateAction<boolean>>;
10
- /**
11
- * Whether or not the message is currently being sent. This is used to decide which button to show: send or cancel.
12
- */
13
- isLoading: boolean;
14
- /**
15
- * A function to run when the send button is clicked.
16
- */
17
- onSend: () => void;
18
- /**
19
- * A function to run when the cancel button is clicked.
20
- */
21
- onCancel: () => void;
22
- }
23
- /**
24
- * Renders the button group at right bottom side of the message input. This includes the send button as well as the buttons to open the
25
- * editor, change the stack, etc.
26
- */
27
- export declare const ButtonGroup: ({ onSend, onCancel, expanded, setExpanded, isLoading }: ButtonGroupProps) => import("react/jsx-runtime").JSX.Element;
28
- export {};
29
- //# sourceMappingURL=ButtonGroup.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ButtonGroup.d.ts","sourceRoot":"","sources":["../../../src/views/MessageInput/ButtonGroup.tsx"],"names":[],"mappings":"AAOA,UAAU,gBAAgB;IACxB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB;;OAEG;IACH,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,2DAA4D,gBAAgB,4CA0EnG,CAAA"}