authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-22 12:22:13-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-22 12:22:13-07:00
logbe80e369394f5d0cb771b51669686f2bc916e543
tree3ac15b3d1e1c4e654abb7b9cd6770b01f3cb6edf
parent7b54af90f79a6858f75ff86d42a2f083d4edfa2a
signature Signed by PGP key B5690EEEBB952194

refactor(web): add SidebarInput (#13028)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

4 files changed, 23 insertions(+), 10 deletions(-)

apps/web/src/components/settings/SettingsSidebarNav.tsx+3-4
...@@ -27,7 +27,6 @@ import {...@@ -27,7 +27,6 @@ import {
27import { useLocation, useNavigate } from "@tanstack/react-router";27import { useLocation, useNavigate } from "@tanstack/react-router";
2828
29import { Button } from "../ui/button";29import { Button } from "../ui/button";
30import { Input } from "../ui/input";
31import { Kbd } from "../ui/kbd";30import { Kbd } from "../ui/kbd";
32import {31import {
33 SidebarContent,32 SidebarContent,
...@@ -37,6 +36,7 @@ import {...@@ -37,6 +36,7 @@ import {
37 SidebarMenuButton,36 SidebarMenuButton,
38 SidebarMenuItem,37 SidebarMenuItem,
39 useSidebar,38 useSidebar,
39 SidebarInput,
40} from "../ui/sidebar";40} from "../ui/sidebar";
41import { SidebarUtilityMenu } from "../sidebar/SidebarChrome";41import { SidebarUtilityMenu } from "../sidebar/SidebarChrome";
42import { scrollToSettingsTarget } from "./settingsLayout";42import { scrollToSettingsTarget } from "./settingsLayout";
...@@ -237,10 +237,9 @@ export function SettingsSidebarNav({ pathname }: { pathname: string }) {...@@ -237,10 +237,9 @@ export function SettingsSidebarNav({ pathname }: { pathname: string }) {
237 <SidebarGroup className="gap-2 p-[var(--sidebar-content-inset)]">237 <SidebarGroup className="gap-2 p-[var(--sidebar-content-inset)]">
238 <div className="flex h-8 items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium text-sidebar-muted-foreground hover:bg-sidebar-row-hover hover:text-sidebar-foreground">238 <div className="flex h-8 items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium text-sidebar-muted-foreground hover:bg-sidebar-row-hover hover:text-sidebar-foreground">
239 <SearchIcon className="size-4 shrink-0 text-sidebar-muted-foreground/80" />239 <SearchIcon className="size-4 shrink-0 text-sidebar-muted-foreground/80" />
240 <Input240 <SidebarInput
241 ref={searchInputRef}241 ref={searchInputRef}
242 nativeInput242 nativeInput
243 unstyled
244 type="search"243 type="search"
245 value={query}244 value={query}
246 onChange={(event) => {245 onChange={(event) => {
...@@ -259,7 +258,7 @@ export function SettingsSidebarNav({ pathname }: { pathname: string }) {...@@ -259,7 +258,7 @@ export function SettingsSidebarNav({ pathname }: { pathname: string }) {
259 ? `settings-search-result-${results[activeResultIndex].id}`258 ? `settings-search-result-${results[activeResultIndex].id}`
260 : undefined259 : undefined
261 }260 }
262 className="min-w-0 flex-1 [&_[data-slot=input]]:h-auto [&_[data-slot=input]]:p-0 [&_[data-slot=input]]:leading-normal [&_[data-slot=input]]:text-sm [&_[data-slot=input]]:font-medium [&_[data-slot=input]]:text-sidebar-foreground [&_[data-slot=input]]:placeholder:text-sidebar-muted-foreground"261 className="min-w-0 flex-1"
263 />262 />
264 {isSearching ? (263 {isSearching ? (
265 <Button264 <Button
apps/web/src/components/sidebar/SidebarThreadHeader.tsx+3-5
...@@ -21,8 +21,7 @@ import {...@@ -21,8 +21,7 @@ import {
2121
22import { cn } from "~/lib/utils";22import { cn } from "~/lib/utils";
23import { Button } from "../ui/button";23import { Button } from "../ui/button";
24import { Input } from "../ui/input";24import { SidebarInput, SidebarMenuButton } from "../ui/sidebar";
25import { SidebarMenuButton } from "../ui/sidebar";
26import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";25import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
2726
28export interface SidebarThreadHeaderProps {27export interface SidebarThreadHeaderProps {
...@@ -85,10 +84,9 @@ export function SidebarThreadHeader({...@@ -85,10 +84,9 @@ export function SidebarThreadHeader({
85 className="flex h-8 min-w-0 flex-1 items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium text-sidebar-muted-foreground hover:bg-sidebar-row-hover hover:text-sidebar-foreground"84 className="flex h-8 min-w-0 flex-1 items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium text-sidebar-muted-foreground hover:bg-sidebar-row-hover hover:text-sidebar-foreground"
86 >85 >
87 <SearchIcon className="size-4 shrink-0 text-[var(--sidebar-icon-color)]" />86 <SearchIcon className="size-4 shrink-0 text-[var(--sidebar-icon-color)]" />
88 <Input87 <SidebarInput
89 ref={searchInputRef}88 ref={searchInputRef}
90 nativeInput89 nativeInput
91 unstyled
92 type="search"90 type="search"
93 value={searchQuery}91 value={searchQuery}
94 onChange={(event) => onSearchQueryChange(event.currentTarget.value)}92 onChange={(event) => onSearchQueryChange(event.currentTarget.value)}
...@@ -104,7 +102,7 @@ export function SidebarThreadHeader({...@@ -104,7 +102,7 @@ export function SidebarThreadHeader({
104 ? `sidebar-thread-search-result-${activeSearchResultIndex}`102 ? `sidebar-thread-search-result-${activeSearchResultIndex}`
105 : undefined103 : undefined
106 }104 }
107 className="min-w-0 flex-1 [&_[data-slot=input]]:h-auto [&_[data-slot=input]]:p-0 [&_[data-slot=input]]:leading-normal [&_[data-slot=input]]:text-sm [&_[data-slot=input]]:font-medium [&_[data-slot=input]]:text-sidebar-foreground [&_[data-slot=input]]:placeholder:text-[var(--sidebar-icon-color)]"105 className="min-w-0 flex-1"
108 />106 />
109 {isSearching ? (107 {isSearching ? (
110 <Button108 <Button
apps/web/src/components/ui/sidebar.tsx+16
...@@ -5,6 +5,7 @@ import { PanelLeftCloseIcon, PanelLeftIcon } from "lucide-react";...@@ -5,6 +5,7 @@ import { PanelLeftCloseIcon, PanelLeftIcon } from "lucide-react";
5import * as React from "react";5import * as React from "react";
6import { cn } from "~/lib/utils";6import { cn } from "~/lib/utils";
7import { Button } from "~/components/ui/button";7import { Button } from "~/components/ui/button";
8import { Input, type InputProps } from "~/components/ui/input";
8import { ScrollArea } from "~/components/ui/scroll-area";9import { ScrollArea } from "~/components/ui/scroll-area";
9import {10import {
10 Sheet,11 Sheet,
...@@ -530,6 +531,20 @@ function SidebarRail({...@@ -530,6 +531,20 @@ function SidebarRail({
530 );531 );
531}532}
532533
534/** A bare search or rename field that sits in a row of sidebar chrome. */
535function SidebarInput({ className, ...props }: Omit<InputProps, "unstyled" | "variant">) {
536 return (
537 <Input
538 className={cn(
539 "[&_[data-slot=input]]:h-auto [&_[data-slot=input]]:p-0 [&_[data-slot=input]]:font-medium [&_[data-slot=input]]:text-sidebar-foreground [&_[data-slot=input]]:text-sm [&_[data-slot=input]]:leading-normal [&_[data-slot=input]]:placeholder:text-sidebar-muted-foreground",
540 className,
541 )}
542 unstyled
543 {...props}
544 />
545 );
546}
547
533function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {548function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
534 return (549 return (
535 <main550 <main
...@@ -770,6 +785,7 @@ function SidebarMenuSubButton({...@@ -770,6 +785,7 @@ function SidebarMenuSubButton({
770}785}
771786
772export {787export {
788 SidebarInput,
773 Sidebar,789 Sidebar,
774 SidebarContent,790 SidebarContent,
775 SidebarFooter,791 SidebarFooter,
scripts/lint-restyle-ceiling.ts+1-1
...@@ -8,7 +8,7 @@ import * as NodeURL from "node:url";...@@ -8,7 +8,7 @@ import * as NodeURL from "node:url";
8// components/ui exports are migrated to variants (see vite.config.ts). This gate keeps the8// components/ui exports are migrated to variants (see vite.config.ts). This gate keeps the
9// count from growing: CI fails when findings exceed the ceiling. Lower the ceiling when you9// count from growing: CI fails when findings exceed the ceiling. Lower the ceiling when you
10// migrate a file, and delete this script when the rule becomes an error.10// migrate a file, and delete this script when the rule becomes an error.
11export const RESTYLE_CEILING = 1043;11export const RESTYLE_CEILING = 1031;
1212
13const RULE = "shadcn(no-restyle)";13const RULE = "shadcn(no-restyle)";
1414