2026-01-15 23:40:21 +08:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import Link from "next/link";
|
|
|
|
|
import { usePathname } from "next/navigation";
|
|
|
|
|
import { useMemo } from "react";
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
Breadcrumb,
|
|
|
|
|
BreadcrumbItem,
|
|
|
|
|
BreadcrumbLink,
|
|
|
|
|
BreadcrumbList,
|
|
|
|
|
BreadcrumbPage,
|
|
|
|
|
BreadcrumbSeparator,
|
|
|
|
|
} from "@/components/ui/breadcrumb";
|
2026-01-20 14:06:47 +08:00
|
|
|
import { useI18n } from "@/core/i18n/hooks";
|
2026-01-15 23:40:21 +08:00
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
|
|
|
|
|
|
import { GithubIcon } from "./github-icon";
|
|
|
|
|
import { Tooltip } from "./tooltip";
|
|
|
|
|
|
|
|
|
|
export function WorkspaceContainer({
|
|
|
|
|
className,
|
|
|
|
|
children,
|
|
|
|
|
...props
|
|
|
|
|
}: React.ComponentProps<"div">) {
|
|
|
|
|
return (
|
|
|
|
|
<div className={cn("flex h-screen w-full flex-col", className)} {...props}>
|
|
|
|
|
{children}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function WorkspaceHeader({
|
|
|
|
|
className,
|
|
|
|
|
children,
|
|
|
|
|
...props
|
|
|
|
|
}: React.ComponentProps<"header">) {
|
2026-01-20 14:06:47 +08:00
|
|
|
const { t } = useI18n();
|
2026-01-15 23:40:21 +08:00
|
|
|
const pathname = usePathname();
|
|
|
|
|
const segments = useMemo(() => {
|
|
|
|
|
const parts = pathname?.split("/") || [];
|
|
|
|
|
if (parts.length > 0) {
|
|
|
|
|
return parts.slice(1, 3);
|
|
|
|
|
}
|
|
|
|
|
}, [pathname]);
|
|
|
|
|
return (
|
|
|
|
|
<header
|
|
|
|
|
className={cn(
|
|
|
|
|
"top-0 right-0 left-0 z-20 flex h-16 shrink-0 items-center justify-between gap-2 border-b backdrop-blur-sm transition-[width,height] ease-out group-has-data-[collapsible=icon]/sidebar-wrapper:h-12",
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
>
|
|
|
|
|
<div className="flex items-center gap-2 px-4">
|
|
|
|
|
<Breadcrumb>
|
|
|
|
|
<BreadcrumbList>
|
|
|
|
|
{segments?.[0] && (
|
|
|
|
|
<BreadcrumbItem className="hidden md:block">
|
|
|
|
|
<BreadcrumbLink asChild>
|
|
|
|
|
<Link href={`/${segments[0]}`}>
|
2026-01-20 14:06:47 +08:00
|
|
|
{nameOfSegment(segments[0], t)}
|
2026-01-15 23:40:21 +08:00
|
|
|
</Link>
|
|
|
|
|
</BreadcrumbLink>
|
|
|
|
|
</BreadcrumbItem>
|
|
|
|
|
)}
|
|
|
|
|
{segments?.[1] && (
|
|
|
|
|
<>
|
|
|
|
|
<BreadcrumbSeparator className="hidden md:block" />
|
|
|
|
|
<BreadcrumbItem>
|
|
|
|
|
{segments.length >= 2 ? (
|
|
|
|
|
<BreadcrumbLink asChild>
|
|
|
|
|
<Link href={`/${segments[0]}/${segments[1]}`}>
|
2026-01-20 14:06:47 +08:00
|
|
|
{nameOfSegment(segments[1], t)}
|
2026-01-15 23:40:21 +08:00
|
|
|
</Link>
|
|
|
|
|
</BreadcrumbLink>
|
|
|
|
|
) : (
|
|
|
|
|
<BreadcrumbPage>
|
2026-01-20 14:06:47 +08:00
|
|
|
{nameOfSegment(segments[1], t)}
|
2026-01-15 23:40:21 +08:00
|
|
|
</BreadcrumbPage>
|
|
|
|
|
)}
|
|
|
|
|
</BreadcrumbItem>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
{children && (
|
|
|
|
|
<>
|
|
|
|
|
<BreadcrumbSeparator />
|
|
|
|
|
{children}
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</BreadcrumbList>
|
|
|
|
|
</Breadcrumb>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="pr-4">
|
2026-01-20 14:06:47 +08:00
|
|
|
<Tooltip content={t.workspace.githubTooltip}>
|
2026-01-15 23:40:21 +08:00
|
|
|
<a
|
|
|
|
|
href="https://github.com/bytedance/deer-flow"
|
|
|
|
|
target="_blank"
|
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
|
className="opacity-75 transition hover:opacity-100"
|
|
|
|
|
>
|
|
|
|
|
<GithubIcon className="size-6" />
|
|
|
|
|
</a>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
</div>
|
|
|
|
|
</header>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function WorkspaceBody({
|
|
|
|
|
className,
|
|
|
|
|
children,
|
|
|
|
|
...props
|
|
|
|
|
}: React.ComponentProps<"main">) {
|
|
|
|
|
return (
|
|
|
|
|
<main
|
|
|
|
|
className={cn(
|
|
|
|
|
"relative flex min-h-0 w-full flex-1 flex-col items-center",
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
>
|
|
|
|
|
<div className="flex h-full w-full flex-col items-center">{children}</div>
|
|
|
|
|
</main>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-20 14:06:47 +08:00
|
|
|
function nameOfSegment(
|
|
|
|
|
segment: string | undefined,
|
|
|
|
|
t: ReturnType<typeof useI18n>["t"],
|
|
|
|
|
) {
|
|
|
|
|
if (!segment) return t.common.home;
|
|
|
|
|
if (segment === "workspace") return t.breadcrumb.workspace;
|
|
|
|
|
if (segment === "chats") return t.breadcrumb.chats;
|
2026-01-15 23:40:21 +08:00
|
|
|
return segment[0]?.toUpperCase() + segment.slice(1);
|
|
|
|
|
}
|