mirror of
https://github.com/YuzuZensai/Pien-Studio.git
synced 2026-09-02 14:18:35 +00:00
♻️ refactor!: massive refactor
This commit is contained in:
@@ -1,9 +1,17 @@
|
||||
import React from "react";
|
||||
import type { FaceBlurMethod, Layer, Project } from "@pien-studio/types";
|
||||
import type {
|
||||
FaceBlurMethod,
|
||||
Layer,
|
||||
LayerEffect,
|
||||
Project,
|
||||
} from "@pien-studio/types";
|
||||
import { FacePanel } from "./face-panel";
|
||||
import { HistoryPanel } from "./history-panel";
|
||||
import { LayersPanel } from "./layers-panel";
|
||||
import type { FaceDetectionOverlay, FacePreview } from "../../hooks/use-face-detection";
|
||||
import type {
|
||||
FaceDetectionOverlay,
|
||||
FacePreview,
|
||||
} from "../../hooks/use-face-detection";
|
||||
|
||||
type EditorSidebarProps = {
|
||||
isDark: boolean;
|
||||
@@ -37,7 +45,11 @@ type EditorSidebarProps = {
|
||||
selectedFaceIndices: number[];
|
||||
onSelectLayer: (layerId: string | null) => void;
|
||||
onSetLayerVisible: (layerId: string, visible: boolean) => void;
|
||||
onSetEffectEnabled: (layerId: string, kind: string, enabled: boolean) => void; // string intentional: UI doesn't need the narrowed union
|
||||
onSetEffectEnabled: (
|
||||
layerId: string,
|
||||
kind: LayerEffect["kind"],
|
||||
enabled: boolean,
|
||||
) => void;
|
||||
onMoveLayerOrder: (direction: "up" | "down") => void;
|
||||
onRemoveSelectedLayer: () => void;
|
||||
onUndo: () => void;
|
||||
@@ -99,7 +111,9 @@ export function EditorSidebar({
|
||||
onClearBlur,
|
||||
}: EditorSidebarProps) {
|
||||
return (
|
||||
<aside className={`border-l p-3 ${isDark ? "border-white/10 bg-[#24262a]" : "border-black/10 bg-[#eceff3]"}`}>
|
||||
<aside
|
||||
className={`border-l p-3 ${isDark ? "border-white/10 bg-[#24262a]" : "border-black/10 bg-[#eceff3]"}`}
|
||||
>
|
||||
<div className="space-y-3">
|
||||
<LayersPanel
|
||||
layers={layers}
|
||||
@@ -114,24 +128,44 @@ export function EditorSidebar({
|
||||
/>
|
||||
|
||||
{tool === "fill" && onSetFillColor && onSetFillTolerance ? (
|
||||
<div className={`rounded-lg border p-3 ${isDark ? "border-white/10 bg-[#2d3036]" : "border-black/10 bg-white"}`}>
|
||||
<p className={`mb-2 text-xs font-semibold uppercase tracking-wider ${isDark ? "text-[#8b9ab1]" : "text-[#6b7280]"}`}>
|
||||
<div
|
||||
className={`rounded-lg border p-3 ${isDark ? "border-white/10 bg-[#2d3036]" : "border-black/10 bg-white"}`}
|
||||
>
|
||||
<p
|
||||
className={`mb-2 text-xs font-semibold uppercase tracking-wider ${isDark ? "text-[#8b9ab1]" : "text-[#6b7280]"}`}
|
||||
>
|
||||
Fill
|
||||
</p>
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<label className={`text-xs ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}>Color</label>
|
||||
<label
|
||||
className={`text-xs ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}
|
||||
>
|
||||
Color
|
||||
</label>
|
||||
<input
|
||||
type="color"
|
||||
value={fillColor ?? "#ff0000"}
|
||||
onChange={(e) => onSetFillColor(e.target.value)}
|
||||
className="h-7 w-10 cursor-pointer rounded border border-black/10 p-0.5"
|
||||
/>
|
||||
<span className={`text-xs font-mono ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}>{fillColor ?? "#ff0000"}</span>
|
||||
<span
|
||||
className={`text-xs font-mono ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}
|
||||
>
|
||||
{fillColor ?? "#ff0000"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className={`text-xs ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}>Tolerance</label>
|
||||
<span className={`text-xs font-mono ${isDark ? "text-[#8b9ab1]" : "text-[#6b7280]"}`}>{fillTolerance ?? 32}</span>
|
||||
<label
|
||||
className={`text-xs ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}
|
||||
>
|
||||
Tolerance
|
||||
</label>
|
||||
<span
|
||||
className={`text-xs font-mono ${isDark ? "text-[#8b9ab1]" : "text-[#6b7280]"}`}
|
||||
>
|
||||
{fillTolerance ?? 32}
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
@@ -154,42 +188,107 @@ export function EditorSidebar({
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{tool === "brush" && onSetBrushColor && onSetBrushSize && onSetBrushOpacity && onSetBrushHardness ? (
|
||||
<div className={`rounded-lg border p-3 ${isDark ? "border-white/10 bg-[#2d3036]" : "border-black/10 bg-white"}`}>
|
||||
<p className={`mb-2 text-xs font-semibold uppercase tracking-wider ${isDark ? "text-[#8b9ab1]" : "text-[#6b7280]"}`}>
|
||||
{tool === "brush" &&
|
||||
onSetBrushColor &&
|
||||
onSetBrushSize &&
|
||||
onSetBrushOpacity &&
|
||||
onSetBrushHardness ? (
|
||||
<div
|
||||
className={`rounded-lg border p-3 ${isDark ? "border-white/10 bg-[#2d3036]" : "border-black/10 bg-white"}`}
|
||||
>
|
||||
<p
|
||||
className={`mb-2 text-xs font-semibold uppercase tracking-wider ${isDark ? "text-[#8b9ab1]" : "text-[#6b7280]"}`}
|
||||
>
|
||||
Brush
|
||||
</p>
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<label className={`text-xs ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}>Color</label>
|
||||
<label
|
||||
className={`text-xs ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}
|
||||
>
|
||||
Color
|
||||
</label>
|
||||
<input
|
||||
type="color"
|
||||
value={brushColor ?? "#000000"}
|
||||
onChange={(e) => onSetBrushColor(e.target.value)}
|
||||
className="h-7 w-10 cursor-pointer rounded border border-black/10 p-0.5"
|
||||
/>
|
||||
<span className={`text-xs font-mono ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}>{brushColor ?? "#000000"}</span>
|
||||
<span
|
||||
className={`text-xs font-mono ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}
|
||||
>
|
||||
{brushColor ?? "#000000"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className={`text-xs ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}>Size</label>
|
||||
<span className={`text-xs font-mono ${isDark ? "text-[#8b9ab1]" : "text-[#6b7280]"}`}>{brushSize ?? 20}px</span>
|
||||
<label
|
||||
className={`text-xs ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}
|
||||
>
|
||||
Size
|
||||
</label>
|
||||
<span
|
||||
className={`text-xs font-mono ${isDark ? "text-[#8b9ab1]" : "text-[#6b7280]"}`}
|
||||
>
|
||||
{brushSize ?? 20}px
|
||||
</span>
|
||||
</div>
|
||||
<input type="range" min={1} max={200} value={brushSize ?? 20} onChange={(e) => onSetBrushSize(Number(e.target.value))} className="w-full accent-[var(--color-accent-strong)]" />
|
||||
<input
|
||||
type="range"
|
||||
min={1}
|
||||
max={200}
|
||||
value={brushSize ?? 20}
|
||||
onChange={(e) => onSetBrushSize(Number(e.target.value))}
|
||||
className="w-full accent-[var(--color-accent-strong)]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className={`text-xs ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}>Opacity</label>
|
||||
<span className={`text-xs font-mono ${isDark ? "text-[#8b9ab1]" : "text-[#6b7280]"}`}>{Math.round((brushOpacity ?? 1) * 100)}%</span>
|
||||
<label
|
||||
className={`text-xs ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}
|
||||
>
|
||||
Opacity
|
||||
</label>
|
||||
<span
|
||||
className={`text-xs font-mono ${isDark ? "text-[#8b9ab1]" : "text-[#6b7280]"}`}
|
||||
>
|
||||
{Math.round((brushOpacity ?? 1) * 100)}%
|
||||
</span>
|
||||
</div>
|
||||
<input type="range" min={0} max={100} value={Math.round((brushOpacity ?? 1) * 100)} onChange={(e) => onSetBrushOpacity(Number(e.target.value) / 100)} className="w-full accent-[var(--color-accent-strong)]" />
|
||||
<input
|
||||
type="range"
|
||||
min={0}
|
||||
max={100}
|
||||
value={Math.round((brushOpacity ?? 1) * 100)}
|
||||
onChange={(e) =>
|
||||
onSetBrushOpacity(Number(e.target.value) / 100)
|
||||
}
|
||||
className="w-full accent-[var(--color-accent-strong)]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className={`text-xs ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}>Hardness</label>
|
||||
<span className={`text-xs font-mono ${isDark ? "text-[#8b9ab1]" : "text-[#6b7280]"}`}>{Math.round((brushHardness ?? 0.8) * 100)}%</span>
|
||||
<label
|
||||
className={`text-xs ${isDark ? "text-[#d7dae0]" : "text-[#1f2430]"}`}
|
||||
>
|
||||
Hardness
|
||||
</label>
|
||||
<span
|
||||
className={`text-xs font-mono ${isDark ? "text-[#8b9ab1]" : "text-[#6b7280]"}`}
|
||||
>
|
||||
{Math.round((brushHardness ?? 0.8) * 100)}%
|
||||
</span>
|
||||
</div>
|
||||
<input type="range" min={0} max={100} value={Math.round((brushHardness ?? 0.8) * 100)} onChange={(e) => onSetBrushHardness(Number(e.target.value) / 100)} className="w-full accent-[var(--color-accent-strong)]" />
|
||||
<input
|
||||
type="range"
|
||||
min={0}
|
||||
max={100}
|
||||
value={Math.round((brushHardness ?? 0.8) * 100)}
|
||||
onChange={(e) =>
|
||||
onSetBrushHardness(Number(e.target.value) / 100)
|
||||
}
|
||||
className="w-full accent-[var(--color-accent-strong)]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -206,7 +305,10 @@ export function EditorSidebar({
|
||||
blurAmount={blurAmount}
|
||||
censorColor={censorColor}
|
||||
selectedFaceIndices={selectedFaceIndices}
|
||||
hasActiveBlur={Boolean(selectedLayer && selectedLayer.effects.some((e) => e.kind === "face-blur"))}
|
||||
hasActiveBlur={Boolean(
|
||||
selectedLayer &&
|
||||
selectedLayer.effects.some((e) => e.kind === "face-blur"),
|
||||
)}
|
||||
onSetBlurMethod={onSetBlurMethod}
|
||||
onSetBlurAmount={onSetBlurAmount}
|
||||
onSetCensorColor={onSetCensorColor}
|
||||
|
||||
Reference in New Issue
Block a user