Spaces:
Sleeping
Sleeping
"use client"; | |
import { | |
Accordion, | |
ActionIcon, | |
SegmentedControl, | |
Textarea, | |
} from "@mantine/core"; | |
import { useForm } from "@mantine/form"; | |
import { | |
IconArrowDownRight, | |
IconMinus, | |
IconPlus, | |
IconRotateClockwise, | |
} from "@tabler/icons-react"; | |
import React, { useEffect } from "react"; | |
import useDebounce from "../hooks/debounce"; | |
import FieldSet from "./FieldSet"; | |
import Label from "./Label"; | |
import SelectInput from "./SelectInput"; | |
import SlideInput from "./SliderInput"; | |
import TextInput from "./TextInput"; | |
export const Controls = React.memo(() => { | |
const form = useForm({ | |
initialValues: { | |
positivePrompt: "some kind of prompt", | |
negativePrompt: "bad hands", | |
steps: 1, | |
guidance: 0.1, | |
seed: 45678, | |
resolution: "720", | |
}, | |
}); | |
const debounce = useDebounce(); | |
const handleChange = (event) => { | |
console.log(event); | |
}; | |
useEffect(() => { | |
if (!form) return; | |
form.isDirty() && debounce(() => handleChange(form.values), 500); | |
}, [form, debounce]); | |
return ( | |
<div className="flex flex-col gap-4"> | |
<Accordion | |
defaultValue="prompt" | |
classNames={{ | |
chevron: "w-[20px] text-indigo-500", | |
label: "font-medium text-zinc-900", | |
control: "hover:bg-zinc-50", | |
item: "border-zinc-200", | |
}} | |
chevron={<IconArrowDownRight size={20} stroke={2} className="block" />} | |
> | |
<Accordion.Item value="prompt" key="prompt"> | |
<Accordion.Control value="prompt">Prompt</Accordion.Control> | |
<Accordion.Panel> | |
<FieldSet> | |
<div className="flex flex-col"> | |
<div className="flex flex-row items-center gap-2 mb-2"> | |
<IconPlus size={20} stroke={1} className="text-emerald-500" /> | |
<span className="font-mono uppercase text-xs tracking-wider text-emerald-600"> | |
Positive Prompt | |
</span> | |
</div> | |
<Textarea | |
autosize | |
className="rounded-md" | |
minRows={3} | |
defaultValue={form.getInputProps("positivePrompt").value} | |
onChange={(e) => | |
form.setFieldValue("positivePrompt", e.target.value) | |
} | |
classNames={{ | |
input: | |
"p-3 font-mono text-emerald-800 bg-emerald-600/[0.07] border-emerald-500/30 focus:border-emerald-500 focus:ring-1 focus:ring-inset focus:ring-emerald-500", | |
}} | |
/> | |
</div> | |
<div className="flex flex-col"> | |
<div className="flex flex-row items-center gap-2 mb-2"> | |
<IconMinus size={20} stroke={1} className="text-rose-500" /> | |
<span className="font-mono uppercase text-xs tracking-wider text-rose-600"> | |
Negative Prompt | |
</span> | |
</div> | |
<Textarea | |
autosize | |
className="rounded-md" | |
minRows={3} | |
defaultValue={form.getInputProps("negativePrompt").value} | |
onChange={(e) => | |
form.setFieldValue("negativePrompt", e.target.value) | |
} | |
classNames={{ | |
input: | |
"p-3 font-mono text-rose-800 bg-rose-600/[0.07] border-rose-500/30 focus:border-rose-500 focus:ring-1 focus:ring-inset focus:ring-rose-500", | |
}} | |
/> | |
</div> | |
</FieldSet> | |
</Accordion.Panel> | |
</Accordion.Item> | |
<Accordion.Item value="camera" key="camera"> | |
<Accordion.Control value="camera">Camera</Accordion.Control> | |
<Accordion.Panel> | |
<FieldSet> | |
<SelectInput label="Device" /> | |
<div> | |
<Label>Resolution</Label> | |
<SegmentedControl | |
fullWidth | |
size="sm" | |
radius="xl" | |
defaultValue={"720"} | |
data={[ | |
{ label: "480P", value: "480" }, | |
{ label: "720P", value: "720" }, | |
{ label: "1080P", value: "1080" }, | |
]} | |
onChange={(v) => form.setFieldValue("resolution", v)} | |
/> | |
</div> | |
</FieldSet> | |
</Accordion.Panel> | |
</Accordion.Item> | |
<Accordion.Item value="diffusion" key="diffusion"> | |
<Accordion.Control value="inference">Diffusion</Accordion.Control> | |
<Accordion.Panel> | |
<div className="flex flex-col gap-4"> | |
<TextInput | |
label="Seed" | |
type="number" | |
fieldProps={form.getInputProps("seed")} | |
> | |
<ActionIcon | |
radius="sm" | |
variant="subtle" | |
onClick={() => | |
form.setFieldValue( | |
"seed", | |
Math.floor(Math.random() * 100000001) | |
) | |
} | |
> | |
<IconRotateClockwise | |
style={{ width: "70%", height: "70%" }} | |
stroke={2} | |
/> | |
</ActionIcon> | |
</TextInput> | |
<SlideInput | |
label="Steps" | |
fieldProps={form.getInputProps("steps")} | |
step={1} | |
min={1} | |
max={15} | |
marks={[ | |
{ value: 1, label: "Low" }, | |
{ value: 15, label: "High" }, | |
]} | |
/> | |
<SlideInput | |
label="Guidance" | |
fieldProps={form.getInputProps("guidance")} | |
step={0.001} | |
min={0} | |
max={30} | |
marks={[ | |
{ value: 0, label: "None" }, | |
{ value: 2.5, label: "Low" }, | |
{ value: 7.5, label: "Normal" }, | |
{ value: 12.5, label: "Strict" }, | |
{ value: 17.5, label: "Very Strict" }, | |
{ value: 30, label: "Max" }, | |
]} | |
/> | |
</div> | |
</Accordion.Panel> | |
</Accordion.Item> | |
<Accordion.Item value="cn" key="cn"> | |
<Accordion.Control value="cn">Control Net</Accordion.Control> | |
<Accordion.Panel>Control net</Accordion.Panel> | |
</Accordion.Item> | |
</Accordion> | |
</div> | |
); | |
}); | |
Controls.displayName = "Controls"; | |
export default Controls; | |