|
1 | 1 | "use client";
|
2 | 2 |
|
3 |
| -import React, {useCallback, useMemo, useRef} from "react"; |
| 3 | +import React, {useCallback, useMemo, useRef, useState} from "react"; |
4 | 4 | import dynamic from "next/dynamic";
|
5 |
| -import {Skeleton, Tab, Tabs} from "@heroui/react"; |
| 5 | +import {addToast, Button, Skeleton, Spinner, Tab, Tabs} from "@heroui/react"; |
6 | 6 | import {useInView} from "framer-motion";
|
| 7 | +import {usePostHog} from "posthog-js/react"; |
| 8 | +import {usePathname} from "next/navigation"; |
7 | 9 |
|
8 | 10 | import {useCodeDemo, UseCodeDemoProps} from "./use-code-demo";
|
9 | 11 | import WindowResizer, {WindowResizerProps} from "./window-resizer";
|
10 | 12 |
|
11 | 13 | import {GradientBoxProps} from "@/components/gradient-box";
|
| 14 | +import {SmallLogo} from "@/components/heroui-logo"; |
| 15 | +import {openInChat} from "@/actions/open-in-chat"; |
12 | 16 |
|
13 | 17 | const DynamicReactLiveDemo = dynamic(
|
14 | 18 | () => import("./react-live-demo").then((m) => m.ReactLiveDemo),
|
@@ -75,6 +79,11 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
|
75 | 79 | margin: "600px",
|
76 | 80 | });
|
77 | 81 |
|
| 82 | + const pathname = usePathname(); |
| 83 | + const posthog = usePostHog(); |
| 84 | + |
| 85 | + const [isLoading, setIsLoading] = useState(false); |
| 86 | + |
78 | 87 | const {noInline, code} = useCodeDemo({
|
79 | 88 | files,
|
80 | 89 | });
|
@@ -166,24 +175,84 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
|
166 | 175 | return true;
|
167 | 176 | }, [showTabs, showPreview, showEditor]);
|
168 | 177 |
|
| 178 | + const isComponentsPage = pathname.includes("/components/"); |
| 179 | + |
| 180 | + const handleOpenInChat = useCallback(async () => { |
| 181 | + setIsLoading(true); |
| 182 | + |
| 183 | + const component = pathname.split("/components/")[1]; |
| 184 | + |
| 185 | + posthog.capture("CodeDemo - Open in Chat", { |
| 186 | + component, |
| 187 | + demo: title, |
| 188 | + }); |
| 189 | + |
| 190 | + const capitalizedPath = component.charAt(0).toUpperCase() + component.slice(1); |
| 191 | + const {data, error} = await openInChat({title: `${capitalizedPath} - ${title}`, files}); |
| 192 | + |
| 193 | + setIsLoading(false); |
| 194 | + |
| 195 | + if (error || !data) { |
| 196 | + posthog.capture("CodeDemo - Open in Chat Error", { |
| 197 | + component, |
| 198 | + demo: title, |
| 199 | + error: error ?? "Unknown error", |
| 200 | + }); |
| 201 | + |
| 202 | + addToast({ |
| 203 | + title: "Error", |
| 204 | + description: error ?? "Unknown error", |
| 205 | + color: "danger", |
| 206 | + }); |
| 207 | + |
| 208 | + return; |
| 209 | + } |
| 210 | + |
| 211 | + window.open(data, "_blank"); |
| 212 | + }, [pathname, title, files, posthog]); |
| 213 | + |
169 | 214 | return (
|
170 |
| - <div ref={ref} className="flex flex-col gap-2"> |
| 215 | + <div ref={ref} className="flex flex-col gap-2 relative"> |
171 | 216 | {shouldRenderTabs ? (
|
172 |
| - <Tabs |
173 |
| - disableAnimation |
174 |
| - aria-label="Code demo tabs" |
175 |
| - classNames={{ |
176 |
| - panel: "pt-0", |
177 |
| - }} |
178 |
| - variant="underlined" |
179 |
| - > |
180 |
| - <Tab key="preview" title="Preview"> |
181 |
| - {previewContent} |
182 |
| - </Tab> |
183 |
| - <Tab key="code" title="Code"> |
184 |
| - {editorContent} |
185 |
| - </Tab> |
186 |
| - </Tabs> |
| 217 | + <> |
| 218 | + <Tabs |
| 219 | + disableAnimation |
| 220 | + aria-label="Code demo tabs" |
| 221 | + classNames={{ |
| 222 | + panel: "pt-0", |
| 223 | + }} |
| 224 | + variant="underlined" |
| 225 | + > |
| 226 | + <Tab key="preview" title="Preview"> |
| 227 | + {previewContent} |
| 228 | + </Tab> |
| 229 | + <Tab key="code" title="Code"> |
| 230 | + {editorContent} |
| 231 | + </Tab> |
| 232 | + </Tabs> |
| 233 | + {isComponentsPage && ( |
| 234 | + <Button |
| 235 | + disableRipple |
| 236 | + className="absolute rounded-[9px] right-1 top-1 border-1 border-default-200 dark:border-default-100 data-[hover=true]:bg-default-50/80" |
| 237 | + isDisabled={isLoading} |
| 238 | + size="sm" |
| 239 | + variant="bordered" |
| 240 | + onPress={handleOpenInChat} |
| 241 | + > |
| 242 | + Open in Chat{" "} |
| 243 | + {isLoading ? ( |
| 244 | + <Spinner |
| 245 | + classNames={{wrapper: "h-4 w-4"}} |
| 246 | + color="current" |
| 247 | + size="sm" |
| 248 | + variant="simple" |
| 249 | + /> |
| 250 | + ) : ( |
| 251 | + <SmallLogo className="w-4 h-4" /> |
| 252 | + )} |
| 253 | + </Button> |
| 254 | + )} |
| 255 | + </> |
187 | 256 | ) : (
|
188 | 257 | <>
|
189 | 258 | {previewContent}
|
|
0 commit comments