Skip to content

Commit beb187b

Browse files
wip
1 parent da6e913 commit beb187b

3 files changed

Lines changed: 245 additions & 3 deletions

File tree

packages/web/src/app/[domain]/components/homepage/agenticSearch.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { SearchModeSelector, SearchModeSelectorProps } from "./toolbar";
1111
import { useLocalStorage } from "usehooks-ts";
1212
import { DemoExamples } from "@/types";
1313
import { AskSourcebotDemoCards } from "./askSourcebotDemoCards";
14+
import { AskSourcebotTutorial } from "./askSourcebotTutorial";
1415

1516
interface AgenticSearchProps {
1617
searchModeSelectorProps: SearchModeSelectorProps;
@@ -35,6 +36,7 @@ export const AgenticSearch = ({
3536
const { createNewChatThread, isLoading } = useCreateNewChatThread();
3637
const [selectedSearchScopes, setSelectedSearchScopes] = useLocalStorage<SearchScope[]>("selectedSearchScopes", [], { initializeWithValue: false });
3738
const [isContextSelectorOpen, setIsContextSelectorOpen] = useState(false);
39+
const [isTutorialOpen, setIsTutorialOpen] = useState(true);
3840

3941
return (
4042
<div className="flex flex-col items-center w-full">
@@ -75,6 +77,11 @@ export const AgenticSearch = ({
7577
demoExamples={demoExamples}
7678
/>
7779
)}
80+
81+
<AskSourcebotTutorial
82+
isOpen={isTutorialOpen}
83+
onClose={() => setIsTutorialOpen(false)}
84+
/>
7885
</div >
7986
)
8087
}
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
"use client"
2+
3+
import { Button } from "@/components/ui/button"
4+
import { Card, CardContent } from "@/components/ui/card"
5+
import { Dialog, DialogContent } from "@/components/ui/dialog"
6+
import { ModelProviderLogo } from "@/features/chat/components/chatBox/modelProviderLogo"
7+
import { cn } from "@/lib/utils"
8+
import githubIcon from "@/public/github.svg"
9+
import { ChevronLeft, ChevronRight, GitBranch, LibraryBigIcon, ScanSearchIcon, Sparkles } from "lucide-react"
10+
import Image from "next/image"
11+
import Link from "next/link"
12+
import { useState } from "react"
13+
14+
interface TutorialModalProps {
15+
isOpen: boolean
16+
onClose: () => void
17+
}
18+
19+
const tutorialSteps = [
20+
{
21+
leftContent: (
22+
<div className="flex flex-col h-full p-8 justify-between gap-4">
23+
<div className="flex flex-col gap-6">
24+
<h2 className="text-5xl font-bold leading-tight">
25+
Ask Source<span className="text-[#851EE6]">bot.</span>
26+
</h2>
27+
<p className="text-lg">
28+
Ask questions about your <span className="font-bold">entire codebase</span> in natural language.
29+
Get back Markdown formatted responses with <span className="font-bold">inline citations</span>.
30+
</p>
31+
<p className="text-md text-muted-foreground">
32+
Ask Sourcebot is an agentic search tool that can answer questions about your codebase by searching, reading files, navigating references, and more. Supports any <Link href="https://docs.sourcebot.dev/docs/configuration/language-model-providers" className="underline">compatible LLM.</Link>
33+
</p>
34+
</div>
35+
<div className="space-y-3 mx-auto flex flex-wrap justify-center gap-4">
36+
<div className="flex flex-wrap items-center gap-4">
37+
<ModelProviderLogo provider="anthropic" />
38+
<ModelProviderLogo provider="openai" />
39+
<ModelProviderLogo provider="google-generative-ai" />
40+
<ModelProviderLogo provider="amazon-bedrock" />
41+
<ModelProviderLogo provider="azure" />
42+
<ModelProviderLogo provider="deepseek" />
43+
<ModelProviderLogo provider="mistral" />
44+
<ModelProviderLogo provider="openrouter" />
45+
<ModelProviderLogo provider="xai" />
46+
</div>
47+
</div>
48+
</div>
49+
),
50+
rightContent: (
51+
<div className="h-full w-full">
52+
<video
53+
src="https://storage.googleapis.com/sourcebot-assets/hero_final.mp4"
54+
autoPlay
55+
loop
56+
muted
57+
playsInline
58+
className="w-full h-full object-cover"
59+
/>
60+
</div>
61+
),
62+
},
63+
{
64+
leftContent: (
65+
<div className="flex flex-col h-full p-8 space-y-6">
66+
<h2 className="text-3xl font-bold leading-tight flex items-center gap-2">
67+
<ScanSearchIcon className="inline-block h-8 w-8 text-primary" />
68+
Search Scopes
69+
</h2>
70+
<p className="text-lg">
71+
{`When asking Sourcebot a question, you can select one or more scopes to constrain the search.`}
72+
</p>
73+
74+
<div className="flex flex-col mb-2">
75+
<p className="mb-4">There are two types of search scopes:</p>
76+
<div className="flex gap-2">
77+
<Image src={githubIcon} alt="GitHub icon" className="w-4 h-4 dark:invert mt-1" />
78+
<span><strong>Repository</strong>: A single repository, indicated by the code host icon.</span>
79+
</div>
80+
<div className="flex gap-2">
81+
<LibraryBigIcon className="h-4 w-4 text-muted-foreground flex-shrink-0 mt-1" />
82+
<span><strong>Reposet</strong>: A set of repositories, indicated by the library icon.</span>
83+
</div>
84+
</div>
85+
</div>
86+
),
87+
rightContent: (
88+
<div>
89+
todo
90+
</div>
91+
),
92+
},
93+
{
94+
leftContent: (
95+
<div className="flex flex-col h-full justify-between p-8">
96+
97+
</div>
98+
),
99+
rightContent: (
100+
<div className="flex items-center justify-center h-full p-8">
101+
<Card className="w-full max-w-md border-2 border-primary bg-accent shadow-lg">
102+
<CardContent className="p-6">
103+
<div className="space-y-4">
104+
<div className="flex items-center gap-2 text-sm text-muted-foreground">
105+
<GitBranch className="w-4 h-4" />
106+
Context dropdown:
107+
</div>
108+
<div className="bg-card rounded-lg p-4 border">
109+
<div className="flex items-center gap-2">
110+
<div className="w-3 h-3 bg-primary rounded-full"></div>
111+
<span className="text-base font-medium">my-frontend-app</span>
112+
<ChevronRight className="w-4 h-4 text-muted-foreground ml-auto" />
113+
</div>
114+
<div className="mt-3 pl-5 space-y-1">
115+
<div className="text-sm text-muted-foreground">• backend-api</div>
116+
<div className="text-sm text-muted-foreground">• mobile-app</div>
117+
<div className="text-sm text-muted-foreground">• shared-components</div>
118+
</div>
119+
</div>
120+
</div>
121+
</CardContent>
122+
</Card>
123+
</div>
124+
),
125+
},
126+
{
127+
leftContent: (
128+
<div className="flex flex-col h-full justify-between p-8">
129+
<p>todo</p>
130+
</div>
131+
),
132+
rightContent: (
133+
<div>
134+
todo
135+
</div>
136+
),
137+
},
138+
]
139+
140+
export function AskSourcebotTutorial({ isOpen, onClose }: TutorialModalProps) {
141+
const [currentStep, setCurrentStep] = useState(0)
142+
143+
const nextStep = () => {
144+
if (currentStep < tutorialSteps.length - 1) {
145+
setCurrentStep(currentStep + 1)
146+
}
147+
}
148+
149+
const prevStep = () => {
150+
if (currentStep > 0) {
151+
setCurrentStep(currentStep - 1)
152+
}
153+
}
154+
155+
const handleClose = () => {
156+
setCurrentStep(0)
157+
onClose()
158+
}
159+
160+
const isLastStep = currentStep === tutorialSteps.length - 1
161+
const isFirstStep = currentStep === 0
162+
163+
const currentStepData = tutorialSteps[currentStep]
164+
165+
return (
166+
<Dialog open={isOpen} onOpenChange={handleClose}>
167+
<DialogContent
168+
className="sm:max-w-[900px] p-0 flex flex-col h-[525px] overflow-hidden rounded-xl border-none bg-transparent"
169+
closeButtonClassName="text-white"
170+
>
171+
<div className="relative flex h-full">
172+
{/* Left Column (Text Content & Navigation) */}
173+
<div className="flex-1 flex flex-col justify-between bg-background">
174+
<div className="p-4 flex-1 overflow-y-auto">
175+
{currentStepData.leftContent}
176+
</div>
177+
178+
{/* Fixed bottom navigation for left column */}
179+
<div className="border-t p-6 flex items-center justify-between">
180+
{/* Left side: Previous button container */}
181+
<div className="w-36 flex justify-start">
182+
<Button
183+
variant="ghost"
184+
onClick={prevStep}
185+
className={cn(
186+
"flex items-center gap-2",
187+
isFirstStep && "opacity-0 pointer-events-none"
188+
)}
189+
>
190+
<ChevronLeft className="w-4 h-4" />
191+
Previous
192+
</Button>
193+
</div>
194+
195+
{/* Center: Progress dots */}
196+
<div className="flex gap-2">
197+
{tutorialSteps.map((_, index) => (
198+
<div
199+
key={index}
200+
className={cn(
201+
"w-2 h-2 rounded-full transition-colors",
202+
index === currentStep ? "bg-primary" : "bg-muted"
203+
)}
204+
/>
205+
))}
206+
</div>
207+
208+
{/* Right side: Next/Start/Get Started button container */}
209+
<div className="w-36 flex justify-end">
210+
{isLastStep ? (
211+
<Button onClick={handleClose}>
212+
Get Started
213+
<Sparkles className="w-4 h-4" />
214+
</Button>
215+
) : (
216+
<Button onClick={nextStep}>
217+
Next
218+
<ChevronRight className="w-4 h-4" />
219+
</Button>
220+
)}
221+
</div>
222+
</div>
223+
</div>
224+
225+
{/* Right Column (Image/Visual Content) */}
226+
<div className="flex-1 flex flex-col justify-between">
227+
<div className="flex-1 overflow-y-auto">{currentStepData.rightContent}</div>
228+
</div>
229+
</div>
230+
</DialogContent>
231+
</Dialog>
232+
)
233+
}

packages/web/src/components/ui/dialog.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
3131

3232
const DialogContent = React.forwardRef<
3333
React.ElementRef<typeof DialogPrimitive.Content>,
34-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
35-
>(({ className, children, ...props }, ref) => (
34+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
35+
closeButtonClassName?: string
36+
}
37+
>(({ className, children, closeButtonClassName, ...props }, ref) => (
3638
<DialogPortal>
3739
<DialogOverlay />
3840
<DialogPrimitive.Content
@@ -45,7 +47,7 @@ const DialogContent = React.forwardRef<
4547
>
4648
{children}
4749
<DialogPrimitive.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-accent data-[state=open]:text-muted-foreground">
48-
<X className="h-4 w-4" />
50+
<X className={cn("h-4 w-4", closeButtonClassName)} />
4951
<span className="sr-only">Close</span>
5052
</DialogPrimitive.Close>
5153
</DialogPrimitive.Content>

0 commit comments

Comments
 (0)