2024-09-19 05:26:00 +00:00
|
|
|
import { listRepositories } from "@/lib/server/searchService";
|
|
|
|
|
import { isServiceError } from "@/lib/utils";
|
2024-08-26 00:57:34 +00:00
|
|
|
import Image from "next/image";
|
2024-09-19 05:26:00 +00:00
|
|
|
import { Suspense } from "react";
|
2024-09-03 01:46:43 +00:00
|
|
|
import logoDark from "../../public/sb_logo_dark_large.png";
|
|
|
|
|
import logoLight from "../../public/sb_logo_light_large.png";
|
Search suggestions (#85)
The motivation for building search suggestions is two-fold: (1) to make the zoekt query language more approachable by presenting all available options to the user, and (2) make it easier for power-users to craft complex queries.
The meat-n-potatoes of this change are concentrated in searchBar.tsx and searchSuggestionBox.tsx. The suggestions box works by maintaining a state-machine of "modes". By default, the box is in the refine mode, where suggestions for different prefixes (e.g., repo:, lang:, etc.) are suggested to the user. When one of these prefixes is matched, the state-machine transitions to the corresponding mode (e.g., repository, language, etc.) and surfaces suggestions for that mode (if any).
The query is split up into parts by spaces " " (e.g., 'test repo:hello' -> ['test', 'repo:hello']). See splitQuery. The part that has the cursor over it is considered the active part. We evaluate which mode the state machine is in based on the active part. When a suggestion is clicked, we only modify the active part of the query.
Three modes are currently missing suggestion data: file (file names), revision (branch / tag names), and symbol (symbol names). In future PRs, we will need to introduce endpoints into the backend to allow the frontend to fetch this data and surface it as suggestions..
2024-11-23 02:50:13 +00:00
|
|
|
import { NavigationMenu } from "./components/navigationMenu";
|
|
|
|
|
import { RepositoryCarousel } from "./components/repositoryCarousel";
|
|
|
|
|
import { SearchBar } from "./components/searchBar";
|
2024-09-19 05:26:00 +00:00
|
|
|
import { Separator } from "@/components/ui/separator";
|
2024-09-25 03:34:06 +00:00
|
|
|
import { SymbolIcon } from "@radix-ui/react-icons";
|
Search suggestions (#85)
The motivation for building search suggestions is two-fold: (1) to make the zoekt query language more approachable by presenting all available options to the user, and (2) make it easier for power-users to craft complex queries.
The meat-n-potatoes of this change are concentrated in searchBar.tsx and searchSuggestionBox.tsx. The suggestions box works by maintaining a state-machine of "modes". By default, the box is in the refine mode, where suggestions for different prefixes (e.g., repo:, lang:, etc.) are suggested to the user. When one of these prefixes is matched, the state-machine transitions to the corresponding mode (e.g., repository, language, etc.) and surfaces suggestions for that mode (if any).
The query is split up into parts by spaces " " (e.g., 'test repo:hello' -> ['test', 'repo:hello']). See splitQuery. The part that has the cursor over it is considered the active part. We evaluate which mode the state machine is in based on the active part. When a suggestion is clicked, we only modify the active part of the query.
Three modes are currently missing suggestion data: file (file names), revision (branch / tag names), and symbol (symbol names). In future PRs, we will need to introduce endpoints into the backend to allow the frontend to fetch this data and surface it as suggestions..
2024-11-23 02:50:13 +00:00
|
|
|
import { UpgradeToast } from "./components/upgradeToast";
|
2024-11-27 18:48:22 +00:00
|
|
|
import Link from "next/link";
|
2024-08-28 04:00:59 +00:00
|
|
|
|
2024-09-19 05:26:00 +00:00
|
|
|
|
|
|
|
|
export default async function Home() {
|
2024-08-25 00:45:44 +00:00
|
|
|
return (
|
2024-09-24 05:30:58 +00:00
|
|
|
<div className="flex flex-col items-center overflow-hidden">
|
2024-09-11 04:55:00 +00:00
|
|
|
<NavigationMenu />
|
2024-10-18 19:03:13 +00:00
|
|
|
<UpgradeToast />
|
2024-09-19 05:26:00 +00:00
|
|
|
|
Search suggestions (#85)
The motivation for building search suggestions is two-fold: (1) to make the zoekt query language more approachable by presenting all available options to the user, and (2) make it easier for power-users to craft complex queries.
The meat-n-potatoes of this change are concentrated in searchBar.tsx and searchSuggestionBox.tsx. The suggestions box works by maintaining a state-machine of "modes". By default, the box is in the refine mode, where suggestions for different prefixes (e.g., repo:, lang:, etc.) are suggested to the user. When one of these prefixes is matched, the state-machine transitions to the corresponding mode (e.g., repository, language, etc.) and surfaces suggestions for that mode (if any).
The query is split up into parts by spaces " " (e.g., 'test repo:hello' -> ['test', 'repo:hello']). See splitQuery. The part that has the cursor over it is considered the active part. We evaluate which mode the state machine is in based on the active part. When a suggestion is clicked, we only modify the active part of the query.
Three modes are currently missing suggestion data: file (file names), revision (branch / tag names), and symbol (symbol names). In future PRs, we will need to introduce endpoints into the backend to allow the frontend to fetch this data and surface it as suggestions..
2024-11-23 02:50:13 +00:00
|
|
|
<div className="flex flex-col justify-center items-center mt-8 mb-8 md:mt-18 w-full px-5">
|
2024-09-03 01:46:43 +00:00
|
|
|
<div className="max-h-44 w-auto">
|
|
|
|
|
<Image
|
|
|
|
|
src={logoDark}
|
2024-09-24 05:30:58 +00:00
|
|
|
className="h-18 md:h-40 w-auto hidden dark:block"
|
2024-09-03 01:46:43 +00:00
|
|
|
alt={"Sourcebot logo"}
|
2024-09-19 05:26:00 +00:00
|
|
|
priority={true}
|
2024-08-28 00:28:35 +00:00
|
|
|
/>
|
2024-09-03 01:46:43 +00:00
|
|
|
<Image
|
|
|
|
|
src={logoLight}
|
2024-09-24 05:30:58 +00:00
|
|
|
className="h-18 md:h-40 w-auto block dark:hidden"
|
2024-09-03 01:46:43 +00:00
|
|
|
alt={"Sourcebot logo"}
|
2024-09-19 05:26:00 +00:00
|
|
|
priority={true}
|
2024-08-28 00:28:35 +00:00
|
|
|
/>
|
2024-09-03 01:46:43 +00:00
|
|
|
</div>
|
Search suggestions (#85)
The motivation for building search suggestions is two-fold: (1) to make the zoekt query language more approachable by presenting all available options to the user, and (2) make it easier for power-users to craft complex queries.
The meat-n-potatoes of this change are concentrated in searchBar.tsx and searchSuggestionBox.tsx. The suggestions box works by maintaining a state-machine of "modes". By default, the box is in the refine mode, where suggestions for different prefixes (e.g., repo:, lang:, etc.) are suggested to the user. When one of these prefixes is matched, the state-machine transitions to the corresponding mode (e.g., repository, language, etc.) and surfaces suggestions for that mode (if any).
The query is split up into parts by spaces " " (e.g., 'test repo:hello' -> ['test', 'repo:hello']). See splitQuery. The part that has the cursor over it is considered the active part. We evaluate which mode the state machine is in based on the active part. When a suggestion is clicked, we only modify the active part of the query.
Three modes are currently missing suggestion data: file (file names), revision (branch / tag names), and symbol (symbol names). In future PRs, we will need to introduce endpoints into the backend to allow the frontend to fetch this data and surface it as suggestions..
2024-11-23 02:50:13 +00:00
|
|
|
<SearchBar
|
|
|
|
|
autoFocus={true}
|
|
|
|
|
className="mt-4 w-full max-w-[800px]"
|
|
|
|
|
/>
|
2024-09-19 05:26:00 +00:00
|
|
|
<div className="mt-8">
|
|
|
|
|
<Suspense fallback={<div>...</div>}>
|
|
|
|
|
<RepositoryList />
|
|
|
|
|
</Suspense>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex flex-col items-center w-fit gap-6">
|
Search suggestions (#85)
The motivation for building search suggestions is two-fold: (1) to make the zoekt query language more approachable by presenting all available options to the user, and (2) make it easier for power-users to craft complex queries.
The meat-n-potatoes of this change are concentrated in searchBar.tsx and searchSuggestionBox.tsx. The suggestions box works by maintaining a state-machine of "modes". By default, the box is in the refine mode, where suggestions for different prefixes (e.g., repo:, lang:, etc.) are suggested to the user. When one of these prefixes is matched, the state-machine transitions to the corresponding mode (e.g., repository, language, etc.) and surfaces suggestions for that mode (if any).
The query is split up into parts by spaces " " (e.g., 'test repo:hello' -> ['test', 'repo:hello']). See splitQuery. The part that has the cursor over it is considered the active part. We evaluate which mode the state machine is in based on the active part. When a suggestion is clicked, we only modify the active part of the query.
Three modes are currently missing suggestion data: file (file names), revision (branch / tag names), and symbol (symbol names). In future PRs, we will need to introduce endpoints into the backend to allow the frontend to fetch this data and surface it as suggestions..
2024-11-23 02:50:13 +00:00
|
|
|
<Separator className="mt-5" />
|
2024-09-19 05:26:00 +00:00
|
|
|
<span className="font-semibold">How to search</span>
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
|
|
|
|
<HowToSection
|
|
|
|
|
title="Search in files or paths"
|
|
|
|
|
>
|
|
|
|
|
<QueryExample>
|
|
|
|
|
<Query query="test todo">test todo</Query> <QueryExplanation>(both test and todo)</QueryExplanation>
|
|
|
|
|
</QueryExample>
|
|
|
|
|
<QueryExample>
|
|
|
|
|
<Query query="test or todo">test <Highlight>or</Highlight> todo</Query> <QueryExplanation>(either test or todo)</QueryExplanation>
|
|
|
|
|
</QueryExample>
|
|
|
|
|
<QueryExample>
|
|
|
|
|
<Query query={`"exit boot"`}>{`"exit boot"`}</Query> <QueryExplanation>(exact match)</QueryExplanation>
|
|
|
|
|
</QueryExample>
|
|
|
|
|
<QueryExample>
|
|
|
|
|
<Query query="TODO case:yes">TODO <Highlight>case:</Highlight>yes</Query> <QueryExplanation>(case sensitive)</QueryExplanation>
|
|
|
|
|
</QueryExample>
|
|
|
|
|
</HowToSection>
|
|
|
|
|
<HowToSection
|
|
|
|
|
title="Filter results"
|
|
|
|
|
>
|
|
|
|
|
<QueryExample>
|
|
|
|
|
<Query query="file:README setup"><Highlight>file:</Highlight>README setup</Query> <QueryExplanation>(by filename)</QueryExplanation>
|
|
|
|
|
</QueryExample>
|
|
|
|
|
<QueryExample>
|
|
|
|
|
<Query query="repo:torvalds/linux test"><Highlight>repo:</Highlight>torvalds/linux test</Query> <QueryExplanation>(by repo)</QueryExplanation>
|
|
|
|
|
</QueryExample>
|
|
|
|
|
<QueryExample>
|
|
|
|
|
<Query query="lang:typescript"><Highlight>lang:</Highlight>typescript</Query> <QueryExplanation>(by language)</QueryExplanation>
|
|
|
|
|
</QueryExample>
|
|
|
|
|
<QueryExample>
|
Search suggestions (#85)
The motivation for building search suggestions is two-fold: (1) to make the zoekt query language more approachable by presenting all available options to the user, and (2) make it easier for power-users to craft complex queries.
The meat-n-potatoes of this change are concentrated in searchBar.tsx and searchSuggestionBox.tsx. The suggestions box works by maintaining a state-machine of "modes". By default, the box is in the refine mode, where suggestions for different prefixes (e.g., repo:, lang:, etc.) are suggested to the user. When one of these prefixes is matched, the state-machine transitions to the corresponding mode (e.g., repository, language, etc.) and surfaces suggestions for that mode (if any).
The query is split up into parts by spaces " " (e.g., 'test repo:hello' -> ['test', 'repo:hello']). See splitQuery. The part that has the cursor over it is considered the active part. We evaluate which mode the state machine is in based on the active part. When a suggestion is clicked, we only modify the active part of the query.
Three modes are currently missing suggestion data: file (file names), revision (branch / tag names), and symbol (symbol names). In future PRs, we will need to introduce endpoints into the backend to allow the frontend to fetch this data and surface it as suggestions..
2024-11-23 02:50:13 +00:00
|
|
|
<Query query="rev:HEAD"><Highlight>rev:</Highlight>HEAD</Query> <QueryExplanation>(by branch or tag)</QueryExplanation>
|
2024-09-19 05:26:00 +00:00
|
|
|
</QueryExample>
|
|
|
|
|
</HowToSection>
|
|
|
|
|
<HowToSection
|
|
|
|
|
title="Advanced"
|
|
|
|
|
>
|
|
|
|
|
<QueryExample>
|
|
|
|
|
<Query query="file:\.py$"><Highlight>file:</Highlight>{`\\.py$`}</Query> <QueryExplanation>{`(files that end in ".py")`}</QueryExplanation>
|
|
|
|
|
</QueryExample>
|
|
|
|
|
<QueryExample>
|
|
|
|
|
<Query query="sym:main"><Highlight>sym:</Highlight>main</Query> <QueryExplanation>{`(symbols named "main")`}</QueryExplanation>
|
|
|
|
|
</QueryExample>
|
|
|
|
|
<QueryExample>
|
|
|
|
|
<Query query="todo -lang:c">todo <Highlight>-lang:c</Highlight></Query> <QueryExplanation>(negate filter)</QueryExplanation>
|
|
|
|
|
</QueryExample>
|
|
|
|
|
<QueryExample>
|
|
|
|
|
<Query query="content:README"><Highlight>content:</Highlight>README</Query> <QueryExplanation>(search content only)</QueryExplanation>
|
|
|
|
|
</QueryExample>
|
|
|
|
|
</HowToSection>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2024-09-03 01:46:43 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
2024-08-25 00:45:44 +00:00
|
|
|
}
|
2024-09-19 05:26:00 +00:00
|
|
|
|
|
|
|
|
const RepositoryList = async () => {
|
|
|
|
|
const _repos = await listRepositories();
|
|
|
|
|
|
|
|
|
|
if (isServiceError(_repos)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const repos = _repos.List.Repos.map((repo) => repo.Repository);
|
|
|
|
|
|
|
|
|
|
if (repos.length === 0) {
|
2024-09-25 03:34:06 +00:00
|
|
|
return (
|
|
|
|
|
<div className="flex flex-row items-center gap-3">
|
|
|
|
|
<SymbolIcon className="h-4 w-4 animate-spin" />
|
|
|
|
|
<span className="text-sm">indexing in progress...</span>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
2024-09-19 05:26:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex flex-col items-center gap-3">
|
|
|
|
|
<span className="text-sm">
|
|
|
|
|
{`Search ${repos.length} `}
|
2024-11-27 18:48:22 +00:00
|
|
|
<Link
|
2024-09-19 05:26:00 +00:00
|
|
|
href="/repos"
|
|
|
|
|
className="text-blue-500"
|
|
|
|
|
>
|
|
|
|
|
{repos.length > 1 ? 'repositories' : 'repository'}
|
2024-11-27 18:48:22 +00:00
|
|
|
</Link>
|
2024-09-19 05:26:00 +00:00
|
|
|
</span>
|
|
|
|
|
<RepositoryCarousel repos={repos} />
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const HowToSection = ({ title, children }: { title: string, children: React.ReactNode }) => {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex flex-col gap-1">
|
|
|
|
|
<span className="dark:text-gray-300 text-sm mb-2 underline">{title}</span>
|
|
|
|
|
{children}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Highlight = ({ children }: { children: React.ReactNode }) => {
|
|
|
|
|
return (
|
2024-11-13 02:43:44 +00:00
|
|
|
<span className="text-highlight">
|
2024-09-19 05:26:00 +00:00
|
|
|
{children}
|
|
|
|
|
</span>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QueryExample = ({ children }: { children: React.ReactNode }) => {
|
|
|
|
|
return (
|
|
|
|
|
<span className="text-sm font-mono">
|
|
|
|
|
{children}
|
|
|
|
|
</span>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QueryExplanation = ({ children }: { children: React.ReactNode }) => {
|
|
|
|
|
return (
|
|
|
|
|
<span className="text-gray-500 dark:text-gray-400 ml-3">
|
|
|
|
|
{children}
|
|
|
|
|
</span>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Query = ({ query, children }: { query: string, children: React.ReactNode }) => {
|
|
|
|
|
return (
|
2024-11-27 18:48:22 +00:00
|
|
|
<Link
|
2024-09-19 05:26:00 +00:00
|
|
|
href={`/search?query=${query}`}
|
|
|
|
|
className="cursor-pointer hover:underline"
|
|
|
|
|
>
|
|
|
|
|
{children}
|
2024-11-27 18:48:22 +00:00
|
|
|
</Link>
|
2024-09-19 05:26:00 +00:00
|
|
|
)
|
|
|
|
|
}
|