refactor(ui): remove excessive hover/focus/shadow effects from chat page

This commit is contained in:
ZhenYi 2026-05-18 21:15:05 +08:00
parent f4967925a7
commit e1bfac3da0
9 changed files with 22 additions and 26 deletions

View File

@ -187,7 +187,7 @@ export function ChatConversationList({
<div className="flex items-center gap-0.5"> <div className="flex items-center gap-0.5">
<button <button
onClick={() => setIsSearchOpen(!isSearchOpen)} onClick={() => setIsSearchOpen(!isSearchOpen)}
className="flex size-8 items-center justify-center rounded-full transition-colors hover:bg-[var(--hover-bg)]" className="flex size-8 items-center justify-center rounded-full"
style={{ color: "var(--text-muted)" }} style={{ color: "var(--text-muted)" }}
title={t("navigation.search_shortcut")} title={t("navigation.search_shortcut")}
> >
@ -196,7 +196,7 @@ export function ChatConversationList({
<button <button
onClick={handleNew} onClick={handleNew}
disabled={createMutation.isPending} disabled={createMutation.isPending}
className="flex size-8 items-center justify-center rounded-full transition-colors hover:bg-[var(--hover-bg)]" className="flex size-8 items-center justify-center rounded-full"
style={{ color: "var(--text-secondary)" }} style={{ color: "var(--text-secondary)" }}
title={t("chat.header.new_chat")} title={t("chat.header.new_chat")}
> >

View File

@ -31,10 +31,6 @@ export function ChatHeader({
return ( return (
<div <div
className="sticky top-0 z-10 flex h-12 shrink-0 items-center justify-between border-b border-border/60 bg-background/85 px-4 backdrop-blur-xl supports-[backdrop-filter]:bg-background/70" className="sticky top-0 z-10 flex h-12 shrink-0 items-center justify-between border-b border-border/60 bg-background/85 px-4 backdrop-blur-xl supports-[backdrop-filter]:bg-background/70"
style={{
boxShadow:
"0 1px 0 color-mix(in oklch, var(--border) 60%, transparent)",
}}
> >
<div className="flex min-w-0 items-center gap-2.5"> <div className="flex min-w-0 items-center gap-2.5">
<Button <Button

View File

@ -209,7 +209,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
} }
return ( return (
<div className="group mx-auto flex w-full max-w-3xl gap-4 rounded-2xl border border-transparent px-4 py-4 transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--surface-secondary)]/40"> <div className="group mx-auto flex w-full max-w-3xl gap-4 rounded-2xl border border-transparent px-4 py-4">
{/* Avatar */} {/* Avatar */}
<div className="shrink-0 pt-0.5"> <div className="shrink-0 pt-0.5">
{isUser ? ( {isUser ? (
@ -409,7 +409,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
{message.version_number > 1 && ( {message.version_number > 1 && (
<button <button
onClick={() => setShowVersions(!showVersions)} onClick={() => setShowVersions(!showVersions)}
className="mt-2 inline-flex items-center gap-2 rounded-full border border-[var(--border-subtle)] bg-[var(--surface-secondary)] px-2.5 py-1 text-[11px] text-muted-foreground transition-colors hover:border-[var(--border-default)] hover:bg-[var(--surface-elevated)]" className="mt-2 inline-flex items-center gap-2 rounded-full border border-[var(--border-subtle)] bg-[var(--surface-secondary)] px-2.5 py-1 text-[11px] text-muted-foreground"
> >
<span className="font-medium text-[var(--text-primary)]"> <span className="font-medium text-[var(--text-primary)]">
v{message.version_number} v{message.version_number}
@ -427,7 +427,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
<button <button
key={v.id} key={v.id}
onClick={() => handleSwitchVersion(v.version_number)} onClick={() => handleSwitchVersion(v.version_number)}
className="flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left transition-colors hover:bg-[var(--hover-bg)]" className="flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left"
style={{ style={{
color: color:
v.version_number === message.version_number v.version_number === message.version_number
@ -467,7 +467,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
<div className="mt-2 flex flex-wrap items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100"> <div className="mt-2 flex flex-wrap items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100">
<button <button
onClick={handleStartEdit} onClick={handleStartEdit}
className="inline-flex items-center gap-1 rounded-full border border-transparent px-2.5 py-1 text-[11px] transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--surface-elevated)]" className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[11px]"
style={{ color: "var(--text-muted)" }} style={{ color: "var(--text-muted)" }}
> >
<Pencil className="size-3" /> <Pencil className="size-3" />
@ -476,7 +476,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
{onRegenerate && ( {onRegenerate && (
<button <button
onClick={handleRegenerate} onClick={handleRegenerate}
className="inline-flex items-center gap-1 rounded-full border border-transparent px-2.5 py-1 text-[11px] transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--surface-elevated)]" className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[11px]"
style={{ color: "var(--text-muted)" }} style={{ color: "var(--text-muted)" }}
> >
<RefreshCw className="size-3" /> <RefreshCw className="size-3" />
@ -491,7 +491,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
<div className="mt-2 flex flex-wrap items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100"> <div className="mt-2 flex flex-wrap items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100">
<button <button
onClick={handleCopyAnswer} onClick={handleCopyAnswer}
className="inline-flex items-center gap-1 rounded-full border border-transparent px-2.5 py-1 text-[11px] transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--surface-elevated)]" className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[11px]"
style={{ color: "var(--text-muted)" }} style={{ color: "var(--text-muted)" }}
> >
{copied === "answer" ? ( {copied === "answer" ? (
@ -504,7 +504,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
{hasThinking && ( {hasThinking && (
<button <button
onClick={handleCopyFull} onClick={handleCopyFull}
className="inline-flex items-center gap-1 rounded-full border border-transparent px-2.5 py-1 text-[11px] transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--surface-elevated)]" className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[11px]"
style={{ color: "var(--text-muted)" }} style={{ color: "var(--text-muted)" }}
> >
{copied === "full" ? ( {copied === "full" ? (
@ -517,7 +517,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
)} )}
<button <button
onClick={handleFork} onClick={handleFork}
className="inline-flex items-center gap-1 rounded-full border border-transparent px-2.5 py-1 text-[11px] transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--surface-elevated)]" className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[11px]"
style={{ color: "var(--text-muted)" }} style={{ color: "var(--text-muted)" }}
> >
<GitFork className="size-3" /> <GitFork className="size-3" />

View File

@ -346,7 +346,7 @@ export function ChatMessageInput({
{showModelWarning && ( {showModelWarning && (
<div <div
className="absolute -top-11 right-0 left-0 flex animate-bounce items-center justify-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-medium shadow-sm" className="absolute -top-11 right-0 left-0 flex animate-bounce items-center justify-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-medium"
style={{ style={{
backgroundColor: "var(--accent-muted)", backgroundColor: "var(--accent-muted)",
color: "var(--accent)", color: "var(--accent)",
@ -359,7 +359,7 @@ export function ChatMessageInput({
</div> </div>
)} )}
<Card className="overflow-hidden border border-[var(--border-subtle)] bg-[var(--surface-secondary)]/80 shadow-lg backdrop-blur"> <Card className="overflow-hidden border border-[var(--border-subtle)] bg-[var(--surface-secondary)]/80 backdrop-blur">
<PromptInput onSubmit={handleSubmit}> <PromptInput onSubmit={handleSubmit}>
<PromptInputBody> <PromptInputBody>
{selectedContexts.length > 0 && ( {selectedContexts.length > 0 && (
@ -381,7 +381,7 @@ export function ChatMessageInput({
</span> </span>
<button <button
type="button" type="button"
className="inline-flex items-center justify-center rounded-full opacity-70 transition-opacity hover:opacity-100" className="inline-flex items-center justify-center rounded-full opacity-70 transition-opacity"
onClick={() => onClick={() =>
setSelectedContexts((current) => setSelectedContexts((current) =>
current.filter( current.filter(

View File

@ -178,7 +178,7 @@ export function ChatMessageList({
{PROMPT_SUGGESTIONS.map((s, i) => ( {PROMPT_SUGGESTIONS.map((s, i) => (
<button <button
key={i} key={i}
className="flex items-start gap-2.5 rounded-2xl border border-[var(--border-subtle)] bg-[var(--surface-ground)] p-4 text-left transition-all duration-200 hover:-translate-y-0.5 hover:border-[var(--border-default)] hover:bg-[var(--surface-elevated)] hover:shadow-sm" className="flex items-start gap-2.5 rounded-2xl border border-[var(--border-subtle)] bg-[var(--surface-ground)] p-4 text-left"
style={{ style={{
color: "var(--text-secondary)", color: "var(--text-secondary)",
}} }}
@ -217,7 +217,7 @@ export function ChatMessageList({
> >
{isStreaming && userScrolledUp && ( {isStreaming && userScrolledUp && (
<div <div
className="absolute bottom-3 left-1/2 z-10 -translate-x-1/2 cursor-pointer rounded-full border px-4 py-1.5 shadow-lg transition-all hover:scale-105" className="absolute bottom-3 left-1/2 z-10 -translate-x-1/2 cursor-pointer rounded-full border px-4 py-1.5"
style={{ style={{
backgroundColor: "var(--surface-elevated)", backgroundColor: "var(--surface-elevated)",
borderColor: "var(--border-subtle)", borderColor: "var(--border-subtle)",
@ -401,7 +401,7 @@ function StreamingBubble({
return ( return (
<div <div
ref={contentRef} ref={contentRef}
className="mx-auto flex w-full max-w-3xl gap-4 rounded-2xl border border-[var(--border-subtle)] bg-[var(--surface-secondary)]/70 px-4 py-3 shadow-sm backdrop-blur" className="mx-auto flex w-full max-w-3xl gap-4 rounded-2xl border border-[var(--border-subtle)] bg-[var(--surface-secondary)]/70 px-4 py-3 backdrop-blur"
> >
<div className="shrink-0 pt-0.5"> <div className="shrink-0 pt-0.5">
<StreamingModelAvatar modelName={selectedModel?.model_name} size={28} /> <StreamingModelAvatar modelName={selectedModel?.model_name} size={28} />

View File

@ -135,7 +135,7 @@ export function ChatModelSelector({
return ( return (
<ModelSelector open={open} onOpenChange={setOpen}> <ModelSelector open={open} onOpenChange={setOpen}>
<ModelSelectorTrigger asChild> <ModelSelectorTrigger asChild>
<button className="inline-flex items-center gap-2 rounded-full border border-[var(--border-subtle)] bg-[var(--surface-elevated)] px-3 py-1.5 text-xs font-medium text-[var(--text-primary)] shadow-sm transition-all hover:-translate-y-0.5 hover:border-[var(--border-default)] hover:bg-[var(--surface-secondary)]"> <button className="inline-flex items-center gap-2 rounded-full border border-[var(--border-subtle)] bg-[var(--surface-elevated)] px-3 py-1.5 text-xs font-medium text-[var(--text-primary)]">
{selectedModel ? ( {selectedModel ? (
<ModelAvatar modelName={selectedModel.model_name} size={18} /> <ModelAvatar modelName={selectedModel.model_name} size={18} />
) : ( ) : (
@ -155,7 +155,7 @@ export function ChatModelSelector({
<ModelSelectorContent <ModelSelectorContent
title={t("chat.model_selector.search_placeholder")} title={t("chat.model_selector.search_placeholder")}
className="w-[min(92vw,38rem)] overflow-hidden rounded-2xl border border-[var(--border-subtle)] bg-[var(--surface-elevated)] p-0 shadow-2xl" className="w-[min(92vw,38rem)] overflow-hidden rounded-2xl border border-[var(--border-subtle)] bg-[var(--surface-elevated)] p-0"
> >
<div className="flex items-center justify-between gap-3 border-b border-[var(--border-subtle)] bg-[var(--surface-secondary)]/70 px-4 py-3"> <div className="flex items-center justify-between gap-3 border-b border-[var(--border-subtle)] bg-[var(--surface-secondary)]/70 px-4 py-3">
<div className="min-w-0"> <div className="min-w-0">

View File

@ -38,7 +38,7 @@ export function ChatSlashCommandMenu({
return ( return (
<div <div
className="absolute inset-x-0 bottom-full z-20 mb-2 overflow-hidden rounded-2xl border shadow-2xl" className="absolute inset-x-0 bottom-full z-20 mb-2 overflow-hidden rounded-2xl border"
style={{ style={{
backgroundColor: "var(--surface-elevated)", backgroundColor: "var(--surface-elevated)",
borderColor: "var(--border-subtle)", borderColor: "var(--border-subtle)",
@ -76,7 +76,7 @@ export function ChatSlashCommandMenu({
type="button" type="button"
onMouseEnter={() => onHoverIndex(index)} onMouseEnter={() => onHoverIndex(index)}
onClick={() => onPickItem(item)} onClick={() => onPickItem(item)}
className="flex w-full items-start justify-between gap-3 rounded-xl px-3 py-2 text-left transition-colors" className="flex w-full items-start justify-between gap-3 rounded-xl px-3 py-2 text-left"
style={{ style={{
backgroundColor: backgroundColor:
activeIndex === index ? "var(--hover-bg)" : "transparent", activeIndex === index ? "var(--hover-bg)" : "transparent",

View File

@ -12,7 +12,7 @@ function Card({
data-slot="card" data-slot="card"
data-size={size} data-size={size}
className={cn( className={cn(
"group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl", "group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
className className
)} )}
{...props} {...props}

View File

@ -14,7 +14,7 @@ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
data-slot="input-group" data-slot="input-group"
role="group" role="group"
className={cn( className={cn(
"group/input-group relative flex h-8 w-full min-w-0 items-center rounded-lg border border-input transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5", "group/input-group relative flex h-8 w-full min-w-0 items-center rounded-lg outline-none has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5",
className className
)} )}
{...props} {...props}