优化会话输入框在当前会话宽度不足时的显示样式

This commit is contained in:
xintaofei
2026-03-11 14:57:45 +08:00
parent 84e2d2bb56
commit c9125edb89
3 changed files with 61 additions and 29 deletions

View File

@@ -7,8 +7,9 @@ import { open } from "@tauri-apps/plugin-dialog"
import Image from "next/image" import Image from "next/image"
import { useTranslations } from "next-intl" import { useTranslations } from "next-intl"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
import { Textarea } from "@/components/ui/textarea" import { Textarea } from "@/components/ui/textarea"
import { FileSearch, Plus, Send, Square, X } from "lucide-react" import { Ellipsis, FileSearch, Plus, Send, Square, X } from "lucide-react"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
import { readFileBase64 } from "@/lib/tauri" import { readFileBase64 } from "@/lib/tauri"
import { disposeTauriListener } from "@/lib/tauri-listener" import { disposeTauriListener } from "@/lib/tauri-listener"
@@ -327,6 +328,8 @@ export function MessageInput({
hasModes && Boolean(effectiveModeId) && !hasConfigOptions hasModes && Boolean(effectiveModeId) && !hasConfigOptions
const showModeLoading = modeLoading && !hasConfigOptions && !showModeSelector const showModeLoading = modeLoading && !hasConfigOptions && !showModeSelector
const showConfigLoading = configOptionsLoading && !hasConfigOptions const showConfigLoading = configOptionsLoading && !hasConfigOptions
const hasAnySelector =
showConfigLoading || hasConfigOptions || showModeLoading || showModeSelector
const imageAttachments = useMemo( const imageAttachments = useMemo(
() => () =>
attachments.filter( attachments.filter(
@@ -996,6 +999,32 @@ export function MessageInput({
const bottomPaddingClass = "pb-10" const bottomPaddingClass = "pb-10"
const showDragActive = isDragActive && !disabled && !isPrompting const showDragActive = isDragActive && !disabled && !isPrompting
const selectorItems = (
<>
{showConfigLoading && (
<SelectorLoadingChip label={t("loadingSettings")} />
)}
{hasConfigOptions &&
availableConfigOptions.map((option) => (
<SessionConfigSelector
key={option.id}
option={option}
onSelect={(configId, valueId) =>
onConfigOptionChange?.(configId, valueId)
}
/>
))}
{showModeLoading && <SelectorLoadingChip label={t("loadingMode")} />}
{showModeSelector && (
<ModeSelector
modes={availableModes}
selectedModeId={effectiveModeId!}
onSelect={handleModeSelect}
/>
)}
</>
)
return ( return (
<div <div
ref={containerRef} ref={containerRef}
@@ -1091,8 +1120,8 @@ export function MessageInput({
{t("dropFilesToAttach")} {t("dropFilesToAttach")}
</div> </div>
)} )}
<div className="absolute left-2 right-24 bottom-2 flex flex-col gap-1"> <div className="@container absolute left-2 right-24 bottom-2">
<div className="flex items-center gap-1 overflow-x-auto"> <div className="flex items-center gap-1">
<Button <Button
onClick={handlePickFiles} onClick={handlePickFiles}
disabled={disabled || isPrompting} disabled={disabled || isPrompting}
@@ -1103,26 +1132,29 @@ export function MessageInput({
> >
<Plus className="size-4" /> <Plus className="size-4" />
</Button> </Button>
{showConfigLoading && ( {/* 宽屏内联显示,窄屏(<300px通过"更多"气泡显示 */}
<SelectorLoadingChip label={t("loadingSettings")} /> <div className="hidden @[300px]:contents">
)} {selectorItems}
{hasConfigOptions && </div>
availableConfigOptions.map((option) => ( {hasAnySelector && (
<SessionConfigSelector <Popover>
key={option.id} <PopoverTrigger asChild>
option={option} <Button
onSelect={(configId, valueId) => variant="ghost"
onConfigOptionChange?.(configId, valueId) size="icon"
} className="h-6 w-6 shrink-0 @[300px]:hidden"
/> >
))} <Ellipsis className="size-4" />
{showModeLoading && <SelectorLoadingChip label={t("loadingMode")} />} </Button>
{showModeSelector && effectiveModeId && ( </PopoverTrigger>
<ModeSelector <PopoverContent
modes={availableModes} side="top"
selectedModeId={effectiveModeId} align="start"
onSelect={handleModeSelect} className="flex w-auto flex-col gap-1 rounded-xl p-1"
/> >
{selectorItems}
</PopoverContent>
</Popover>
)} )}
</div> </div>
</div> </div>

View File

@@ -34,11 +34,11 @@ export function ModeSelector({
<Button <Button
variant="ghost" variant="ghost"
size="xs" size="xs"
className={cn("gap-1", isActive && "text-primary")} className={cn("gap-1 min-w-0", isActive && "text-primary")}
title={selectedMode?.description ?? selectedMode?.name} title={selectedMode?.description ?? selectedMode?.name}
> >
{label} <span className="truncate">{label}</span>
<ChevronUp className="size-3" /> <ChevronUp className="size-3 shrink-0" />
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent side="top" align="start" className="min-w-72"> <DropdownMenuContent side="top" align="start" className="min-w-72">

View File

@@ -39,11 +39,11 @@ export function SessionConfigSelector({
<Button <Button
variant="ghost" variant="ghost"
size="xs" size="xs"
className={cn("gap-1 shrink-0", isActive && "text-primary")} className={cn("gap-1 min-w-0", isActive && "text-primary")}
title={option.description ?? option.name} title={option.description ?? option.name}
> >
{label} <span className="truncate">{label}</span>
<ChevronUp className="size-3" /> <ChevronUp className="size-3 shrink-0" />
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent side="top" align="start" className="min-w-72"> <DropdownMenuContent side="top" align="start" className="min-w-72">