@stack-spot/ai-chat-widget 1.6.0 → 1.7.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-metadata.json +7 -7
- package/dist/components/Selector/index.d.ts +20 -0
- package/dist/components/Selector/index.d.ts.map +1 -0
- package/dist/components/Selector/index.js +134 -0
- package/dist/components/Selector/index.js.map +1 -0
- package/dist/components/Selector/styled.d.ts +2 -0
- package/dist/components/Selector/styled.d.ts.map +1 -0
- package/dist/components/Selector/styled.js +144 -0
- package/dist/components/Selector/styled.js.map +1 -0
- package/dist/regex.d.ts +1 -0
- package/dist/regex.d.ts.map +1 -1
- package/dist/regex.js +1 -0
- package/dist/regex.js.map +1 -1
- package/dist/views/Agents/AgentsTab.js +4 -4
- package/dist/views/Agents/AgentsTab.js.map +1 -1
- package/dist/views/Chat/AgentInfo.js +1 -1
- package/dist/views/Home/CustomAgent.js +3 -3
- package/dist/views/Home/CustomAgent.js.map +1 -1
- package/dist/views/Home/styled.js +1 -1
- package/dist/views/MessageInput/AgentSelector.d.ts +4 -0
- package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -0
- package/dist/views/MessageInput/AgentSelector.js +31 -0
- package/dist/views/MessageInput/AgentSelector.js.map +1 -0
- package/dist/views/MessageInput/ButtonAgent.d.ts +2 -0
- package/dist/views/MessageInput/ButtonAgent.d.ts.map +1 -0
- package/dist/views/MessageInput/ButtonAgent.js +17 -0
- package/dist/views/MessageInput/ButtonAgent.js.map +1 -0
- package/dist/views/MessageInput/ButtonGroup.d.ts +1 -1
- package/dist/views/MessageInput/ButtonGroup.d.ts.map +1 -1
- package/dist/views/MessageInput/ButtonGroup.js +4 -6
- package/dist/views/MessageInput/ButtonGroup.js.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.d.ts +2 -11
- package/dist/views/MessageInput/QuickCommandSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.js +17 -130
- package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
- package/dist/views/MessageInput/dictionary.d.ts +1 -1
- package/dist/views/MessageInput/dictionary.d.ts.map +1 -1
- package/dist/views/MessageInput/dictionary.js +4 -2
- package/dist/views/MessageInput/dictionary.js.map +1 -1
- package/dist/views/MessageInput/index.d.ts.map +1 -1
- package/dist/views/MessageInput/index.js +4 -1
- package/dist/views/MessageInput/index.js.map +1 -1
- package/dist/views/MessageInput/styled.d.ts.map +1 -1
- package/dist/views/MessageInput/styled.js +51 -144
- package/dist/views/MessageInput/styled.js.map +1 -1
- package/package.json +1 -1
- package/src/app-metadata.json +7 -7
- package/src/components/Selector/index.tsx +245 -0
- package/src/components/Selector/styled.ts +145 -0
- package/src/regex.ts +1 -0
- package/src/views/Agents/AgentsTab.tsx +4 -4
- package/src/views/Chat/AgentInfo.tsx +1 -1
- package/src/views/Home/CustomAgent.tsx +3 -3
- package/src/views/Home/styled.ts +1 -1
- package/src/views/MessageInput/AgentSelector.tsx +35 -0
- package/src/views/MessageInput/ButtonAgent.tsx +36 -0
- package/src/views/MessageInput/ButtonGroup.tsx +3 -10
- package/src/views/MessageInput/QuickCommandSelector.tsx +21 -205
- package/src/views/MessageInput/dictionary.ts +4 -2
- package/src/views/MessageInput/index.tsx +8 -3
- package/src/views/MessageInput/styled.ts +51 -144
|
@@ -1,218 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ExternalLink, QuickCommand } from '@citric/icons'
|
|
3
|
-
import { IconButton } from '@citric/ui'
|
|
4
|
-
import { useKeyboardControls } from '@stack-spot/portal-components'
|
|
1
|
+
import { QuickCommand } from '@citric/icons'
|
|
5
2
|
import { aiClient } from '@stack-spot/portal-network'
|
|
6
|
-
import { QuickCommandListResponse
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { Fading } from '../../components/Fading'
|
|
10
|
-
import { FallbackBoundary } from '../../components/FallbackBoundary'
|
|
3
|
+
import { QuickCommandListResponse } from '@stack-spot/portal-network/api/ai'
|
|
4
|
+
import { useCallback } from 'react'
|
|
5
|
+
import { Selector } from '../../components/Selector'
|
|
11
6
|
import { useCurrentChat, useCurrentChatState } from '../../context/hooks'
|
|
12
7
|
import { quickCommandRegex } from '../../regex'
|
|
13
|
-
import { getUrlToStackSpotAI } from '../../utils/url'
|
|
14
8
|
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* A reference to the input this quick commands panel is attached to.
|
|
18
|
-
*/
|
|
19
|
-
inputRef: React.RefObject<HTMLTextAreaElement | HTMLInputElement>,
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
interface ContentProps extends Props {
|
|
23
|
-
filter?: string,
|
|
24
|
-
onClose: () => void,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface ListProps {
|
|
28
|
-
filter?: string,
|
|
29
|
-
visibility?: VisibilityLevelEnum,
|
|
30
|
-
onSelect: (slug: string) => void,
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
interface ItemProps {
|
|
34
|
-
qc: QuickCommandListResponse,
|
|
35
|
-
onSelect: (slug: string) => void,
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const sections = [undefined, 'personal', 'workspace', 'account', 'shared'] as const
|
|
39
|
-
|
|
40
|
-
const CommandListItem = ({ qc, onSelect }: ItemProps) => {
|
|
41
|
-
const t = useTranslate(dictionary)
|
|
42
|
-
return (
|
|
43
|
-
<li>
|
|
44
|
-
<button
|
|
45
|
-
className="qc"
|
|
46
|
-
onClick={() => onSelect(qc.slug)}
|
|
47
|
-
// the following line prevents a new line character in the message when the user presses enter to select a qc.
|
|
48
|
-
onKeyDown={e => e.key === 'Enter' && e.preventDefault()}
|
|
49
|
-
onFocus={e => e.target.closest('li')?.classList.add('focus')}
|
|
50
|
-
onBlur={e => e.target.closest('li')?.classList.remove('focus')}
|
|
51
|
-
>
|
|
52
|
-
<p className="qc-title">/{qc.slug}</p>
|
|
53
|
-
<p className="qc-description">{qc.description}</p>
|
|
54
|
-
</button>
|
|
55
|
-
<IconButton as="a" title={t.openQC} aria-label={t.openQC} href={`${getUrlToStackSpotAI()}/quick-command/${qc.slug}`} target="_blank">
|
|
56
|
-
<ExternalLink />
|
|
57
|
-
</IconButton>
|
|
58
|
-
</li>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const CommandList = ({ filter, visibility, onSelect }: ListProps) => {
|
|
63
|
-
const t = useTranslate(dictionary)
|
|
64
|
-
const quickCommands = aiClient.quickCommands.useQuery({ order: 'a-to-z' })
|
|
65
|
-
let filtered = quickCommands
|
|
66
|
-
|
|
67
|
-
if (visibility || filter) {
|
|
68
|
-
const lowerFilter = filter?.toLocaleLowerCase()
|
|
69
|
-
filtered = quickCommands.filter(
|
|
70
|
-
qc => (!lowerFilter || qc.slug.toLocaleLowerCase().startsWith(lowerFilter)) && (!visibility || qc.visibility_level === visibility),
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
if (!quickCommands.length) return <Text className="empty" colorScheme="light.700">{t.noData}</Text>
|
|
74
|
-
if (!filtered.length) return <Text className="empty" colorScheme="light.700">{t.noResults}</Text>
|
|
75
|
-
return (
|
|
76
|
-
<ul className="command-list">
|
|
77
|
-
{filtered.map(qc => <CommandListItem key={qc.id} qc={qc} onSelect={onSelect} />)}
|
|
78
|
-
</ul>
|
|
79
|
-
)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const SelectorContent = ({ filter, onClose, inputRef }: ContentProps) => {
|
|
83
|
-
const t = useTranslate(dictionary)
|
|
84
|
-
const ref = useRef<HTMLDivElement>(null)
|
|
9
|
+
export const QuickCommandSelector = ({ inputRef }: { inputRef: React.RefObject<HTMLTextAreaElement | HTMLInputElement> }) => {
|
|
85
10
|
const chat = useCurrentChat()
|
|
86
|
-
const [visibility, setVisibility] = useState<VisibilityLevelEnum | undefined>()
|
|
87
11
|
|
|
88
|
-
const
|
|
89
|
-
const newValue = `/${slug}`
|
|
12
|
+
const onSelectItem = useCallback((qc: QuickCommandListResponse) => {
|
|
13
|
+
const newValue = `/${qc.slug}`
|
|
90
14
|
chat.set('nextMessage', newValue)
|
|
91
|
-
|
|
15
|
+
|
|
92
16
|
if (!inputRef.current) return
|
|
93
|
-
// the following line prevents bugs by setting the text area value before react gets the chance to.
|
|
94
17
|
inputRef.current.value = newValue
|
|
95
18
|
inputRef.current.focus()
|
|
96
19
|
}, [])
|
|
97
20
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
{t[action || 'all']}
|
|
112
|
-
</button>
|
|
113
|
-
</li>
|
|
114
|
-
)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return (
|
|
118
|
-
<div ref={ref}>
|
|
119
|
-
<header>
|
|
120
|
-
<IconBox><QuickCommand /></IconBox>
|
|
121
|
-
<Text as="h3">QUICK COMMANDS</Text>
|
|
122
|
-
</header>
|
|
123
|
-
<div className="body">
|
|
124
|
-
<ul className="tabs">{sections.map(createSectionItem)}</ul>
|
|
125
|
-
<FallbackBoundary message={t.error} mini>
|
|
126
|
-
<CommandList onSelect={onSelectQC} filter={filter} visibility={visibility} />
|
|
127
|
-
</FallbackBoundary>
|
|
128
|
-
</div>
|
|
129
|
-
</div>
|
|
130
|
-
)
|
|
21
|
+
return <Selector
|
|
22
|
+
inputRef={inputRef}
|
|
23
|
+
selectorConfig={{
|
|
24
|
+
resourceName: 'Quick Command',
|
|
25
|
+
shortcut: '/',
|
|
26
|
+
icon: <QuickCommand />,
|
|
27
|
+
url: '/quick-command/',
|
|
28
|
+
regex: quickCommandRegex,
|
|
29
|
+
data: () => aiClient.quickCommands.useQuery({ order: 'a-to-z' }),
|
|
30
|
+
isEnabled: useCurrentChatState('features').quickCommands,
|
|
31
|
+
onSelect: onSelectItem,
|
|
32
|
+
}}
|
|
33
|
+
/>
|
|
131
34
|
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* This renders the floating Quick Commands panel that allows the user to select a quick command. This appears whenever the user types "/"
|
|
135
|
-
* in the textarea.
|
|
136
|
-
*/
|
|
137
|
-
export const QuickCommandSelector = ({ inputRef }: Props) => {
|
|
138
|
-
const value = useCurrentChatState('nextMessage') ?? ''
|
|
139
|
-
const filter = useMemo(() => value === '/' || quickCommandRegex.test(value) ? value.substring(1) : undefined, [value])
|
|
140
|
-
const [isClosed, setClosed] = useState(false)
|
|
141
|
-
const selectorRef = useRef<HTMLDivElement>(null)
|
|
142
|
-
const isEnabled = useCurrentChatState('features').quickCommands
|
|
143
|
-
const shouldRender = isEnabled && filter !== undefined && !isClosed
|
|
144
|
-
|
|
145
|
-
// Resets the closed state whenever the message input is cleared
|
|
146
|
-
useEffect(() => {
|
|
147
|
-
if (!value) setClosed(false)
|
|
148
|
-
}, [value])
|
|
149
|
-
|
|
150
|
-
// Creates the following behavior while the user types in the message input:
|
|
151
|
-
// auto-complete on tab; move focus to the qc panel on press up or down; and close the qc panel on esc.
|
|
152
|
-
useEffect(() => {
|
|
153
|
-
function getFirst() {
|
|
154
|
-
return selectorRef.current?.querySelector('.qc') as HTMLElement | null
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function onKeyDown(event: Event) {
|
|
158
|
-
const key = (event as KeyboardEvent).key
|
|
159
|
-
if (!selectorRef.current) return
|
|
160
|
-
if (key === 'Tab') {
|
|
161
|
-
getFirst()?.click()
|
|
162
|
-
event.preventDefault()
|
|
163
|
-
}
|
|
164
|
-
else if (key === 'ArrowDown' || key === 'ArrowUp') {
|
|
165
|
-
getFirst()?.focus()
|
|
166
|
-
event.preventDefault()
|
|
167
|
-
}
|
|
168
|
-
if (key === 'Escape') {
|
|
169
|
-
setClosed(true)
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
inputRef.current?.addEventListener('keydown', onKeyDown)
|
|
174
|
-
return () => inputRef.current?.removeEventListener('keydown', onKeyDown)
|
|
175
|
-
}, [])
|
|
176
|
-
|
|
177
|
-
// Closes the panel when the user clicks outside the qc panel or the message input.
|
|
178
|
-
useEffect(() => {
|
|
179
|
-
if (!shouldRender) return
|
|
180
|
-
function onClickOut(e: Event) {
|
|
181
|
-
const target = e.target as HTMLElement | null
|
|
182
|
-
if (!selectorRef.current?.contains(target) && !inputRef.current?.contains(target)) setClosed(true)
|
|
183
|
-
}
|
|
184
|
-
document.addEventListener('click', onClickOut)
|
|
185
|
-
return () => document.removeEventListener('click', onClickOut)
|
|
186
|
-
}, [shouldRender])
|
|
187
|
-
|
|
188
|
-
return (
|
|
189
|
-
<Fading visible={shouldRender} ref={selectorRef} className="quick-command-selector">
|
|
190
|
-
<SelectorContent filter={filter} onClose={() => setClosed(true)} inputRef={inputRef} />
|
|
191
|
-
</Fading>
|
|
192
|
-
)
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const dictionary = {
|
|
196
|
-
en: {
|
|
197
|
-
all: 'All',
|
|
198
|
-
personal: 'Personal',
|
|
199
|
-
account: 'Account',
|
|
200
|
-
shared: 'Shared',
|
|
201
|
-
workspace: 'Workspace',
|
|
202
|
-
error: 'Could not load the quick commands.',
|
|
203
|
-
noData: 'You don\'t have any quick command yet.',
|
|
204
|
-
noResults: 'There are no quick commands to show here.',
|
|
205
|
-
openQC: 'Open this quick command\'s settings in a new tab.',
|
|
206
|
-
},
|
|
207
|
-
pt: {
|
|
208
|
-
all: 'Todos',
|
|
209
|
-
personal: 'Pessoal',
|
|
210
|
-
account: 'Conta',
|
|
211
|
-
shared: 'Compartilhado',
|
|
212
|
-
workspace: 'Workspace',
|
|
213
|
-
error: 'Não foi possível carregar os quick commands.',
|
|
214
|
-
noData: 'Você ainda não possui quick commands.',
|
|
215
|
-
noResults: 'Não há quick commands para mostrar aqui.',
|
|
216
|
-
openQC: 'Abra as configurações deste quick command em uma nova aba.',
|
|
217
|
-
},
|
|
218
|
-
} satisfies Dictionary
|
|
@@ -10,7 +10,7 @@ const dictionary = {
|
|
|
10
10
|
collapse: 'Hide buttons',
|
|
11
11
|
expand: 'Show buttons',
|
|
12
12
|
send: 'Send message',
|
|
13
|
-
placeholder: '
|
|
13
|
+
placeholder: 'Message to %s',
|
|
14
14
|
cancel: 'Cancel',
|
|
15
15
|
removeConfig: 'Remove all the configuration',
|
|
16
16
|
removeStack: 'Stop using the current stack',
|
|
@@ -18,6 +18,7 @@ const dictionary = {
|
|
|
18
18
|
removeKS: 'Stop using this knowledge source',
|
|
19
19
|
selected: 'Selected',
|
|
20
20
|
removeSelection: 'Remove current code selection',
|
|
21
|
+
remove: 'Remove',
|
|
21
22
|
},
|
|
22
23
|
pt: {
|
|
23
24
|
stack: 'Selecionar stack',
|
|
@@ -28,7 +29,7 @@ const dictionary = {
|
|
|
28
29
|
collapse: 'Esconder botões',
|
|
29
30
|
expand: 'Mostrar botões',
|
|
30
31
|
send: 'Enviar mensagem',
|
|
31
|
-
placeholder: '
|
|
32
|
+
placeholder: 'Mensagem para %s',
|
|
32
33
|
cancel: 'Cancelar',
|
|
33
34
|
removeConfig: 'Remover todas as configurações',
|
|
34
35
|
removeStack: 'Parar de usar a stack atual',
|
|
@@ -36,6 +37,7 @@ const dictionary = {
|
|
|
36
37
|
removeKS: 'Parar de usar este knowledge source',
|
|
37
38
|
selected: 'Selecionado',
|
|
38
39
|
removeSelection: 'Desfazer seleção de código',
|
|
40
|
+
remove: 'Remover',
|
|
39
41
|
},
|
|
40
42
|
} satisfies Dictionary
|
|
41
43
|
|
|
@@ -5,6 +5,8 @@ import { ProgressBar } from '../../components/ProgressBar'
|
|
|
5
5
|
import { useCurrentChat, useCurrentChatState, useWidgetState } from '../../context/hooks'
|
|
6
6
|
import { quickCommandRegex } from '../../regex'
|
|
7
7
|
import { ChatEntry } from '../../state/ChatEntry'
|
|
8
|
+
import { AgentSelector } from './AgentSelector'
|
|
9
|
+
import { ButtonAgent } from './ButtonAgent'
|
|
8
10
|
import { ButtonGroup } from './ButtonGroup'
|
|
9
11
|
import { useMessageInputDictionary } from './dictionary'
|
|
10
12
|
import { InfoBar } from './InfoBar'
|
|
@@ -26,7 +28,8 @@ export const MessageInput = () => {
|
|
|
26
28
|
const value = useCurrentChatState('nextMessage') ?? ''
|
|
27
29
|
const isMinimized = useWidgetState('isMinimized')
|
|
28
30
|
const textAreaRef = useRef<HTMLTextAreaElement>(null)
|
|
29
|
-
|
|
31
|
+
const agentLabel = useCurrentChatState('agent')?.label ?? 'Stackspot AI'
|
|
32
|
+
|
|
30
33
|
const onSend = useCallback(async () => {
|
|
31
34
|
const message = chat.get('nextMessage')
|
|
32
35
|
if (!message) return
|
|
@@ -53,12 +56,14 @@ export const MessageInput = () => {
|
|
|
53
56
|
<MessageInputBox aria-busy={isLoading} className="message-input">
|
|
54
57
|
<ProgressBar visible={isLoading} shimmer />
|
|
55
58
|
<InfoBar />
|
|
59
|
+
<QuickCommandSelector inputRef={textAreaRef} />
|
|
60
|
+
<AgentSelector inputRef={textAreaRef} />
|
|
56
61
|
<div className={listToClass(['action-box', focused && 'focused', isLoading && 'disabled'])}>
|
|
57
|
-
<
|
|
62
|
+
<ButtonAgent />
|
|
58
63
|
<AdaptiveTextArea
|
|
59
64
|
ref={textAreaRef}
|
|
60
65
|
disabled={isLoading}
|
|
61
|
-
placeholder={t.placeholder}
|
|
66
|
+
placeholder={t.placeholder.replace('%s', agentLabel)}
|
|
62
67
|
onChange={e => chat.set('nextMessage', e.target.value)}
|
|
63
68
|
value={value}
|
|
64
69
|
onFocus={() => setFocused(true)}
|
|
@@ -88,12 +88,12 @@ export const MessageInputBox = styled.div`
|
|
|
88
88
|
display: flex;
|
|
89
89
|
position: relative;
|
|
90
90
|
flex-direction: row;
|
|
91
|
-
gap:
|
|
91
|
+
gap: 8px;
|
|
92
92
|
align-items: end;
|
|
93
93
|
border-radius: 4px;
|
|
94
94
|
border: 1px solid ${theme.color.light[500]};
|
|
95
95
|
background-color: ${theme.color.light[300]};
|
|
96
|
-
padding: 8px
|
|
96
|
+
padding: 10px 8px;
|
|
97
97
|
transition: border-color 0.3s, background-color 0.3s;
|
|
98
98
|
|
|
99
99
|
&.focused {
|
|
@@ -150,12 +150,16 @@ export const MessageInputBox = styled.div`
|
|
|
150
150
|
svg {
|
|
151
151
|
transform: rotate(180deg);
|
|
152
152
|
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
&.agent
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
&.agent {
|
|
156
|
+
border-radius: 50%;
|
|
157
|
+
opacity: 1;
|
|
158
|
+
img {
|
|
159
|
+
width: 100%;
|
|
160
|
+
height: 100%;
|
|
161
|
+
border-radius: 50%;
|
|
162
|
+
}
|
|
159
163
|
}
|
|
160
164
|
}
|
|
161
165
|
|
|
@@ -191,6 +195,45 @@ export const MessageInputBox = styled.div`
|
|
|
191
195
|
width: 24px;
|
|
192
196
|
height: 24px;
|
|
193
197
|
}
|
|
198
|
+
|
|
199
|
+
.group-agent {
|
|
200
|
+
display: flex;
|
|
201
|
+
margin-left: 0.5rem;
|
|
202
|
+
margin-right: 0.5rem;
|
|
203
|
+
|
|
204
|
+
button {
|
|
205
|
+
margin-right: -0.5rem;
|
|
206
|
+
margin-left: -0.5rem;
|
|
207
|
+
border-radius: 50%;
|
|
208
|
+
background-color: ${theme.color.light[300]};
|
|
209
|
+
border: 1px solid ${theme.color.light[600]};
|
|
210
|
+
display: flex;
|
|
211
|
+
|
|
212
|
+
&.agent-selected:hover:before {
|
|
213
|
+
content: '';
|
|
214
|
+
width: 22px;
|
|
215
|
+
height: 22px;
|
|
216
|
+
position: absolute;
|
|
217
|
+
background-color: ${theme.color.light[300]};
|
|
218
|
+
border-radius: 100%;
|
|
219
|
+
opacity: 0.4;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.icon-remove {
|
|
223
|
+
display: none;
|
|
224
|
+
fill: ${theme.color.light.contrastText};
|
|
225
|
+
position: absolute;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
&:hover .icon-remove {
|
|
229
|
+
display: flex;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.image {
|
|
233
|
+
margin: 1px;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
194
237
|
}
|
|
195
238
|
|
|
196
239
|
textarea {
|
|
@@ -206,140 +249,4 @@ export const MessageInputBox = styled.div`
|
|
|
206
249
|
box-shadow: none;
|
|
207
250
|
}
|
|
208
251
|
}
|
|
209
|
-
|
|
210
|
-
.quick-command-selector {
|
|
211
|
-
position: absolute;
|
|
212
|
-
border-radius: 4px;
|
|
213
|
-
border: 1px solid ${theme.color.light[600]};
|
|
214
|
-
background-color: ${theme.color.light[500]};
|
|
215
|
-
box-shadow: 0px 2px 16px 0px #0000005C;
|
|
216
|
-
display: flex;
|
|
217
|
-
flex-direction: column;
|
|
218
|
-
width: 480px;
|
|
219
|
-
bottom: 55px;
|
|
220
|
-
|
|
221
|
-
.loading, .error {
|
|
222
|
-
padding-bottom: 26px;
|
|
223
|
-
p {
|
|
224
|
-
width: 200px;
|
|
225
|
-
text-align: center;
|
|
226
|
-
line-height: 20px;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
.empty {
|
|
231
|
-
padding-bottom: 26px;
|
|
232
|
-
width: 200px;
|
|
233
|
-
text-align: center;
|
|
234
|
-
line-height: 20px;
|
|
235
|
-
margin: auto;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
header {
|
|
239
|
-
display: flex;
|
|
240
|
-
flex-direction: row;
|
|
241
|
-
gap: 8px;
|
|
242
|
-
align-items: center;
|
|
243
|
-
padding: 8px;
|
|
244
|
-
font-family: 'San Francisco';
|
|
245
|
-
font-weight: 500;
|
|
246
|
-
font-size: 11px;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
.body {
|
|
250
|
-
display: flex;
|
|
251
|
-
flex-direction: row;
|
|
252
|
-
align-items: center;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
ul {
|
|
256
|
-
margin: 0;
|
|
257
|
-
padding: 0;
|
|
258
|
-
list-style: none;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
ul.tabs {
|
|
262
|
-
display: flex;
|
|
263
|
-
flex-direction: column;
|
|
264
|
-
|
|
265
|
-
li {
|
|
266
|
-
display: flex;
|
|
267
|
-
flex-direction: column;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
button {
|
|
271
|
-
box-sizing: border-box;
|
|
272
|
-
color: ${theme.color.light[700]};
|
|
273
|
-
text-align: left;
|
|
274
|
-
padding: 10px;
|
|
275
|
-
font-weight: 600;
|
|
276
|
-
font-size: 12px;
|
|
277
|
-
transition: background-color 0.3s;
|
|
278
|
-
border-top-right-radius: 4px;
|
|
279
|
-
border-bottom-right-radius: 4px;
|
|
280
|
-
background-color: transparent;
|
|
281
|
-
border: none;
|
|
282
|
-
cursor: pointer;
|
|
283
|
-
outline: none;
|
|
284
|
-
|
|
285
|
-
&:hover, &.active, &:focus {
|
|
286
|
-
background-color: ${theme.color.light[600]};
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
&.active {
|
|
290
|
-
border-left: 1px solid ${theme.color.light.contrastText};
|
|
291
|
-
color: ${theme.color.light.contrastText};
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
ul.command-list {
|
|
297
|
-
align-self: stretch;
|
|
298
|
-
display: flex;
|
|
299
|
-
flex-direction: column;
|
|
300
|
-
gap: 2px;
|
|
301
|
-
overflow-y: auto;
|
|
302
|
-
flex: 1;
|
|
303
|
-
max-height: 170px;
|
|
304
|
-
|
|
305
|
-
li {
|
|
306
|
-
display: flex;
|
|
307
|
-
flex-direction: row;
|
|
308
|
-
align-items: center;
|
|
309
|
-
gap: 8px;
|
|
310
|
-
padding: 8px;
|
|
311
|
-
border-radius: 4px;
|
|
312
|
-
|
|
313
|
-
&:hover, &.focus {
|
|
314
|
-
background-color: ${theme.color.light[600]};
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
button.qc {
|
|
318
|
-
flex: 1;
|
|
319
|
-
border: none;
|
|
320
|
-
text-align: left;
|
|
321
|
-
background-color: transparent;
|
|
322
|
-
text-align: left;
|
|
323
|
-
outline: none;
|
|
324
|
-
overflow: hidden;
|
|
325
|
-
cursor: pointer;
|
|
326
|
-
|
|
327
|
-
.qc-title {
|
|
328
|
-
font-size: 11px;
|
|
329
|
-
margin: 0 0 4px 0;
|
|
330
|
-
color: ${theme.color.light.contrastText};
|
|
331
|
-
text-transform: uppercase;
|
|
332
|
-
text-overflow: ellipsis;
|
|
333
|
-
overflow: hidden;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
.qc-description {
|
|
337
|
-
color: ${theme.color.light[700]};
|
|
338
|
-
font-size: 12px;
|
|
339
|
-
margin: 0;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
252
|
`
|