'feat:智能体暗色模式样式修改'

This commit is contained in:
zjy committed 2026-05-29 09:51:44 +08:00
1 parent 621fdc9244
commit 8aa52e7e3c
10 files changed
+151 -61

No files matched your search

+3 -3
View File
@@ -7,7 +7,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
<div <div
data-slot="card" data-slot="card"
className={cn( className={cn(
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", "bg-card text-card-foreground flex flex-col gap-6 rounded-[4px] border py-6 shadow-sm dark:border-[#0049A5] dark:bg-[#02244C]",
className, className,
)} )}
{...props} {...props}
@@ -42,7 +42,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot="card-description" data-slot="card-description"
className={cn("text-muted-foreground text-sm", className)} className={cn("text-muted-foreground text-sm dark:text-[#F2F3F5]", className)}
{...props} {...props}
/> />
); );
@@ -65,7 +65,7 @@ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot="card-content" data-slot="card-content"
className={cn("px-6", className)} className={cn("px-6 ", className)}
{...props} {...props}
/> />
); );
@@ -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 border-input/50 dark:bg-background/80 relative flex w-full items-center rounded-md border bg-white/80 shadow-xs transition-[color,box-shadow] outline-none", "group/input-group relative flex w-full items-center rounded-md border border-input/50 bg-white/80 shadow-xs transition-[color,box-shadow] outline-none dark:border-[#1B477E] dark:bg-[#022248]",
"h-9 min-w-0 has-[>textarea]:h-auto", "h-9 min-w-0 has-[>textarea]:h-auto",
// Variants based on alignment. // Variants based on alignment.
+6 -3
View File
@@ -8,9 +8,12 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
type={type} type={type}
data-slot="input" data-slot="input"
className={cn( className={cn(
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", "h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base outline-none transition-[color,box-shadow] md:text-sm",
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "border-input placeholder:text-muted-foreground",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", "dark:border-[#1B477E] dark:bg-[#022248] dark:text-[#AACEFF] dark:placeholder:text-[#566B7F] rounded-[4px] text-[16px]",
"file:text-foreground selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] dark:focus-visible:border-[#3b82f6] dark:focus-visible:ring-[#3b82f6]/30",
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
className, className,
)} )}
{...props} {...props}
+9 -3
View File
@@ -30,7 +30,8 @@ const tabsListVariants = cva(
{ {
variants: { variants: {
variant: { variant: {
default: "bg-muted", default:
"bg-muted dark:group-data-[orientation=horizontal]/tabs:h-8! dark:items-stretch dark:gap-0 dark:overflow-hidden dark:rounded-[2px] dark:border dark:border-[#55A6FE] dark:bg-[#022248] dark:p-0",
line: "gap-1 bg-transparent", line: "gap-1 bg-transparent",
}, },
}, },
@@ -67,9 +68,14 @@ const TabsTrigger = React.forwardRef<
ref={ref} ref={ref}
data-slot="tabs-trigger" data-slot="tabs-trigger"
className={cn( className={cn(
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"dark:text-muted-foreground dark:hover:text-foreground",
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent", "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 data-[state=active]:text-foreground", "data-[state=active]:bg-background data-[state=active]:text-foreground",
"dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-input dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-input/30 dark:group-data-[variant=line]/tabs-list:data-[state=active]:text-foreground",
"dark:group-data-[variant=default]/tabs-list:relative dark:group-data-[variant=default]/tabs-list:!h-full dark:group-data-[variant=default]/tabs-list:self-stretch dark:group-data-[variant=default]/tabs-list:flex-none dark:group-data-[variant=default]/tabs-list:rounded-none dark:group-data-[variant=default]/tabs-list:border-0 dark:group-data-[variant=default]/tabs-list:bg-transparent dark:group-data-[variant=default]/tabs-list:px-4 dark:group-data-[variant=default]/tabs-list:!py-0 dark:group-data-[variant=default]/tabs-list:!leading-none dark:group-data-[variant=default]/tabs-list:shadow-none dark:group-data-[variant=default]/tabs-list:focus-visible:ring-0 dark:group-data-[variant=default]/tabs-list:[&_svg]:text-[#CCD2DA]",
"dark:group-data-[variant=default]/tabs-list:not(:first-child):border-l dark:group-data-[variant=default]/tabs-list:not(:first-child):border-[#1d3961] dark:group-data-[variant=default]/tabs-list:data-[state=active]:border-l-0",
"dark:group-data-[variant=default]/tabs-list:data-[state=active]:rounded-none dark:group-data-[variant=default]/tabs-list:data-[state=active]:border-0 dark:group-data-[variant=default]/tabs-list:data-[state=active]:bg-[#0062D9] dark:group-data-[variant=default]/tabs-list:data-[state=active]:text-[#FFFFFF] dark:group-data-[variant=default]/tabs-list:data-[state=active]:shadow-none dark:group-data-[variant=default]/tabs-list:data-[state=active]:[&_svg]:text-[#FFFFFF] dark:group-data-[variant=default]/tabs-list:hover:text-[#CCD2DA]",
"after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100", "after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100",
className, className,
)} )}
+3 -1
View File
@@ -7,7 +7,9 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
<textarea <textarea
data-slot="textarea" data-slot="textarea"
className={cn( className={cn(
"border-input placeholder:text-muted-foreground/60 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", "border-input placeholder:text-muted-foreground/60 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"dark:border-[#1B477E] dark:bg-[#022248] dark:text-[#AACEFF] ",
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
className, className,
)} )}
{...props} {...props}
@@ -188,15 +188,18 @@ export function AgentCard({ agent }: AgentCardProps) {
return ( return (
<> <>
<Card className="group flex flex-col transition-shadow hover:shadow-md"> <Card className="group flex min-w-0 flex-col transition-shadow hover:shadow-md">
<CardHeader className="pb-3"> <CardHeader className="min-w-0 pb-3">
<div className="flex items-start justify-between gap-2"> <div className="flex min-w-0 items-start justify-between gap-2">
<div className="flex min-w-0 flex-1 items-center gap-2"> <div className="flex min-w-0 flex-1 items-center gap-2 overflow-hidden">
<div className="bg-primary/10 text-primary flex h-9 w-9 shrink-0 items-center justify-center rounded-lg"> <div className="bg-primary/10 text-primary flex h-9 w-9 shrink-0 items-center justify-center rounded-lg">
<BotIcon className="h-5 w-5" /> <BotIcon className="h-5 w-5" />
</div> </div>
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1 overflow-hidden">
<CardTitle className="truncate text-base" title={desensitize(agent.name)}> <CardTitle
className="block w-full min-w-0 overflow-hidden text-base text-ellipsis whitespace-nowrap"
title={desensitize(agent.name)}
>
{desensitize(agent.name)} {desensitize(agent.name)}
</CardTitle> </CardTitle>
{agent.model && ( {agent.model && (
@@ -49,15 +49,21 @@ export function AgentGallery() {
const renderEmpty = (description: string, showNewButton = false) => ( const renderEmpty = (description: string, showNewButton = false) => (
<div className="flex h-64 flex-col items-center justify-center gap-3 text-center"> <div className="flex h-64 flex-col items-center justify-center gap-3 text-center">
<div className="bg-muted flex h-14 w-14 items-center justify-center rounded-full"> <div className="bg-muted flex h-14 w-14 items-center justify-center rounded-full dark:bg-[#022248]">
<BotIcon className="text-muted-foreground h-7 w-7" /> <BotIcon className="text-muted-foreground h-7 w-7 dark:text-[#AACEFF]" />
</div> </div>
<div> <div>
<p className="font-medium">{t.agents.emptyTitle}</p> <p className="font-medium dark:text-[#AACEFF]">{t.agents.emptyTitle}</p>
<p className="text-muted-foreground mt-1 text-sm">{description}</p> <p className="text-muted-foreground mt-1 text-sm dark:text-[#55A6FE]">
{description}
</p>
</div> </div>
{showNewButton && ( {showNewButton && (
<Button variant="outline" className="mt-2" onClick={handleNewAgent}> <Button
variant="outline"
className="mt-2 dark:border-[#2580FF] dark:bg-[#2580FF] dark:text-white dark:hover:border-[#2580FF] dark:hover:bg-[#2580FF]/90 dark:hover:text-white"
onClick={handleNewAgent}
>
<PlusIcon className="mr-1.5 h-4 w-4" /> <PlusIcon className="mr-1.5 h-4 w-4" />
{t.agents.newAgent} {t.agents.newAgent}
</Button> </Button>
@@ -68,7 +68,7 @@ export function TagSearchBar({
return ( return (
<div className={cn("flex flex-col gap-2.5", className)}> <div className={cn("flex flex-col gap-2.5", className)}>
<div className="relative"> <div className="relative">
<SearchIcon className="text-muted-foreground absolute left-2.5 top-1/2 size-4 -translate-y-1/2" /> <SearchIcon className="text-muted-foreground dark:text-[#60a5fa]/90 absolute left-2.5 top-1/2 size-4 -translate-y-1/2" />
<Input <Input
value={input} value={input}
onChange={(e) => setInput(e.target.value)} onChange={(e) => setInput(e.target.value)}
+105 -35
View File
@@ -19,6 +19,13 @@ import {
} from "@/components/ai-elements/prompt-input"; } from "@/components/ai-elements/prompt-input";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
import { ArtifactsProvider } from "@/components/workspace/artifacts"; import { ArtifactsProvider } from "@/components/workspace/artifacts";
import { import {
@@ -115,10 +122,34 @@ export default function NewAgentPage() {
return; return;
} }
const first = models[0]!.name; const first = models[0]!.name;
setModelInput((prev) => prev || first); setModelInput((prev) =>
setChatModelInput((prev) => prev || first); prev && models.some((m) => m.name === prev) ? prev : first,
);
setChatModelInput((prev) =>
prev && models.some((m) => m.name === prev) ? prev : first,
);
}, [models]); }, [models]);
const resolvedModelInput = useMemo(() => {
if (models.length === 0) {
return "";
}
if (modelInput && models.some((m) => m.name === modelInput)) {
return modelInput;
}
return models[0]!.name;
}, [modelInput, models]);
const resolvedChatModelInput = useMemo(() => {
if (models.length === 0) {
return "";
}
if (chatModelInput && models.some((m) => m.name === chatModelInput)) {
return chatModelInput;
}
return models[0]!.name;
}, [chatModelInput, models]);
const [thread, sendMessage] = useThreadStream({ const [thread, sendMessage] = useThreadStream({
threadId, threadId,
assistantId: agentId || undefined, assistantId: agentId || undefined,
@@ -347,23 +378,42 @@ export default function NewAgentPage() {
<span className="text-muted-foreground text-xs"> <span className="text-muted-foreground text-xs">
当前对话模型 当前对话模型
</span> </span>
<select {isModelsLoading || models.length === 0 ? (
value={chatModelInput} <div className="border-input bg-background text-muted-foreground flex h-7 min-w-[10rem] items-center rounded-md border px-2 text-xs shadow-xs dark:border-[#1B477E] dark:bg-[#022248]">
onChange={(event) => {isModelsLoading ? "加载中…" : "暂无模型"}
setChatModelInput(event.currentTarget.value) </div>
} ) : (
disabled={isModelsLoading || thread.isLoading} <Select
className="border-input bg-background h-7 min-w-[10rem] rounded-md border px-2 text-xs shadow-xs outline-none" value={resolvedChatModelInput}
> onValueChange={setChatModelInput}
<option value="" disabled> disabled={thread.isLoading}
选择模型 >
</option> <SelectTrigger
{models.map((model) => ( className={cn(
<option key={model.name} value={model.name}> "border-input bg-background h-7 min-w-[10rem] px-2 text-xs shadow-xs outline-none",
{model.display_name || model.name} "dark:border-[#1B477E] dark:bg-[#022248] dark:text-[#AACEFF] dark:hover:bg-[#022248]",
</option> "data-[placeholder]:text-muted-foreground",
))} "[&_svg]:dark:text-[#AACEE2]",
</select> )}
>
<SelectValue placeholder="选择模型" />
</SelectTrigger>
<SelectContent
position="popper"
className="w-[var(--radix-select-trigger-width)] dark:border-[#1B477E] dark:bg-[#022248]"
>
{models.map((model) => (
<SelectItem
key={model.name}
value={model.name}
className="dark:text-[#AACEFF] dark:data-[highlighted]:bg-[#0062D9] dark:data-[highlighted]:text-white"
>
{model.display_name || model.name}
</SelectItem>
))}
</SelectContent>
</Select>
)}
</div> </div>
<PromptInput <PromptInput
onSubmit={({ text }) => void handleChatSubmit(text)} onSubmit={({ text }) => void handleChatSubmit(text)}
@@ -415,21 +465,41 @@ export default function NewAgentPage() {
<div className="space-y-2"> <div className="space-y-2">
<label className="text-sm font-medium">模型</label> <label className="text-sm font-medium">模型</label>
<select {isModelsLoading || models.length === 0 ? (
value={modelInput} <div className="border-input bg-background text-muted-foreground flex h-9 w-full items-center rounded-md border px-3 text-sm shadow-xs dark:border-[#1B477E] dark:bg-[#022248]">
onChange={(event) => setModelInput(event.currentTarget.value)} {isModelsLoading ? "加载模型…" : "暂无可用模型"}
disabled={isModelsLoading} </div>
className="border-input bg-background h-9 w-full rounded-md border px-3 text-sm shadow-xs outline-none" ) : (
> <Select
<option value="" disabled> value={resolvedModelInput}
选择模型 onValueChange={setModelInput}
</option> >
{models.map((model) => ( <SelectTrigger
<option key={model.name} value={model.name}> className={cn(
{model.display_name || model.name} "border-input bg-background h-9 w-full shadow-xs outline-none",
</option> "dark:border-[#1B477E] dark:bg-[#022248] dark:text-[#AACEFF] dark:hover:bg-[#022248]",
))} "data-[placeholder]:text-muted-foreground",
</select> "[&_svg]:dark:text-[#AACEE2]",
)}
>
<SelectValue placeholder="选择模型" />
</SelectTrigger>
<SelectContent
position="popper"
className="w-[var(--radix-select-trigger-width)] dark:border-[#1B477E] dark:bg-[#022248]"
>
{models.map((model) => (
<SelectItem
key={model.name}
value={model.name}
className="dark:text-[#AACEFF] dark:data-[highlighted]:bg-[#0062D9] dark:data-[highlighted]:text-white"
>
{model.display_name || model.name}
</SelectItem>
))}
</SelectContent>
</Select>
)}
<p className="text-muted-foreground text-xs"> <p className="text-muted-foreground text-xs">
该智能体被使用时调用的模型。 该智能体被使用时调用的模型。
</p> </p>
@@ -463,7 +533,7 @@ export default function NewAgentPage() {
/> />
</div> </div>
)} )}
<div className="max-h-[240px] overflow-y-auto rounded-md border p-2"> <div className="max-h-[240px] overflow-y-auto rounded-md border p-2 dark:border-[#1B477E] dark:bg-[#022248]">
{isSkillsLoading ? ( {isSkillsLoading ? (
<p className="text-muted-foreground text-sm">技能加载中...</p> <p className="text-muted-foreground text-sm">技能加载中...</p>
) : enabledSkills.length === 0 ? ( ) : enabledSkills.length === 0 ? (
+3 -3
View File
@@ -129,14 +129,14 @@ agents_api:
enabled: true enabled: true
database: database:
backend: mysql backend: sqlite
mysql_url: $MYSQL_DATABASE_URL sqlite_dir: .deer-flow/data
pool_size: 10 pool_size: 10
echo_sql: false echo_sql: false
checkpointer: checkpointer:
type: sqlite type: sqlite
connection_string: D:\cursor-work\offline-backend-20260512\backend\.deer-flow\data\deerflow.db connection_string: D:\05271502\deerflow-server\offline-backend-20260512\backend\.deer-flow\data\deerflow.db
# 记忆子系统:跨会话持久化用户画像与 agent 私有记忆。 # 记忆子系统:跨会话持久化用户画像与 agent 私有记忆。
# 三层覆盖优先级(高->低): # 三层覆盖优先级(高->低):