@@ -9,6 +9,7 @@ import { ContextItem, RepoContextItem, SearchContextItem } from "@/features/chat
99import { DemoExamples , DemoSearchExample , DemoSearchContextExample , DemoSearchContext } from "@/types" ;
1010import { cn , getCodeHostIcon } from "@/lib/utils" ;
1111import { RepositoryQuery , SearchContextQuery } from "@/lib/types" ;
12+ import useCaptureEvent from "@/hooks/useCaptureEvent" ;
1213
1314interface AskSourcebotDemoCardsProps {
1415 demoExamples : DemoExamples ;
@@ -25,7 +26,14 @@ export const AskSourcebotDemoCards = ({
2526 searchContexts,
2627 repos,
2728} : AskSourcebotDemoCardsProps ) => {
29+ const captureEvent = useCaptureEvent ( ) ;
30+
2831 const handleExampleClick = ( example : DemoSearchExample ) => {
32+ captureEvent ( 'wa_demo_search_example_card_pressed' , {
33+ exampleTitle : example . title ,
34+ exampleUrl : example . url || '' ,
35+ } ) ;
36+
2937 if ( example . url ) {
3038 window . open ( example . url , '_blank' ) ;
3139 }
@@ -63,6 +71,12 @@ export const AskSourcebotDemoCards = ({
6371 return ;
6472 }
6573
74+ captureEvent ( 'wa_demo_search_context_card_pressed' , {
75+ contextType : context . type ,
76+ contextName : context . value ,
77+ contextDisplayName : context . displayName ,
78+ } ) ;
79+
6680 const isDemoMode = process . env . NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT === "demo" ;
6781 const isSelected = selectedItems . some ( ( item ) => item . value === context . value ) ;
6882 if ( isSelected ) {
@@ -109,112 +123,129 @@ export const AskSourcebotDemoCards = ({
109123 }
110124
111125 return (
112- < div className = "w-full mt-8 space-y-12 px-4 max-w-[1000px]" >
113- { /* Search Context Row */ }
114- < div className = "space-y-4" >
115- < div className = "text-center mb-8" >
116- < div className = "flex items-center justify-center gap-2 mb-2" >
117- < Layers className = "h-5 w-5 text-muted-foreground" />
118- < h3 className = "text-lg font-semibold" > Search Contexts</ h3 >
126+ < >
127+ { process . env . NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT === "demo" && (
128+ < p className = "text-sm text-muted-foreground text-center mt-6" >
129+ Interested in using Sourcebot on your code? Check out our{ ' ' }
130+ < a
131+ href = "https://docs.sourcebot.dev/docs/overview"
132+ target = "_blank"
133+ rel = "noopener noreferrer"
134+ className = "text-primary hover:underline"
135+ onClick = { ( ) => captureEvent ( 'wa_demo_docs_link_pressed' , { } ) }
136+ >
137+ docs
138+ </ a >
139+ </ p >
140+ ) }
141+
142+ < div className = "w-full mt-8 space-y-12 px-4 max-w-[1000px]" >
143+ { /* Search Context Row */ }
144+ < div className = "space-y-4" >
145+ < div className = "text-center mb-8" >
146+ < div className = "flex items-center justify-center gap-2 mb-2" >
147+ < Layers className = "h-5 w-5 text-muted-foreground" />
148+ < h3 className = "text-lg font-semibold" > Search Contexts</ h3 >
149+ </ div >
150+ < p className = "text-sm text-muted-foreground" > Select the context you want to ask questions about</ p >
119151 </ div >
120- < p className = "text-sm text-muted-foreground" > Select the context you want to ask questions about </ p >
121- </ div >
122- < div className = "flex flex-wrap justify-center gap-3" >
123- { demoExamples . searchContextExamples . map ( ( contextExample ) => {
124- const context = demoExamples . searchContexts . find ( ( context ) => context . id === contextExample . searchContext )
125- if ( ! context ) {
126- console . error ( `Search context ${ contextExample . searchContext } not found on handleContextClick` ) ;
127- return null ;
128- }
129-
130- const isSelected = selectedItems . some (
131- ( selected ) => ( selected . type === 'context' && selected . value === context . value ) ||
132- ( selected . type === 'repo' && selected . value === context . value )
133- ) ;
134-
135- const searchContext = searchContexts . find ( ( item ) => item . name === context . value ) ;
136- const numRepos = searchContext ? searchContext . repoNames . length : undefined ;
137- return (
138- < Card
139- key = { context . value }
140- className = { `cursor-pointer transition-all duration-200 hover:shadow-md hover:scale-105 group w-full max-w-[280px] ${ isSelected ? "border-primary bg-primary/5 shadow-sm" : "hover:border-primary/50"
141- } ` }
142- onClick = { ( ) => handleContextClick ( demoExamples . searchContexts , contextExample ) }
143- >
144- < CardContent className = "p-4" >
145- < div className = " flex items-start gap-3" >
146- < div
147- className = { `flex-shrink-0 p-2 rounded-lg transition-transform group-hover:scale-105` }
148- >
149- { getContextIcon ( context ) }
150- </ div >
151- < div className = "flex-1 min-w-0" >
152- < div className = "flex items-center gap-2 mb-1" >
153- < h4
154- className = { `font-medium text-sm transition-colors ${ isSelected ? "text-primary" : "group-hover:text-primary"
155- } ` }
156- >
157- { context . displayName }
158- </ h4 >
159- { numRepos && (
160- < Badge className = "text-[10px] px-1.5 py-0.5 h-4" >
161- { numRepos } repos
162- </ Badge >
163- ) }
152+ < div className = "flex flex-wrap justify-center gap-3" >
153+ { demoExamples . searchContextExamples . map ( ( contextExample ) => {
154+ const context = demoExamples . searchContexts . find ( ( context ) => context . id === contextExample . searchContext )
155+ if ( ! context ) {
156+ console . error ( `Search context ${ contextExample . searchContext } not found on handleContextClick` ) ;
157+ return null ;
158+ }
159+
160+ const isSelected = selectedItems . some (
161+ ( selected ) => ( selected . type === 'context' && selected . value === context . value ) ||
162+ ( selected . type === 'repo' && selected . value === context . value )
163+ ) ;
164+
165+ const searchContext = searchContexts . find ( ( item ) => item . name === context . value ) ;
166+ const numRepos = searchContext ? searchContext . repoNames . length : undefined ;
167+ return (
168+ < Card
169+ key = { context . value }
170+ className = { `cursor-pointer transition-all duration-200 hover:shadow-md hover:scale-105 group w-full max-w-[280px] ${ isSelected ? "border-primary bg-primary/5 shadow-sm" : "hover:border-primary/50"
171+ } ` }
172+ onClick = { ( ) => handleContextClick ( demoExamples . searchContexts , contextExample ) }
173+ >
174+ < CardContent className = "p-4" >
175+ < div className = "flex items-start gap-3" >
176+ < div
177+ className = { ` flex-shrink-0 p-2 rounded-lg transition-transform group-hover:scale-105` }
178+ >
179+ { getContextIcon ( context ) }
180+ </ div >
181+ < div className = "flex-1 min-w-0" >
182+ < div className = "flex items-center gap-2 mb-1" >
183+ < h4
184+ className = { `font-medium text-sm transition-colors ${ isSelected ? "text-primary" : "group-hover:text-primary"
185+ } ` }
186+ >
187+ { context . displayName }
188+ </ h4 >
189+ { numRepos && (
190+ < Badge className = "text-[10px] px-1.5 py-0.5 h-4" >
191+ { numRepos } repos
192+ </ Badge >
193+ ) }
194+ </ div >
195+ < p className = "text-xs text-muted-foreground" > { contextExample . description } </ p >
164196 </ div >
165- < p className = "text-xs text-muted-foreground" > { contextExample . description } </ p >
166197 </ div >
167- </ div >
168- </ CardContent >
169- </ Card >
170- )
171- } ) }
198+ </ CardContent >
199+ </ Card >
200+ )
201+ } ) }
202+ </ div >
172203 </ div >
173- </ div >
174204
175- { /* Example Searches Row */ }
176- < div className = "space-y-4" >
177- < div className = "text-center mb-8" >
178- < div className = "flex items-center justify-center gap-2 mb-2" >
179- < Search className = "h-5 w-5 text-muted-foreground" />
180- < h3 className = "text-lg font-semibold" > Community Ask Results</ h3 >
205+ { /* Example Searches Row */ }
206+ < div className = "space-y-4" >
207+ < div className = "text-center mb-8" >
208+ < div className = "flex items-center justify-center gap-2 mb-2" >
209+ < Search className = "h-5 w-5 text-muted-foreground" />
210+ < h3 className = "text-lg font-semibold" > Community Ask Results</ h3 >
211+ </ div >
212+ < p className = "text-sm text-muted-foreground" > Check out these featured ask results from the community</ p >
181213 </ div >
182- < p className = "text-sm text-muted-foreground" > Check out these featured ask results from the community</ p >
183- </ div >
184- < div className = "flex flex-wrap justify-center gap-3" >
185- { demoExamples . searchExamples . map ( ( example ) => {
186- const searchContexts = demoExamples . searchContexts . filter ( ( context ) => example . searchContext . includes ( context . id ) )
187- return (
188- < Card
189- key = { example . url }
190- className = "cursor-pointer transition-all duration-200 hover:shadow-md hover:scale-105 hover:border-primary/50 group w-full max-w-[350px]"
191- onClick = { ( ) => handleExampleClick ( example ) }
192- >
193- < CardContent className = "p-4" >
194- < div className = "space-y-3" >
195- < div className = "flex items-center justify-between" >
196- { searchContexts . map ( ( context ) => (
197- < Badge key = { context . value } variant = "secondary" className = "text-[10px] px-1.5 py-0.5 h-4 flex items-center gap-1" >
198- { getContextIcon ( context , 12 ) }
199- { context . displayName }
200- </ Badge >
201- ) ) }
202- </ div >
203- < div className = "space-y-1" >
204- < h4 className = "font-semibold text-sm group-hover:text-primary transition-colors line-clamp-2" >
205- { example . title }
206- </ h4 >
207- < p className = "text-xs text-muted-foreground line-clamp-3 leading-relaxed" >
208- { example . description }
209- </ p >
214+ < div className = "flex flex-wrap justify-center gap-3" >
215+ { demoExamples . searchExamples . map ( ( example ) => {
216+ const searchContexts = demoExamples . searchContexts . filter ( ( context ) => example . searchContext . includes ( context . id ) )
217+ return (
218+ < Card
219+ key = { example . url }
220+ className = "cursor-pointer transition-all duration-200 hover:shadow-md hover:scale-105 hover:border-primary/50 group w-full max-w-[350px]"
221+ onClick = { ( ) => handleExampleClick ( example ) }
222+ >
223+ < CardContent className = "p-4" >
224+ < div className = "space-y-3" >
225+ < div className = "flex items-center justify-between" >
226+ { searchContexts . map ( ( context ) => (
227+ < Badge key = { context . value } variant = "secondary" className = "text-[10px] px-1.5 py-0.5 h-4 flex items-center gap-1" >
228+ { getContextIcon ( context , 12 ) }
229+ { context . displayName }
230+ </ Badge >
231+ ) ) }
232+ </ div >
233+ < div className = "space-y-1" >
234+ < h4 className = "font-semibold text-sm group-hover:text-primary transition-colors line-clamp-2" >
235+ { example . title }
236+ </ h4 >
237+ < p className = "text-xs text-muted-foreground line-clamp-3 leading-relaxed" >
238+ { example . description }
239+ </ p >
240+ </ div >
210241 </ div >
211- </ div >
212- </ CardContent >
213- </ Card >
214- )
215- } ) }
242+ </ CardContent >
243+ </ Card >
244+ )
245+ } ) }
246+ </ div >
216247 </ div >
217248 </ div >
218- </ div >
249+ </ >
219250 ) ;
220251} ;
0 commit comments