1+ "use client"
2+
3+ import { useState } from "react"
4+ import { Button } from "@/components/ui/button"
5+ import { generateWebPromptDeeplink , formatRuleAsPrompt , isPromptValidForDeeplink } from "@/lib/cursor-deeplink"
6+ import { track } from "@vercel/analytics"
7+ import { toast } from "sonner"
8+ import { ExternalLink } from "lucide-react"
9+
10+ interface TryInCursorButtonProps {
11+ /** The rule title */
12+ title : string
13+ /** The rule content */
14+ content : string
15+ /** The rule ID for analytics tracking */
16+ ruleId : string
17+ /** Button variant */
18+ variant ?: "default" | "secondary" | "ghost" | "outline"
19+ /** Button size */
20+ size ?: "sm" | "default" | "lg"
21+ /** Additional CSS classes */
22+ className ?: string
23+ /** Button text (defaults to "Try in Cursor") */
24+ children ?: React . ReactNode
25+ /** Analytics context for tracking */
26+ analyticsContext ?: string
27+ }
28+
29+ export function TryInCursorButton ( {
30+ title,
31+ content,
32+ ruleId,
33+ variant = "default" ,
34+ size = "sm" ,
35+ className,
36+ children = "Try in Cursor" ,
37+ analyticsContext = "unknown"
38+ } : TryInCursorButtonProps ) {
39+ const [ isClicked , setIsClicked ] = useState ( false )
40+
41+ const handleClick = ( ) => {
42+ try {
43+ const promptText = formatRuleAsPrompt ( title , content )
44+
45+ // Check if the prompt would fit in a deeplink URL
46+ if ( ! isPromptValidForDeeplink ( promptText ) ) {
47+ toast . error ( "This rule is too long to share as a Cursor deeplink" )
48+ return
49+ }
50+
51+ const deeplink = generateWebPromptDeeplink ( promptText )
52+
53+ // Open the deeplink in a new window/tab
54+ window . open ( deeplink , '_blank' , 'noopener,noreferrer' )
55+
56+ // Show feedback
57+ setIsClicked ( true )
58+ setTimeout ( ( ) => setIsClicked ( false ) , 2000 )
59+
60+ // Track the event
61+ track ( "Try in Cursor Clicked" , {
62+ ruleId,
63+ ruleTitle : title ,
64+ context : analyticsContext ,
65+ promptLength : promptText . length
66+ } )
67+
68+ toast . success ( "Opening in Cursor..." )
69+ } catch ( error ) {
70+ console . error ( "Error generating Cursor deeplink:" , error )
71+ toast . error ( "Failed to generate Cursor deeplink" )
72+ }
73+ }
74+
75+ return (
76+ < Button
77+ onClick = { handleClick }
78+ variant = { variant }
79+ size = { size }
80+ className = { className }
81+ disabled = { isClicked }
82+ >
83+ { isClicked ? (
84+ < >
85+ < svg xmlns = "http://www.w3.org/2000/svg" width = "16" height = "16" viewBox = "0 0 18 18" >
86+ < g fill = "currentColor" >
87+ < path d = "M9 1.5C4.86 1.5 1.5 4.86 1.5 9C1.5 13.14 4.86 16.5 9 16.5C13.14 16.5 16.5 13.14 16.5 9C16.5 4.86 13.14 1.5 9 1.5ZM7.5 12.75L3.75 9L5.16 7.59L7.5 9.93L12.84 4.59L14.25 6L7.5 12.75Z" />
88+ </ g >
89+ </ svg >
90+ Opened!
91+ </ >
92+ ) : (
93+ < >
94+ < svg
95+ xmlns = "http://www.w3.org/2000/svg"
96+ width = "16"
97+ height = "16"
98+ viewBox = "0 0 24 24"
99+ fill = "none"
100+ stroke = "currentColor"
101+ strokeWidth = "2"
102+ strokeLinecap = "round"
103+ strokeLinejoin = "round"
104+ >
105+ < path d = "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
106+ < polyline points = "15,3 21,3 21,9" />
107+ < line x1 = "10" y1 = "14" x2 = "21" y2 = "3" />
108+ </ svg >
109+ { children }
110+ </ >
111+ ) }
112+ </ Button >
113+ )
114+ }
0 commit comments