|
|
|
@ -43,14 +43,6 @@ function EmptyImageIcon() { |
|
|
|
} |
|
|
|
|
|
|
|
type ImageToolbarIconKind = |
|
|
|
| "crop" |
|
|
|
| "draw" |
|
|
|
| "multiAngle" |
|
|
|
| "enhance" |
|
|
|
| "lighting" |
|
|
|
| "repaint" |
|
|
|
| "grid" |
|
|
|
| "folder" |
|
|
|
| "download" |
|
|
|
| "focus" |
|
|
|
| "delete" |
|
|
|
@ -66,22 +58,6 @@ function ImageToolbarIcon({ kind }: { kind: ImageToolbarIconKind }) { |
|
|
|
}; |
|
|
|
|
|
|
|
switch (kind) { |
|
|
|
case "crop": |
|
|
|
return <svg {...commonProps}><path strokeLinecap="round" strokeLinejoin="round" d="M7 3v14h14M3 7h14v14M7 7h10v10" /></svg>; |
|
|
|
case "draw": |
|
|
|
return <svg {...commonProps}><path strokeLinecap="round" strokeLinejoin="round" d="m4 20 4.5-1 9.5-9.5-3.5-3.5L5 15.5 4 20zM13.5 7 17 3.5 20.5 7 17 10.5" /></svg>; |
|
|
|
case "multiAngle": |
|
|
|
return <svg {...commonProps}><path strokeLinecap="round" strokeLinejoin="round" d="M12 3 4 7v10l8 4 8-4V7l-8-4zM4 7l8 4 8-4M12 11v10" /></svg>; |
|
|
|
case "enhance": |
|
|
|
return <svg {...commonProps}><circle cx="12" cy="12" r="8" /><path strokeLinecap="round" d="M12 7v10M7 12h10M8.5 8.5l7 7M15.5 8.5l-7 7" /></svg>; |
|
|
|
case "lighting": |
|
|
|
return <svg {...commonProps}><path strokeLinecap="round" strokeLinejoin="round" d="M12 3v2M12 19v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M3 12h2M19 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4" /><circle cx="12" cy="12" r="4" /></svg>; |
|
|
|
case "repaint": |
|
|
|
return <svg {...commonProps}><path strokeLinecap="round" strokeLinejoin="round" d="M4 20h5l10-10a3.5 3.5 0 0 0-5-5L4 15v5zM13 6l5 5M8 16h4" /></svg>; |
|
|
|
case "grid": |
|
|
|
return <svg {...commonProps}><path d="M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z" /></svg>; |
|
|
|
case "folder": |
|
|
|
return <svg {...commonProps}><path strokeLinecap="round" strokeLinejoin="round" d="M3 7h6l2 2h10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7z" /></svg>; |
|
|
|
case "download": |
|
|
|
return <svg {...commonProps}><path strokeLinecap="round" strokeLinejoin="round" d="M12 4v11m0 0 4-4m-4 4-4-4M4 17v2h16v-2" /></svg>; |
|
|
|
case "focus": |
|
|
|
@ -93,23 +69,6 @@ function ImageToolbarIcon({ kind }: { kind: ImageToolbarIconKind }) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function ToolbarDivider() { |
|
|
|
return <span className="h-9 w-px bg-neutral-600/70" aria-hidden="true" />; |
|
|
|
} |
|
|
|
|
|
|
|
function StaticImageToolbarItem({ label, icon }: { label: string; icon: ImageToolbarIconKind }) { |
|
|
|
return ( |
|
|
|
<span |
|
|
|
aria-label={label} |
|
|
|
title={label} |
|
|
|
className="flex h-10 items-center gap-3 rounded-md px-2 text-neutral-300" |
|
|
|
> |
|
|
|
<ImageToolbarIcon kind={icon} /> |
|
|
|
<span className="whitespace-nowrap">{label}</span> |
|
|
|
</span> |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
export function ImageInputNode({ id, data, selected }: NodeProps<ImageInputNodeType>) { |
|
|
|
const { t } = useI18n(); |
|
|
|
const nodeData = data; |
|
|
|
@ -274,43 +233,23 @@ export function ImageInputNode({ id, data, selected }: NodeProps<ImageInputNodeT |
|
|
|
<ImageToolbarIcon kind="upload" /> |
|
|
|
<span>{t("imageInput.localUpload")}</span> |
|
|
|
</button> |
|
|
|
<button |
|
|
|
type="button" |
|
|
|
onClick={(e) => { |
|
|
|
e.preventDefault(); |
|
|
|
e.stopPropagation(); |
|
|
|
}} |
|
|
|
aria-label={t("imageInput.fromAssets")} |
|
|
|
title={t("imageInput.fromAssets")} |
|
|
|
className="flex h-14 items-center gap-3 whitespace-nowrap rounded-xl border border-neutral-600/70 bg-neutral-800 px-5 text-xl text-neutral-200 shadow-xl shadow-black/30 transition-colors hover:border-neutral-500 hover:bg-neutral-700 hover:text-neutral-100" |
|
|
|
> |
|
|
|
<ImageToolbarIcon kind="folder" /> |
|
|
|
<span>{t("imageInput.fromAssets")}</span> |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
)} |
|
|
|
|
|
|
|
{selected && hasImage && ( |
|
|
|
<div className="nodrag nopan absolute left-1/2 -top-[132px] z-[10002] flex -translate-x-1/2 items-center gap-4 rounded-xl border border-neutral-600/70 bg-neutral-800 px-5 py-3 text-xl text-neutral-300 shadow-2xl shadow-black/40"> |
|
|
|
<StaticImageToolbarItem label={t("imageInput.crop")} icon="crop" /> |
|
|
|
<StaticImageToolbarItem label={t("imageInput.draw")} icon="draw" /> |
|
|
|
<StaticImageToolbarItem label={t("imageInput.multiAngle")} icon="multiAngle" /> |
|
|
|
<StaticImageToolbarItem label={t("imageInput.enhance")} icon="enhance" /> |
|
|
|
<StaticImageToolbarItem label={t("imageInput.lighting")} icon="lighting" /> |
|
|
|
<StaticImageToolbarItem label={t("imageInput.repaint")} icon="repaint" /> |
|
|
|
<StaticImageToolbarItem label={t("imageInput.splitGrid")} icon="grid" /> |
|
|
|
<ToolbarDivider /> |
|
|
|
<div className="nodrag nopan absolute left-1/2 -top-[132px] z-[10002] flex -translate-x-1/2 items-center gap-2 rounded-xl border border-neutral-600/70 bg-neutral-800 px-4 py-3 text-xl text-neutral-300 shadow-2xl shadow-black/40"> |
|
|
|
<button |
|
|
|
type="button" |
|
|
|
onClick={(e) => { |
|
|
|
e.preventDefault(); |
|
|
|
e.stopPropagation(); |
|
|
|
handleOpenFileDialog(); |
|
|
|
}} |
|
|
|
aria-label={t("imageInput.fromAssets")} |
|
|
|
title={t("imageInput.fromAssets")} |
|
|
|
aria-label={t("imageInput.replace")} |
|
|
|
title={t("imageInput.replace")} |
|
|
|
className="flex h-10 items-center justify-center rounded-md px-2 text-neutral-300 transition-colors hover:bg-neutral-700 hover:text-neutral-100" |
|
|
|
> |
|
|
|
<ImageToolbarIcon kind="folder" /> |
|
|
|
<ImageToolbarIcon kind="upload" /> |
|
|
|
</button> |
|
|
|
<button |
|
|
|
type="button" |
|
|
|
|