app-tutor-ai-consumer 1.3.0 → 1.4.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 +12 -0
- package/config/vitest/setupTests.ts +6 -1
- package/package.json +11 -2
- package/public/assets/images/default-image.png +0 -0
- package/src/@types/declarations.d.ts +12 -3
- package/src/config/dayjs/index.ts +2 -0
- package/src/config/dayjs/init.ts +28 -0
- package/src/config/dayjs/utils/format-fulldate.ts +7 -0
- package/src/config/dayjs/utils/format-time.ts +20 -0
- package/src/config/dayjs/utils/index.ts +2 -0
- package/src/config/styles/global.css +19 -1
- package/src/config/tanstack/query-provider.tsx +1 -1
- package/src/config/tests/handlers.ts +6 -0
- package/src/index.tsx +4 -0
- package/src/lib/components/index.ts +1 -0
- package/src/lib/components/markdownrenderer/__tests__/markdown.stub.ts +334 -0
- package/src/lib/components/markdownrenderer/components/index.ts +1 -0
- package/src/lib/components/markdownrenderer/components/md-code-block/index.ts +1 -0
- package/src/lib/components/markdownrenderer/components/md-code-block/md-code-block.tsx +71 -0
- package/src/lib/components/markdownrenderer/index.ts +2 -0
- package/src/lib/components/markdownrenderer/markdownrenderer.tsx +115 -0
- package/src/lib/utils/constants.ts +1 -1
- package/src/lib/utils/copy-text-to-clipboard.tsx +13 -0
- package/src/lib/utils/extract-text-from-react-nodes.ts +23 -0
- package/src/lib/utils/index.ts +3 -0
- package/src/lib/utils/urls.ts +20 -0
- package/src/modules/messages/__tests__/imessage-with-sender-data.builder.ts +113 -0
- package/src/modules/messages/__tests__/imessage-with-sender-data.mock.ts +15 -0
- package/src/modules/messages/components/index.ts +2 -0
- package/src/modules/messages/components/message-img/index.ts +1 -0
- package/src/modules/messages/components/message-img/message-img.tsx +47 -0
- package/src/modules/messages/components/message-item/index.ts +2 -0
- package/src/modules/messages/components/message-item/message-item.spec.tsx +26 -0
- package/src/modules/messages/components/message-item/message-item.tsx +15 -0
- package/src/modules/messages/components/messages-list/messages-list.tsx +46 -17
- package/src/modules/messages/hooks/index.ts +1 -0
- package/src/modules/messages/hooks/use-fetch-messages/index.ts +2 -0
- package/src/modules/messages/hooks/use-fetch-messages/use-fetch-messages.spec.tsx +46 -0
- package/src/modules/messages/hooks/use-fetch-messages/use-fetch-messages.tsx +103 -0
- package/src/modules/messages/service.ts +26 -3
- package/src/modules/messages/types.ts +33 -2
- package/src/modules/messages/utils/index.ts +1 -0
- package/src/modules/messages/utils/messages-parser/index.ts +1 -0
- package/src/modules/messages/utils/messages-parser/utils.ts +28 -0
- package/src/modules/profile/__tests__/profile-api-props.builder.ts +74 -0
- package/src/modules/profile/__tests__/profile-props.builder.ts +42 -0
- package/src/modules/profile/constants.ts +3 -0
- package/src/modules/profile/hooks/index.ts +1 -0
- package/src/modules/profile/hooks/use-get-profile/index.ts +1 -0
- package/src/modules/profile/hooks/use-get-profile/use-get-profile.spec.tsx +20 -0
- package/src/modules/profile/hooks/use-get-profile/use-get-profile.tsx +14 -0
- package/src/modules/profile/index.ts +4 -0
- package/src/modules/profile/service.tsx +19 -0
- package/src/modules/profile/types.ts +17 -0
- package/src/modules/widget/components/chat-page/chat-page.tsx +3 -3
- package/src/modules/widget/components/container/container.tsx +1 -1
- package/src/modules/widget/components/onboarding-page/onboarding-page.tsx +16 -14
- package/src/modules/widget/components/starter-page/starter-page.tsx +3 -3
- package/src/modules/widget/store/widget-settings.atom.ts +3 -1
- package/src/config/styles/shared-styles.module.css +0 -16
- package/src/modules/widget/components/container/styles.module.css +0 -11
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import type { Message
|
|
1
|
+
import type { Message } from '@hotmart/sparkie/dist/MessageService'
|
|
2
2
|
|
|
3
3
|
import { ApiError } from '@/src/config/request'
|
|
4
4
|
import { HttpCodes } from '@/src/lib/utils'
|
|
5
5
|
import { SparkieService } from '../sparkie'
|
|
6
6
|
|
|
7
|
+
import { MSG_MAX_COUNT } from './constants'
|
|
7
8
|
import type {
|
|
9
|
+
FetchMessagesResponse,
|
|
10
|
+
IFetchMessagesOptions,
|
|
8
11
|
IGetMessagesPayload,
|
|
12
|
+
IMessageWithSenderData,
|
|
9
13
|
ISendImageMessagePayload,
|
|
10
14
|
ISendTextMessagePayload
|
|
11
15
|
} from './types'
|
|
@@ -30,12 +34,31 @@ class MessagesService {
|
|
|
30
34
|
async getMessages({
|
|
31
35
|
conversationId,
|
|
32
36
|
before
|
|
33
|
-
}: IGetMessagesPayload): Promise<Array<
|
|
37
|
+
}: IGetMessagesPayload): Promise<Array<IMessageWithSenderData>> {
|
|
34
38
|
const data = await this.sparkieMessageService.getAll(conversationId, {
|
|
35
39
|
before
|
|
36
40
|
})
|
|
37
41
|
|
|
38
|
-
return data ?? []
|
|
42
|
+
return (data ?? []) as Array<IMessageWithSenderData>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async fetchMessages({
|
|
46
|
+
currentMessages,
|
|
47
|
+
conversationId,
|
|
48
|
+
loadFirstPage
|
|
49
|
+
}: IFetchMessagesOptions): Promise<FetchMessagesResponse> {
|
|
50
|
+
let before: number | undefined
|
|
51
|
+
|
|
52
|
+
if (currentMessages && currentMessages.length && !loadFirstPage) {
|
|
53
|
+
before = currentMessages.slice().sort((a, b) => a.sentAt - b.sentAt)[0].sentAt
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const messages = (await this.getMessages({ conversationId, before })) ?? []
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
messages,
|
|
60
|
+
hasMore: messages.length === MSG_MAX_COUNT
|
|
61
|
+
}
|
|
39
62
|
}
|
|
40
63
|
|
|
41
64
|
async sendTextMessage({
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import type { Message } from '@hotmart/sparkie/dist/MessageService'
|
|
1
|
+
import type { Message as SparkieMsg, SenderData } from '@hotmart/sparkie/dist/MessageService'
|
|
2
2
|
|
|
3
|
-
export type IMessage =
|
|
3
|
+
export type IMessage = SparkieMsg & {
|
|
4
|
+
metadata: {
|
|
5
|
+
author: 'ai' | 'user'
|
|
6
|
+
sessionId: string
|
|
7
|
+
externalId: string
|
|
8
|
+
correlationId: string
|
|
9
|
+
}
|
|
4
10
|
sending?: boolean // indicates when the current message is being sent
|
|
5
11
|
}
|
|
6
12
|
|
|
@@ -45,3 +51,28 @@ export type IFetchMessagesOptions = {
|
|
|
45
51
|
conversationId: string
|
|
46
52
|
loadFirstPage?: boolean
|
|
47
53
|
}
|
|
54
|
+
|
|
55
|
+
export type IMessageWithSenderData = IMessage & SenderData
|
|
56
|
+
|
|
57
|
+
export type MessageParserArgs = {
|
|
58
|
+
messages: Array<IMessageWithSenderData>
|
|
59
|
+
profileId: string
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type ParsedMessage = {
|
|
63
|
+
from: string
|
|
64
|
+
id: string
|
|
65
|
+
isRead: boolean
|
|
66
|
+
time: string
|
|
67
|
+
contact: IMessageWithSenderData['contact']
|
|
68
|
+
metadata: IMessageWithSenderData['metadata']
|
|
69
|
+
parentId: IMessageWithSenderData['parentId']
|
|
70
|
+
sending: IMessageWithSenderData['sending']
|
|
71
|
+
threadId: IMessageWithSenderData['threadId']
|
|
72
|
+
timestamp: IMessageWithSenderData['sentAt']
|
|
73
|
+
} & IMessageWithSenderData['content']
|
|
74
|
+
|
|
75
|
+
export type FetchMessagesResponse = {
|
|
76
|
+
messages: IMessageWithSenderData[]
|
|
77
|
+
hasMore: boolean
|
|
78
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './messages-parser'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './utils'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import dayjs from 'dayjs'
|
|
2
|
+
|
|
3
|
+
import type { IMessageWithSenderData, MessageParserArgs, ParsedMessage } from '../../types'
|
|
4
|
+
|
|
5
|
+
export const msgParser = (msg: IMessageWithSenderData, profileId: string) => ({
|
|
6
|
+
id: msg.id,
|
|
7
|
+
time: dayjs(msg.sentAt).format('LT'),
|
|
8
|
+
timestamp: msg.sentAt,
|
|
9
|
+
from: msg.contactId === profileId ? 'me' : msg.contactId,
|
|
10
|
+
contact: msg.contact,
|
|
11
|
+
sending: msg.sending,
|
|
12
|
+
parentId: msg.parentId,
|
|
13
|
+
threadId: msg.threadId,
|
|
14
|
+
isRead: false,
|
|
15
|
+
metadata: msg.metadata || {},
|
|
16
|
+
...msg.content
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
export const messagesParser = ({
|
|
20
|
+
messages,
|
|
21
|
+
profileId
|
|
22
|
+
}: MessageParserArgs): Array<ParsedMessage> => {
|
|
23
|
+
if (!(Number(messages.length) > 0) || !profileId) return []
|
|
24
|
+
|
|
25
|
+
return messages
|
|
26
|
+
.map((msg) => msgParser(msg, profileId))
|
|
27
|
+
.sort((a, b) => a.timestamp - b.timestamp) as Array<ParsedMessage>
|
|
28
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { chance } from '@/src/config/tests'
|
|
2
|
+
import type { ProfileAPIProps } from '../types'
|
|
3
|
+
|
|
4
|
+
class ProfileAPIPropsBuilder implements ProfileAPIProps {
|
|
5
|
+
id: string
|
|
6
|
+
name: string
|
|
7
|
+
user_id: number
|
|
8
|
+
picture: string
|
|
9
|
+
is_anonymous: boolean
|
|
10
|
+
created_at: string
|
|
11
|
+
updated_at: string
|
|
12
|
+
deleted_at: string
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
this.id = chance.guid()
|
|
16
|
+
this.name = chance.name()
|
|
17
|
+
this.user_id = chance.integer({ min: 1000 })
|
|
18
|
+
this.picture = chance.avatar()
|
|
19
|
+
this.is_anonymous = false
|
|
20
|
+
this.created_at = Date.now().toString()
|
|
21
|
+
this.updated_at = Date.now().toString()
|
|
22
|
+
this.deleted_at = ''
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
withId(id: typeof this.id) {
|
|
26
|
+
this.id = id
|
|
27
|
+
|
|
28
|
+
return this
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
withName(name: typeof this.name) {
|
|
32
|
+
this.name = name
|
|
33
|
+
|
|
34
|
+
return this
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
withUser_id(user_id: typeof this.user_id) {
|
|
38
|
+
this.user_id = user_id
|
|
39
|
+
|
|
40
|
+
return this
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
withPicture(picture: typeof this.picture) {
|
|
44
|
+
this.picture = picture
|
|
45
|
+
|
|
46
|
+
return this
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
withIs_anonymous(is_anonymous: typeof this.is_anonymous) {
|
|
50
|
+
this.is_anonymous = is_anonymous
|
|
51
|
+
|
|
52
|
+
return this
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
withCreated_at(created_at: typeof this.created_at) {
|
|
56
|
+
this.created_at = created_at
|
|
57
|
+
|
|
58
|
+
return this
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
withUpdated_at(updated_at: typeof this.updated_at) {
|
|
62
|
+
this.updated_at = updated_at
|
|
63
|
+
|
|
64
|
+
return this
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
withDeleted_at(deleted_at: typeof this.deleted_at) {
|
|
68
|
+
this.deleted_at = deleted_at
|
|
69
|
+
|
|
70
|
+
return this
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default ProfileAPIPropsBuilder
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { chance } from '@/src/config/tests'
|
|
2
|
+
import type { ProfileProps } from '../types'
|
|
3
|
+
|
|
4
|
+
class ProfilePropsBuilder implements ProfileProps {
|
|
5
|
+
id: string
|
|
6
|
+
name: string
|
|
7
|
+
avatar: string
|
|
8
|
+
userId: string | number
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
this.id = chance.guid()
|
|
12
|
+
this.name = chance.name()
|
|
13
|
+
this.avatar = chance.avatar()
|
|
14
|
+
this.userId = chance.guid()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
withId(id: typeof this.id) {
|
|
18
|
+
this.id = id
|
|
19
|
+
|
|
20
|
+
return this
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
withName(name: typeof this.name) {
|
|
24
|
+
this.name = name
|
|
25
|
+
|
|
26
|
+
return this
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
withAvatar(avatar: typeof this.avatar) {
|
|
30
|
+
this.avatar = avatar
|
|
31
|
+
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
withUserId(userId: typeof this.userId) {
|
|
36
|
+
this.userId = userId
|
|
37
|
+
|
|
38
|
+
return this
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default ProfilePropsBuilder
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './use-get-profile'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './use-get-profile'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { renderHook, waitFor } from '@/src/config/tests'
|
|
2
|
+
|
|
3
|
+
import { useGetProfile } from './use-get-profile'
|
|
4
|
+
|
|
5
|
+
describe('useGetProfile', () => {
|
|
6
|
+
const render = (enabled = true) => renderHook(() => useGetProfile(enabled))
|
|
7
|
+
|
|
8
|
+
it('should render without errors', async () => {
|
|
9
|
+
const { result } = render()
|
|
10
|
+
|
|
11
|
+
await waitFor(() => expect(result.current.isSuccess).toBeTruthy())
|
|
12
|
+
|
|
13
|
+
expect(result.current.data).toMatchObject({
|
|
14
|
+
id: expect.any(String) as string,
|
|
15
|
+
name: expect.any(String) as string,
|
|
16
|
+
avatar: expect.any(String) as string,
|
|
17
|
+
userId: expect.any(Number) as number
|
|
18
|
+
})
|
|
19
|
+
})
|
|
20
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query'
|
|
2
|
+
|
|
3
|
+
import { ProfileEndpoints } from '../../constants'
|
|
4
|
+
import ProfileService from '../../service'
|
|
5
|
+
|
|
6
|
+
export const getProfileQuery = (enabled: boolean) => ({
|
|
7
|
+
queryKey: [ProfileEndpoints.getProfile()],
|
|
8
|
+
queryFn: () => ProfileService.getProfile(),
|
|
9
|
+
enabled
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
export function useGetProfile(enabled: boolean = true) {
|
|
13
|
+
return useQuery(getProfileQuery(enabled))
|
|
14
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { api } from '@/src/config/request'
|
|
2
|
+
|
|
3
|
+
import { ProfileEndpoints } from './constants'
|
|
4
|
+
import type { ProfileAPIProps, ProfileProps } from './types'
|
|
5
|
+
|
|
6
|
+
class ProfileService {
|
|
7
|
+
async getProfile(): Promise<ProfileProps> {
|
|
8
|
+
const { data } = await api.get<ProfileAPIProps>(ProfileEndpoints.getProfile())
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
id: data.id,
|
|
12
|
+
name: data.name,
|
|
13
|
+
avatar: data.picture,
|
|
14
|
+
userId: data.user_id
|
|
15
|
+
} as ProfileProps
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default new ProfileService()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type ProfileAPIProps = {
|
|
2
|
+
id: string
|
|
3
|
+
user_id: number
|
|
4
|
+
name: string
|
|
5
|
+
picture: string
|
|
6
|
+
is_anonymous: boolean
|
|
7
|
+
created_at: string
|
|
8
|
+
updated_at: string
|
|
9
|
+
deleted_at: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ProfileProps = {
|
|
13
|
+
id: string
|
|
14
|
+
name: string
|
|
15
|
+
avatar: string
|
|
16
|
+
userId: string | number
|
|
17
|
+
}
|
|
@@ -6,14 +6,14 @@ function ChatPage() {
|
|
|
6
6
|
const chatInputRef = useRef<HTMLInputElement>(null)
|
|
7
7
|
|
|
8
8
|
return (
|
|
9
|
-
|
|
10
|
-
<div className='
|
|
9
|
+
<>
|
|
10
|
+
<div className='overflow-auto px-5 py-4'>
|
|
11
11
|
<MessagesList />
|
|
12
12
|
</div>
|
|
13
13
|
<div className='border-t border-t-neutral-700 px-5 py-4'>
|
|
14
14
|
<ChatInput name='new-chat-msg-input' ref={chatInputRef} />
|
|
15
15
|
</div>
|
|
16
|
-
|
|
16
|
+
</>
|
|
17
17
|
)
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -22,7 +22,7 @@ function WidgetContainer() {
|
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
24
|
<div className='flex min-h-svh flex-col items-center justify-center bg-neutral-900'>
|
|
25
|
-
<div className='
|
|
25
|
+
<div className='grid h-svh w-full grid-rows-[1fr_max-content]'>
|
|
26
26
|
{WIDGET_TABS[widgetTabs.currentTab]}
|
|
27
27
|
</div>
|
|
28
28
|
</div>
|
|
@@ -12,26 +12,28 @@ function WidgetOnboardingPage() {
|
|
|
12
12
|
const { t } = useTranslation()
|
|
13
13
|
|
|
14
14
|
return (
|
|
15
|
-
|
|
16
|
-
<div className=
|
|
17
|
-
<div className='mx-
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<
|
|
22
|
-
{
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
<>
|
|
16
|
+
<div className={styles.bg}>
|
|
17
|
+
<div className='mx-4 flex h-full flex-col justify-center gap-6 px-0.5'>
|
|
18
|
+
<div className='mx-auto max-w-[67%]'>
|
|
19
|
+
<img src={TutorOnboardingSVG} aria-hidden />
|
|
20
|
+
</div>
|
|
21
|
+
<div className='flex flex-col gap-2'>
|
|
22
|
+
<h3 className={clsx(styles.gradientTxt, 'text-center text-xl/tight font-semibold')}>
|
|
23
|
+
{t('onboarding.title')}
|
|
24
|
+
</h3>
|
|
25
|
+
<p className='text-center text-sm/snug font-normal text-gray-400'>
|
|
26
|
+
{t('onboarding.description')}
|
|
27
|
+
</p>
|
|
28
|
+
</div>
|
|
27
29
|
</div>
|
|
28
30
|
</div>
|
|
29
|
-
<div className='flex gap-4'>
|
|
31
|
+
<div className='mx-4 mb-4 mt-auto flex flex-col gap-4'>
|
|
30
32
|
<Button variant='brand' className='flex-1' onClick={() => setWidgetTabs('starter')}>
|
|
31
33
|
{t('general.buttons.start')}
|
|
32
34
|
</Button>
|
|
33
35
|
</div>
|
|
34
|
-
|
|
36
|
+
</>
|
|
35
37
|
)
|
|
36
38
|
}
|
|
37
39
|
|
|
@@ -23,8 +23,8 @@ function WidgetStarterPage() {
|
|
|
23
23
|
})
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
|
-
|
|
27
|
-
<div className='flex flex-
|
|
26
|
+
<>
|
|
27
|
+
<div className='flex flex-col justify-center px-5 py-4'>
|
|
28
28
|
<GreetingsCard author={settings?.author ?? ''} tutorName={settings?.tutorName ?? ''} />
|
|
29
29
|
</div>
|
|
30
30
|
<div className='border-t border-t-neutral-700 px-5 py-4'>
|
|
@@ -34,7 +34,7 @@ function WidgetStarterPage() {
|
|
|
34
34
|
onSend={() => setWidgetTabs('chat')}
|
|
35
35
|
/>
|
|
36
36
|
</div>
|
|
37
|
-
|
|
37
|
+
</>
|
|
38
38
|
)
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { atom, useAtom } from 'jotai'
|
|
1
|
+
import { atom, useAtom, useAtomValue } from 'jotai'
|
|
2
2
|
|
|
3
3
|
import type { WidgetSettingProps } from '@/src/types'
|
|
4
4
|
|
|
@@ -10,3 +10,5 @@ export const setWidgetSettingsAtom = atom(
|
|
|
10
10
|
)
|
|
11
11
|
|
|
12
12
|
export const useWidgetSettingsAtom = () => useAtom(setWidgetSettingsAtom)
|
|
13
|
+
|
|
14
|
+
export const useWidgetSettingsAtomValue = () => useAtomValue(setWidgetSettingsAtom)
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
.scrollbar {
|
|
2
|
-
&::-webkit-scrollbar {
|
|
3
|
-
width: var(--hc-size-spacing-2);
|
|
4
|
-
height: var(--hc-size-spacing-2);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
&::-webkit-scrollbar-track {
|
|
8
|
-
background: transparent;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
&::-webkit-scrollbar-thumb {
|
|
12
|
-
background: var(--hc-color-neutral-400);
|
|
13
|
-
border-radius: var(--hc-size-border-medium);
|
|
14
|
-
border: calc(var(--hc-size-border-medium) / 2) solid transparent;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
.main {
|
|
2
|
-
background:
|
|
3
|
-
linear-gradient(
|
|
4
|
-
186.9deg,
|
|
5
|
-
rgb(from var(--ai-color-primary) r g b / 0.2) 6.65%,
|
|
6
|
-
rgb(from var(--ai-color-secondary) r g b / 0.2) 28.99%,
|
|
7
|
-
rgb(from var(--ai-color-dark) r g b / 0.2) 46.97%,
|
|
8
|
-
rgb(from var(--hc-color-neutral-1000) r g b / 0.2) 57.9%
|
|
9
|
-
),
|
|
10
|
-
linear-gradient(0deg, var(--hc-color-neutral-1000), var(--hc-color-neutral-1000));
|
|
11
|
-
}
|