diff options
Diffstat (limited to 'src/client/views/nodes')
| -rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/scrapbook/ScrapbookBox.tsx | 136 |
2 files changed, 114 insertions, 23 deletions
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 9d459d7eb..0eb74740f 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -7,7 +7,6 @@ import { observer } from 'mobx-react'; import { extname } from 'path'; import * as React from 'react'; import { AiOutlineSend } from 'react-icons/ai'; -import { ImageLabelBoxData } from '../collections/collectionFreeForm/ImageLabelBox'; import ReactLoading from 'react-loading'; import { ClientUtils, imageUrlToBase64, DashColor, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, UpdateIcon } from '../../../ClientUtils'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; diff --git a/src/client/views/nodes/scrapbook/ScrapbookBox.tsx b/src/client/views/nodes/scrapbook/ScrapbookBox.tsx index ced2df6c5..ad3bfa7ad 100644 --- a/src/client/views/nodes/scrapbook/ScrapbookBox.tsx +++ b/src/client/views/nodes/scrapbook/ScrapbookBox.tsx @@ -1,4 +1,4 @@ -import { action, makeObservable, observable } from 'mobx'; +import { action, makeObservable, observable, reaction } from 'mobx'; import * as React from 'react'; import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; @@ -18,7 +18,11 @@ import { ImageBox } from '../ImageBox'; import { FireflyImageDimensions } from '../../smartdraw/FireflyConstants'; import { SmartDrawHandler } from '../../smartdraw/SmartDrawHandler'; import { ImageCast } from '../../../../fields/Types'; -import { lengthToDegrees } from '@turf/turf'; +import { SnappingManager } from '../../../util/SnappingManager'; +import { IReactionDisposer } from 'mobx'; +import { observer } from 'mobx-react'; +import { ImageField } from '../../../../fields/URLField'; +import { runInAction } from 'mobx'; enum ScrapbookPresetType { Classic = 'Classic', @@ -28,16 +32,17 @@ enum ScrapbookPresetType { } // Scrapbook view: a container that lays out its child items in a grid/template +@observer export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { - state = { - loading: false, - src: '', - }; - - @observable createdDate: string; + @observable loading = false; + @observable src = ''; + @observable imgDoc: Doc | undefined; + private _disposers: { [name: string]: IReactionDisposer } = {}; + private imageBoxRef = React.createRef<ImageBox>(); + // @observable configs : ScrapbookItemConfig[] constructor(props: FieldViewProps) { @@ -337,7 +342,7 @@ export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>() } } - + async generateAiImage() { this.setState({ loading: true }); @@ -365,10 +370,98 @@ export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>() componentDidMount() { //this.initScrapbook(ScrapbookPresetType.Default); this.setTitle(); - this.generateAiImage(); + this.generateAiImageCorrect(); + + this._disposers.propagateResize = reaction( + () => ({ w: this.layoutDoc._width, h: this.layoutDoc._height }), + (dims, prev) => { + // prev is undefined on the first run, so bail early + if (!prev || !SnappingManager.ShiftKey || !this.imgDoc) return; + + // either guard the ref… + const imageBox = this.imageBoxRef.current; + if (!imageBox) return; + + // …or just hard-code the fieldKey if you know it’s always `"data"` + const key = imageBox.props.fieldKey; + + runInAction(() => { + if(!this.imgDoc){ + return + } + // use prev.w/h (the *old* size) as your orig dims + this.imgDoc[key + '_outpaintOriginalWidth'] = prev.w; + this.imgDoc[key + '_outpaintOriginalHeight'] = prev.h; + ;(this.imageBoxRef.current as any).layoutDoc._width = dims.w + ;(this.imageBoxRef.current as any).layoutDoc._height = dims.h + + // tell the imageDoc to resize itself to the *new* scrapbook size + //this.imgDoc._width = dims.w; + //this.imgDoc._height = dims.h; + //Doc.SetNativeWidth(this.imgDoc, dims.w); + //Doc.SetNativeHeight(this.imgDoc, dims.h); + }); + } + ); + /* + this._disposers.propagateResize = reaction( + () => ({ w: this.layoutDoc._width, h: this.layoutDoc._height }), + ({ w, h }, prev) => { + // only when shift is held (i.e. outpaint mode) + if (SnappingManager.ShiftKey && this.imgDoc) { + const key = this.imageBoxRef.current!.props.fieldKey; // “data” + // record original size on the *image* doc: + this.imgDoc[key + '_outpaintOriginalWidth'] = this.imgDoc._width; + this.imgDoc[key + '_outpaintOriginalHeight'] = this.imgDoc._height; + } + } + );*/ + + + // this._disposers.outpaint = reaction( + // () => this.imgDoc?.[this.imgDoc.fieldKey + '_outpaintOriginalWidth'], + // originalWidth => { + // if (originalWidth !== undefined && !SnappingManager.ShiftKey) { + // this.imageBoxRef.current?.openOutpaintPrompt(); // ✅ CORRECT! + // } + // } + // ); } + async generateAiImageCorrect() { + this.loading = true; + + const prompt = 'A serene mountain landscape at sunrise, ultra-wide, pastel sky, abstract, scrapbook background'; + const dimensions = FireflyImageDimensions.Square; + + SmartDrawHandler.CreateWithFirefly(prompt, dimensions) + .then(action(doc => { + if (doc instanceof Doc) { + const imgField = ImageCast(doc.data); + if (imgField?.url.href) { + this.src = imgField.url.href; + const url = new ImageField(this.src); + this.imgDoc = Docs.Create.ImageDocument(url, { title: 'Generated Background', _width: 1792, _height: 2304, + _nativeWidth: 1792, _nativeHeight: 1792 + }, ); + } else { + alert('Image URL missing.'); + this.src = ''; + } + + } else { + alert('Failed to generate document.'); + } + })) + .catch(e => { + alert(`Generation error: ${e}`); + }) + .finally(action(() => { + this.loading = false; + })); + } + childRejectDrop = (de: DragManager.DropEvent, subView?: DocumentView) => { return true; // disable dropping documents onto any child of the scrapbook. }; @@ -446,18 +539,18 @@ export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>() }; render() { - const { loading, src } = this.state; + return ( <div style={{ background: 'beige', width: '100%', height: '100%' }}> - {loading && ( + {this.loading && ( <div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center', background: 'rgba(255,255,255,0.8)' }}> <ReactLoading type="spin" width={50} height={50} /> </div> )} - {loading && ( + {this.loading && ( <div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center', background: 'rgba(255,255,255,0.8)', zIndex: 10 }}> @@ -465,15 +558,14 @@ export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>() </div> )} {/* Render AI-generated background */} - {src && ( - <ImageBox - {...this._props} - Document={Docs.Create.ImageDocument(src, { title: 'Generated Background' })} - fieldKey="data" - /> - )} - - <CollectionView + {this.src && this.imgDoc && ( + <ImageBox + ref={this.imageBoxRef} + {...this._props} + Document={this.imgDoc} + fieldKey="data" + /> + )} <CollectionView {...this._props} // setContentViewBox={emptyFunction} rejectDrop={this.rejectDrop} |
