@stack-spot/ai-chat-widget 1.22.0 → 1.23.1-beta.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/CHANGELOG.md +15 -0
- package/dist/StackspotAIWidget.d.ts +5 -1
- package/dist/StackspotAIWidget.d.ts.map +1 -1
- package/dist/StackspotAIWidget.js +2 -2
- package/dist/StackspotAIWidget.js.map +1 -1
- package/dist/app-metadata.json +2 -2
- package/dist/components/AgentCard/AgentCardCreate.d.ts +4 -0
- package/dist/components/AgentCard/AgentCardCreate.d.ts.map +1 -0
- package/dist/components/AgentCard/AgentCardCreate.js +35 -0
- package/dist/components/AgentCard/AgentCardCreate.js.map +1 -0
- package/dist/components/AgentCard/dictionary.d.ts +2 -0
- package/dist/components/AgentCard/dictionary.d.ts.map +1 -1
- package/dist/components/AgentCard/dictionary.js +2 -0
- package/dist/components/AgentCard/dictionary.js.map +1 -1
- package/dist/components/Code.d.ts.map +1 -1
- package/dist/components/Code.js +44 -15
- package/dist/components/Code.js.map +1 -1
- package/dist/components/QuickStartButton.d.ts +1 -7
- package/dist/components/QuickStartButton.d.ts.map +1 -1
- package/dist/components/QuickStartButton.js +4 -44
- package/dist/components/QuickStartButton.js.map +1 -1
- package/dist/components/TabManager.d.ts.map +1 -1
- package/dist/components/TabManager.js +5 -2
- package/dist/components/TabManager.js.map +1 -1
- package/dist/layout.css +17 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/views/ChatTabSelection.d.ts.map +1 -1
- package/dist/views/ChatTabSelection.js +5 -2
- package/dist/views/ChatTabSelection.js.map +1 -1
- package/dist/views/Home/BuiltInAgent.d.ts.map +1 -1
- package/dist/views/Home/BuiltInAgent.js +5 -6
- package/dist/views/Home/BuiltInAgent.js.map +1 -1
- package/dist/views/Home/CustomAgent.d.ts.map +1 -1
- package/dist/views/Home/CustomAgent.js +1 -2
- package/dist/views/Home/CustomAgent.js.map +1 -1
- package/dist/views/Home/index.d.ts +1 -1
- package/dist/views/Home/index.d.ts.map +1 -1
- package/dist/views/Home/index.js +3 -8
- package/dist/views/Home/index.js.map +1 -1
- package/dist/views/Home/styled.d.ts.map +1 -1
- package/dist/views/Home/styled.js +26 -12
- package/dist/views/Home/styled.js.map +1 -1
- package/dist/views/Home/types.d.ts +4 -0
- package/dist/views/Home/types.d.ts.map +1 -1
- package/dist/views/MessageInput/ButtonBar.d.ts +1 -5
- package/dist/views/MessageInput/ButtonBar.d.ts.map +1 -1
- package/dist/views/MessageInput/ButtonBar.js +2 -2
- package/dist/views/MessageInput/ButtonBar.js.map +1 -1
- package/dist/views/MessageInput/SelectContent.d.ts.map +1 -1
- package/dist/views/MessageInput/SelectContent.js +2 -2
- package/dist/views/MessageInput/SelectContent.js.map +1 -1
- package/dist/views/MessageInput/index.js +1 -1
- package/dist/views/MessageInput/index.js.map +1 -1
- package/dist/views/MessageInput/styled.d.ts +1 -3
- package/dist/views/MessageInput/styled.d.ts.map +1 -1
- package/dist/views/MessageInput/styled.js +4 -5
- package/dist/views/MessageInput/styled.js.map +1 -1
- package/package.json +1 -1
- package/src/StackspotAIWidget.tsx +6 -1
- package/src/app-metadata.json +2 -2
- package/src/components/AgentCard/AgentCardCreate.tsx +46 -0
- package/src/components/AgentCard/dictionary.ts +2 -0
- package/src/components/Code.tsx +91 -51
- package/src/components/QuickStartButton.tsx +9 -57
- package/src/components/TabManager.tsx +28 -12
- package/src/layout.css +17 -1
- package/src/types.ts +2 -1
- package/src/views/ChatTabSelection.tsx +5 -2
- package/src/views/Home/BuiltInAgent.tsx +7 -15
- package/src/views/Home/CustomAgent.tsx +0 -3
- package/src/views/Home/index.tsx +3 -7
- package/src/views/Home/styled.ts +26 -12
- package/src/views/Home/types.ts +4 -0
- package/src/views/MessageInput/ButtonBar.tsx +2 -6
- package/src/views/MessageInput/SelectContent.tsx +3 -2
- package/src/views/MessageInput/index.tsx +2 -2
- package/src/views/MessageInput/styled.ts +5 -6
package/src/components/Code.tsx
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Copied from the extension's webview.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { Text } from '@citric/core'
|
|
6
|
+
import { AddCode, ChevronDoubleDown, Collapse, Copy, Download } from '@citric/icons'
|
|
6
7
|
import { IconButton } from '@citric/ui'
|
|
7
8
|
import { theme, useThemeKind } from '@stack-spot/portal-theme'
|
|
8
9
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
@@ -12,6 +13,7 @@ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
|
|
|
12
13
|
import { materialDark, vs } from 'react-syntax-highlighter/dist/esm/styles/prism'
|
|
13
14
|
import styled from 'styled-components'
|
|
14
15
|
import { WithChildren } from '../types'
|
|
16
|
+
import { languages } from '../utils/programming-languages'
|
|
15
17
|
|
|
16
18
|
export type CodeAction = (
|
|
17
19
|
code: string,
|
|
@@ -53,23 +55,28 @@ const CodeBox = styled.code`
|
|
|
53
55
|
}
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
.
|
|
58
|
+
.header-code {
|
|
57
59
|
display: flex;
|
|
58
60
|
flex-direction: row;
|
|
59
|
-
justify-content:
|
|
61
|
+
justify-content: space-between;
|
|
60
62
|
background: ${theme.color.light[600]};
|
|
61
63
|
padding: 4px 6px;
|
|
62
64
|
border-top-left-radius: 6px;
|
|
63
65
|
border-top-right-radius: 6px;
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
.action-bar {
|
|
68
|
+
display: flex;
|
|
69
|
+
flex-direction: row;
|
|
70
|
+
|
|
71
|
+
button {
|
|
72
|
+
background: transparent;
|
|
73
|
+
border: none;
|
|
74
|
+
opacity: 0.75;
|
|
75
|
+
transition: opacity 0.2s;
|
|
70
76
|
|
|
71
|
-
|
|
72
|
-
|
|
77
|
+
&:hover {
|
|
78
|
+
opacity: 1;
|
|
79
|
+
}
|
|
73
80
|
}
|
|
74
81
|
}
|
|
75
82
|
}
|
|
@@ -108,6 +115,7 @@ export const Code = ({
|
|
|
108
115
|
const match = /language-(\w+)/.exec(className || '')
|
|
109
116
|
const computedLanguage = language ?? (match ?? [])[1]?.toLowerCase() ?? 'txt'
|
|
110
117
|
const content = String(children ?? '').replaceAll(/\n\t/g, '\n').trim()
|
|
118
|
+
const languageExtension = languages.find(l => l.value === computedLanguage)?.extensions?.[0] ?? '.txt'
|
|
111
119
|
|
|
112
120
|
function onClickInsert() {
|
|
113
121
|
onInsertCode?.(content, computedLanguage)
|
|
@@ -137,47 +145,75 @@ export const Code = ({
|
|
|
137
145
|
return (
|
|
138
146
|
<CodeBox className={['code-box', themeKind, className].join(' ')}>
|
|
139
147
|
{showActionBar && (
|
|
140
|
-
<div className="
|
|
141
|
-
<
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
148
|
+
<div className="header-code">
|
|
149
|
+
<div>
|
|
150
|
+
<Text appearance="code2">{computedLanguage ?? ''}</Text>
|
|
151
|
+
</div>
|
|
152
|
+
<div className="action-bar" role="toolbar">
|
|
153
|
+
<IconButton
|
|
154
|
+
aria-label={showLines ? t.hideLines : t.showLines}
|
|
155
|
+
title={showLines ? t.hideLines : t.showLines}
|
|
156
|
+
onClick={() => setShowLines(v => !v)}
|
|
157
|
+
style={{ position: 'relative', transform: showLines ? undefined : 'rotate(180deg)', transition: 'transform 0.2s' }}
|
|
158
|
+
>
|
|
159
|
+
<Collapse />
|
|
160
|
+
</IconButton>
|
|
161
|
+
<IconButton
|
|
162
|
+
aria-label={t.downloadCode}
|
|
163
|
+
title={t.downloadCode}
|
|
164
|
+
onClick={() => {
|
|
165
|
+
try {
|
|
166
|
+
const extension = languageExtension
|
|
167
|
+
const filename = `download${extension}`
|
|
168
|
+
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' })
|
|
169
|
+
const link = document.createElement('a')
|
|
170
|
+
link.href = URL.createObjectURL(blob)
|
|
171
|
+
link.download = filename
|
|
172
|
+
document.body.appendChild(link)
|
|
173
|
+
link.click()
|
|
174
|
+
document.body.removeChild(link)
|
|
175
|
+
URL.revokeObjectURL(link.href)
|
|
176
|
+
} catch (e) {
|
|
177
|
+
// eslint-disable-next-line no-console
|
|
178
|
+
console.error(t.downloadError, e)
|
|
179
|
+
}
|
|
180
|
+
}}
|
|
181
|
+
>
|
|
182
|
+
<Download />
|
|
183
|
+
</IconButton>
|
|
184
|
+
<IconButton
|
|
185
|
+
aria-label={t.copy}
|
|
186
|
+
title={t.copy}
|
|
187
|
+
onClick={onClickCopy}
|
|
188
|
+
style={{ position: 'relative' }}
|
|
189
|
+
>
|
|
190
|
+
<Copy />
|
|
191
|
+
</IconButton>
|
|
192
|
+
{onInsertCode
|
|
193
|
+
? (
|
|
194
|
+
<IconButton
|
|
195
|
+
aria-label={t.insert}
|
|
196
|
+
title={t.insert}
|
|
197
|
+
onClick={onClickInsert}
|
|
198
|
+
style={{ position: 'relative' }}
|
|
199
|
+
>
|
|
200
|
+
<ChevronDoubleDown style={{ transform: 'rotate(90deg)' }} />
|
|
201
|
+
</IconButton>
|
|
202
|
+
)
|
|
203
|
+
: null}
|
|
204
|
+
{onNewFile
|
|
205
|
+
? (
|
|
206
|
+
<IconButton
|
|
207
|
+
aria-label={t.newFile}
|
|
208
|
+
title={t.newFile}
|
|
209
|
+
onClick={onClickNewFile}
|
|
210
|
+
style={{ position: 'relative' }}
|
|
211
|
+
>
|
|
212
|
+
<AddCode />
|
|
213
|
+
</IconButton>
|
|
214
|
+
)
|
|
215
|
+
: null}
|
|
216
|
+
</div>
|
|
181
217
|
</div>
|
|
182
218
|
)}
|
|
183
219
|
<div>
|
|
@@ -205,6 +241,8 @@ const dictionary = {
|
|
|
205
241
|
newFile: 'Creates a new file with this code as its content',
|
|
206
242
|
hideLines: 'Hide line numbers',
|
|
207
243
|
showLines: 'Show line numbers',
|
|
244
|
+
downloadCode: 'Download the code',
|
|
245
|
+
downloadError: 'Error downloading code',
|
|
208
246
|
},
|
|
209
247
|
pt: {
|
|
210
248
|
copy: 'Copiar código para a área de transferência',
|
|
@@ -212,5 +250,7 @@ const dictionary = {
|
|
|
212
250
|
newFile: 'Criar um novo arquivo com este código como conteúdo',
|
|
213
251
|
hideLines: 'Esconder números das linhas',
|
|
214
252
|
showLines: 'Mostrar números das linhas',
|
|
253
|
+
downloadCode: 'Fazer download do código',
|
|
254
|
+
downloadError: 'Erro ao fazer download do código',
|
|
215
255
|
},
|
|
216
256
|
} satisfies Dictionary
|
|
@@ -1,66 +1,18 @@
|
|
|
1
|
-
import { IconBox, Text } from '@citric/core'
|
|
2
|
-
import {
|
|
3
|
-
import { styled } from 'styled-components'
|
|
1
|
+
import { Button, IconBox, Text } from '@citric/core'
|
|
2
|
+
import { WithStyle } from '@stack-spot/portal-theme'
|
|
4
3
|
import { ButtonAction } from '../types'
|
|
5
|
-
import { FadingOverflow } from './FadingOverflow'
|
|
6
4
|
|
|
7
|
-
interface Props extends ButtonAction, WithStyle {
|
|
8
|
-
background?: string,
|
|
9
|
-
/**
|
|
10
|
-
* Whether or not the vertical overflow of this button should be managed by the component {@link FadingOverflow}.
|
|
11
|
-
* @default false
|
|
12
|
-
*/
|
|
13
|
-
manageOverflow?: boolean,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* A button for quick starting a conversation.
|
|
18
|
-
*/
|
|
19
|
-
const QuickButton = styled.button<{ $color?: string, $bg?: string }>`
|
|
20
|
-
display: flex;
|
|
21
|
-
flex-direction: column;
|
|
22
|
-
padding: 12px;
|
|
23
|
-
gap: 12px;
|
|
24
|
-
background-color: ${theme.color.light[500]};
|
|
25
|
-
border: none;
|
|
26
|
-
color: inherit;
|
|
27
|
-
flex: 1;
|
|
28
|
-
border-radius: 4px;
|
|
29
|
-
border: 2px solid;
|
|
30
|
-
border-color: ${theme.color.light[500]};
|
|
31
|
-
transition: border-color 0.3s;
|
|
32
|
-
cursor: pointer;
|
|
33
|
-
text-align: left;
|
|
34
|
-
|
|
35
|
-
&:hover {
|
|
36
|
-
border-color: ${theme.color.light[600]};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
i {
|
|
40
|
-
border-radius: 2px;
|
|
41
|
-
display: flex;
|
|
42
|
-
align-items: center;
|
|
43
|
-
justify-content: center;
|
|
44
|
-
background-color: ${({ $bg }) => $bg || 'transparent'};
|
|
45
|
-
${({ $color }) => $color
|
|
46
|
-
? `
|
|
47
|
-
svg {
|
|
48
|
-
fill: ${$color};
|
|
49
|
-
}`
|
|
50
|
-
: ''
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
`
|
|
5
|
+
interface Props extends ButtonAction, WithStyle { }
|
|
54
6
|
|
|
55
|
-
export const QuickStartButton = ({ label, onClick,
|
|
7
|
+
export const QuickStartButton = ({ label, onClick, className, icon, style }: Props) => {
|
|
56
8
|
const content = <>
|
|
57
|
-
{icon && <IconBox aria-hidden>{icon}</IconBox>}
|
|
58
|
-
<Text>{label}</Text>
|
|
9
|
+
{icon && <IconBox color="light" aria-hidden>{icon}</IconBox>}
|
|
10
|
+
<Text nowrapEllipsis>{label}</Text>
|
|
59
11
|
</>
|
|
60
12
|
|
|
61
13
|
return (
|
|
62
|
-
<
|
|
63
|
-
{
|
|
64
|
-
</
|
|
14
|
+
<Button colorScheme="light" size="md" className={className} style={style} onClick={onClick}>
|
|
15
|
+
{content}
|
|
16
|
+
</Button>
|
|
65
17
|
)
|
|
66
18
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* Tabs to select chat and add new chats */
|
|
2
2
|
|
|
3
|
+
import { Button, IconBox } from '@citric/core'
|
|
3
4
|
import { TimesMini } from '@citric/icons'
|
|
4
5
|
import { IconButton } from '@citric/ui'
|
|
5
6
|
import { listToClass, theme } from '@stack-spot/portal-theme'
|
|
@@ -188,18 +189,33 @@ export function TabManager<T, Key extends React.Key>(
|
|
|
188
189
|
</li>
|
|
189
190
|
)), [tabs, active])
|
|
190
191
|
|
|
191
|
-
const extras = useMemo(() => buttons.map(({ label, onClick, icon, className, style }) => (
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
192
|
+
const extras = useMemo(() => buttons.map(({ ariaLabel, label, onClick, icon, className, style }) => (
|
|
193
|
+
<>
|
|
194
|
+
{label ?
|
|
195
|
+
<Button
|
|
196
|
+
sx={{ paddingLeft: 0, marginRight: '4px', fontWeight: '400' }}
|
|
197
|
+
colorScheme="light"
|
|
198
|
+
size="md"
|
|
199
|
+
key={ariaLabel}
|
|
200
|
+
title={label}
|
|
201
|
+
style={style}
|
|
202
|
+
onClick={onClick}>
|
|
203
|
+
<IconBox size="sm" sx={{ width: '32px', height: '16px', paddingInline: '8px' }} >
|
|
204
|
+
{icon}
|
|
205
|
+
</IconBox>
|
|
206
|
+
{label}
|
|
207
|
+
</Button> :
|
|
208
|
+
<IconButton
|
|
209
|
+
key={ariaLabel}
|
|
210
|
+
aria-label={ariaLabel}
|
|
211
|
+
title={label}
|
|
212
|
+
className={listToClass([className, 'extra'])}
|
|
213
|
+
style={style}
|
|
214
|
+
onClick={onClick}
|
|
215
|
+
>
|
|
216
|
+
{icon}
|
|
217
|
+
</IconButton>}
|
|
218
|
+
</>)), [buttons])
|
|
203
219
|
|
|
204
220
|
// when a new tab is added, we should scroll to it if there are more tabs that we can show.
|
|
205
221
|
useEffect(() => {
|
package/src/layout.css
CHANGED
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
.home-page {
|
|
53
53
|
.title {
|
|
54
54
|
margin-top: 40px;
|
|
55
|
-
font-size: 18px;
|
|
56
55
|
}
|
|
57
56
|
.subtitle {
|
|
58
57
|
font-size: 14px;
|
|
@@ -100,6 +99,23 @@
|
|
|
100
99
|
display: flex;
|
|
101
100
|
flex-direction: column;
|
|
102
101
|
flex: 1;
|
|
102
|
+
.agent-list .agent-card {
|
|
103
|
+
flex-direction: row;
|
|
104
|
+
align-items: center;
|
|
105
|
+
gap: 8px;
|
|
106
|
+
border-radius: 4px;
|
|
107
|
+
padding: 10px 8px;
|
|
108
|
+
img {
|
|
109
|
+
width: 32px;
|
|
110
|
+
height: 32px;
|
|
111
|
+
border-radius: 4px;
|
|
112
|
+
}
|
|
113
|
+
h6 {
|
|
114
|
+
font-weight: 400;
|
|
115
|
+
font-size: 13px;
|
|
116
|
+
line-height: 14px;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
103
119
|
}
|
|
104
120
|
|
|
105
121
|
.chat-content {
|
package/src/types.ts
CHANGED
|
@@ -9,7 +9,8 @@ export type PropsOf<T extends React.FunctionComponent> = T extends React.Functio
|
|
|
9
9
|
export interface ButtonAction extends WithStyle {
|
|
10
10
|
icon?: React.ReactElement,
|
|
11
11
|
color?: string,
|
|
12
|
-
label
|
|
12
|
+
label?: string,
|
|
13
|
+
ariaLabel?: string,
|
|
13
14
|
onClick: () => any,
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -41,13 +41,14 @@ export const ChatTabSelection = () => {
|
|
|
41
41
|
() => {
|
|
42
42
|
const actions: ButtonAction[] = [{
|
|
43
43
|
icon: <Plus />,
|
|
44
|
-
|
|
44
|
+
ariaLabel: t.newChat,
|
|
45
45
|
onClick: create,
|
|
46
46
|
}]
|
|
47
47
|
if (chatHistory) {
|
|
48
48
|
actions.push({
|
|
49
49
|
icon: <Clock />,
|
|
50
|
-
label: t.
|
|
50
|
+
label: t.history,
|
|
51
|
+
ariaLabel: t.openHistory,
|
|
51
52
|
className: 'test',
|
|
52
53
|
style: { marginLeft: 'auto' },
|
|
53
54
|
onClick: () => widget.set('panel', 'history'),
|
|
@@ -71,10 +72,12 @@ export const ChatTabSelection = () => {
|
|
|
71
72
|
|
|
72
73
|
const dictionary = {
|
|
73
74
|
en: {
|
|
75
|
+
history: 'History',
|
|
74
76
|
openHistory: 'Open chat history',
|
|
75
77
|
newChat: 'New chat',
|
|
76
78
|
},
|
|
77
79
|
pt: {
|
|
80
|
+
history: 'Histórico',
|
|
78
81
|
openHistory: 'Abrir histórico da conversa',
|
|
79
82
|
newChat: 'Novo chat',
|
|
80
83
|
},
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { theme } from '@stack-spot/portal-theme'
|
|
1
|
+
import { Text } from '@citric/core'
|
|
2
|
+
import { FaceSmile, KnowledgeSource, QuickCommand, StackSpot } from '@citric/icons'
|
|
4
3
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
5
4
|
import { QuickStartButton } from '../../components/QuickStartButton'
|
|
6
5
|
import { useCurrentChat } from '../../context/hooks'
|
|
@@ -21,35 +20,28 @@ export const BuiltInAgent = ({ username }: HomeProps) => {
|
|
|
21
20
|
|
|
22
21
|
return (
|
|
23
22
|
<HomeBox className="home-page">
|
|
24
|
-
<h2 className="title">{t.hello}, {username}</
|
|
25
|
-
<h3 className="subtitle">{t.subtitle}</
|
|
23
|
+
<Text appearance="h2" className="title">{t.hello}, {username}</Text>
|
|
24
|
+
<Text appearance="h3" className="subtitle">{t.subtitle}</Text>
|
|
26
25
|
<div className="shortcuts">
|
|
27
26
|
<QuickStartButton
|
|
28
27
|
label={t['question.meta']}
|
|
29
28
|
onClick={() => send(t['question.meta'])}
|
|
30
|
-
icon={<
|
|
31
|
-
background={theme.color.orange[50]}
|
|
29
|
+
icon={<StackSpot />}
|
|
32
30
|
/>
|
|
33
31
|
<QuickStartButton
|
|
34
32
|
label={t['question.ks']}
|
|
35
33
|
onClick={() => send(t['question.ks'])}
|
|
36
34
|
icon={<KnowledgeSource />}
|
|
37
|
-
background={theme.color.cyan[50]}
|
|
38
|
-
color={theme.color.cyan[600]}
|
|
39
35
|
/>
|
|
40
36
|
<QuickStartButton
|
|
41
37
|
label={t['question.agents']}
|
|
42
38
|
onClick={() => send(t['question.agents'])}
|
|
43
39
|
icon={<FaceSmile />}
|
|
44
|
-
background={theme.color.pink[50]}
|
|
45
|
-
color={theme.color.pink[600]}
|
|
46
40
|
/>
|
|
47
41
|
<QuickStartButton
|
|
48
42
|
label={t['question.qc']}
|
|
49
43
|
onClick={() => send(t['question.qc'])}
|
|
50
44
|
icon={<QuickCommand />}
|
|
51
|
-
background={theme.color.purple[50]}
|
|
52
|
-
color={theme.color.purple[600]}
|
|
53
45
|
/>
|
|
54
46
|
</div>
|
|
55
47
|
</HomeBox>
|
|
@@ -59,7 +51,7 @@ export const BuiltInAgent = ({ username }: HomeProps) => {
|
|
|
59
51
|
const dictionary = {
|
|
60
52
|
en: {
|
|
61
53
|
hello: 'Hello',
|
|
62
|
-
subtitle:
|
|
54
|
+
subtitle: 'What really matters takes time, let us help you with the rest.',
|
|
63
55
|
'question.meta': 'What is StackSpot AI?',
|
|
64
56
|
'question.ks': 'What are Knowledge Sources?',
|
|
65
57
|
'question.agents': 'How do Agents work?',
|
|
@@ -67,7 +59,7 @@ const dictionary = {
|
|
|
67
59
|
},
|
|
68
60
|
pt: {
|
|
69
61
|
hello: 'Olá',
|
|
70
|
-
subtitle: '
|
|
62
|
+
subtitle: 'O que realmente importa leva tempo, deixe que a gente cuide do resto.',
|
|
71
63
|
'question.meta': 'O que é a StackSpot AI?',
|
|
72
64
|
'question.ks': 'O que são Knowledge Sources?',
|
|
73
65
|
'question.agents': 'Como funcionam os agentes?',
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { IconBox, Text } from '@citric/core'
|
|
2
2
|
import { Agent } from '@citric/icons'
|
|
3
3
|
import { agentClient } from '@stack-spot/portal-network'
|
|
4
|
-
import { theme } from '@stack-spot/portal-theme'
|
|
5
4
|
import { useMemo } from 'react'
|
|
6
5
|
import { QuickStartButton } from '../../components/QuickStartButton'
|
|
7
6
|
import { useCurrentChat, useCurrentChatState } from '../../context/hooks'
|
|
@@ -20,8 +19,6 @@ export const CustomAgent = () => {
|
|
|
20
19
|
key={index}
|
|
21
20
|
label={prompt}
|
|
22
21
|
onClick={() => send(prompt)}
|
|
23
|
-
background={theme.color.light[500]}
|
|
24
|
-
manageOverflow
|
|
25
22
|
/>
|
|
26
23
|
)), [agent?.suggested_prompts])
|
|
27
24
|
|
package/src/views/Home/index.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FadingOverflow } from '@stack-spot/portal-components/FadingOverflow'
|
|
2
2
|
import { styled } from 'styled-components'
|
|
3
3
|
import { AgentCard } from '../../components/AgentCard'
|
|
4
|
+
import { AgentCardCreate } from '../../components/AgentCard/AgentCardCreate'
|
|
4
5
|
import { FallbackBoundary } from '../../components/FallbackBoundary'
|
|
5
6
|
import { useCurrentChatState } from '../../context/hooks'
|
|
6
7
|
import { BuiltInAgent } from './BuiltInAgent'
|
|
@@ -17,12 +18,6 @@ const AgentList = styled.ul`
|
|
|
17
18
|
|
|
18
19
|
li {
|
|
19
20
|
flex-shrink: 0;
|
|
20
|
-
&:first-child {
|
|
21
|
-
margin-left: auto;
|
|
22
|
-
}
|
|
23
|
-
&:last-child {
|
|
24
|
-
margin-right: auto;
|
|
25
|
-
}
|
|
26
21
|
}
|
|
27
22
|
`
|
|
28
23
|
|
|
@@ -31,7 +26,7 @@ const AgentList = styled.ul`
|
|
|
31
26
|
*
|
|
32
27
|
* The home page can be replaced by providing children to the component `StackspotAIWidget`.
|
|
33
28
|
*/
|
|
34
|
-
export const Home = ({ initialAgents, ...props }: HomeProps) => {
|
|
29
|
+
export const Home = ({ initialAgents, onClickCreateAgent, ...props }: HomeProps) => {
|
|
35
30
|
const agent = useCurrentChatState('agent')
|
|
36
31
|
const isAgentEnabled = useCurrentChatState('features').agent
|
|
37
32
|
|
|
@@ -41,6 +36,7 @@ export const Home = ({ initialAgents, ...props }: HomeProps) => {
|
|
|
41
36
|
{!!initialAgents && isAgentEnabled && (
|
|
42
37
|
<FadingOverflow enableHorizontalScrollWithVerticalWheel sides={['left', 'right']} scroll="arrows">
|
|
43
38
|
<AgentList className="agent-list">
|
|
39
|
+
{onClickCreateAgent && <li><AgentCardCreate onClickCreateAgent={onClickCreateAgent} /></li>}
|
|
44
40
|
{initialAgents.map((agent) => <li key={agent.id}><AgentCard agent={agent} /></li>)}
|
|
45
41
|
</AgentList>
|
|
46
42
|
</FadingOverflow>
|
package/src/views/Home/styled.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
+
import { theme } from '@stack-spot/portal-theme'
|
|
1
2
|
import { styled } from 'styled-components'
|
|
2
3
|
|
|
3
4
|
export const HomeBox = styled.div`
|
|
4
5
|
margin: auto 0;
|
|
5
6
|
|
|
6
7
|
.title, .subtitle {
|
|
7
|
-
font-family: 'San Francisco';
|
|
8
|
-
font-size: 26px;
|
|
9
|
-
font-weight: 600;
|
|
10
8
|
margin: 0;
|
|
11
9
|
}
|
|
12
10
|
|
|
@@ -14,22 +12,36 @@ export const HomeBox = styled.div`
|
|
|
14
12
|
display: inline-block;
|
|
15
13
|
background: linear-gradient(72.81deg, #FF9900 0.96%, #FF6633 100%);
|
|
16
14
|
background-clip: text;
|
|
17
|
-
margin-bottom: 10px;
|
|
18
15
|
color: transparent;
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
.subtitle {
|
|
22
19
|
color: #A0A0A0;
|
|
23
|
-
margin-bottom:
|
|
20
|
+
margin-bottom: 24px;
|
|
24
21
|
}
|
|
25
22
|
|
|
26
23
|
.shortcuts {
|
|
27
|
-
display: flex;
|
|
28
|
-
flex-direction: row;
|
|
29
|
-
gap: 15px;
|
|
30
24
|
li {
|
|
31
25
|
flex: 1;
|
|
32
26
|
}
|
|
27
|
+
button {
|
|
28
|
+
padding-left: 0;
|
|
29
|
+
border-radius: 50px;
|
|
30
|
+
padding-inline: 16px;
|
|
31
|
+
padding-block: 8px;
|
|
32
|
+
font-weight: 400;
|
|
33
|
+
line-height: normal;
|
|
34
|
+
border: none;
|
|
35
|
+
max-width: 30vw;
|
|
36
|
+
i {
|
|
37
|
+
width: 16px;
|
|
38
|
+
height: 16px;
|
|
39
|
+
margin-right: 8px;
|
|
40
|
+
}
|
|
41
|
+
&:hover, &:visited, &:active, &:focus {
|
|
42
|
+
background-color: ${theme.color.light[600]}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
33
45
|
}
|
|
34
46
|
|
|
35
47
|
.avatar, .avatar svg {
|
|
@@ -45,14 +57,16 @@ export const HomeBox = styled.div`
|
|
|
45
57
|
gap: 20px;
|
|
46
58
|
|
|
47
59
|
.shortcuts {
|
|
48
|
-
|
|
60
|
+
display: inline-block;
|
|
61
|
+
text-align: center;
|
|
49
62
|
button {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
63
|
+
margin-bottom: 10px;
|
|
64
|
+
margin-left: 4px;
|
|
65
|
+
margin-right: 4px;
|
|
53
66
|
p {
|
|
54
67
|
overflow: hidden;
|
|
55
68
|
}
|
|
69
|
+
|
|
56
70
|
}
|
|
57
71
|
}
|
|
58
72
|
}
|
package/src/views/Home/types.ts
CHANGED
|
@@ -15,20 +15,16 @@ interface SelectionBarProps {
|
|
|
15
15
|
* Whether or not the message is currently being sent. This is used to decide which button to show: send or cancel.
|
|
16
16
|
*/
|
|
17
17
|
isLoading?: boolean,
|
|
18
|
-
/**
|
|
19
|
-
* State to determine whether the input is focused
|
|
20
|
-
*/
|
|
21
|
-
focused?: boolean,
|
|
22
18
|
}
|
|
23
19
|
|
|
24
|
-
export const ButtonBar = ({ onSend, isLoading
|
|
20
|
+
export const ButtonBar = ({ onSend, isLoading }: SelectionBarProps) => {
|
|
25
21
|
const t = useMessageInputDictionary()
|
|
26
22
|
const chat = useCurrentChat()
|
|
27
23
|
const widget = useWidget()
|
|
28
24
|
const features = useCurrentChatState('features')
|
|
29
25
|
|
|
30
26
|
return (
|
|
31
|
-
<SelectionBarWrapper className="button-group"
|
|
27
|
+
<SelectionBarWrapper className="button-group">
|
|
32
28
|
<Flex sx={{ gap: '4px' }}>
|
|
33
29
|
<SelectContent />
|
|
34
30
|
{features.editor && (
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { KnowledgeSource, Plus, Spaces, Stack } from '@citric/icons'
|
|
2
2
|
import { IconButton } from '@citric/ui'
|
|
3
3
|
import { SelectionList } from '@stack-spot/portal-components/SelectionList'
|
|
4
4
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
@@ -52,6 +52,7 @@ export const SelectContent = () => {
|
|
|
52
52
|
return (
|
|
53
53
|
<>
|
|
54
54
|
<IconButton
|
|
55
|
+
id="button-content-select"
|
|
55
56
|
color="light"
|
|
56
57
|
appearance="square"
|
|
57
58
|
role="button"
|
|
@@ -59,7 +60,7 @@ export const SelectContent = () => {
|
|
|
59
60
|
data-test-hint="button-options"
|
|
60
61
|
aria-label={visibleMenu ? t.collapse : t.expand}
|
|
61
62
|
onClick={() => setVisibleMenu(state => !state)}>
|
|
62
|
-
<
|
|
63
|
+
<Plus />
|
|
63
64
|
</IconButton>
|
|
64
65
|
<SelectionList
|
|
65
66
|
style={{
|
|
@@ -81,9 +81,9 @@ export const MessageInput = () => {
|
|
|
81
81
|
</div>
|
|
82
82
|
</div>
|
|
83
83
|
<ProgressBar visible={true} animate={isLoading}
|
|
84
|
-
backgroundColor={isLoading || !focused ? theme.color.light[
|
|
84
|
+
backgroundColor={isLoading || !focused ? theme.color.light[500] : theme.color.primary[500]} />
|
|
85
85
|
<InfoBar />
|
|
86
|
-
<ButtonBar
|
|
86
|
+
<ButtonBar onSend={onSend} isLoading={isLoading} />
|
|
87
87
|
</MessageInputBox>
|
|
88
88
|
)
|
|
89
89
|
}
|