Skip to content

Commit ddf4658

Browse files
committed
tweaks from Christin's feedback
1 parent 59345c7 commit ddf4658

File tree

14 files changed

+204
-142
lines changed

14 files changed

+204
-142
lines changed

packages/core/src/semsearch/schema.input.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const searchQuerySchema = z.string().superRefine((query, ctx) => {
5757
if (repoQueries.length === 0 && ownerQueries.length === 0) {
5858
ctx.addIssue({
5959
code: z.ZodIssueCode.custom,
60-
message: "Please specify an org or repo for your search",
60+
message: "Please filter by either an org or a repo",
6161
});
6262
}
6363
if (repoQueries.length === 1 && ownerQueries.length === 0) {

packages/web/src/components/embed/EmbedBadgePopover.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function EmbedBadgePopover({
3333
<PopoverTrigger asChild>
3434
<Button variant={buttonVariant} size="sm" className="gap-2">
3535
<PlusIcon className="size-4" />
36-
<span>Embed</span>
36+
<span>Add to Repo</span>
3737
</Button>
3838
</PopoverTrigger>
3939
<PopoverContent className="w-96" align="end">
Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1+
import { MonitorCogIcon, MoonIcon, SunIcon } from "lucide-react";
2+
13
import { useThemeToggle } from "@/lib/hooks/useThemeToggle";
24
import { Button } from "@/components/ui/button";
5+
import {
6+
DropdownMenu,
7+
DropdownMenuContent,
8+
DropdownMenuItem,
9+
DropdownMenuTrigger,
10+
} from "@/components/ui/dropdown-menu";
311

412
interface DarkModeToggleProps {
513
onToggleCountChange: () => void;
@@ -8,15 +16,33 @@ interface DarkModeToggleProps {
816
export function DarkModeToggle({ onToggleCountChange }: DarkModeToggleProps) {
917
const { ThemeIcon, handleThemeChange } = useThemeToggle();
1018

11-
const handleClick = () => {
19+
const setThemeAndNotify = (newTheme: string) => {
1220
onToggleCountChange();
13-
handleThemeChange();
21+
handleThemeChange(newTheme);
1422
};
1523

1624
return (
17-
<Button variant="ghost" size="icon" onClick={handleClick}>
18-
<ThemeIcon className="size-[1.2rem] animate-in fade-in" />
19-
<span className="sr-only">Toggle theme</span>
20-
</Button>
25+
<DropdownMenu>
26+
<DropdownMenuTrigger asChild>
27+
<Button variant="ghost" size="icon">
28+
<ThemeIcon className="size-[1.2rem] animate-in fade-in" />
29+
<span className="sr-only">Toggle theme</span>
30+
</Button>
31+
</DropdownMenuTrigger>
32+
<DropdownMenuContent align="end">
33+
<DropdownMenuItem onClick={() => setThemeAndNotify("light")}>
34+
<SunIcon className="mr-2 size-4" />
35+
<span>Light</span>
36+
</DropdownMenuItem>
37+
<DropdownMenuItem onClick={() => setThemeAndNotify("dark")}>
38+
<MoonIcon className="mr-2 size-4" />
39+
<span>Dark</span>
40+
</DropdownMenuItem>
41+
<DropdownMenuItem onClick={() => setThemeAndNotify("system")}>
42+
<MonitorCogIcon className="mr-2 size-4" />
43+
<span>System</span>
44+
</DropdownMenuItem>
45+
</DropdownMenuContent>
46+
</DropdownMenu>
2147
);
2248
}

packages/web/src/components/navbar/LoginButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export function LoginButton() {
1414
return (
1515
<Button variant="outline" onClick={handleLogin} className="gap-2">
1616
<GithubIcon className="size-4" />
17-
Sign in
17+
Sign In
1818
</Button>
1919
);
2020
}

packages/web/src/components/navbar/Navbar.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { Link } from "@tanstack/react-router";
1+
import { Link, useLocation } from "@tanstack/react-router";
22
import { useTheme } from "next-themes";
33
import { useEffect, useRef, useState } from "react";
44

55
import { useSession } from "@/lib/hooks/useSession";
66
import { useAudio } from "@/hooks/useAudio";
7+
import { EmbedBadgePopover } from "@/components/embed/EmbedBadgePopover";
78
import { DarkModeToggle } from "@/components/navbar/DarkModeToggle";
89
import { LoginButton } from "@/components/navbar/LoginButton";
910
import { UserNav } from "@/components/navbar/UserNav";
@@ -64,6 +65,8 @@ export function Navbar() {
6465
</span>
6566
</h1>
6667
);
68+
69+
const location = useLocation();
6770
return (
6871
<div className="flex h-16 w-full items-center justify-between px-4">
6972
<div className="flex items-center gap-2">
@@ -73,6 +76,10 @@ export function Navbar() {
7376
</Link>
7477
</div>
7578
<nav className="flex items-center gap-4">
79+
{/* avoids showing two EmbedBadgePopovers on the same page */}
80+
{!location.pathname.startsWith("/r/") && (
81+
<EmbedBadgePopover owner="your" repo="repo" />
82+
)}
7683
{isAuthenticated ? (
7784
<>
7885
<Link

packages/web/src/components/navbar/UserNav.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export function UserNav({ user }: { user: User }) {
5959
<div className="flex flex-col gap-1 p-2">
6060
<Button
6161
variant="ghost"
62-
onClick={handleThemeChange}
62+
onClick={() => handleThemeChange()}
6363
className="w-full justify-start gap-2 pl-2 text-muted-foreground hover:text-foreground"
6464
>
6565
<ThemeIcon className="size-4" />
@@ -71,7 +71,7 @@ export function UserNav({ user }: { user: User }) {
7171
className="w-full justify-start gap-2 pl-2 text-muted-foreground hover:text-foreground"
7272
>
7373
<LogOutIcon className="size-4" />
74-
Sign out
74+
Sign Out
7575
</Button>
7676
</div>
7777
</DropdownMenuContent>

packages/web/src/components/search/HighlightedInput.tsx

Lines changed: 5 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
import * as React from "react";
22
import { useMemo } from "react";
33

4-
import type {
5-
SearchOperator} from "@/core/constants/search.constant";
6-
import {
7-
SEARCH_OPERATORS
8-
} from "@/core/constants/search.constant";
4+
import type { SearchOperator } from "@/core/constants/search.constant";
95
import { cn } from "@/lib/utils";
6+
import { useOperatorHighlighting } from "@/hooks/useOperatorHighlighting";
107

118
// component inspired by https://akashhamirwasia.com/blog/building-highlighted-input-field-in-react/
129
// with significant modifications
@@ -18,20 +15,7 @@ const HighlightedInput = React.forwardRef<
1815
}
1916
>(({ className, type, value, removedOperators = [], ...props }, ref) => {
2017
const rendererRef = React.useRef<HTMLDivElement>(null);
21-
22-
const filteredSearchOperators = useMemo(() => {
23-
return SEARCH_OPERATORS.filter(
24-
(op) => !removedOperators.includes(op.operator),
25-
);
26-
}, [removedOperators]);
27-
28-
// Create regex pattern from filtered search operators that captures both operator and value
29-
const operatorRegex = useMemo(() => {
30-
return new RegExp(
31-
`(${filteredSearchOperators.map(({ operator }) => `${operator}:`).join("|")})(?:"([^"]*)"|([^\\s]*))`,
32-
"g",
33-
);
34-
}, [filteredSearchOperators]);
18+
const highlightedParts = useOperatorHighlighting(value, removedOperators);
3519

3620
const syncScroll = (e: React.UIEvent<HTMLInputElement>) => {
3721
if (rendererRef.current) {
@@ -46,51 +30,8 @@ const HighlightedInput = React.forwardRef<
4630
const textStyles =
4731
"font-sans text-[16px] leading-normal tracking-normal font-normal";
4832

49-
const inputWithHighlights = useMemo(() => {
50-
const parts = [];
51-
let lastIndex = 0;
52-
let match;
53-
54-
while ((match = operatorRegex.exec(value)) !== null) {
55-
// Add text before the match
56-
if (match.index > lastIndex) {
57-
parts.push({
58-
text: value.slice(lastIndex, match.index),
59-
type: "text",
60-
});
61-
}
62-
63-
// Add operator
64-
parts.push({
65-
text: match[1], // The operator with colon
66-
type: "operator",
67-
});
68-
69-
// Add value (including quotes if present)
70-
if (match[0] && match[1]) {
71-
const valueWithQuotes = match[0].slice(match[1].length); // Get everything after the operator
72-
parts.push({
73-
text: valueWithQuotes,
74-
type: "value",
75-
});
76-
}
77-
78-
lastIndex = match.index + match[0].length;
79-
}
80-
81-
// Add remaining text
82-
if (lastIndex < value.length) {
83-
parts.push({
84-
text: value.slice(lastIndex),
85-
type: "text",
86-
});
87-
}
88-
89-
return parts;
90-
}, [value, operatorRegex]);
91-
9233
const renderedContent = useMemo(() => {
93-
return inputWithHighlights.map((part, i) => (
34+
return highlightedParts.map((part, i) => (
9435
<span
9536
key={i}
9637
className={
@@ -104,7 +45,7 @@ const HighlightedInput = React.forwardRef<
10445
{part.text}
10546
</span>
10647
));
107-
}, [inputWithHighlights]);
48+
}, [highlightedParts]);
10849

10950
return (
11051
<div className="relative">

packages/web/src/components/search/HomepageSearch.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,23 @@ export function HomepageSearch() {
1111
<div className="relative flex w-full justify-center pt-28">
1212
<div className="w-full max-w-screen-xl px-4 text-center">
1313
<h1 className="mb-4 font-serif text-5xl tracking-tight">
14-
<span className="text-blue-600 dark:text-blue-400">Sem</span>antic
15-
search for Git<span className="text-orange-500">Hub</span>
16-
<span className="animate-cursor text-blue-600 dark:text-blue-400">
17-
_
14+
<span className="bg-gradient-to-r from-blue-600 to-orange-500 bg-clip-text text-transparent dark:from-blue-400 dark:to-orange-400">
15+
Sem
16+
</span>
17+
antic search for Git
18+
<span className="bg-gradient-to-r from-blue-600 to-orange-500 bg-clip-text text-transparent dark:from-blue-400 dark:to-orange-400">
19+
Hub
1820
</span>
1921
</h1>
20-
<HomepageSearchBar />
2122

22-
<div className="mx-auto mt-8 flex max-w-lg flex-col items-center gap-2">
23-
{suggestedSearches.map((search) => (
23+
{/* Search bar section */}
24+
<div className="relative">
25+
<HomepageSearchBar />
26+
</div>
27+
28+
{/* Suggested searches section */}
29+
<div className="mx-auto mt-24 grid max-w-xl grid-cols-1 gap-2 sm:mt-8 sm:grid-cols-2 sm:gap-4">
30+
{suggestedSearches.slice(0, 4).map((search) => (
2431
<SuggestedSearchCard key={search} search={search} />
2532
))}
2633
</div>

0 commit comments

Comments
 (0)