Spaces:
Configuration error
Configuration error
| import { FolderIcon, PhotoIcon } from '@heroicons/react/24/outline' | |
| import { PlayIcon, ReloadIcon } from '@radix-ui/react-icons' | |
| import React, { useCallback, useState } from 'react' | |
| import { useRecoilState, useRecoilValue } from 'recoil' | |
| import * as PopoverPrimitive from '@radix-ui/react-popover' | |
| import { | |
| enableFileManagerState, | |
| fileState, | |
| isInpaintingState, | |
| isPix2PixState, | |
| isSDState, | |
| maskState, | |
| runManuallyState, | |
| showFileManagerState, | |
| } from '../../store/Atoms' | |
| import Button from '../shared/Button' | |
| import Shortcuts from '../Shortcuts/Shortcuts' | |
| import { ThemeChanger } from './ThemeChanger' | |
| import SettingIcon from '../Settings/SettingIcon' | |
| import PromptInput from './PromptInput' | |
| import CoffeeIcon from '../CoffeeIcon/CoffeeIcon' | |
| import emitter, { EVENT_CUSTOM_MASK, RERUN_LAST_MASK } from '../../event' | |
| import { useImage } from '../../utils' | |
| import useHotKey from '../../hooks/useHotkey' | |
| const Header = () => { | |
| const isInpainting = useRecoilValue(isInpaintingState) | |
| const [file, setFile] = useRecoilState(fileState) | |
| const [mask, setMask] = useRecoilState(maskState) | |
| const [maskImage, maskImageLoaded] = useImage(mask) | |
| const [uploadElemId] = useState(`file-upload-${Math.random().toString()}`) | |
| const [maskUploadElemId] = useState(`mask-upload-${Math.random().toString()}`) | |
| const isSD = useRecoilValue(isSDState) | |
| const isPix2Pix = useRecoilValue(isPix2PixState) | |
| const runManually = useRecoilValue(runManuallyState) | |
| const [openMaskPopover, setOpenMaskPopover] = useState(false) | |
| const [showFileManager, setShowFileManager] = | |
| useRecoilState(showFileManagerState) | |
| const enableFileManager = useRecoilValue(enableFileManagerState) | |
| useHotKey( | |
| 'f', | |
| () => { | |
| if (enableFileManager && !isInpainting) { | |
| setShowFileManager(!showFileManager) | |
| } | |
| }, | |
| {}, | |
| [showFileManager, enableFileManager, isInpainting] | |
| ) | |
| const handleRerunLastMask = useCallback(() => { | |
| emitter.emit(RERUN_LAST_MASK) | |
| }, []) | |
| useHotKey( | |
| 'r', | |
| () => { | |
| if (!isInpainting) { | |
| handleRerunLastMask() | |
| } | |
| }, | |
| {}, | |
| [isInpainting, handleRerunLastMask] | |
| ) | |
| const renderHeader = () => { | |
| return ( | |
| <header> | |
| <div | |
| style={{ | |
| display: 'flex', | |
| justifyContent: 'center', | |
| alignItems: 'center', | |
| gap: 4, | |
| }} | |
| > | |
| {enableFileManager ? ( | |
| <Button | |
| icon={<FolderIcon />} | |
| style={{ border: 0 }} | |
| toolTip="Open File Manager" | |
| disabled={isInpainting} | |
| onClick={() => { | |
| setShowFileManager(true) | |
| }} | |
| /> | |
| ) : ( | |
| <></> | |
| )} | |
| <label htmlFor={uploadElemId}> | |
| <Button | |
| icon={<PhotoIcon />} | |
| style={{ border: 0, gap: 0 }} | |
| disabled={isInpainting} | |
| toolTip="Upload image" | |
| > | |
| <input | |
| style={{ display: 'none' }} | |
| id={uploadElemId} | |
| name={uploadElemId} | |
| type="file" | |
| onChange={ev => { | |
| const newFile = ev.currentTarget.files?.[0] | |
| if (newFile) { | |
| setFile(newFile) | |
| } | |
| }} | |
| accept="image/png, image/jpeg" | |
| /> | |
| </Button> | |
| </label> | |
| <div | |
| style={{ | |
| visibility: file ? 'visible' : 'hidden', | |
| display: 'flex', | |
| justifyContent: 'center', | |
| alignItems: 'center', | |
| }} | |
| > | |
| <label htmlFor={maskUploadElemId}> | |
| <Button | |
| style={{ border: 0 }} | |
| disabled={isInpainting} | |
| toolTip="Upload custom mask" | |
| > | |
| <input | |
| style={{ display: 'none' }} | |
| id={maskUploadElemId} | |
| name={maskUploadElemId} | |
| type="file" | |
| onClick={e => { | |
| const element = e.target as HTMLInputElement | |
| element.value = '' | |
| }} | |
| onChange={ev => { | |
| const newFile = ev.currentTarget.files?.[0] | |
| if (newFile) { | |
| setMask(newFile) | |
| console.info('Send custom mask') | |
| if (!runManually) { | |
| emitter.emit(EVENT_CUSTOM_MASK, { mask: newFile }) | |
| } | |
| } | |
| }} | |
| accept="image/png, image/jpeg" | |
| /> | |
| Mask | |
| </Button> | |
| </label> | |
| {mask ? ( | |
| <PopoverPrimitive.Root open={openMaskPopover}> | |
| <PopoverPrimitive.Trigger | |
| className="btn-primary side-panel-trigger" | |
| onMouseEnter={() => setOpenMaskPopover(true)} | |
| onMouseLeave={() => setOpenMaskPopover(false)} | |
| style={{ | |
| visibility: mask ? 'visible' : 'hidden', | |
| outline: 'none', | |
| }} | |
| onClick={() => { | |
| if (mask) { | |
| emitter.emit(EVENT_CUSTOM_MASK, { mask }) | |
| } | |
| }} | |
| > | |
| <PlayIcon /> | |
| </PopoverPrimitive.Trigger> | |
| <PopoverPrimitive.Portal> | |
| <PopoverPrimitive.Content | |
| style={{ | |
| outline: 'none', | |
| }} | |
| > | |
| {maskImageLoaded ? ( | |
| <img | |
| src={maskImage.src} | |
| alt="mask" | |
| className="mask-preview" | |
| /> | |
| ) : ( | |
| <></> | |
| )} | |
| </PopoverPrimitive.Content> | |
| </PopoverPrimitive.Portal> | |
| </PopoverPrimitive.Root> | |
| ) : ( | |
| <></> | |
| )} | |
| <Button | |
| icon={<ReloadIcon style={{ height: 16, width: 16 }} />} | |
| style={{ border: 0, gap: 0 }} | |
| disabled={isInpainting} | |
| toolTip="Rerun last mask [r]" | |
| onClick={handleRerunLastMask} | |
| /> | |
| </div> | |
| </div> | |
| {(isSD || isPix2Pix) && file ? <PromptInput /> : <></>} | |
| <div className="header-icons-wrapper"> | |
| <CoffeeIcon /> | |
| <ThemeChanger /> | |
| <div className="header-icons"> | |
| <Shortcuts /> | |
| <SettingIcon /> | |
| </div> | |
| </div> | |
| </header> | |
| ) | |
| } | |
| return renderHeader() | |
| } | |
| export default Header | |