@copilotkit/react-ui 0.1.0 → 0.3.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/.turbo/turbo-build.log +13 -15
- package/CHANGELOG.md +19 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +36 -2
- package/dist/index.js +48 -10
- package/dist/index.mjs +26 -0
- package/package.json +39 -8
- package/src/components/chat-components/chat-list.tsx +32 -0
- package/src/components/chat-components/chat-message-actions.tsx +40 -0
- package/src/components/chat-components/chat-message.tsx +74 -0
- package/src/components/chat-components/chat-panel.tsx +77 -0
- package/src/components/chat-components/chat-scroll-anchor.tsx +29 -0
- package/src/components/chat-components/clear-history.tsx +73 -0
- package/src/components/chat-components/copilot-chat.tsx +61 -0
- package/src/components/chat-components/default-empty-screen.tsx +62 -0
- package/src/components/chat-components/external-link.tsx +29 -0
- package/src/components/chat-components/markdown.tsx +9 -0
- package/src/components/chat-components/prompt-form.tsx +91 -0
- package/src/components/chat-components/theme-toggle.tsx +31 -0
- package/src/components/chat-components/toaster.tsx +3 -0
- package/src/components/chat-components/ui/alert-dialog.tsx +150 -0
- package/src/components/chat-components/ui/badge.tsx +36 -0
- package/src/components/chat-components/ui/button.tsx +57 -0
- package/src/components/chat-components/ui/codeblock.tsx +142 -0
- package/src/components/chat-components/ui/dialog.tsx +128 -0
- package/src/components/chat-components/ui/dropdown-menu.tsx +128 -0
- package/src/components/chat-components/ui/icons.tsx +507 -0
- package/src/components/chat-components/ui/input.tsx +25 -0
- package/src/components/chat-components/ui/label.tsx +26 -0
- package/src/components/chat-components/ui/select.tsx +119 -0
- package/src/components/chat-components/ui/separator.tsx +31 -0
- package/src/components/chat-components/ui/sheet.tsx +122 -0
- package/src/components/chat-components/ui/switch.tsx +29 -0
- package/src/components/chat-components/ui/textarea.tsx +24 -0
- package/src/components/chat-components/ui/tooltip.tsx +30 -0
- package/src/components/index.ts +7 -0
- package/src/components/sidebar/copilot-sidebar-ui-provider.tsx +74 -0
- package/src/components/sidebar/copilot-sidebar.tsx +40 -0
- package/src/components/sidebar/sidebar-context.tsx +11 -0
- package/src/context/index.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-at-bottom.tsx +23 -0
- package/src/hooks/use-copy-to-clipboard.tsx +33 -0
- package/src/hooks/use-enter-submit.tsx +23 -0
- package/src/index.tsx +4 -3
- package/src/lib/utils.ts +43 -0
- package/src/types/index.ts +1 -0
- package/src/types/types.ts +18 -0
- package/tailwind.config.js +1 -1
- package/tsconfig.json +1 -1
- package/dist/Button.d.ts +0 -3
- package/dist/Button.js +0 -10
- package/dist/Card.d.ts +0 -7
- package/dist/Card.js +0 -10
- package/dist/chunk-6OZR7L23.js +0 -7
- package/dist/chunk-FGO3LSHH.js +0 -7
- package/src/Button.tsx +0 -16
- package/src/Card.tsx +0 -27
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import * as SeparatorPrimitive from '@radix-ui/react-separator'
|
|
5
|
+
|
|
6
|
+
import { cn } from '../../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const Separator = React.forwardRef<
|
|
9
|
+
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
|
|
11
|
+
>(
|
|
12
|
+
(
|
|
13
|
+
{ className, orientation = 'horizontal', decorative = true, ...props },
|
|
14
|
+
ref
|
|
15
|
+
) => (
|
|
16
|
+
<SeparatorPrimitive.Root
|
|
17
|
+
ref={ref}
|
|
18
|
+
decorative={decorative}
|
|
19
|
+
orientation={orientation}
|
|
20
|
+
className={cn(
|
|
21
|
+
'shrink-0 bg-border',
|
|
22
|
+
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
|
|
23
|
+
className
|
|
24
|
+
)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
)
|
|
28
|
+
)
|
|
29
|
+
Separator.displayName = SeparatorPrimitive.Root.displayName
|
|
30
|
+
|
|
31
|
+
export { Separator }
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import * as SheetPrimitive from '@radix-ui/react-dialog'
|
|
5
|
+
|
|
6
|
+
import { cn } from '../../../lib/utils'
|
|
7
|
+
import { IconClose } from './icons'
|
|
8
|
+
|
|
9
|
+
const Sheet = SheetPrimitive.Root
|
|
10
|
+
|
|
11
|
+
const SheetTrigger = SheetPrimitive.Trigger
|
|
12
|
+
|
|
13
|
+
const SheetClose = SheetPrimitive.Close
|
|
14
|
+
|
|
15
|
+
const SheetPortal = ({
|
|
16
|
+
className,
|
|
17
|
+
children,
|
|
18
|
+
...props
|
|
19
|
+
}: SheetPrimitive.DialogPortalProps) => (
|
|
20
|
+
<SheetPrimitive.Portal
|
|
21
|
+
className={cn('fixed inset-0 z-50 flex', className)}
|
|
22
|
+
{...props}
|
|
23
|
+
>
|
|
24
|
+
{children}
|
|
25
|
+
</SheetPrimitive.Portal>
|
|
26
|
+
)
|
|
27
|
+
SheetPortal.displayName = SheetPrimitive.Portal.displayName
|
|
28
|
+
|
|
29
|
+
const SheetOverlay = React.forwardRef<
|
|
30
|
+
React.ElementRef<typeof SheetPrimitive.Overlay>,
|
|
31
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
|
32
|
+
>(({ className, children, ...props }, ref) => (
|
|
33
|
+
<SheetPrimitive.Overlay
|
|
34
|
+
className={cn(
|
|
35
|
+
'fixed inset-0 z-50 transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in',
|
|
36
|
+
className
|
|
37
|
+
)}
|
|
38
|
+
{...props}
|
|
39
|
+
ref={ref}
|
|
40
|
+
/>
|
|
41
|
+
))
|
|
42
|
+
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
|
|
43
|
+
|
|
44
|
+
const SheetContent = React.forwardRef<
|
|
45
|
+
React.ElementRef<typeof SheetPrimitive.Content>,
|
|
46
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>
|
|
47
|
+
>(({ className, children, ...props }, ref) => (
|
|
48
|
+
<SheetPortal>
|
|
49
|
+
<SheetPrimitive.Content
|
|
50
|
+
ref={ref}
|
|
51
|
+
className={cn(
|
|
52
|
+
'fixed z-50 h-full border-r bg-background p-6 opacity-100 shadow-lg data-[state=closed]:animate-slide-to-left data-[state=open]:animate-slide-from-left',
|
|
53
|
+
className
|
|
54
|
+
)}
|
|
55
|
+
{...props}
|
|
56
|
+
>
|
|
57
|
+
{children}
|
|
58
|
+
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
|
|
59
|
+
<IconClose />
|
|
60
|
+
<span className="sr-only">Close</span>
|
|
61
|
+
</SheetPrimitive.Close>
|
|
62
|
+
</SheetPrimitive.Content>
|
|
63
|
+
</SheetPortal>
|
|
64
|
+
))
|
|
65
|
+
SheetContent.displayName = SheetPrimitive.Content.displayName
|
|
66
|
+
|
|
67
|
+
const SheetHeader = ({
|
|
68
|
+
className,
|
|
69
|
+
...props
|
|
70
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
71
|
+
<div className={cn('flex flex-col space-y-2', className)} {...props} />
|
|
72
|
+
)
|
|
73
|
+
SheetHeader.displayName = 'SheetHeader'
|
|
74
|
+
|
|
75
|
+
const SheetFooter = ({
|
|
76
|
+
className,
|
|
77
|
+
...props
|
|
78
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
79
|
+
<div
|
|
80
|
+
className={cn(
|
|
81
|
+
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
|
82
|
+
className
|
|
83
|
+
)}
|
|
84
|
+
{...props}
|
|
85
|
+
/>
|
|
86
|
+
)
|
|
87
|
+
SheetFooter.displayName = 'SheetFooter'
|
|
88
|
+
|
|
89
|
+
const SheetTitle = React.forwardRef<
|
|
90
|
+
React.ElementRef<typeof SheetPrimitive.Title>,
|
|
91
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
|
|
92
|
+
>(({ className, ...props }, ref) => (
|
|
93
|
+
<SheetPrimitive.Title
|
|
94
|
+
ref={ref}
|
|
95
|
+
className={cn('text-lg font-semibold text-foreground', className)}
|
|
96
|
+
{...props}
|
|
97
|
+
/>
|
|
98
|
+
))
|
|
99
|
+
SheetTitle.displayName = SheetPrimitive.Title.displayName
|
|
100
|
+
|
|
101
|
+
const SheetDescription = React.forwardRef<
|
|
102
|
+
React.ElementRef<typeof SheetPrimitive.Description>,
|
|
103
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
|
|
104
|
+
>(({ className, ...props }, ref) => (
|
|
105
|
+
<SheetPrimitive.Description
|
|
106
|
+
ref={ref}
|
|
107
|
+
className={cn('text-sm text-muted-foreground', className)}
|
|
108
|
+
{...props}
|
|
109
|
+
/>
|
|
110
|
+
))
|
|
111
|
+
SheetDescription.displayName = SheetPrimitive.Description.displayName
|
|
112
|
+
|
|
113
|
+
export {
|
|
114
|
+
Sheet,
|
|
115
|
+
SheetTrigger,
|
|
116
|
+
SheetClose,
|
|
117
|
+
SheetContent,
|
|
118
|
+
SheetHeader,
|
|
119
|
+
SheetFooter,
|
|
120
|
+
SheetTitle,
|
|
121
|
+
SheetDescription
|
|
122
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import * as SwitchPrimitives from '@radix-ui/react-switch'
|
|
5
|
+
|
|
6
|
+
import { cn } from '../../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const Switch = React.forwardRef<
|
|
9
|
+
React.ElementRef<typeof SwitchPrimitives.Root>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
|
11
|
+
>(({ className, ...props }, ref) => (
|
|
12
|
+
<SwitchPrimitives.Root
|
|
13
|
+
className={cn(
|
|
14
|
+
'peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
|
|
15
|
+
className
|
|
16
|
+
)}
|
|
17
|
+
{...props}
|
|
18
|
+
ref={ref}
|
|
19
|
+
>
|
|
20
|
+
<SwitchPrimitives.Thumb
|
|
21
|
+
className={cn(
|
|
22
|
+
'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0'
|
|
23
|
+
)}
|
|
24
|
+
/>
|
|
25
|
+
</SwitchPrimitives.Root>
|
|
26
|
+
))
|
|
27
|
+
Switch.displayName = SwitchPrimitives.Root.displayName
|
|
28
|
+
|
|
29
|
+
export { Switch }
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../../lib/utils'
|
|
4
|
+
|
|
5
|
+
export interface TextareaProps
|
|
6
|
+
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
|
7
|
+
|
|
8
|
+
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
9
|
+
({ className, ...props }, ref) => {
|
|
10
|
+
return (
|
|
11
|
+
<textarea
|
|
12
|
+
className={cn(
|
|
13
|
+
'flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
|
14
|
+
className
|
|
15
|
+
)}
|
|
16
|
+
ref={ref}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
Textarea.displayName = 'Textarea'
|
|
23
|
+
|
|
24
|
+
export { Textarea }
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip'
|
|
5
|
+
|
|
6
|
+
import { cn } from '../../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const TooltipProvider = TooltipPrimitive.Provider
|
|
9
|
+
|
|
10
|
+
const Tooltip = TooltipPrimitive.Root
|
|
11
|
+
|
|
12
|
+
const TooltipTrigger = TooltipPrimitive.Trigger
|
|
13
|
+
|
|
14
|
+
const TooltipContent = React.forwardRef<
|
|
15
|
+
React.ElementRef<typeof TooltipPrimitive.Content>,
|
|
16
|
+
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
|
17
|
+
>(({ className, sideOffset = 4, ...props }, ref) => (
|
|
18
|
+
<TooltipPrimitive.Content
|
|
19
|
+
ref={ref}
|
|
20
|
+
sideOffset={sideOffset}
|
|
21
|
+
className={cn(
|
|
22
|
+
'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-xs font-medium text-popover-foreground shadow-md animate-in fade-in-50 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1',
|
|
23
|
+
className
|
|
24
|
+
)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
))
|
|
28
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName
|
|
29
|
+
|
|
30
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { CopilotChat } from './chat-components/copilot-chat'
|
|
2
|
+
export { Tooltip, TooltipProvider } from './chat-components/ui/tooltip'
|
|
3
|
+
|
|
4
|
+
export { CopilotSidebarUIProvider } from './sidebar/copilot-sidebar-ui-provider'
|
|
5
|
+
export { CopilotSidebar } from './sidebar/copilot-sidebar'
|
|
6
|
+
export { CopilotSidebarContext } from './sidebar/sidebar-context'
|
|
7
|
+
export type { CopilotSidebarContextType } from './sidebar/sidebar-context'
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React, { ReactNode, useCallback } from 'react'
|
|
2
|
+
import { useState } from 'react'
|
|
3
|
+
import { CopilotSidebar } from './copilot-sidebar'
|
|
4
|
+
import { CopilotSidebarContext } from './sidebar-context'
|
|
5
|
+
|
|
6
|
+
export interface CopilotSidebarUIProviderProps {
|
|
7
|
+
children: ReactNode
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function CopilotSidebarUIProvider({
|
|
11
|
+
children
|
|
12
|
+
}: CopilotSidebarUIProviderProps) {
|
|
13
|
+
const [sidebarOpen, setSidebarOpen] = useState(true)
|
|
14
|
+
|
|
15
|
+
const toggleSidebar = useCallback(() => {
|
|
16
|
+
setSidebarOpen(prev => !prev)
|
|
17
|
+
}, [])
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<CopilotSidebarContext.Provider
|
|
21
|
+
value={{ isSidebarOpen: sidebarOpen, toggleSidebar }}
|
|
22
|
+
>
|
|
23
|
+
<>
|
|
24
|
+
<div
|
|
25
|
+
style={{
|
|
26
|
+
height: '100vh',
|
|
27
|
+
width: '100vw',
|
|
28
|
+
position: 'relative'
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
31
|
+
<div
|
|
32
|
+
style={{
|
|
33
|
+
overflowY: 'auto',
|
|
34
|
+
overflowX: 'hidden',
|
|
35
|
+
height: '100%',
|
|
36
|
+
width: sidebarOpen ? 'calc(100% - 450px)' : '100%',
|
|
37
|
+
position: 'absolute',
|
|
38
|
+
transition: 'width 0.5s ease-in-out' // New
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
<main>{children}</main>
|
|
42
|
+
</div>
|
|
43
|
+
<div
|
|
44
|
+
style={{
|
|
45
|
+
overflowY: 'auto',
|
|
46
|
+
height: '100%',
|
|
47
|
+
width: '450px',
|
|
48
|
+
position: 'absolute',
|
|
49
|
+
right: sidebarOpen ? '0' : '-450px',
|
|
50
|
+
transition: 'right 0.5s ease-in-out'
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<CopilotSidebar setSidebarOpen={setSidebarOpen} />
|
|
54
|
+
</div>
|
|
55
|
+
{!sidebarOpen && (
|
|
56
|
+
<button
|
|
57
|
+
onClick={toggleSidebar}
|
|
58
|
+
style={{
|
|
59
|
+
position: 'absolute',
|
|
60
|
+
top: '5%',
|
|
61
|
+
right: '20px',
|
|
62
|
+
transform: 'translateY(-50%)',
|
|
63
|
+
transition: 'opacity 0.5s ease-in-out'
|
|
64
|
+
}}
|
|
65
|
+
className="bg-slate-100 ring-2 ring-slate-600 font-semibold text-black p-2 rounded-lg shadow-lg"
|
|
66
|
+
>
|
|
67
|
+
Open Copilot
|
|
68
|
+
</button>
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
71
|
+
</>
|
|
72
|
+
</CopilotSidebarContext.Provider>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { CopilotChat } from '../chat-components/copilot-chat'
|
|
3
|
+
|
|
4
|
+
export interface SidebarProps {
|
|
5
|
+
setSidebarOpen: (open: boolean) => void
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function CopilotSidebar(props: SidebarProps): JSX.Element {
|
|
9
|
+
return (
|
|
10
|
+
<div
|
|
11
|
+
className="shadow-lg bg-white flex flex-col"
|
|
12
|
+
style={{ width: '100%', height: '100%' }}
|
|
13
|
+
>
|
|
14
|
+
<TopBar {...props} />
|
|
15
|
+
<CopilotChat />
|
|
16
|
+
</div>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
import { XMarkIcon } from '@heroicons/react/24/outline'
|
|
21
|
+
|
|
22
|
+
function TopBar(props: SidebarProps): JSX.Element {
|
|
23
|
+
return (
|
|
24
|
+
<div className="py-6 bg-white flex items-center justify-between px-4">
|
|
25
|
+
<h1 className="text-base font-semibold leading-6 text-gray-900">
|
|
26
|
+
Copilot Chat
|
|
27
|
+
</h1>
|
|
28
|
+
<div className="ml-3 flex h-7 items-center">
|
|
29
|
+
<button
|
|
30
|
+
type="button"
|
|
31
|
+
className="rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
|
|
32
|
+
onClick={() => props.setSidebarOpen(false)}
|
|
33
|
+
>
|
|
34
|
+
<span className="sr-only">Close panel</span>
|
|
35
|
+
<XMarkIcon className="h-6 w-6" aria-hidden="true" />
|
|
36
|
+
</button>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createContext, ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
export interface CopilotSidebarContextType {
|
|
4
|
+
isSidebarOpen: boolean
|
|
5
|
+
toggleSidebar: () => void
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const CopilotSidebarContext = createContext<CopilotSidebarContextType>({
|
|
9
|
+
isSidebarOpen: false,
|
|
10
|
+
toggleSidebar: () => {}
|
|
11
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
|
|
3
|
+
export function useAtBottom(offset = 0) {
|
|
4
|
+
const [isAtBottom, setIsAtBottom] = React.useState(false)
|
|
5
|
+
|
|
6
|
+
React.useEffect(() => {
|
|
7
|
+
const handleScroll = () => {
|
|
8
|
+
setIsAtBottom(
|
|
9
|
+
window.innerHeight + window.scrollY >=
|
|
10
|
+
document.body.offsetHeight - offset
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
window.addEventListener('scroll', handleScroll, { passive: true })
|
|
15
|
+
handleScroll()
|
|
16
|
+
|
|
17
|
+
return () => {
|
|
18
|
+
window.removeEventListener('scroll', handleScroll)
|
|
19
|
+
}
|
|
20
|
+
}, [offset])
|
|
21
|
+
|
|
22
|
+
return isAtBottom
|
|
23
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
export interface useCopyToClipboardProps {
|
|
6
|
+
timeout?: number
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function useCopyToClipboard({
|
|
10
|
+
timeout = 2000
|
|
11
|
+
}: useCopyToClipboardProps) {
|
|
12
|
+
const [isCopied, setIsCopied] = React.useState<Boolean>(false)
|
|
13
|
+
|
|
14
|
+
const copyToClipboard = (value: string) => {
|
|
15
|
+
if (typeof window === 'undefined' || !navigator.clipboard?.writeText) {
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!value) {
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
navigator.clipboard.writeText(value).then(() => {
|
|
24
|
+
setIsCopied(true)
|
|
25
|
+
|
|
26
|
+
setTimeout(() => {
|
|
27
|
+
setIsCopied(false)
|
|
28
|
+
}, timeout)
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { isCopied, copyToClipboard }
|
|
33
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useRef, type RefObject } from 'react'
|
|
2
|
+
|
|
3
|
+
export function useEnterSubmit(): {
|
|
4
|
+
formRef: RefObject<HTMLFormElement>
|
|
5
|
+
onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void
|
|
6
|
+
} {
|
|
7
|
+
const formRef = useRef<HTMLFormElement>(null)
|
|
8
|
+
|
|
9
|
+
const handleKeyDown = (
|
|
10
|
+
event: React.KeyboardEvent<HTMLTextAreaElement>
|
|
11
|
+
): void => {
|
|
12
|
+
if (
|
|
13
|
+
event.key === 'Enter' &&
|
|
14
|
+
!event.shiftKey &&
|
|
15
|
+
!event.nativeEvent.isComposing
|
|
16
|
+
) {
|
|
17
|
+
formRef.current?.requestSubmit()
|
|
18
|
+
event.preventDefault()
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return { formRef, onKeyDown: handleKeyDown }
|
|
23
|
+
}
|
package/src/index.tsx
CHANGED
package/src/lib/utils.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { clsx, type ClassValue } from 'clsx'
|
|
2
|
+
import { customAlphabet } from 'nanoid'
|
|
3
|
+
import { twMerge } from 'tailwind-merge'
|
|
4
|
+
|
|
5
|
+
export function cn(...inputs: ClassValue[]) {
|
|
6
|
+
return twMerge(clsx(inputs))
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const nanoid = customAlphabet(
|
|
10
|
+
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
|
|
11
|
+
7
|
|
12
|
+
) // 7-character random string
|
|
13
|
+
|
|
14
|
+
export async function fetcher<JSON = any>(
|
|
15
|
+
input: RequestInfo,
|
|
16
|
+
init?: RequestInit
|
|
17
|
+
): Promise<JSON> {
|
|
18
|
+
const res = await fetch(input, init)
|
|
19
|
+
|
|
20
|
+
if (!res.ok) {
|
|
21
|
+
const json = await res.json()
|
|
22
|
+
if (json.error) {
|
|
23
|
+
const error = new Error(json.error) as Error & {
|
|
24
|
+
status: number
|
|
25
|
+
}
|
|
26
|
+
error.status = res.status
|
|
27
|
+
throw error
|
|
28
|
+
} else {
|
|
29
|
+
throw new Error('An unexpected error occurred')
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return res.json()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function formatDate(input: string | number | Date): string {
|
|
37
|
+
const date = new Date(input)
|
|
38
|
+
return date.toLocaleDateString('en-US', {
|
|
39
|
+
month: 'long',
|
|
40
|
+
day: 'numeric',
|
|
41
|
+
year: 'numeric'
|
|
42
|
+
})
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Message } from 'ai'
|
|
2
|
+
|
|
3
|
+
export interface Chat extends Record<string, any> {
|
|
4
|
+
id: string
|
|
5
|
+
title: string
|
|
6
|
+
createdAt: Date
|
|
7
|
+
userId: string
|
|
8
|
+
path: string
|
|
9
|
+
messages: Message[]
|
|
10
|
+
sharePath?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type ServerActionResult<Result> = Promise<
|
|
14
|
+
| Result
|
|
15
|
+
| {
|
|
16
|
+
error: string
|
|
17
|
+
}
|
|
18
|
+
>
|
package/tailwind.config.js
CHANGED
package/tsconfig.json
CHANGED
package/dist/Button.d.ts
DELETED
package/dist/Button.js
DELETED
package/dist/Card.d.ts
DELETED
package/dist/Card.js
DELETED
package/dist/chunk-6OZR7L23.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
|
|
5
|
-
var n=({title:e,cta:t,href:u})=>jsxRuntime.jsx("a",{target:"_blank",rel:"noopener noreferrer",href:u,className:"ui-group ui-mt-4 ui-rounded-lg ui-border ui-border-transparent ui-overflow-hidden ui-bg-origin-border ui-bg-gradient-to-r ui-from-brandred ui-to-brandblue ui-text-[#6b7280]",children:jsxRuntime.jsxs("div",{className:"ui-p-4 ui-bg-zinc-900 ui-h-full",children:[jsxRuntime.jsx("p",{className:"ui-inline-block ui-text-xl ui-text-white",children:e}),jsxRuntime.jsxs("div",{className:"ui-text-xs ui-mt-4 group-hover:ui-underline",children:[t," \u2192"]})]})});
|
|
6
|
-
|
|
7
|
-
exports.a = n;
|
package/dist/chunk-FGO3LSHH.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
|
|
5
|
-
var u=()=>jsxRuntime.jsx("div",{className:"rounded-md ",children:jsxRuntime.jsx("a",{href:"https://turbo.build/repo/docs",children:jsxRuntime.jsxs("div",{className:"ui-flex ui-w-full ui-items-center ui-justify-center ui-rounded-md ui-border ui-border-transparent ui-px-8 ui-py-3 ui-text-base ui-font-medium ui-no-underline ui-bg-white ui-text-black hover:ui-bg-gray-300 md:ui-py-3 md:ui-px-10 md:ui-text-lg md:ui-leading-6",children:["Read the docs",jsxRuntime.jsx("span",{className:"ui-ml-2 ui-bg-gradient-to-r ui-from-brandred ui-to-brandblue ui-bg-clip-text ui-text-transparent",children:"\u2192"})]})})});
|
|
6
|
-
|
|
7
|
-
exports.a = u;
|
package/src/Button.tsx
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
export const Button = () => {
|
|
4
|
-
return (
|
|
5
|
-
<div className="rounded-md ">
|
|
6
|
-
<a href="https://turbo.build/repo/docs">
|
|
7
|
-
<div className="ui-flex ui-w-full ui-items-center ui-justify-center ui-rounded-md ui-border ui-border-transparent ui-px-8 ui-py-3 ui-text-base ui-font-medium ui-no-underline ui-bg-white ui-text-black hover:ui-bg-gray-300 md:ui-py-3 md:ui-px-10 md:ui-text-lg md:ui-leading-6">
|
|
8
|
-
Read the docs
|
|
9
|
-
<span className="ui-ml-2 ui-bg-gradient-to-r ui-from-brandred ui-to-brandblue ui-bg-clip-text ui-text-transparent">
|
|
10
|
-
→
|
|
11
|
-
</span>
|
|
12
|
-
</div>
|
|
13
|
-
</a>
|
|
14
|
-
</div>
|
|
15
|
-
);
|
|
16
|
-
};
|
package/src/Card.tsx
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
export const Card = ({
|
|
4
|
-
title,
|
|
5
|
-
cta,
|
|
6
|
-
href,
|
|
7
|
-
}: {
|
|
8
|
-
title: string;
|
|
9
|
-
cta: string;
|
|
10
|
-
href: string;
|
|
11
|
-
}) => {
|
|
12
|
-
return (
|
|
13
|
-
<a
|
|
14
|
-
target="_blank"
|
|
15
|
-
rel="noopener noreferrer"
|
|
16
|
-
href={href}
|
|
17
|
-
className="ui-group ui-mt-4 ui-rounded-lg ui-border ui-border-transparent ui-overflow-hidden ui-bg-origin-border ui-bg-gradient-to-r ui-from-brandred ui-to-brandblue ui-text-[#6b7280]"
|
|
18
|
-
>
|
|
19
|
-
<div className="ui-p-4 ui-bg-zinc-900 ui-h-full">
|
|
20
|
-
<p className="ui-inline-block ui-text-xl ui-text-white">{title}</p>
|
|
21
|
-
<div className="ui-text-xs ui-mt-4 group-hover:ui-underline">
|
|
22
|
-
{cta} →
|
|
23
|
-
</div>
|
|
24
|
-
</div>
|
|
25
|
-
</a>
|
|
26
|
-
);
|
|
27
|
-
};
|