fix: move flow board toolbar to sidebar
This commit is contained in:
parent
0870739a7d
commit
3c45bdfef9
@ -31,7 +31,6 @@ import { fetchUploadWithRetry } from "@/lib/client/upload-with-retry";
|
||||
import {
|
||||
CheckCircle2,
|
||||
ChevronDown,
|
||||
ChevronLeft,
|
||||
FileText,
|
||||
FolderOpen,
|
||||
Flag,
|
||||
@ -47,6 +46,12 @@ import {
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { useTheme } from "next-themes";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import {
|
||||
type ChangeEvent,
|
||||
type ClipboardEvent,
|
||||
@ -116,6 +121,10 @@ const FLOW_BOARD_IMAGE_UPLOAD_TYPES = new Set([
|
||||
"image/png",
|
||||
"image/webp",
|
||||
]);
|
||||
const FLOW_BOARD_SIDEBAR_BUTTON_CLASS =
|
||||
"flex h-10 w-10 items-center justify-center rounded-full text-[#4f566b] transition-colors hover:bg-black/5 hover:text-[#111827] disabled:cursor-not-allowed disabled:opacity-45";
|
||||
const FLOW_BOARD_SIDEBAR_BUTTON_ACTIVE_CLASS =
|
||||
"bg-[#111827] text-white shadow-sm hover:bg-[#1f2937] hover:text-white";
|
||||
const FLOW_BOARD_MARKER_GROUPS: FlowBoardMarkerGroup[] = [
|
||||
{
|
||||
id: "tag",
|
||||
@ -1374,132 +1383,154 @@ export function DrawnixWorkspace({
|
||||
ref={mindMapFileInputRef}
|
||||
type="file"
|
||||
/>
|
||||
<div className="pointer-events-none absolute top-4 left-4 z-20 flex items-center">
|
||||
<div
|
||||
className="pointer-events-auto flex h-11 items-center gap-3 rounded-2xl border border-black/5 bg-white px-3 shadow-sm transition-all hover:shadow-md"
|
||||
data-flow-board-shell-control="true"
|
||||
>
|
||||
<button
|
||||
className="group flex items-center gap-1 rounded-xl px-2 py-1.5 font-medium text-[#4f566b] text-sm transition-colors hover:bg-black/5 hover:text-[#111827]"
|
||||
onClick={() => {
|
||||
window.location.href = "/";
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<ChevronLeft className="group-hover:-translate-x-0.5 h-4 w-4 transition-transform" />
|
||||
返回
|
||||
</button>
|
||||
|
||||
<div className="h-5 w-px bg-black/10" />
|
||||
|
||||
<div className="flex items-center gap-2.5 px-1">
|
||||
{displayLogo ? (
|
||||
<img
|
||||
alt={siteName}
|
||||
className="h-6 w-6 rounded-md object-cover shadow-sm"
|
||||
src={displayLogo}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-[#111827] font-bold text-white text-xs shadow-sm">
|
||||
{siteName.slice(0, 1).toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
aria-label="流程白板文件名"
|
||||
className="h-7 w-fit min-w-[120px] max-w-[200px] rounded-lg border border-transparent bg-transparent px-2 font-bold text-[#111827] text-sm tracking-wide outline-none transition focus:border-black/10 focus:bg-[#f7f8fb]"
|
||||
onBlur={handleTitleCommit}
|
||||
onChange={(event) => setCurrentTitle(event.target.value)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter") {
|
||||
event.currentTarget.blur();
|
||||
}
|
||||
}}
|
||||
value={currentTitle}
|
||||
/>
|
||||
<span className="shrink-0 rounded-md bg-[#f7f8fb] px-1.5 py-0.5 font-medium text-[#7a8297] text-[11px]">
|
||||
{siteName}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="h-5 w-px bg-black/10" />
|
||||
|
||||
<div className="flex flex-1 items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<aside
|
||||
className="pointer-events-none absolute top-4 left-4 z-20 flex flex-col items-center gap-2 lg:top-6 lg:left-6"
|
||||
data-flow-board-shell-control="true"
|
||||
>
|
||||
<TooltipProvider delayDuration={120}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
className="flex h-8 items-center gap-1.5 rounded-xl px-2.5 font-medium text-[#4f566b] text-xs transition-colors hover:bg-black/5 hover:text-[#111827]"
|
||||
disabled={isSavingNow}
|
||||
onClick={() => flushPendingSave(true)}
|
||||
type="button"
|
||||
>
|
||||
{isSavingNow ? (
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
||||
) : (
|
||||
<Save className="h-3.5 w-3.5" />
|
||||
)}
|
||||
保存云端
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="flex h-8 items-center gap-1.5 rounded-xl px-2.5 font-medium text-[#4f566b] text-xs transition-colors hover:bg-black/5 hover:text-[#111827]"
|
||||
onClick={handleOpenFilePanel}
|
||||
type="button"
|
||||
>
|
||||
<FolderOpen className="h-3.5 w-3.5" />
|
||||
云文件
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="flex h-8 items-center gap-1.5 rounded-xl px-2.5 font-medium text-[#4f566b] text-xs transition-colors hover:bg-black/5 hover:text-[#111827] disabled:cursor-not-allowed disabled:opacity-50"
|
||||
disabled={isSavingNow || isImportingMindMap}
|
||||
onClick={() => mindMapFileInputRef.current?.click()}
|
||||
type="button"
|
||||
>
|
||||
{isImportingMindMap ? (
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
||||
) : (
|
||||
<Upload className="h-3.5 w-3.5" />
|
||||
)}
|
||||
导入
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={`flex h-8 items-center gap-1.5 rounded-xl px-2.5 font-medium text-xs transition-colors ${
|
||||
isMarkerPanelOpen
|
||||
? "bg-[#111827] text-white shadow-sm hover:bg-[#1f2937]"
|
||||
: "text-[#4f566b] hover:bg-black/5 hover:text-[#111827]"
|
||||
}`}
|
||||
className="pointer-events-auto flex h-[52px] w-[52px] items-center justify-center gap-3 rounded-full border border-black/10 bg-white px-2.5 text-left shadow transition hover:bg-black/[0.03] hover:shadow-md lg:w-[164px] lg:justify-start lg:px-4"
|
||||
onClick={() => {
|
||||
setIsFilePanelOpen(false);
|
||||
setIsMarkerPanelOpen((open) => !open);
|
||||
refreshMarkerSelectionState();
|
||||
window.location.href = "/";
|
||||
}}
|
||||
title="返回首页"
|
||||
type="button"
|
||||
>
|
||||
<Tag className="h-3.5 w-3.5" />
|
||||
标记
|
||||
{displayLogo ? (
|
||||
<img
|
||||
alt={siteName}
|
||||
className="h-8 w-8 rounded-full object-cover"
|
||||
src={displayLogo}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-black font-bold text-white text-sm">
|
||||
{siteName.slice(0, 1).toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
<span className="hidden min-w-0 truncate font-semibold text-[#111827] text-[15px] leading-none tracking-tight lg:block">
|
||||
{siteName}
|
||||
</span>
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">返回首页</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<button
|
||||
className="flex h-8 items-center gap-1.5 rounded-xl px-2.5 font-medium text-[#4f566b] text-xs transition-colors hover:bg-black/5 hover:text-[#111827]"
|
||||
onClick={handleCreateCloudFile}
|
||||
type="button"
|
||||
>
|
||||
<Plus className="h-3.5 w-3.5" />
|
||||
新建
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex shrink-0 items-center gap-1.5 pl-2 text-[#7a8297]">
|
||||
<Save className="h-3.5 w-3.5" />
|
||||
<span className="whitespace-nowrap font-medium text-xs">
|
||||
{formatSavedAt(lastSavedAt)}
|
||||
</span>
|
||||
<div className="pointer-events-auto hidden w-[164px] rounded-[22px] border border-black/10 bg-white px-3 py-2 shadow lg:block">
|
||||
<div className="mb-1 px-1 font-medium text-[#7a8297] text-[10px] uppercase tracking-[0.18em]">
|
||||
流程白板
|
||||
</div>
|
||||
<input
|
||||
aria-label="流程白板文件名"
|
||||
className="h-8 w-full rounded-xl border border-transparent bg-transparent px-1 font-semibold text-[#111827] text-sm tracking-wide outline-none transition focus:border-black/10 focus:bg-[#f7f8fb]"
|
||||
onBlur={handleTitleCommit}
|
||||
onChange={(event) => setCurrentTitle(event.target.value)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter") {
|
||||
event.currentTarget.blur();
|
||||
}
|
||||
}}
|
||||
value={currentTitle}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pointer-events-auto flex max-h-[calc(100vh-148px)] w-[56px] flex-col items-center gap-1 overflow-y-auto rounded-[28px] border border-black/10 bg-white px-1.5 py-2.5 shadow lg:max-h-[calc(100vh-236px)]">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
className={FLOW_BOARD_SIDEBAR_BUTTON_CLASS}
|
||||
disabled={isSavingNow}
|
||||
onClick={() => flushPendingSave(true)}
|
||||
title="保存云端"
|
||||
type="button"
|
||||
>
|
||||
{isSavingNow ? (
|
||||
<Loader2 className="h-[18px] w-[18px] animate-spin" />
|
||||
) : (
|
||||
<Save className="h-[18px] w-[18px]" />
|
||||
)}
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">保存云端</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
className={FLOW_BOARD_SIDEBAR_BUTTON_CLASS}
|
||||
onClick={handleOpenFilePanel}
|
||||
title="云文件"
|
||||
type="button"
|
||||
>
|
||||
<FolderOpen className="h-[18px] w-[18px]" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">云文件</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
className={FLOW_BOARD_SIDEBAR_BUTTON_CLASS}
|
||||
disabled={isSavingNow || isImportingMindMap}
|
||||
onClick={() => mindMapFileInputRef.current?.click()}
|
||||
title="导入"
|
||||
type="button"
|
||||
>
|
||||
{isImportingMindMap ? (
|
||||
<Loader2 className="h-[18px] w-[18px] animate-spin" />
|
||||
) : (
|
||||
<Upload className="h-[18px] w-[18px]" />
|
||||
)}
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">导入</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
className={`${FLOW_BOARD_SIDEBAR_BUTTON_CLASS} ${
|
||||
isMarkerPanelOpen ? FLOW_BOARD_SIDEBAR_BUTTON_ACTIVE_CLASS : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setIsFilePanelOpen(false);
|
||||
setIsMarkerPanelOpen((open) => !open);
|
||||
refreshMarkerSelectionState();
|
||||
}}
|
||||
title="标记"
|
||||
type="button"
|
||||
>
|
||||
<Tag className="h-[18px] w-[18px]" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">标记</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
className={FLOW_BOARD_SIDEBAR_BUTTON_CLASS}
|
||||
onClick={handleCreateCloudFile}
|
||||
title="新建"
|
||||
type="button"
|
||||
>
|
||||
<Plus className="h-[18px] w-[18px]" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">新建</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<div className="pointer-events-auto hidden max-w-[164px] items-center gap-1.5 rounded-full border border-black/10 bg-white px-3 py-1.5 text-[#7a8297] shadow lg:flex">
|
||||
<Save className="h-3.5 w-3.5 shrink-0" />
|
||||
<span className="truncate font-medium text-[11px]">
|
||||
{formatSavedAt(lastSavedAt)}
|
||||
</span>
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
</aside>
|
||||
|
||||
{isFilePanelOpen ? (
|
||||
<aside
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user