|
| 1 | +import { listRepositories } from "@/lib/server/searchService"; |
| 2 | +import { isServiceError } from "@/lib/utils"; |
1 | 3 | import Image from "next/image";
|
| 4 | +import { Suspense } from "react"; |
2 | 5 | import logoDark from "../../public/sb_logo_dark_large.png";
|
3 | 6 | import logoLight from "../../public/sb_logo_light_large.png";
|
4 | 7 | import { NavigationMenu } from "./navigationMenu";
|
| 8 | +import { RepositoryCarousel } from "./repositoryCarousel"; |
5 | 9 | import { SearchBar } from "./searchBar";
|
| 10 | +import { Separator } from "@/components/ui/separator"; |
6 | 11 |
|
7 |
| -export default function Home() { |
| 12 | + |
| 13 | +export default async function Home() { |
8 | 14 | return (
|
9 | 15 | <div className="h-screen flex flex-col items-center">
|
10 | 16 | {/* TopBar */}
|
11 | 17 | <NavigationMenu />
|
12 |
| - |
13 |
| - <div className="flex flex-col justify-center items-center p-4 mt-48"> |
| 18 | + |
| 19 | + <div className="flex flex-col justify-center items-center mt-8 md:mt-32 max-w-[90%]"> |
14 | 20 | <div className="max-h-44 w-auto">
|
15 | 21 | <Image
|
16 | 22 | src={logoDark}
|
17 | 23 | className="w-full h-full hidden dark:block"
|
18 | 24 | alt={"Sourcebot logo"}
|
| 25 | + priority={true} |
19 | 26 | />
|
20 | 27 | <Image
|
21 | 28 | src={logoLight}
|
22 | 29 | className="w-full h-full block dark:hidden"
|
23 | 30 | alt={"Sourcebot logo"}
|
| 31 | + priority={true} |
24 | 32 | />
|
25 | 33 | </div>
|
26 | 34 | <div className="w-full flex flex-row mt-4">
|
27 | 35 | <SearchBar
|
28 | 36 | autoFocus={true}
|
29 | 37 | />
|
30 | 38 | </div>
|
| 39 | + <div className="mt-8"> |
| 40 | + <Suspense fallback={<div>...</div>}> |
| 41 | + <RepositoryList /> |
| 42 | + </Suspense> |
| 43 | + </div> |
| 44 | + <Separator className="mt-5 mb-8" /> |
| 45 | + <div className="flex flex-col items-center w-fit gap-6"> |
| 46 | + <span className="font-semibold">How to search</span> |
| 47 | + <div className="grid grid-cols-1 md:grid-cols-2 gap-5"> |
| 48 | + <HowToSection |
| 49 | + title="Search in files or paths" |
| 50 | + > |
| 51 | + <QueryExample> |
| 52 | + <Query query="test todo">test todo</Query> <QueryExplanation>(both test and todo)</QueryExplanation> |
| 53 | + </QueryExample> |
| 54 | + <QueryExample> |
| 55 | + <Query query="test or todo">test <Highlight>or</Highlight> todo</Query> <QueryExplanation>(either test or todo)</QueryExplanation> |
| 56 | + </QueryExample> |
| 57 | + <QueryExample> |
| 58 | + <Query query={`"exit boot"`}>{`"exit boot"`}</Query> <QueryExplanation>(exact match)</QueryExplanation> |
| 59 | + </QueryExample> |
| 60 | + <QueryExample> |
| 61 | + <Query query="TODO case:yes">TODO <Highlight>case:</Highlight>yes</Query> <QueryExplanation>(case sensitive)</QueryExplanation> |
| 62 | + </QueryExample> |
| 63 | + </HowToSection> |
| 64 | + <HowToSection |
| 65 | + title="Filter results" |
| 66 | + > |
| 67 | + <QueryExample> |
| 68 | + <Query query="file:README setup"><Highlight>file:</Highlight>README setup</Query> <QueryExplanation>(by filename)</QueryExplanation> |
| 69 | + </QueryExample> |
| 70 | + <QueryExample> |
| 71 | + <Query query="repo:torvalds/linux test"><Highlight>repo:</Highlight>torvalds/linux test</Query> <QueryExplanation>(by repo)</QueryExplanation> |
| 72 | + </QueryExample> |
| 73 | + <QueryExample> |
| 74 | + <Query query="lang:typescript"><Highlight>lang:</Highlight>typescript</Query> <QueryExplanation>(by language)</QueryExplanation> |
| 75 | + </QueryExample> |
| 76 | + <QueryExample> |
| 77 | + <Query query="branch:HEAD"><Highlight>branch:</Highlight>HEAD</Query> <QueryExplanation>(by branch)</QueryExplanation> |
| 78 | + </QueryExample> |
| 79 | + </HowToSection> |
| 80 | + <HowToSection |
| 81 | + title="Advanced" |
| 82 | + > |
| 83 | + <QueryExample> |
| 84 | + <Query query="file:\.py$"><Highlight>file:</Highlight>{`\\.py$`}</Query> <QueryExplanation>{`(files that end in ".py")`}</QueryExplanation> |
| 85 | + </QueryExample> |
| 86 | + <QueryExample> |
| 87 | + <Query query="sym:main"><Highlight>sym:</Highlight>main</Query> <QueryExplanation>{`(symbols named "main")`}</QueryExplanation> |
| 88 | + </QueryExample> |
| 89 | + <QueryExample> |
| 90 | + <Query query="todo -lang:c">todo <Highlight>-lang:c</Highlight></Query> <QueryExplanation>(negate filter)</QueryExplanation> |
| 91 | + </QueryExample> |
| 92 | + <QueryExample> |
| 93 | + <Query query="content:README"><Highlight>content:</Highlight>README</Query> <QueryExplanation>(search content only)</QueryExplanation> |
| 94 | + </QueryExample> |
| 95 | + </HowToSection> |
| 96 | + </div> |
| 97 | + </div> |
31 | 98 | </div>
|
32 | 99 | </div>
|
33 | 100 | )
|
34 | 101 | }
|
| 102 | + |
| 103 | +const RepositoryList = async () => { |
| 104 | + const _repos = await listRepositories(); |
| 105 | + |
| 106 | + if (isServiceError(_repos)) { |
| 107 | + return null; |
| 108 | + } |
| 109 | + |
| 110 | + const repos = _repos.List.Repos.map((repo) => repo.Repository); |
| 111 | + |
| 112 | + if (repos.length === 0) { |
| 113 | + return <span> |
| 114 | + Get started |
| 115 | + <a |
| 116 | + href="https://github.com/TaqlaAI/sourcebot/blob/main/README.md" |
| 117 | + className="text-blue-500" |
| 118 | + > |
| 119 | + {` configuring Sourcebot.`} |
| 120 | + </a> |
| 121 | + </span>; |
| 122 | + } |
| 123 | + |
| 124 | + return ( |
| 125 | + <div className="flex flex-col items-center gap-3"> |
| 126 | + <span className="text-sm"> |
| 127 | + {`Search ${repos.length} `} |
| 128 | + <a |
| 129 | + href="/repos" |
| 130 | + className="text-blue-500" |
| 131 | + > |
| 132 | + {repos.length > 1 ? 'repositories' : 'repository'} |
| 133 | + </a> |
| 134 | + </span> |
| 135 | + <RepositoryCarousel repos={repos} /> |
| 136 | + </div> |
| 137 | + ) |
| 138 | +} |
| 139 | + |
| 140 | +const HowToSection = ({ title, children }: { title: string, children: React.ReactNode }) => { |
| 141 | + return ( |
| 142 | + <div className="flex flex-col gap-1"> |
| 143 | + <span className="dark:text-gray-300 text-sm mb-2 underline">{title}</span> |
| 144 | + {children} |
| 145 | + </div> |
| 146 | + ) |
| 147 | + |
| 148 | +} |
| 149 | + |
| 150 | +const Highlight = ({ children }: { children: React.ReactNode }) => { |
| 151 | + return ( |
| 152 | + <span className="text-blue-700 dark:text-blue-500"> |
| 153 | + {children} |
| 154 | + </span> |
| 155 | + ) |
| 156 | +} |
| 157 | + |
| 158 | +const QueryExample = ({ children }: { children: React.ReactNode }) => { |
| 159 | + return ( |
| 160 | + <span className="text-sm font-mono"> |
| 161 | + {children} |
| 162 | + </span> |
| 163 | + ) |
| 164 | +} |
| 165 | + |
| 166 | +const QueryExplanation = ({ children }: { children: React.ReactNode }) => { |
| 167 | + return ( |
| 168 | + <span className="text-gray-500 dark:text-gray-400 ml-3"> |
| 169 | + {children} |
| 170 | + </span> |
| 171 | + ) |
| 172 | +} |
| 173 | + |
| 174 | +const Query = ({ query, children }: { query: string, children: React.ReactNode }) => { |
| 175 | + return ( |
| 176 | + <a |
| 177 | + href={`/search?query=${query}`} |
| 178 | + className="cursor-pointer hover:underline" |
| 179 | + > |
| 180 | + {children} |
| 181 | + </a> |
| 182 | + ) |
| 183 | +} |
0 commit comments