refine realtime canvas controls
This commit is contained in:
parent
e3f6bf5457
commit
f0340d3d96
@ -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">
|
||||
暂无图层
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user