wip: add setting page
This commit is contained in:
parent
aa411c7524
commit
78d6b1cc3e
@ -17,6 +17,7 @@
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"rules": {
|
||||
"jsx-a11y/click-events-have-key-events": 0,
|
||||
"react/jsx-props-no-spreading": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"react/jsx-no-bind": "off",
|
||||
|
@ -0,0 +1,7 @@
|
||||
.hd-setting-block {
|
||||
.inline-tip {
|
||||
display: inline;
|
||||
cursor: pointer;
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ function PixelSizeInputSetting(props: PixelSizeInputProps) {
|
||||
|
||||
return (
|
||||
<SettingBlock
|
||||
className="sub-setting-block"
|
||||
title={title}
|
||||
input={
|
||||
<div
|
||||
@ -54,14 +55,23 @@ function HDSettingBlock() {
|
||||
}
|
||||
|
||||
const onResizeLimitChange = (value: string) => {
|
||||
const val = value.length === 0 ? 0 : parseInt(value, 10)
|
||||
setSettingState(old => {
|
||||
return { ...old, hdStrategyResizeLimit: value }
|
||||
return { ...old, hdStrategyResizeLimit: val }
|
||||
})
|
||||
}
|
||||
|
||||
const onCropTriggerSizeChange = (value: string) => {
|
||||
const val = value.length === 0 ? 0 : parseInt(value, 10)
|
||||
setSettingState(old => {
|
||||
return { ...old, hdStrategyCropTrigerSize: value }
|
||||
return { ...old, hdStrategyCropTrigerSize: val }
|
||||
})
|
||||
}
|
||||
|
||||
const onCropMarginChange = (value: string) => {
|
||||
const val = value.length === 0 ? 0 : parseInt(value, 10)
|
||||
setSettingState(old => {
|
||||
return { ...old, hdStrategyCropMargin: val }
|
||||
})
|
||||
}
|
||||
|
||||
@ -69,7 +79,16 @@ function HDSettingBlock() {
|
||||
return (
|
||||
<div>
|
||||
Use the original resolution of the picture, suitable for picture size
|
||||
below 2K, of course you can try it on higher resolution pictures
|
||||
below 2K. Try{' '}
|
||||
<div
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
className="inline-tip"
|
||||
onClick={() => onStrategyChange(HDStrategy.REISIZE)}
|
||||
>
|
||||
Resize Strategy
|
||||
</div>{' '}
|
||||
if you do not get good results on high resolution images.
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -79,7 +98,7 @@ function HDSettingBlock() {
|
||||
<div>
|
||||
<div>
|
||||
Resize the longer side of the image to a specific size(keep ratio),
|
||||
then do inpainting on the entire resized image.
|
||||
then do inpainting on the resized image.
|
||||
</div>
|
||||
<PixelSizeInputSetting
|
||||
title="Size limit"
|
||||
@ -103,6 +122,11 @@ function HDSettingBlock() {
|
||||
value={`${setting.hdStrategyCropTrigerSize}`}
|
||||
onValue={onCropTriggerSizeChange}
|
||||
/>
|
||||
<PixelSizeInputSetting
|
||||
title="Crop margin"
|
||||
value={`${setting.hdStrategyCropMargin}`}
|
||||
onValue={onCropMarginChange}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -122,9 +146,11 @@ function HDSettingBlock() {
|
||||
|
||||
return (
|
||||
<SettingBlock
|
||||
className="hd-setting-block"
|
||||
title="High Resolution Strategy"
|
||||
input={
|
||||
<Selector
|
||||
value={setting.hdStrategy as string}
|
||||
options={Object.values(HDStrategy)}
|
||||
onChange={val => onStrategyChange(val as HDStrategy)}
|
||||
/>
|
||||
|
@ -0,0 +1,4 @@
|
||||
.model-desc-link {
|
||||
color: var(--text-color-gray);
|
||||
text-decoration: none;
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
import React, { ReactNode } from 'react'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { settingState } from '../../store/Atoms'
|
||||
import Selector from '../shared/Selector'
|
||||
import SettingBlock from './SettingBlock'
|
||||
|
||||
export enum AIModel {
|
||||
LAMA = 'LaMa',
|
||||
LDM = 'LDM',
|
||||
}
|
||||
|
||||
function ModelSettingBlock() {
|
||||
const [setting, setSettingState] = useRecoilState(settingState)
|
||||
|
||||
const onModelChange = (value: AIModel) => {
|
||||
setSettingState(old => {
|
||||
return { ...old, model: value }
|
||||
})
|
||||
}
|
||||
|
||||
const renderModelDesc = (
|
||||
name: string,
|
||||
paperUrl: string,
|
||||
githubUrl: string
|
||||
) => {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<a
|
||||
className="model-desc-link"
|
||||
href={paperUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
{name}
|
||||
</a>
|
||||
|
||||
<br />
|
||||
|
||||
<a
|
||||
className="model-desc-link"
|
||||
href={githubUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
style={{ marginTop: '8px' }}
|
||||
>
|
||||
{githubUrl}
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const renderOptionDesc = (): ReactNode => {
|
||||
switch (setting.model) {
|
||||
case AIModel.LAMA:
|
||||
return renderModelDesc(
|
||||
'Resolution-robust Large Mask Inpainting with Fourier Convolutions',
|
||||
'https://arxiv.org/abs/2109.07161',
|
||||
'https://github.com/saic-mdal/lama'
|
||||
)
|
||||
case AIModel.LDM:
|
||||
return renderModelDesc(
|
||||
'High-Resolution Image Synthesis with Latent Diffusion Models',
|
||||
'https://arxiv.org/abs/2112.10752',
|
||||
'https://github.com/CompVis/latent-diffusion'
|
||||
)
|
||||
default:
|
||||
return <></>
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingBlock
|
||||
className="model-setting-block"
|
||||
title="Inpainting Model"
|
||||
input={
|
||||
<Selector
|
||||
value={setting.model as string}
|
||||
options={Object.values(AIModel)}
|
||||
onChange={val => onModelChange(val as AIModel)}
|
||||
/>
|
||||
}
|
||||
optionDesc={renderOptionDesc()}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default ModelSettingBlock
|
@ -6,7 +6,7 @@ import SettingBlock from './SettingBlock'
|
||||
function SavePathSettingBlock() {
|
||||
return (
|
||||
<SettingBlock
|
||||
title="Download image at same folder of origin image"
|
||||
title="Download image beside origin image"
|
||||
input={
|
||||
<Switch defaultChecked>
|
||||
<SwitchThumb />
|
||||
|
@ -1,12 +1,14 @@
|
||||
@use '../../styles/Mixins/' as *;
|
||||
@import './SettingBlock.scss';
|
||||
@import './HDSettingBlock.scss';
|
||||
@import './ModelSettingBlock.scss';
|
||||
|
||||
.modal-setting {
|
||||
grid-area: main-content;
|
||||
background-color: var(--modal-bg);
|
||||
color: var(--modal-text-color);
|
||||
box-shadow: 0px 0px 20px rgb(0, 0, 40, 0.2);
|
||||
min-height: 450px;
|
||||
min-height: 600px;
|
||||
width: 700px;
|
||||
|
||||
@include mobile {
|
||||
|
@ -1,13 +1,18 @@
|
||||
.setting-block {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 12px;
|
||||
|
||||
.option-desc {
|
||||
color: var(--text-color-gray);
|
||||
margin-top: 12px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.3rem;
|
||||
padding: 2rem;
|
||||
|
||||
.sub-setting-block {
|
||||
margin-top: 8px;
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { useRecoilState } from 'recoil'
|
||||
import { settingState } from '../../store/Atoms'
|
||||
import Modal from '../shared/Modal'
|
||||
import HDSettingBlock from './HDSettingBlock'
|
||||
import ModelSettingBlock from './ModelSettingBlock'
|
||||
import SavePathSettingBlock from './SavePathSettingBlock'
|
||||
|
||||
export default function SettingModal() {
|
||||
@ -23,6 +24,7 @@ export default function SettingModal() {
|
||||
show={setting.show}
|
||||
>
|
||||
<SavePathSettingBlock />
|
||||
<ModelSettingBlock />
|
||||
<HDSettingBlock />
|
||||
</Modal>
|
||||
)
|
||||
|
@ -7,6 +7,7 @@ type SelectorChevronDirection = 'up' | 'down'
|
||||
type SelectorProps = {
|
||||
minWidth?: number
|
||||
chevronDirection?: SelectorChevronDirection
|
||||
value: string
|
||||
options: string[]
|
||||
onChange: (value: string) => void
|
||||
}
|
||||
@ -17,9 +18,8 @@ const selectorDefaultProps = {
|
||||
}
|
||||
|
||||
function Selector(props: SelectorProps) {
|
||||
const { minWidth, chevronDirection, options, onChange } = props
|
||||
const { minWidth, chevronDirection, value, options, onChange } = props
|
||||
const [showOptions, setShowOptions] = useState<boolean>(false)
|
||||
const [index, setIndex] = useState<number>(0)
|
||||
const selectorRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
const showOptionsHandler = () => {
|
||||
@ -46,7 +46,6 @@ function Selector(props: SelectorProps) {
|
||||
const currentRes = e.target.textContent.split('x')
|
||||
onChange(currentRes[0])
|
||||
setShowOptions(false)
|
||||
setIndex(newIndex)
|
||||
}
|
||||
|
||||
return (
|
||||
@ -57,7 +56,7 @@ function Selector(props: SelectorProps) {
|
||||
onClick={showOptionsHandler}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<p>{options[index]}</p>
|
||||
<p>{value}</p>
|
||||
<div className="selector-icon">
|
||||
{chevronDirection === 'up' ? <ChevronUpIcon /> : <ChevronDownIcon />}
|
||||
</div>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { atom } from 'recoil'
|
||||
import { HDStrategy } from '../components/Setting/HDSettingBlock'
|
||||
import { AIModel } from '../components/Setting/ModelSettingBlock'
|
||||
|
||||
export const fileState = atom<File | undefined>({
|
||||
key: 'fileState',
|
||||
@ -13,17 +14,23 @@ export const shortcutsState = atom<boolean>({
|
||||
|
||||
export interface Setting {
|
||||
show: boolean
|
||||
saveImageBesideOrigin: boolean
|
||||
model: AIModel
|
||||
hdStrategy: HDStrategy
|
||||
hdStrategyResizeLimit: string
|
||||
hdStrategyCropTrigerSize: string
|
||||
hdStrategyResizeLimit: number
|
||||
hdStrategyCropTrigerSize: number
|
||||
hdStrategyCropMargin: number
|
||||
}
|
||||
|
||||
export const settingState = atom<Setting>({
|
||||
key: 'settingsState',
|
||||
default: {
|
||||
show: false,
|
||||
saveImageBesideOrigin: false,
|
||||
model: AIModel.LAMA,
|
||||
hdStrategy: HDStrategy.ORIGINAL,
|
||||
hdStrategyResizeLimit: '2048',
|
||||
hdStrategyCropTrigerSize: '2048',
|
||||
hdStrategyResizeLimit: 2048,
|
||||
hdStrategyCropTrigerSize: 2048,
|
||||
hdStrategyCropMargin: 128,
|
||||
},
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user