plugins add dropdown menu; realesrgan support 2x 4x

This commit is contained in:
Qing
2023-03-25 13:39:56 +08:00
parent a5997e9332
commit 003a104406
9 changed files with 877 additions and 149 deletions

View File

@@ -153,12 +153,16 @@ export function modelDownloaded(name: string) {
export async function runPlugin(
name: string,
imageFile: File,
upscale?: number,
maskFile?: File | null,
clicks?: number[][]
) {
const fd = new FormData()
fd.append('name', name)
fd.append('image', imageFile)
if (upscale) {
fd.append('upscale', upscale.toString())
}
if (clicks) {
fd.append('clicks', JSON.stringify(clicks))
}

View File

@@ -562,7 +562,7 @@ export default function Editor() {
})
const runRenderablePlugin = useCallback(
async (name: string) => {
async (name: string, data?: any) => {
if (isProcessing) {
return
}
@@ -570,7 +570,7 @@ export default function Editor() {
// TODO 要不要加 undoCurrentLine
setIsPluginRunning(true)
const targetFile = await getCurrentRender()
const res = await runPlugin(name, targetFile)
const res = await runPlugin(name, targetFile, data?.upscale)
if (!res) {
throw new Error('Something went wrong on server side.')
}
@@ -603,8 +603,8 @@ export default function Editor() {
}, [runRenderablePlugin])
useEffect(() => {
emitter.on(PluginName.RealESRGAN, () => {
runRenderablePlugin(PluginName.RealESRGAN)
emitter.on(PluginName.RealESRGAN, (data: any) => {
runRenderablePlugin(PluginName.RealESRGAN, data)
})
return () => {
emitter.off(PluginName.RealESRGAN)
@@ -845,8 +845,9 @@ export default function Editor() {
try {
const res = await runPlugin(
PluginName.InteractiveSeg.toString(),
PluginName.InteractiveSeg,
targetFile,
undefined,
prevMask,
newClicks
)
@@ -938,7 +939,7 @@ export default function Editor() {
}
const onMouseDown = (ev: SyntheticEvent) => {
if (isInteractiveSeg) {
if (isProcessing) {
return
}
if (isChangingBrushSizeByMouse) {
@@ -954,9 +955,6 @@ export default function Editor() {
if (!canvas) {
return
}
if (isInpainting) {
return
}
if (isRightClick(ev)) {
return

View File

@@ -3,90 +3,131 @@
.plugins {
position: absolute;
top: 68px;
left: 1rem;
padding: 0.1rem 0.3rem;
left: 24px;
z-index: 4;
border-radius: 0.8rem;
border-style: solid;
border-color: var(--border-color);
border-width: 1px;
border: 1px solid var(--border-color);
border-radius: 8px;
}
.plugins-trigger {
font-family: 'WorkSans', sans-serif;
font-size: 16px;
border: 0px;
}
.plugins-content {
outline: none;
position: relative;
font-family: 'WorkSans', sans-serif;
font-size: 14px;
top: 8px;
left: 1rem;
padding: 0.8rem 0.5rem;
z-index: 9;
// backdrop-filter: blur(12px);
color: var(--text-color);
.DropdownMenuContent,
.DropdownMenuSubContent {
border: 1px solid var(--border-color);
min-width: 80px;
background-color: var(--page-bg);
border-radius: 6px;
padding: 5px;
box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2);
animation-duration: 400ms;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
will-change: transform, opacity;
}
.DropdownMenuContent[data-side='top'],
.DropdownMenuSubContent[data-side='top'] {
animation-name: slideDownAndFade;
}
.DropdownMenuContent[data-side='right'],
.DropdownMenuSubContent[data-side='right'] {
animation-name: slideLeftAndFade;
}
.DropdownMenuContent[data-side='bottom'],
.DropdownMenuSubContent[data-side='bottom'] {
animation-name: slideUpAndFade;
}
.DropdownMenuContent[data-side='left'],
.DropdownMenuSubContent[data-side='left'] {
animation-name: slideRightAndFade;
}
border-radius: 0.8rem;
border-style: solid;
border-color: var(--border-color);
border-width: 1px;
.DropdownMenuItem,
.DropdownMenuCheckboxItem,
.DropdownMenuRadioItem,
.DropdownMenuSubTrigger {
font-size: 13px;
line-height: 1;
color: var(--btn-text-color);
border-radius: 3px;
display: flex;
flex-direction: column;
gap: 12px;
.setting-block-content {
gap: 1rem;
}
// input {
// height: 24px;
// // border-radius: 4px;
// }
// button {
// height: 28px;
// // border-radius: 4px;
// }
align-items: center;
height: 25px;
padding: 0 5px;
position: relative;
user-select: none;
outline: none;
gap: 8px;
}
.DropdownMenuSubTrigger[data-state='open'] {
background-color: var(--page-bg);
color: var(--btn-text-color);
}
.DropdownMenuItem[data-disabled],
.DropdownMenuCheckboxItem[data-disabled],
.DropdownMenuRadioItem[data-disabled],
.DropdownMenuSubTrigger[data-disabled] {
color: var(--text-color-disabled);
pointer-events: none;
}
.DropdownMenuItem[data-highlighted],
.DropdownMenuCheckboxItem[data-highlighted],
.DropdownMenuRadioItem[data-highlighted],
.DropdownMenuSubTrigger[data-highlighted] {
background-color: var(--yellow-accent);
color: var(--btn-text-hover-color);
}
.negative-prompt {
all: unset;
border-width: 0;
border-radius: 0.5rem;
min-height: 150px;
max-width: 200px;
width: 100%;
padding: 12px 0.8rem;
outline: 1px solid var(--border-color);
&:focus-visible {
border-width: 0;
outline: 1px solid var(--yellow-accent);
}
&:-webkit-input-placeholder {
padding-top: 10px;
}
&:-moz-input-placeholder {
padding-top: 10px;
}
&:-ms-input-placeholder {
padding-top: 10px;
}
.RightSlot {
margin-left: auto;
padding-left: 10px;
color: var(--btn-text-color);
display: flex;
align-items: center;
}
.resize-title-tile {
width: 86px;
font-size: 0.5rem;
[data-highlighted] > .RightSlot {
color: var(--btn-text-hover-color);
}
[data-disabled] .RightSlot {
color: var(--text-color-gray);
}
@keyframes slideUpAndFade {
from {
opacity: 0;
transform: translateY(2px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideRightAndFade {
from {
opacity: 0;
transform: translateX(-2px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideDownAndFade {
from {
opacity: 0;
transform: translateY(-2px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideLeftAndFade {
from {
opacity: 0;
transform: translateX(2px);
}
to {
opacity: 1;
transform: translateX(0);
}
}

View File

@@ -1,13 +1,16 @@
import React, { FormEvent } from 'react'
import { useRecoilValue } from 'recoil'
import { CursorArrowRaysIcon, GifIcon } from '@heroicons/react/24/outline'
import { BoxModelIcon, MarginIcon, HobbyKnifeIcon } from '@radix-ui/react-icons'
import {
BoxModelIcon,
ChevronRightIcon,
HobbyKnifeIcon,
MixIcon,
} from '@radix-ui/react-icons'
import { useToggle } from 'react-use'
import * as PopoverPrimitive from '@radix-ui/react-popover'
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import {
fileState,
isInpaintingState,
isPluginRunningState,
isProcessingState,
serverConfigState,
} from '../../store/Atoms'
@@ -41,50 +44,97 @@ const pluginMap = {
}
const Plugins = () => {
const [open, toggleOpen] = useToggle(true)
// const [open, toggleOpen] = useToggle(true)
const serverConfig = useRecoilValue(serverConfigState)
const file = useRecoilValue(fileState)
const isProcessing = useRecoilValue(isProcessingState)
const disabled = !file || isProcessing
const onPluginClick = (pluginName: string) => {
if (isProcessing) {
return
if (!disabled) {
emitter.emit(pluginName)
}
emitter.emit(pluginName)
}
const onRealESRGANClick = (upscale: number) => {
if (!disabled) {
emitter.emit(PluginName.RealESRGAN, { upscale })
}
}
const renderRealESRGANPlugin = () => {
return (
<DropdownMenu.Sub>
<DropdownMenu.SubTrigger
className="DropdownMenuSubTrigger"
disabled={disabled}
>
<BoxModelIcon />
RealESRGAN
<div className="RightSlot">
<ChevronRightIcon />
</div>
</DropdownMenu.SubTrigger>
<DropdownMenu.Portal>
<DropdownMenu.SubContent className="DropdownMenuSubContent">
<DropdownMenu.Item
className="DropdownMenuItem"
onClick={() => onRealESRGANClick(2)}
>
upscale 2x
</DropdownMenu.Item>
<DropdownMenu.Item
className="DropdownMenuItem"
onClick={() => onRealESRGANClick(4)}
disabled={disabled}
>
upscale 4x
</DropdownMenu.Item>
</DropdownMenu.SubContent>
</DropdownMenu.Portal>
</DropdownMenu.Sub>
)
}
const renderPlugins = () => {
return serverConfig.plugins.map((plugin: string) => {
const { IconClass } = pluginMap[plugin as PluginName]
if (plugin === PluginName.RealESRGAN) {
return renderRealESRGANPlugin()
}
return (
<Button
style={{ gap: 6 }}
icon={<IconClass style={{ width: 15 }} />}
<DropdownMenu.Item
className="DropdownMenuItem"
onClick={() => onPluginClick(plugin)}
disabled={!file || isProcessing}
disabled={disabled}
>
{pluginMap[plugin as PluginName].showName}
</Button>
<IconClass style={{ width: 15 }} />
{plugin}
</DropdownMenu.Item>
)
})
}
if (serverConfig.plugins.length === 0) {
return null
}
return (
<div className="plugins">
<PopoverPrimitive.Root open={open}>
<PopoverPrimitive.Trigger
className="btn-primary plugins-trigger"
onClick={() => toggleOpen()}
<DropdownMenu.Root>
<DropdownMenu.Trigger className="plugins">
<Button icon={<MixIcon />} />
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
className="DropdownMenuContent"
side="bottom"
align="start"
sideOffset={5}
>
Plugins
</PopoverPrimitive.Trigger>
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content className="plugins-content">
{renderPlugins()}
</PopoverPrimitive.Content>
</PopoverPrimitive.Portal>
</PopoverPrimitive.Root>
</div>
{renderPlugins()}
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
)
}

View File

@@ -32,6 +32,7 @@
// Text
--text-color: #040404;
--text-color-gray: rgb(107, 111, 118);
--text-color-disabled: rgb(107, 111, 118);
// Shared
--btn-text-color: var(--text-color);

View File

@@ -30,6 +30,7 @@
// Text
--text-color: white;
--text-color-gray: rgb(195, 196, 198);
--text-color-disabled: rgb(107, 111, 118);
// Shared
--btn-text-color: var(--text-color);