sd-canvas-editor/src/index.js

225 lines
6.5 KiB
JavaScript

import React from 'react';
import ReactDOM from 'react-dom/client';
import {PolotnoContainer, SidePanelWrap, WorkspaceWrap} from 'polotno';
import {Toolbar} from 'polotno/toolbar/toolbar';
import {ZoomButtons} from 'polotno/toolbar/zoom-buttons';
import {SidePanel} from 'polotno/side-panel';
import {Workspace} from 'polotno/canvas/workspace';
import {getImageSize} from 'polotno/utils/image';
import {createStore} from 'polotno/model/store';
import {ImagesGrid} from 'polotno/side-panel/images-grid';
import {observer} from 'mobx-react-lite';
import {SectionTab} from 'polotno/side-panel';
import {
TemplatesSection,
TextSection,
PhotosSection,
ElementsSection,
UploadSection,
BackgroundSection,
LayersSection,
SizeSection,
} from 'polotno/side-panel';
import {DEFAULT_SECTIONS} from "polotno/side-panel/side-panel";
let _txt2imgInfoJSON;
let _img2imgInfoJSON;
export const setTxt2imgInfoJSON = (txt2imgInfoJSON) => {
_txt2imgInfoJSON = txt2imgInfoJSON;
}
export const setImg2imgInfoJSON = (img2imgInfoJSON) => {
_img2imgInfoJSON = img2imgInfoJSON;
}
let txt2ImgPageNum = 2;
let img2ImgPageNum = 2;
export const Txt2ImgPhotosPanel = observer(({store}) => {
const [images, setImages] = React.useState([]);
async function loadImages() {
setImages(_txt2imgInfoJSON);
await new Promise((resolve) => setTimeout(resolve, 3000));
}
React.useEffect(() => {
loadImages();
},
[]
);
return (
<div style={{height: '100%', display: 'flex', flexDirection: 'column'}}>
<p>txt2img Library</p>
<ImagesGrid
images={images}
getPreview={(image) => image.url}
onSelect={async (image, pos) => {
const {width, height} = await getImageSize(image.url);
store.activePage.addElement({
type: 'image',
src: image.url,
width,
height,
x: pos ? pos.x : store.width / 2 - width / 2,
y: pos ? pos.y : store.height / 2 - height / 2,
});
}}
rowsNumber={2}
isLoading={!images.length}
loadMore={async () => {
let pageInfo = '{"type": "txt2img", "num": pageNum, "size": 15}';
pageInfo = pageInfo.replace("pageNum", txt2ImgPageNum.toString());
const txt2ImgFilePaths = await _loadMoreFunc('getImgFilePaths', pageInfo)
const txt2ImgFilePathsJsonData = JSON.parse(txt2ImgFilePaths);
_txt2imgInfoJSON = _txt2imgInfoJSON.concat(txt2ImgFilePathsJsonData);
await loadImages();
txt2ImgPageNum = txt2ImgPageNum + 1;
}
}
/>
</div>
);
});
let _loadMoreFunc;
export const setLoadMoreFunc = (loadMoreFunc) => {
_loadMoreFunc = loadMoreFunc;
}
export const Img2TxtPhotosPanel = observer(({store}) => {
const [images, setImages] = React.useState([]);
async function loadImages() {
// here we should implement your own API requests
setImages(_img2imgInfoJSON);
await new Promise((resolve) => setTimeout(resolve, 3000));
}
React.useEffect(() => {
loadImages();
}, []);
return (
<div style={{height: '100%', display: 'flex', flexDirection: 'column'}}>
<p>img2img Library</p>
<ImagesGrid
images={images}
getPreview={(image) => image.url}
onSelect={async (image, pos) => {
const {width, height} = await getImageSize(image.url);
store.activePage.addElement({
type: 'image',
src: image.url,
width,
height,
x: pos ? pos.x : store.width / 2 - width / 2,
y: pos ? pos.y : store.height / 2 - height / 2,
});
}}
rowsNumber={2}
isLoading={!images.length}
loadMore={async () => {
let pageInfo = '{"type": "img2img", "num": pageNum, "size": 15}';
pageInfo = pageInfo.replace("pageNum", img2ImgPageNum.toString());
const img2ImgFilePaths = await _loadMoreFunc('getImgFilePaths', pageInfo)
const img2ImgFilePathsJsonData = JSON.parse(img2ImgFilePaths);
_img2imgInfoJSON = _img2imgInfoJSON.concat(img2ImgFilePathsJsonData);
await loadImages();
img2ImgPageNum = img2ImgPageNum + 1;
}
}
/>
</div>
);
});
const Txt2ImgPhotos = {
name: 'sd-txt2img',
Tab: (props) => (
<SectionTab name="Txt2img" {...props}>
</SectionTab>
),
Panel: Txt2ImgPhotosPanel,
};
const Img2ImgPhotos = {
name: 'sd-img2img',
Tab: (props) => (
<SectionTab name="Img2img" {...props}>
</SectionTab>
),
// we need observer to update component automatically on any store changes
Panel: Img2TxtPhotosPanel,
};
const sections = [
TemplatesSection,
TextSection,
PhotosSection,
ElementsSection,
UploadSection,
BackgroundSection,
LayersSection,
SizeSection,
Txt2ImgPhotos,
Img2ImgPhotos,
];
export const App = ({store}) => {
return (
<PolotnoContainer style={{width: '95vw', height: '90vh'}}>
<SidePanelWrap>
<SidePanel store={store} sections={sections}/>
</SidePanelWrap>
<WorkspaceWrap>
<Toolbar store={store}/>
<Workspace store={store}/>
<ZoomButtons store={store}/>
</WorkspaceWrap>
</PolotnoContainer>
);
};
let _store;
export const createPolotnoApp = ({key, container}) => {
const store = createStore({
key: key,
showCredit: true,
});
store.addPage();
const root = ReactDOM.createRoot(container);
root.render(<App store={store}/>);
_store = store;
};
export const getPolotnoStore = () => {
return _store;
};
window.createPolotnoApp = createPolotnoApp;
window.getPolotnoStore = getPolotnoStore;
window.setTxt2imgInfoJSON = setTxt2imgInfoJSON;
window.setImg2imgInfoJSON = setImg2imgInfoJSON;
window.setLoadMoreFunc = setLoadMoreFunc;