Merge branch 'dhk-1' into 'master'
样式修改 See merge request knowledge-base-bj/deerflow-server!29
This commit is contained in:
commit
628bbe14a8
24 files changed
+936
-154
No files matched your search
@@ -514,9 +514,15 @@ export function InputBox({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={cn(isNewThread && "gemini-gradient-border gemini-shadow")}>
|
||||
<PromptInput
|
||||
className={cn(
|
||||
"rounded-[1.85rem] border border-[#eadfce] bg-white shadow-[0_24px_70px_-34px_rgba(120,83,42,0.32)] ring-1 ring-[#f6efe5] transition-all duration-300 ease-out *:data-[slot='input-group']:rounded-[1.85rem] dark:bg-slate-800 dark:border-slate-700 dark:ring-slate-700 dark:shadow-none",
|
||||
"transition-all duration-300 ease-out *:data-[slot='input-group']:rounded-3xl",
|
||||
// landing 态:透明,让外层 gemini-gradient-border 提供白卡 + 旋转描边
|
||||
// 对话态:常规白卡 + 中性边框 + 轻阴影
|
||||
isNewThread
|
||||
? "rounded-3xl bg-transparent border-0 shadow-none ring-0"
|
||||
: "rounded-3xl bg-background border border-border shadow-sm dark:bg-slate-800 dark:border-slate-700",
|
||||
className,
|
||||
)}
|
||||
disabled={disabled}
|
||||
@@ -531,7 +537,8 @@ export function InputBox({
|
||||
<PromptInputBody className="absolute top-0 right-0 left-0 z-3">
|
||||
<PromptInputTextarea
|
||||
className={cn(
|
||||
"size-full px-2 py-1 text-[15px] leading-7 placeholder:text-[#b7ab9a] dark:placeholder:text-slate-500",
|
||||
"size-full px-2 py-1 text-[15px] leading-7 placeholder:text-muted-foreground/60",
|
||||
isNewThread && "min-h-[110px]!",
|
||||
)}
|
||||
disabled={disabled}
|
||||
placeholder={t.inputBox.placeholder}
|
||||
@@ -539,7 +546,7 @@ export function InputBox({
|
||||
defaultValue={initialValue}
|
||||
/>
|
||||
</PromptInputBody>
|
||||
<PromptInputFooter className="flex items-center border-t border-[#f4ede4] dark:border-slate-700 px-2 pt-2.5 pb-1.5">
|
||||
<PromptInputFooter className="flex items-center border-t-0 px-2 pt-1 pb-1.5">
|
||||
<PromptInputTools className="gap-1.5">
|
||||
{/* TODO: Add more connectors here
|
||||
<PromptInputActionMenu>
|
||||
@@ -550,7 +557,7 @@ export function InputBox({
|
||||
/>
|
||||
</PromptInputActionMenuContent>
|
||||
</PromptInputActionMenu> */}
|
||||
<AddAttachmentsButton className="rounded-full border border-[#eee3d5] bg-[#fffaf5] px-2.5! shadow-none hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700" />
|
||||
<AddAttachmentsButton className="rounded-full border-0 bg-transparent px-2.5! shadow-none text-muted-foreground hover:bg-muted/70 hover:text-foreground dark:text-slate-400 dark:hover:bg-slate-700/70 dark:hover:text-slate-100" />
|
||||
<Tooltip
|
||||
content={
|
||||
context.writing_mode
|
||||
@@ -560,10 +567,10 @@ export function InputBox({
|
||||
>
|
||||
<PromptInputButton
|
||||
className={cn(
|
||||
"gap-1.5! rounded-full border px-3! shadow-none",
|
||||
"gap-1.5! rounded-full px-3! shadow-none",
|
||||
context.writing_mode
|
||||
? "border-[#d8b878] bg-[#fff3cf] text-[#6d5625] hover:bg-[#ffedbd]"
|
||||
: "border-[#eee3d5] bg-[#fffaf5] text-[#7e6a57] hover:bg-white",
|
||||
? "border border-amber-300 bg-amber-50 text-amber-700 hover:bg-amber-100 dark:border-amber-700 dark:bg-amber-950/40 dark:text-amber-200"
|
||||
: "border-0 bg-transparent text-muted-foreground hover:bg-muted/70 hover:text-foreground dark:text-slate-400 dark:hover:bg-slate-700/70 dark:hover:text-slate-100",
|
||||
)}
|
||||
onClick={handleWritingModeToggle}
|
||||
>
|
||||
@@ -582,7 +589,7 @@ export function InputBox({
|
||||
: "flash"
|
||||
}
|
||||
>
|
||||
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3! text-[#7e6a57] shadow-none hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700">
|
||||
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border-0 bg-transparent px-3! text-muted-foreground shadow-none hover:bg-muted/70 hover:text-foreground dark:text-slate-400 dark:hover:bg-slate-700/70 dark:hover:text-slate-100">
|
||||
<div>
|
||||
{context.mode === "flash" && <ZapIcon className="size-3" />}
|
||||
{context.mode === "thinking" && (
|
||||
@@ -744,7 +751,7 @@ export function InputBox({
|
||||
</PromptInputActionMenu>
|
||||
{supportReasoningEffort && context.mode !== "flash" && (
|
||||
<PromptInputActionMenu>
|
||||
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3! text-[#7e6a57] shadow-none hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700">
|
||||
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border-0 bg-transparent px-3! text-muted-foreground shadow-none hover:bg-muted/70 hover:text-foreground dark:text-slate-400 dark:hover:bg-slate-700/70 dark:hover:text-slate-100">
|
||||
<div className="text-xs font-normal">
|
||||
{t.inputBox.reasoningEffort}:
|
||||
{context.reasoning_effort === "minimal" &&
|
||||
@@ -873,17 +880,17 @@ export function InputBox({
|
||||
onClick={promptPrefix.onToggle}
|
||||
aria-pressed={promptPrefix.on}
|
||||
className={cn(
|
||||
"rounded-full border px-3 shadow-none transition-colors",
|
||||
"rounded-full px-3 shadow-none transition-colors",
|
||||
promptPrefix.on
|
||||
? "border-[#d6a868] bg-[#fff3df] text-[#7a5417] hover:bg-[#ffe8c4]"
|
||||
: "border-[#eee3d5] bg-[#fffaf5] text-[#8a7558] hover:bg-white",
|
||||
? "border border-amber-300 bg-amber-50 text-amber-700 hover:bg-amber-100 dark:border-amber-700 dark:bg-amber-950/40 dark:text-amber-200"
|
||||
: "border-0 bg-transparent text-muted-foreground hover:bg-muted/70 hover:text-foreground",
|
||||
)}
|
||||
>
|
||||
<span className="max-w-[160px] truncate text-xs font-normal">
|
||||
{promptPrefix.label}
|
||||
</span>
|
||||
{promptPrefix.on && (
|
||||
<CheckIcon className="ml-1 size-3.5 text-[#7a5417]" />
|
||||
<CheckIcon className="ml-1 size-3.5 text-amber-700 dark:text-amber-200" />
|
||||
)}
|
||||
</PromptInputButton>
|
||||
</Tooltip>
|
||||
@@ -893,7 +900,7 @@ export function InputBox({
|
||||
onOpenChange={setModelDialogOpen}
|
||||
>
|
||||
<ModelSelectorTrigger asChild>
|
||||
<PromptInputButton className="rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3 shadow-none hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700">
|
||||
<PromptInputButton className="rounded-full border-0 bg-transparent px-3 shadow-none text-muted-foreground hover:bg-muted/70 hover:text-foreground dark:text-slate-400 dark:hover:bg-slate-700/70 dark:hover:text-slate-100">
|
||||
<div className="flex min-w-0 flex-col items-start text-left">
|
||||
<ModelSelectorName className="text-xs font-normal">
|
||||
{selectedModel?.display_name}
|
||||
@@ -927,7 +934,7 @@ export function InputBox({
|
||||
</ModelSelectorContent>
|
||||
</ModelSelector>
|
||||
<PromptInputSubmit
|
||||
className="rounded-full border-[#e7d9c7] bg-white shadow-[0_10px_24px_-18px_rgba(120,83,42,0.34)] dark:bg-blue-500 dark:border-blue-500 dark:text-white dark:hover:bg-blue-400 dark:shadow-none"
|
||||
className="rounded-full border-border bg-background shadow-sm hover:bg-muted dark:bg-blue-500 dark:border-blue-500 dark:text-white dark:hover:bg-blue-400 dark:shadow-none"
|
||||
disabled={disabled}
|
||||
variant="outline"
|
||||
status={status}
|
||||
@@ -935,9 +942,10 @@ export function InputBox({
|
||||
</PromptInputTools>
|
||||
</PromptInputFooter>
|
||||
{!isNewThread && (
|
||||
<div className="absolute right-0 -bottom-[17px] left-0 z-0 h-4 bg-[#fffdfa] dark:bg-background"></div>
|
||||
<div className="absolute right-0 -bottom-[17px] left-0 z-0 h-4 bg-background"></div>
|
||||
)}
|
||||
</PromptInput>
|
||||
</div>
|
||||
|
||||
<Dialog open={confirmOpen} onOpenChange={setConfirmOpen}>
|
||||
<DialogContent>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Message } from "@langchain/langgraph-sdk";
|
||||
import {
|
||||
BookOpenTextIcon,
|
||||
ChevronDownIcon,
|
||||
ChevronUp,
|
||||
FolderOpenIcon,
|
||||
GlobeIcon,
|
||||
@@ -23,6 +24,18 @@ import {
|
||||
} from "@/components/ai-elements/chain-of-thought";
|
||||
import { CodeBlock } from "@/components/ai-elements/code-block";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { useI18n } from "@/core/i18n/hooks";
|
||||
import {
|
||||
extractReasoningContentFromMessage,
|
||||
@@ -208,19 +221,10 @@ function ToolCall({
|
||||
if (typeof args.query === "string") {
|
||||
label = t.toolCalls.searchOnWebFor(args.query);
|
||||
}
|
||||
const items = normalizeSearchResults(result);
|
||||
return (
|
||||
<ChainOfThoughtStep key={id} label={label} icon={SearchIcon}>
|
||||
{Array.isArray(result) && (
|
||||
<ChainOfThoughtSearchResults>
|
||||
{result.map((item) => (
|
||||
<ChainOfThoughtSearchResult key={item.url}>
|
||||
<a href={item.url} target="_blank" rel="noopener noreferrer">
|
||||
{item.title}
|
||||
</a>
|
||||
</ChainOfThoughtSearchResult>
|
||||
))}
|
||||
</ChainOfThoughtSearchResults>
|
||||
)}
|
||||
{items.length > 0 && <WebSearchResultsList results={items} />}
|
||||
</ChainOfThoughtStep>
|
||||
);
|
||||
} else if (name === "image_search") {
|
||||
@@ -496,3 +500,117 @@ function convertToSteps(messages: Message[]): CoTStep[] {
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
|
||||
type WebSearchItem = {
|
||||
title?: string;
|
||||
url?: string;
|
||||
snippet?: string;
|
||||
content?: string;
|
||||
published_date?: string;
|
||||
publishedDate?: string;
|
||||
date?: string;
|
||||
};
|
||||
|
||||
function normalizeSearchResults(
|
||||
result: string | Record<string, unknown> | undefined,
|
||||
): WebSearchItem[] {
|
||||
if (Array.isArray(result)) {
|
||||
return result as WebSearchItem[];
|
||||
}
|
||||
if (result && typeof result === "object") {
|
||||
const nested = (result as { results?: unknown }).results;
|
||||
if (Array.isArray(nested)) {
|
||||
return nested as WebSearchItem[];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function WebSearchResultsList({ results }: { results: WebSearchItem[] }) {
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<Collapsible open={open} onOpenChange={setOpen} className="w-full">
|
||||
<CollapsibleTrigger className="text-muted-foreground hover:text-foreground flex items-center gap-1 text-xs">
|
||||
<ChevronDownIcon
|
||||
className={cn(
|
||||
"size-3.5 transition-transform duration-200",
|
||||
open && "rotate-180",
|
||||
)}
|
||||
/>
|
||||
<span>{results.length} 条检索结果</span>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="mt-2 flex flex-col gap-2">
|
||||
{results.map((item, idx) => (
|
||||
<SearchResultCard key={item.url ?? idx} item={item} />
|
||||
))}
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
);
|
||||
}
|
||||
|
||||
function SearchResultCard({ item }: { item: WebSearchItem }) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const content = item.snippet ?? item.content;
|
||||
const date = item.published_date ?? item.publishedDate ?? item.date;
|
||||
let source: string | undefined;
|
||||
if (item.url) {
|
||||
try {
|
||||
source = new URL(item.url).hostname.replace(/^www\./, "");
|
||||
} catch {
|
||||
source = undefined;
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOpen(true)}
|
||||
className="bg-card hover:bg-accent block w-full cursor-pointer rounded-lg border p-3 text-left transition-colors"
|
||||
>
|
||||
{item.title && (
|
||||
<div className="text-foreground line-clamp-1 text-sm font-medium">
|
||||
{item.title}
|
||||
</div>
|
||||
)}
|
||||
{(source || date) && (
|
||||
<div className="text-muted-foreground mt-1 flex items-center gap-2 text-xs">
|
||||
{source && <span className="truncate">{source}</span>}
|
||||
{source && date && <span>·</span>}
|
||||
{date && <span>{date}</span>}
|
||||
</div>
|
||||
)}
|
||||
{content && (
|
||||
<div className="text-muted-foreground mt-1.5 line-clamp-2 text-xs leading-relaxed">
|
||||
{content}
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent className="max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="pr-6 text-base leading-relaxed">
|
||||
{item.title ?? "检索结果"}
|
||||
</DialogTitle>
|
||||
{(source || date) && (
|
||||
<DialogDescription className="flex items-center gap-2 text-xs">
|
||||
{source && <span>{source}</span>}
|
||||
{source && date && <span>·</span>}
|
||||
{date && <span>{date}</span>}
|
||||
</DialogDescription>
|
||||
)}
|
||||
</DialogHeader>
|
||||
{content && (
|
||||
<div className="text-foreground max-h-[60vh] overflow-y-auto whitespace-pre-wrap text-sm leading-relaxed">
|
||||
{content}
|
||||
</div>
|
||||
)}
|
||||
{item.url && (
|
||||
<div className="text-muted-foreground border-t pt-3 text-xs break-all">
|
||||
{item.url}
|
||||
</div>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -158,15 +158,15 @@ export function RecentChatList() {
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<SidebarGroup className="px-2">
|
||||
<SidebarGroupLabel className="text-muted-foreground/90 px-2 text-[11px] font-semibold tracking-wide uppercase">
|
||||
<SidebarGroup className="px-2 pt-3 mt-2 border-t border-sidebar-border/60">
|
||||
<SidebarGroupLabel className="text-muted-foreground/70 px-3 mb-1 text-[10px] font-semibold tracking-[0.12em] uppercase">
|
||||
{env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY !== "true"
|
||||
? t.sidebar.recentChats
|
||||
: t.sidebar.demoChats}
|
||||
</SidebarGroupLabel>
|
||||
<SidebarGroupContent className="group-data-[collapsible=icon]:pointer-events-none group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0">
|
||||
<SidebarMenu>
|
||||
<div className="flex w-full flex-col gap-1">
|
||||
<div className="flex w-full flex-col gap-0.5">
|
||||
{visibleThreads.map((thread) => {
|
||||
const isActive = pathOfThread(thread) === pathname;
|
||||
return (
|
||||
@@ -174,9 +174,17 @@ export function RecentChatList() {
|
||||
key={thread.thread_id}
|
||||
className="group/side-menu-item"
|
||||
>
|
||||
<SidebarMenuButton isActive={isActive} asChild>
|
||||
<SidebarMenuButton
|
||||
isActive={isActive}
|
||||
asChild
|
||||
className={
|
||||
"rounded-lg h-7 px-3 text-[13px] text-muted-foreground hover:text-foreground hover:bg-sidebar-accent/60 " +
|
||||
"data-[active=true]:bg-white data-[active=true]:text-foreground data-[active=true]:shadow-[0_1px_2px_rgba(15,23,42,0.05)] " +
|
||||
"dark:data-[active=true]:bg-slate-700/80 dark:data-[active=true]:text-slate-100 dark:data-[active=true]:shadow-none"
|
||||
}
|
||||
>
|
||||
<Link
|
||||
className="text-muted-foreground block w-full whitespace-nowrap group-hover/side-menu-item:overflow-hidden"
|
||||
className="block w-full whitespace-nowrap group-hover/side-menu-item:overflow-hidden"
|
||||
href={pathOfThread(thread)}
|
||||
>
|
||||
{titleOfThread(thread)}
|
||||
|
||||
@@ -36,12 +36,12 @@ export function Welcome({
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="text-2xl font-bold">
|
||||
<div className="text-[26px] font-medium tracking-tight text-foreground/85">
|
||||
{searchParams.get("mode") === "skill" ? (
|
||||
`✨ ${t.welcome.createYourOwnSkill} ✨`
|
||||
) : (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={cn("inline-block", !waved ? "animate-wave" : "")}>
|
||||
<div className="flex items-center gap-2.5">
|
||||
<div className={cn("inline-block text-2xl", !waved ? "animate-wave" : "")}>
|
||||
{isUltra ? "🚀" : "👋"}
|
||||
</div>
|
||||
<AuroraText colors={colors}>{t.welcome.greeting}</AuroraText>
|
||||
|
||||
@@ -15,26 +15,43 @@ import { useI18n } from "@/core/i18n/hooks";
|
||||
// import { BotIcon, BrainIcon, ListChecks, MessageSquarePlus, MessagesSquare, SparklesIcon, UsersIcon } from "lucide-react";
|
||||
import { BotIcon, BrainIcon, CalendarClock, ListChecks, MessageSquarePlus, MessagesSquare, SparklesIcon, UsersIcon } from "lucide-react";
|
||||
|
||||
// 普通导航项:默认中性色,激活态与「新对话」一致——主色浅底 + 主色文字/图标
|
||||
const NAV_ITEM_CLASS =
|
||||
"text-sidebar-foreground/80 hover:text-primary rounded-xl h-9 px-3 transition-colors hover:bg-primary/10 " +
|
||||
"data-[active=true]:bg-primary/15 data-[active=true]:text-primary data-[active=true]:shadow-none " +
|
||||
"dark:hover:bg-primary/15 dark:data-[active=true]:bg-primary/25 dark:data-[active=true]:text-primary-foreground";
|
||||
|
||||
// 「新对话」专属:默认仅主色文字/图标(显眼但不是选中态),命中 /chats/new 时才上主色底
|
||||
const NEW_CHAT_CLASS =
|
||||
"rounded-xl h-9 px-3 text-primary transition-colors hover:bg-primary/10 hover:text-primary " +
|
||||
"data-[active=true]:bg-primary/15 data-[active=true]:text-primary data-[active=true]:shadow-none " +
|
||||
"dark:text-primary-foreground dark:hover:bg-primary/15 dark:data-[active=true]:bg-primary/25";
|
||||
|
||||
export function WorkspaceNavChatList() {
|
||||
const { t } = useI18n();
|
||||
const pathname = usePathname();
|
||||
return (
|
||||
<SidebarGroup className="px-2 pt-2">
|
||||
<SidebarMenu>
|
||||
<SidebarMenu className="gap-1">
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton
|
||||
isActive={pathname === "/page/workspace/chats/new"}
|
||||
asChild
|
||||
className={NEW_CHAT_CLASS}
|
||||
>
|
||||
<Link className="text-sidebar-foreground" href="/page/workspace/chats/new">
|
||||
<Link href="/page/workspace/chats/new">
|
||||
<MessageSquarePlus />
|
||||
<span>{t.sidebar.newChat}</span>
|
||||
</Link>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton isActive={pathname === "/page/workspace/chats"} asChild>
|
||||
<Link className="text-sidebar-foreground" href="/page/workspace/chats">
|
||||
<SidebarMenuButton
|
||||
isActive={pathname === "/page/workspace/chats"}
|
||||
asChild
|
||||
className={NAV_ITEM_CLASS}
|
||||
>
|
||||
<Link href="/page/workspace/chats">
|
||||
<MessagesSquare />
|
||||
<span>{t.sidebar.chats}</span>
|
||||
</Link>
|
||||
@@ -44,8 +61,9 @@ export function WorkspaceNavChatList() {
|
||||
<SidebarMenuButton
|
||||
isActive={pathname.startsWith("/page/workspace/agents")}
|
||||
asChild
|
||||
className={NAV_ITEM_CLASS}
|
||||
>
|
||||
<Link className="text-sidebar-foreground" href="/page/workspace/agents">
|
||||
<Link href="/page/workspace/agents">
|
||||
<BotIcon />
|
||||
<span>{t.sidebar.agents}</span>
|
||||
</Link>
|
||||
@@ -55,8 +73,9 @@ export function WorkspaceNavChatList() {
|
||||
<SidebarMenuButton
|
||||
isActive={pathname.startsWith("/page/workspace/skills")}
|
||||
asChild
|
||||
className={NAV_ITEM_CLASS}
|
||||
>
|
||||
<Link className="text-sidebar-foreground" href="/page/workspace/skills">
|
||||
<Link href="/page/workspace/skills">
|
||||
<SparklesIcon />
|
||||
<span>技能</span>
|
||||
</Link>
|
||||
@@ -66,8 +85,9 @@ export function WorkspaceNavChatList() {
|
||||
<SidebarMenuButton
|
||||
isActive={pathname.startsWith("/page/workspace/memory")}
|
||||
asChild
|
||||
className={NAV_ITEM_CLASS}
|
||||
>
|
||||
<Link className="text-sidebar-foreground" href="/page/workspace/memory">
|
||||
<Link href="/page/workspace/memory">
|
||||
<BrainIcon />
|
||||
<span>记忆</span>
|
||||
</Link>
|
||||
@@ -77,8 +97,9 @@ export function WorkspaceNavChatList() {
|
||||
<SidebarMenuButton
|
||||
isActive={pathname === "/page/workspace/scheduled/tasks"}
|
||||
asChild
|
||||
className={NAV_ITEM_CLASS}
|
||||
>
|
||||
<Link className="text-sidebar-foreground" href="/page/workspace/scheduled/tasks">
|
||||
<Link href="/page/workspace/scheduled/tasks">
|
||||
<ListChecks />
|
||||
<span>任务管理</span>
|
||||
</Link>
|
||||
|
||||
Reference in new issue
Block a user