refine realtime canvas controls
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-03-08 01:40:59 +08:00
parent e3f6bf5457
commit f0340d3d96

View File

@ -34,7 +34,6 @@ import {
Upload,
ChevronDown,
ChevronUp,
RefreshCw,
Sparkles,
Save,
Trash2,
@ -115,7 +114,6 @@ const FALLBACK_PROMPT =
const CANVAS_BACKGROUND = "#ffffff";
const DEFAULT_BRUSH_COLOR = "#18181b";
const DRAW_LAYER_ID = "__draw_layer__";
const CANVAS_BACKGROUND_PRESETS = ["#ffffff", "#f4f4f5", "#fdf2f8", "#ecfeff", "#f0fdf4"] as const;
const REALTIME_PROJECTS_STORAGE_KEY = "ai-chatbot:realtime-canvas-projects";
function cloneImageLayers(layers: ImageLayer[]) {
@ -2208,17 +2206,6 @@ export function RealtimeCanvasDialog({
[importFilesAsLayers]
);
const handleCanvasBackgroundChange = useCallback(
(nextColor: string) => {
canvasBackgroundRef.current = nextColor;
setCanvasBackground(nextColor);
saveHistory(undefined, nextColor);
markCanvasDirty(null);
scheduleFlush(true);
},
[markCanvasDirty, saveHistory, scheduleFlush]
);
const handleDownloadCanvas = useCallback(async () => {
const compositeCanvas = await buildCompositeCanvas();
if (!compositeCanvas) return;
@ -2357,18 +2344,6 @@ export function RealtimeCanvasDialog({
>
<Plus className="h-4 w-4" />
</Button>
{standalone ? (
<Button
type="button"
size="icon"
variant="ghost"
className="h-8 w-8 rounded-full"
onClick={() => onOpenChange(false)}
title="返回画布"
>
<X className="h-4 w-4" />
</Button>
) : null}
</div>
<div className="flex h-10 shrink-0 items-center gap-0.5 rounded-full border border-black/10 bg-white px-1">
@ -2379,7 +2354,10 @@ export function RealtimeCanvasDialog({
"h-8 w-8 rounded-full text-zinc-600 hover:bg-zinc-100",
brushMode === "brush" && "bg-black text-white hover:bg-black"
)}
onClick={() => setBrushMode("brush")}
onClick={() => {
setSelectedLayerId(DRAW_LAYER_ID);
setBrushMode("brush");
}}
title="画笔"
>
<Paintbrush className="h-5 w-5" />
@ -2391,7 +2369,10 @@ export function RealtimeCanvasDialog({
"h-8 w-8 rounded-full text-zinc-600 hover:bg-zinc-100",
brushMode === "eraser" && "bg-black text-white hover:bg-black"
)}
onClick={() => setBrushMode("eraser")}
onClick={() => {
setSelectedLayerId(DRAW_LAYER_ID);
setBrushMode("eraser");
}}
title="橡皮"
>
<Eraser className="h-5 w-5" />
@ -2403,7 +2384,10 @@ export function RealtimeCanvasDialog({
"h-8 w-8 rounded-full text-zinc-600 hover:bg-zinc-100",
brushMode === "rect" && "bg-black text-white hover:bg-black"
)}
onClick={() => setBrushMode("rect")}
onClick={() => {
setSelectedLayerId(DRAW_LAYER_ID);
setBrushMode("rect");
}}
title="矩形"
>
<Square className="h-5 w-5" />
@ -2415,7 +2399,10 @@ export function RealtimeCanvasDialog({
"h-8 w-8 rounded-full text-zinc-600 hover:bg-zinc-100",
brushMode === "circle" && "bg-black text-white hover:bg-black"
)}
onClick={() => setBrushMode("circle")}
onClick={() => {
setSelectedLayerId(DRAW_LAYER_ID);
setBrushMode("circle");
}}
title="圆形"
>
<CircleIcon className="h-5 w-5" />
@ -2427,7 +2414,10 @@ export function RealtimeCanvasDialog({
"h-8 w-8 rounded-full text-zinc-600 hover:bg-zinc-100",
brushMode === "line" && "bg-black text-white hover:bg-black"
)}
onClick={() => setBrushMode("line")}
onClick={() => {
setSelectedLayerId(DRAW_LAYER_ID);
setBrushMode("line");
}}
title="直线"
>
<Slash className="h-5 w-5" />
@ -2471,21 +2461,6 @@ export function RealtimeCanvasDialog({
thumbClassName="h-5 w-5 border border-zinc-300 bg-white shadow-sm"
/>
</div>
<div className="flex h-8 items-center gap-1 rounded-full border border-black/10 bg-white px-2">
{CANVAS_BACKGROUND_PRESETS.map((color) => (
<button
key={color}
type="button"
className={cn(
"h-5 w-5 rounded-full border border-black/15 transition-all",
canvasBackground === color && "scale-110 ring-2 ring-black/20"
)}
style={{ backgroundColor: color }}
onClick={() => handleCanvasBackgroundChange(color)}
title="画布底色"
/>
))}
</div>
</div>
<div className="flex h-10 shrink-0 items-center gap-0.5 rounded-full border border-black/10 bg-white px-1">
@ -2498,15 +2473,6 @@ export function RealtimeCanvasDialog({
>
<Upload className="h-5 w-5" />
</Button>
<Button
size="icon"
variant="ghost"
className="h-8 w-8 rounded-full text-zinc-600 hover:bg-zinc-100"
onClick={clearSketch}
title="清空"
>
<Trash2 className="h-5 w-5" />
</Button>
<Button
size="icon"
variant="ghost"
@ -2536,17 +2502,23 @@ export function RealtimeCanvasDialog({
>
<Download className="h-5 w-5" />
</Button>
<Button
size="icon"
variant="ghost"
className="h-8 w-8 rounded-full text-zinc-600 hover:bg-zinc-100"
onClick={forceReconnect}
title="重连"
>
<RefreshCw className="h-5 w-5" />
</Button>
</div>
{standalone ? (
<div className="flex h-10 shrink-0 items-center rounded-full border border-black/10 bg-white px-1">
<Button
type="button"
size="icon"
variant="ghost"
className="h-8 w-8 rounded-full"
onClick={() => onOpenChange(false)}
title="关闭页面"
>
<X className="h-4 w-4" />
</Button>
</div>
) : null}
</div>
</div>
</div>
@ -2690,7 +2662,7 @@ export function RealtimeCanvasDialog({
/>
</div>
</div>
<div className="absolute left-3 top-28 bottom-4 z-10 flex w-[4.9rem] max-w-[20vw] flex-col rounded-[20px] border border-black/10 bg-white/96 p-2 shadow-xl">
<div className="absolute left-3 top-28 bottom-4 z-10 flex w-[4.4rem] max-w-[18vw] flex-col rounded-[18px] border border-black/10 bg-white/96 p-1.5 shadow-xl">
<div className="flex items-center justify-between border-b border-black/10 pb-2">
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-zinc-50 text-zinc-900">
<Layers3 className="h-4 w-4" />
@ -2699,22 +2671,7 @@ export function RealtimeCanvasDialog({
{imageLayers.length} 张
</span>
</div>
<div className="mt-2 flex-1 space-y-2 overflow-y-auto pr-0.5">
<button
type="button"
className={cn(
"flex w-full flex-col items-center gap-1 rounded-2xl border px-1.5 py-2 text-center transition",
selectedLayerId === DRAW_LAYER_ID
? "border-black/20 bg-zinc-900 text-white shadow-sm"
: "border-dashed border-black/10 bg-zinc-50 text-zinc-900 hover:bg-zinc-100"
)}
onClick={() => setSelectedLayerId(DRAW_LAYER_ID)}
>
<Paintbrush className={cn("h-4 w-4", selectedLayerId === DRAW_LAYER_ID ? "text-white" : "text-zinc-700")} />
<div className={cn("text-[10px] font-medium", selectedLayerId === DRAW_LAYER_ID ? "text-white" : "text-zinc-600")}>
画笔
</div>
</button>
<div className="mt-2 flex-1 space-y-1.5 overflow-y-auto pr-0.5">
{imageLayers.length === 0 ? (
<div className="rounded-2xl border border-dashed border-black/10 px-1 py-4 text-center text-[10px] leading-4 text-zinc-400">
暂无图层