refactor: enhance UI components with improved hover effects and color consistency

This commit is contained in:
Anish Sarkar 2026-05-14 02:07:53 +05:30
parent bd5f1b3cdf
commit cbfbf59c46
12 changed files with 33 additions and 35 deletions

View file

@ -261,9 +261,9 @@ export function DriveFolderTree({
<div <div
className={cn( className={cn(
"flex items-center group gap-1 sm:gap-2 h-auto py-1 sm:py-2 px-1 sm:px-2 rounded-md", "flex items-center group gap-1 sm:gap-2 h-auto py-1 sm:py-2 px-1 sm:px-2 rounded-md",
isFolder && "hover:bg-accent cursor-pointer", isFolder && "hover:bg-accent hover:text-accent-foreground cursor-pointer",
!isFolder && "cursor-default opacity-60", !isFolder && "cursor-default opacity-60",
isSelected && "bg-accent/50" isSelected && "bg-accent text-accent-foreground"
)} )}
> >
{isFolder ? ( {isFolder ? (

View file

@ -237,9 +237,9 @@ export function GoogleDriveFolderTree({
<div <div
className={cn( className={cn(
"flex items-center group gap-1 sm:gap-2 h-auto py-1 sm:py-2 px-1 sm:px-2 rounded-md", "flex items-center group gap-1 sm:gap-2 h-auto py-1 sm:py-2 px-1 sm:px-2 rounded-md",
isFolder && "hover:bg-accent cursor-pointer", isFolder && "hover:bg-accent hover:text-accent-foreground cursor-pointer",
!isFolder && "cursor-default opacity-60", !isFolder && "cursor-default opacity-60",
isSelected && "bg-accent/50" isSelected && "bg-accent text-accent-foreground"
)} )}
> >
{isFolder ? ( {isFolder ? (

View file

@ -145,7 +145,7 @@ export const DocumentNode = React.memo(function DocumentNode({
ref={attachRef} ref={attachRef}
className={cn( className={cn(
"group flex h-8 w-full items-center gap-2.5 rounded-md px-1 text-sm hover:bg-accent hover:text-accent-foreground cursor-pointer select-none text-left", "group flex h-8 w-full items-center gap-2.5 rounded-md px-1 text-sm hover:bg-accent hover:text-accent-foreground cursor-pointer select-none text-left",
isMentioned && "bg-accent/30", isMentioned && "bg-accent text-accent-foreground",
isDragging && "opacity-40" isDragging && "opacity-40"
)} )}
style={{ paddingLeft: `${depth * 16 + 4}px` }} style={{ paddingLeft: `${depth * 16 + 4}px` }}

View file

@ -67,7 +67,6 @@ const ACCEPT_EXTENSIONS = Array.from(ANON_ALLOWED_EXTENSIONS).join(",");
export const FreeComposer: FC = () => { export const FreeComposer: FC = () => {
const aui = useAui(); const aui = useAui();
const isRunning = useAuiState(({ thread }) => thread.isRunning); const isRunning = useAuiState(({ thread }) => thread.isRunning);
const isEmpty = useAuiState(({ thread }) => thread.isEmpty);
const { gate } = useLoginGate(); const { gate } = useLoginGate();
const anonMode = useAnonymousMode(); const anonMode = useAnonymousMode();
const [text, setText] = useState(""); const [text, setText] = useState("");
@ -191,7 +190,7 @@ export const FreeComposer: FC = () => {
onClick={handleUploadClick} onClick={handleUploadClick}
className={cn( className={cn(
"flex items-center gap-1.5 rounded-md px-2 py-1 text-xs transition-colors", "flex items-center gap-1.5 rounded-md px-2 py-1 text-xs transition-colors",
"text-muted-foreground hover:text-foreground hover:bg-accent/50", "text-muted-foreground hover:text-accent-foreground hover:bg-accent",
hasUploadedDoc && "text-primary" hasUploadedDoc && "text-primary"
)} )}
> >
@ -212,7 +211,7 @@ export const FreeComposer: FC = () => {
<TooltipTrigger asChild> <TooltipTrigger asChild>
<label <label
htmlFor="free-web-search-toggle" htmlFor="free-web-search-toggle"
className="flex items-center gap-1.5 cursor-pointer select-none rounded-md px-2 py-1 text-xs text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors" className="flex items-center gap-1.5 cursor-pointer select-none rounded-md px-2 py-1 text-xs text-muted-foreground hover:text-accent-foreground hover:bg-accent transition-colors"
> >
<Globe className="size-3.5" /> <Globe className="size-3.5" />
<span className="hidden sm:inline">Web</span> <span className="hidden sm:inline">Web</span>

View file

@ -164,10 +164,10 @@ export function FreeModelSelector({ className }: { className?: string }) {
onMouseEnter={() => setFocusedIndex(index)} onMouseEnter={() => setFocusedIndex(index)}
className={cn( className={cn(
"group flex items-center gap-2.5 px-3 py-2 rounded-xl cursor-pointer", "group flex items-center gap-2.5 px-3 py-2 rounded-xl cursor-pointer",
"transition-all duration-150 mx-2", "transition-colors duration-150 mx-2",
"hover:bg-accent/40", "hover:bg-accent hover:text-accent-foreground",
isSelected && "bg-primary/6 dark:bg-primary/8", isFocused && "bg-accent text-accent-foreground",
isFocused && "bg-accent/50" isSelected && "bg-accent text-accent-foreground"
)} )}
> >
<div className="shrink-0"> <div className="shrink-0">

View file

@ -198,7 +198,7 @@ export function TabBar({
className={cn( className={cn(
"group relative flex h-full items-center px-3 w-[180px] min-h-0 overflow-hidden text-[13px] font-medium rounded-md transition-colors duration-150 shrink-0", "group relative flex h-full items-center px-3 w-[180px] min-h-0 overflow-hidden text-[13px] font-medium rounded-md transition-colors duration-150 shrink-0",
isActive isActive
? "bg-muted text-foreground" ? "bg-accent text-accent-foreground"
: "bg-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground" : "bg-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground"
)} )}
> >
@ -210,9 +210,7 @@ export function TabBar({
className={cn( className={cn(
"pointer-events-none absolute right-0 top-0 bottom-0 flex items-center rounded-r-md pl-8 pr-2 opacity-0 transition-opacity duration-150", "pointer-events-none absolute right-0 top-0 bottom-0 flex items-center rounded-r-md pl-8 pr-2 opacity-0 transition-opacity duration-150",
"group-hover:opacity-100 group-focus-within:opacity-100", "group-hover:opacity-100 group-focus-within:opacity-100",
isActive "bg-gradient-to-l from-accent from-60% to-transparent"
? "bg-gradient-to-l from-muted from-60% to-transparent"
: "bg-gradient-to-l from-accent from-60% to-transparent"
)} )}
> >
{/* biome-ignore lint/a11y/useSemanticElements: cannot nest button inside button */} {/* biome-ignore lint/a11y/useSemanticElements: cannot nest button inside button */}

View file

@ -190,10 +190,10 @@ export function ChatShareButton({ thread, onVisibilityChange, className }: ChatS
key={option.value} key={option.value}
onClick={() => handleVisibilityChange(option.value)} onClick={() => handleVisibilityChange(option.value)}
className={cn( className={cn(
"w-full flex items-center gap-2.5 px-2.5 py-2 rounded-md transition-all", "w-full flex items-center gap-2.5 px-2.5 py-2 rounded-md transition-colors",
"hover:bg-accent/40 cursor-pointer", "hover:bg-accent hover:text-accent-foreground cursor-pointer",
"focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
isSelected && "bg-primary/6 dark:bg-primary/8" isSelected && "bg-accent text-accent-foreground"
)} )}
> >
<div <div
@ -239,8 +239,8 @@ export function ChatShareButton({ thread, onVisibilityChange, className }: ChatS
onClick={handleCreatePublicLink} onClick={handleCreatePublicLink}
disabled={isCreatingSnapshot} disabled={isCreatingSnapshot}
className={cn( className={cn(
"w-full flex items-center gap-2.5 px-2.5 py-2 rounded-md transition-all", "w-full flex items-center gap-2.5 px-2.5 py-2 rounded-md transition-colors",
"hover:bg-accent/40 cursor-pointer", "hover:bg-accent hover:text-accent-foreground cursor-pointer",
"focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:opacity-50 disabled:cursor-not-allowed" "disabled:opacity-50 disabled:cursor-not-allowed"
)} )}

View file

@ -502,7 +502,7 @@ export const DocumentMentionPicker = forwardRef<
className={cn( className={cn(
"w-full flex items-center gap-2 px-3 py-2 text-left transition-colors rounded-md", "w-full flex items-center gap-2 px-3 py-2 text-left transition-colors rounded-md",
isAlreadySelected ? "opacity-50 cursor-not-allowed" : "cursor-pointer", isAlreadySelected ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
isHighlighted && "bg-accent" isHighlighted && "bg-accent text-accent-foreground"
)} )}
> >
<span className="shrink-0 text-muted-foreground text-sm"> <span className="shrink-0 text-muted-foreground text-sm">
@ -559,7 +559,7 @@ export const DocumentMentionPicker = forwardRef<
className={cn( className={cn(
"w-full flex items-center gap-2 px-3 py-2 text-left transition-colors rounded-md", "w-full flex items-center gap-2 px-3 py-2 text-left transition-colors rounded-md",
isAlreadySelected ? "opacity-50 cursor-not-allowed" : "cursor-pointer", isAlreadySelected ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
isHighlighted && "bg-accent" isHighlighted && "bg-accent text-accent-foreground"
)} )}
> >
<span className="shrink-0 text-muted-foreground text-sm"> <span className="shrink-0 text-muted-foreground text-sm">
@ -613,7 +613,7 @@ export const DocumentMentionPicker = forwardRef<
className={cn( className={cn(
"w-full flex items-center gap-2 px-3 py-2 text-left transition-colors rounded-md", "w-full flex items-center gap-2 px-3 py-2 text-left transition-colors rounded-md",
isAlreadySelected ? "opacity-50 cursor-not-allowed" : "cursor-pointer", isAlreadySelected ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
isHighlighted && "bg-accent" isHighlighted && "bg-accent text-accent-foreground"
)} )}
> >
<span className="shrink-0 text-muted-foreground text-sm"> <span className="shrink-0 text-muted-foreground text-sm">

View file

@ -1041,9 +1041,10 @@ export function ModelSelector({
onMouseEnter={() => setFocusedIndex(index)} onMouseEnter={() => setFocusedIndex(index)}
className={cn( className={cn(
"group flex items-center gap-2.5 px-3 py-2 rounded-xl", "group flex items-center gap-2.5 px-3 py-2 rounded-xl",
"transition-all duration-150 mx-2 cursor-pointer hover:bg-accent/40", "transition-colors duration-150 mx-2 cursor-pointer",
isSelected && "bg-primary/6 dark:bg-primary/8", "hover:bg-accent hover:text-accent-foreground",
isFocused && "bg-accent/50" isFocused && "bg-accent text-accent-foreground",
isSelected && "bg-accent text-accent-foreground"
)} )}
> >
{/* Provider icon */} {/* Provider icon */}

View file

@ -161,7 +161,7 @@ export const PromptPicker = forwardRef<PromptPickerRef, PromptPickerProps>(funct
onMouseEnter={() => setHighlightedIndex(index)} onMouseEnter={() => setHighlightedIndex(index)}
className={cn( className={cn(
"w-full flex items-center gap-2 px-3 py-2 text-left text-sm transition-colors rounded-md cursor-pointer", "w-full flex items-center gap-2 px-3 py-2 text-left text-sm transition-colors rounded-md cursor-pointer",
index === highlightedIndex && "bg-accent" index === highlightedIndex && "bg-accent text-accent-foreground"
)} )}
> >
<span className="shrink-0 text-muted-foreground"> <span className="shrink-0 text-muted-foreground">
@ -183,7 +183,7 @@ export const PromptPicker = forwardRef<PromptPickerRef, PromptPickerProps>(funct
className={cn( className={cn(
"w-full flex items-center gap-2 px-3 py-2 text-left text-sm transition-colors rounded-md cursor-pointer text-muted-foreground", "w-full flex items-center gap-2 px-3 py-2 text-left text-sm transition-colors rounded-md cursor-pointer text-muted-foreground",
highlightedIndex === createPromptIndex highlightedIndex === createPromptIndex
? "bg-accent text-foreground" ? "bg-accent text-accent-foreground"
: "hover:text-accent-foreground hover:bg-accent" : "hover:text-accent-foreground hover:bg-accent"
)} )}
> >

View file

@ -107,7 +107,7 @@ function ContextMenuItem({
data-inset={inset} data-inset={inset}
data-variant={variant} data-variant={variant}
className={cn( className={cn(
"focus:bg-accent focus:text-accent-foreground dark:focus:bg-neutral-700 relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", "focus:bg-accent focus:text-accent-foreground relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
className className
)} )}
{...props} {...props}
@ -189,7 +189,7 @@ function ContextMenuSeparator({
return ( return (
<ContextMenuPrimitive.Separator <ContextMenuPrimitive.Separator
data-slot="context-menu-separator" data-slot="context-menu-separator"
className={cn("bg-border dark:bg-neutral-700 -mx-1 my-1 h-px", className)} className={cn("bg-border -mx-1 my-1 h-px", className)}
{...props} {...props}
/> />
); );

View file

@ -61,7 +61,7 @@ function DropdownMenuItem({
data-inset={inset} data-inset={inset}
data-variant={variant} data-variant={variant}
className={cn( className={cn(
"focus:bg-neutral-200 focus:text-accent-foreground dark:focus:bg-neutral-700 [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className className
)} )}
{...props} {...props}
@ -79,7 +79,7 @@ function DropdownMenuCheckboxItem({
<DropdownMenuPrimitive.CheckboxItem <DropdownMenuPrimitive.CheckboxItem
data-slot="dropdown-menu-checkbox-item" data-slot="dropdown-menu-checkbox-item"
className={cn( className={cn(
"focus:bg-neutral-200 focus:text-accent-foreground dark:focus:bg-neutral-700 relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className className
)} )}
checked={checked} checked={checked}
@ -110,7 +110,7 @@ function DropdownMenuRadioItem({
<DropdownMenuPrimitive.RadioItem <DropdownMenuPrimitive.RadioItem
data-slot="dropdown-menu-radio-item" data-slot="dropdown-menu-radio-item"
className={cn( className={cn(
"focus:bg-neutral-200 focus:text-accent-foreground dark:focus:bg-neutral-700 relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className className
)} )}
{...props} {...props}
@ -182,7 +182,7 @@ function DropdownMenuSubTrigger({
data-slot="dropdown-menu-sub-trigger" data-slot="dropdown-menu-sub-trigger"
data-inset={inset} data-inset={inset}
className={cn( className={cn(
"focus:bg-neutral-200 focus:text-accent-foreground dark:focus:bg-neutral-700 data-[state=open]:bg-neutral-200 data-[state=open]:text-accent-foreground dark:data-[state=open]:bg-neutral-700 [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className className
)} )}
{...props} {...props}