Skip to content

Commit 91893b1

Browse files
committed
Minor code refactoring and cleanup
1 parent 6d5e535 commit 91893b1

File tree

14 files changed

+124
-74
lines changed

14 files changed

+124
-74
lines changed

Diff for: .github/workflows/docker.chatgpt-lite.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
- main
88

99
jobs:
10-
build_and_push_image:
10+
build-and-push-image:
1111
name: Push image to Docker Hub
1212
runs-on: ubuntu-latest
1313
steps:

Diff for: components/Chat/PersonaPanel.tsx renamed to app/chat/PersonaPanel.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ import {
1616
import { debounce } from 'lodash-es'
1717
import { AiOutlineClose, AiOutlineDelete, AiOutlineEdit } from 'react-icons/ai'
1818
import { LuMessageSquarePlus } from 'react-icons/lu'
19-
import ChatContext from './chatContext'
20-
import { Persona } from './interface'
19+
import { ChatContext, Persona } from '@/components'
2120

2221
export interface PersonaPanelProps {}
2322

Diff for: app/chat/page.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
'use client'
22
import { Suspense } from 'react'
33
import { Flex } from '@radix-ui/themes'
4-
import { Chat, ChatContext, ChatSideBar, PersonaPanel, useChatHook } from '@/components'
4+
import { Chat, ChatContext, ChatSideBar, useChatHook } from '@/components'
55
import PersonaModal from './PersonaModal'
6+
import PersonaPanel from './PersonaPanel'
67

78
const ChatProvider = () => {
89
const provider = useChatHook()

Diff for: components/Chat/Chat.tsx

-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
useState
1111
} from 'react'
1212
import { Flex, Heading, IconButton, ScrollArea, Tooltip } from '@radix-ui/themes'
13-
import clipboard from 'clipboard'
1413
import ContentEditable from 'react-contenteditable'
1514
import toast from 'react-hot-toast'
1615
import { AiOutlineClear, AiOutlineLoading3Quarters, AiOutlineUnorderedList } from 'react-icons/ai'
@@ -206,10 +205,6 @@ const Chat = (props: ChatProps, ref: any) => {
206205
}
207206
})
208207

209-
useEffect(() => {
210-
new clipboard('.copy-btn').on('success', () => {})
211-
}, [])
212-
213208
return (
214209
<Flex direction="column" height="100%" className="relative" gap="3">
215210
<Flex

Diff for: components/Chat/Message.tsx

+32-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
'use client'
22

3-
import { Avatar, Flex } from '@radix-ui/themes'
3+
import { useCallback, useState } from 'react'
4+
import { Avatar, Flex, IconButton, Tooltip } from '@radix-ui/themes'
5+
import { FaRegCopy } from 'react-icons/fa'
46
import { HiUser } from 'react-icons/hi'
5-
import { SiOpenai } from 'react-icons/si'
7+
import { RiRobot2Line } from 'react-icons/ri'
68
import { Markdown } from '@/components'
9+
import { useCopyToClipboard } from '@/hooks/useCopyToClipboard'
710
import { ChatMessage } from './interface'
811

912
export interface MessageProps {
@@ -13,11 +16,21 @@ export interface MessageProps {
1316
const Message = (props: MessageProps) => {
1417
const { role, content } = props.message
1518
const isUser = role === 'user'
19+
const copy = useCopyToClipboard()
20+
const [tooltipOpen, setTooltipOpen] = useState<boolean>(false)
21+
22+
const onCopy = useCallback(() => {
23+
copy(content, (isSuccess) => {
24+
if (isSuccess) {
25+
setTooltipOpen(true)
26+
}
27+
})
28+
}, [content, copy])
1629

1730
return (
1831
<Flex gap="4" className="mb-5">
1932
<Avatar
20-
fallback={isUser ? <HiUser className="size-4" /> : <SiOpenai className="size-4" />}
33+
fallback={isUser ? <HiUser className="size-4" /> : <RiRobot2Line className="size-4" />}
2134
color={isUser ? undefined : 'green'}
2235
size="2"
2336
radius="full"
@@ -34,7 +47,22 @@ const Message = (props: MessageProps) => {
3447
}}
3548
></div>
3649
) : (
37-
<Markdown>{content}</Markdown>
50+
<Flex direction="column" gap="4">
51+
<Markdown>{content}</Markdown>
52+
<Flex gap="4" align="center">
53+
<Tooltip open={tooltipOpen} content="Copied!">
54+
<IconButton
55+
className="cursor-pointer"
56+
variant="outline"
57+
color="gray"
58+
onClick={onCopy}
59+
onMouseLeave={() => setTooltipOpen(false)}
60+
>
61+
<FaRegCopy />
62+
</IconButton>
63+
</Tooltip>
64+
</Flex>
65+
</Flex>
3866
)}
3967
</div>
4068
</Flex>

Diff for: components/Chat/index.ts

-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
'use client'
2-
31
export * from './interface'
42
export { default as Chat } from './Chat'
53
export { default as ChatSideBar } from './ChatSideBar'
6-
export { default as PersonaPanel } from './PersonaPanel'
74
export { default as ChatContext } from './chatContext'
85
export { default as useChatHook } from './useChatHook'

Diff for: components/Header.tsx renamed to components/Header/Header.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { Avatar, Flex, Heading, IconButton, Select, Tooltip } from '@radix-ui/th
66
import cs from 'classnames'
77
import NextLink from 'next/link'
88
import { FaAdjust, FaGithub, FaMoon, FaRegSun } from 'react-icons/fa'
9-
import { Link } from './Link'
10-
import { useTheme } from './Themes'
9+
import { Link } from '../Link'
10+
import { useTheme } from '../Themes'
1111

1212
export const Header = () => {
1313
const { theme, setTheme } = useTheme()

Diff for: components/Header/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './Header'

Diff for: components/Link.tsx

+10-3
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,19 @@ interface LinkProps {
88
className?: string
99
color?: LinkOwnProps['color']
1010
children?: React.ReactNode
11+
disabled?: boolean
12+
highContrast?: boolean
1113
}
1214

13-
export const Link = ({ href, className, children, color }: LinkProps) => {
15+
export const Link = ({ href, className, children, color, highContrast, disabled }: LinkProps) => {
1416
return (
15-
<NextLink href={href} passHref legacyBehavior>
16-
<RadixLink className={className} color={color}>
17+
<NextLink href={href} passHref legacyBehavior aria-disabled={disabled}>
18+
<RadixLink
19+
className={className}
20+
color={color}
21+
aria-disabled={disabled}
22+
highContrast={highContrast}
23+
>
1724
{children}
1825
</RadixLink>
1926
</NextLink>

Diff for: components/Markdown.tsx

+48-24
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
import { IconButton } from '@radix-ui/themes'
1+
'use client'
2+
3+
import { ClassAttributes, Fragment, HTMLAttributes, useCallback, useState } from 'react'
4+
import { IconButton, Tooltip } from '@radix-ui/themes'
25
import cs from 'classnames'
36
import { RxClipboardCopy } from 'react-icons/rx'
4-
import ReactMarkdown from 'react-markdown'
7+
import ReactMarkdown, { ExtraProps } from 'react-markdown'
58
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
69
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
710
import rehypeKatex from 'rehype-katex'
@@ -11,12 +14,54 @@ import remarkGfm from 'remark-gfm'
1114
import remarkMath from 'remark-math'
1215
import remarkParse from 'remark-parse'
1316
import remarkRehype from 'remark-rehype'
17+
import { useCopyToClipboard } from '@/hooks/useCopyToClipboard'
1418

1519
export interface MarkdownProps {
1620
className?: string
1721
children: string
1822
}
1923

24+
const HighlightCode = (
25+
props: ClassAttributes<HTMLElement> & HTMLAttributes<HTMLElement> & ExtraProps
26+
) => {
27+
const { children, className, ref, ...rest } = props
28+
const match = /language-(\w+)/.exec(className || '')
29+
const copy = useCopyToClipboard()
30+
const [tooltipOpen, setTooltipOpen] = useState<boolean>(false)
31+
32+
const code = match ? String(children).replace(/\n$/, '') : ''
33+
34+
const onCopy = useCallback(() => {
35+
copy(code, (isSuccess) => {
36+
if (isSuccess) {
37+
setTooltipOpen(true)
38+
}
39+
})
40+
}, [code, copy])
41+
42+
return match ? (
43+
<Fragment>
44+
<Tooltip open={tooltipOpen} content="Copied!">
45+
<IconButton
46+
className="absolute right-4 top-4 cursor-pointer"
47+
variant="solid"
48+
onClick={onCopy}
49+
onMouseLeave={() => setTooltipOpen(false)}
50+
>
51+
<RxClipboardCopy />
52+
</IconButton>
53+
</Tooltip>
54+
<SyntaxHighlighter {...rest} style={vscDarkPlus} language={match[1]} PreTag="div">
55+
{code}
56+
</SyntaxHighlighter>
57+
</Fragment>
58+
) : (
59+
<code ref={ref} {...rest} className={cs('highlight', className)}>
60+
{children}
61+
</code>
62+
)
63+
}
64+
2065
export const Markdown = ({ className, children }: MarkdownProps) => {
2166
return (
2267
<ReactMarkdown
@@ -25,32 +70,11 @@ export const Markdown = ({ className, children }: MarkdownProps) => {
2570
rehypePlugins={[rehypeRaw, rehypeKatex, rehypeStringify]}
2671
components={{
2772
code(props) {
28-
const { children, className, ref, ...rest } = props
29-
const match = /language-(\w+)/.exec(className || '')
30-
return match ? (
31-
<>
32-
<IconButton
33-
className="absolute right-4 top-4 copy-btn cursor-pointer"
34-
variant="solid"
35-
data-clipboard-text={children}
36-
>
37-
<RxClipboardCopy />
38-
</IconButton>
39-
<SyntaxHighlighter {...rest} style={vscDarkPlus} language={match[1]} PreTag="div">
40-
{String(children).replace(/\n$/, '')}
41-
</SyntaxHighlighter>
42-
</>
43-
) : (
44-
<code ref={ref} {...rest} className={cs('highlight', className)}>
45-
{children}
46-
</code>
47-
)
73+
return <HighlightCode {...props} />
4874
}
4975
}}
5076
>
5177
{children}
5278
</ReactMarkdown>
5379
)
5480
}
55-
56-
export default Markdown

Diff for: components/Themes/ThemeContext.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
'use client'
2+
13
import { createContext } from 'react'
24
import { UseThemeProps } from './interface'
35

Diff for: components/Themes/index.ts

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use client'
2-
31
export * from './interface'
42
export * from './useTheme'
53
export * from './ThemeProvider'

Diff for: hooks/useCopyToClipboard.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { useCallback } from 'react'
2+
3+
type CopyFn = (text: string, callback?: (data: any) => void) => Promise<boolean> // Return success
4+
5+
export const useCopyToClipboard = (): CopyFn => {
6+
const copy: CopyFn = useCallback(async (text, callback) => {
7+
if (!navigator?.clipboard) {
8+
console.warn('Clipboard not supported')
9+
callback?.(false)
10+
return false
11+
}
12+
13+
try {
14+
await navigator.clipboard.writeText(text)
15+
callback?.(true)
16+
return true
17+
} catch (error) {
18+
console.warn('Copy failed', error)
19+
callback?.(false)
20+
return false
21+
}
22+
}, [])
23+
24+
return copy
25+
}

Diff for: styles/globals.scss

-27
Original file line numberDiff line numberDiff line change
@@ -424,33 +424,6 @@ body {
424424
@apply flex flex-col;
425425
}
426426

427-
.table-fixed-header {
428-
.rt-TableRootTable {
429-
overflow: initial !important;
430-
}
431-
432-
.rt-TableHeader {
433-
--table-row-background-color: var(--gray-2) !important;
434-
position: relative;
435-
z-index: 1;
436-
.rt-TableCell {
437-
&:first-child {
438-
border-top-left-radius: calc(var(--table-border-radius) - 1px);
439-
}
440-
&:last-child {
441-
border-top-right-radius: calc(var(--table-border-radius) - 1px);
442-
}
443-
}
444-
}
445-
446-
.react-loading-skeleton {
447-
z-index: 0;
448-
}
449-
.rt-ScrollAreaScrollbar {
450-
z-index: 2;
451-
}
452-
}
453-
454427
.navbar-collapse {
455428
@apply max-md:absolute max-md:top-14 max-md:gap-0 max-md:left-0 max-md:right-0 max-md:px-1 max-md:flex-col max-md:items-start max-md:backdrop-blur-md max-md:bg-[--color-page-background] max-md:shadow-sm max-md:overflow-hidden;
456429
height: 0;

0 commit comments

Comments
 (0)