wip: add setting page

This commit is contained in:
Sanster 2022-04-14 20:43:07 +08:00
parent aa411c7524
commit 78d6b1cc3e
11 changed files with 155 additions and 15 deletions

View File

@ -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",

View File

@ -0,0 +1,7 @@
.hd-setting-block {
.inline-tip {
display: inline;
cursor: pointer;
color: var(--text-color);
}
}

View File

@ -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)}
/>

View File

@ -0,0 +1,4 @@
.model-desc-link {
color: var(--text-color-gray);
text-decoration: none;
}

View File

@ -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

View File

@ -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 />

View File

@ -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 {

View File

@ -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);
}
}
}

View File

@ -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>
)

View File

@ -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>

View File

@ -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,
},
})