Files
deerflow-code/frontend-web/src/components/workspace/workspace-header.tsx
T

109 lines
3.5 KiB
TypeScript

"use client";
import { ChevronLeft, ChevronRight, Trophy } from "lucide-react";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import { useSidebar } from "@/components/ui/sidebar";
import { useI18n } from "@/core/i18n/hooks";
import { env } from "@/env";
import { cn } from "@/lib/utils";
function BrandMark({ className }: { className?: string }) {
return (
<div
className={cn(
"bg-primary text-primary-foreground flex size-9 shrink-0 items-center justify-center rounded-lg text-sm font-bold shadow-sm",
className,
)}
aria-hidden
>
C
</div>
);
}
export function SidebarCollapseButton({ className }: { className?: string }) {
const { open, toggleSidebar } = useSidebar();
return (
<Button
data-sidebar="trigger"
data-slot="sidebar-trigger"
type="button"
variant="ghost"
size="icon"
className={cn(
"text-muted-foreground hover:text-sidebar-foreground size-8 shrink-0",
className,
)}
onClick={() => toggleSidebar()}
>
{open ? (
<ChevronLeft className="size-4" strokeWidth={2} />
) : (
<ChevronRight className="size-4" strokeWidth={2} />
)}
<span className="sr-only">Toggle Sidebar</span>
</Button>
);
}
export function WorkspaceHeader({ className }: { className?: string }) {
const { t } = useI18n();
const { state } = useSidebar();
const titleBlock = (
<div className="min-w-0 flex-1">
<div className="text-sidebar-foreground truncate text-sm font-semibold leading-tight tracking-tight">
{t.pages.appName}
</div>
</div>
);
return (
<div
className={cn(
"group/workspace-header border-sidebar-border/80 border-b",
className,
)}
>
{state === "collapsed" ? (
<div className="group/workspace-header relative flex min-h-[3.75rem] items-center justify-center py-2">
<div className="rounded-[1.15rem] bg-white/92 p-1.5 shadow-[0_16px_32px_-24px_rgba(15,23,42,0.3)] ring-1 ring-black/4 transition-opacity group-hover/workspace-header:pointer-events-none group-hover/workspace-header:opacity-0">
<BrandMark className="size-10 rounded-[0.95rem] text-base" />
</div>
<div className="absolute inset-0 flex items-center justify-center opacity-0 transition-opacity group-hover/workspace-header:opacity-100">
<SidebarCollapseButton className="rounded-2xl bg-white/92 shadow-sm ring-1 ring-black/5" />
</div>
</div>
) : (
<div className="flex items-center gap-2 px-2.5 py-2">
<BrandMark />
{env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true" ? (
<Link href="/page/workspace/chats/new" className="min-w-0 flex-1 outline-none">
{titleBlock}
</Link>
) : (
titleBlock
)}
{/* 用户排行榜入口:紧挨左上角的应用名,新标签打开免登录的公开排行榜页。 */}
<Button
type="button"
variant="ghost"
size="sm"
onClick={() =>
window.open("#/public/leaderboard", "_blank", "noopener")
}
title="打开用户排行榜公开页"
className="text-muted-foreground hover:text-sidebar-foreground h-8 shrink-0 gap-1 px-1.5 text-xs font-medium"
>
<Trophy className="size-4" />
<span>排行榜</span>
</Button>
<SidebarCollapseButton />
</div>
)}
</div>
);
}