From a162057114fd3d961e447d6c3051c1c8c0c6b46d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 26 Feb 2025 23:41:07 -0500
Subject: made ai. button draggable to regenerate images.

---
 src/client/views/smartdraw/DrawingFillHandler.tsx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'src/client/views/smartdraw/DrawingFillHandler.tsx')

diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx
index d0a840883..7447f8afb 100644
--- a/src/client/views/smartdraw/DrawingFillHandler.tsx
+++ b/src/client/views/smartdraw/DrawingFillHandler.tsx
@@ -47,11 +47,11 @@ export class DrawingFillHandler {
                 return imageUrlToBase64(structureUrl)
                     .then(gptDescribeImage)
                     .then((prompt, newPrompt = user_prompt || prompt) =>
-                        Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: `${newPrompt}`, width: dims.width, height: dims.height, structure: structureUrl, strength, presets: styles, styleUrl })
-                            .then((infos: Upload.ImageInformation[]) => {
+                        Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: `${newPrompt}`, width: dims.width, height: dims.height, structureUrl, strength, presets: styles, styleUrl })
+                            .then(res => {
                                 const genratedDocs = DocCast(drawing.ai_firefly_generatedDocs) ?? Docs.Create.MasonryDocument([], { _width: 400, _height: 400 });
                                 drawing[DocData].ai_firefly_generatedDocs = genratedDocs;
-                                infos.map(info =>
+                                (res as Upload.ImageInformation[]).map(info =>
                                     Doc.AddDocToList(
                                         genratedDocs,
                                         undefined,
-- 
cgit v1.2.3-70-g09d2


From 532f0fa22281fef1e35e3d0a6064ee57e4673253 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 28 Feb 2025 14:52:39 -0500
Subject: added drop target for regenerating images

---
 src/client/util/DragManager.ts                    |  3 +
 src/client/views/nodes/ImageBox.scss              |  8 ++
 src/client/views/nodes/ImageBox.tsx               | 90 +++++++++++++++--------
 src/client/views/smartdraw/DrawingFillHandler.tsx | 23 +++---
 4 files changed, 83 insertions(+), 41 deletions(-)

(limited to 'src/client/views/smartdraw/DrawingFillHandler.tsx')

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 81ea840f1..6c8179c82 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -555,9 +555,12 @@ export namespace DragManager {
         let scrollAwaiter: Opt<NodeJS.Timeout>;
 
         let startWindowDragTimer: NodeJS.Timeout | undefined;
+        let startCanEmbed = SnappingManager.CanEmbed;
         const moveHandler = (e: PointerEvent) => {
             e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop
             if (docDragData) {
+                if (e.ctrlKey) SnappingManager.SetCanEmbed(true);
+                else if (!startCanEmbed) SnappingManager.SetCanEmbed(false);
                 docDragData.userDropAction = e.ctrlKey && e.altKey ? dropActionType.copy : e.shiftKey ? dropActionType.move : e.ctrlKey ? dropActionType.embed : docDragData.defaultDropAction;
                 const targClassName = e.target instanceof HTMLElement && typeof e.target.className === 'string' ? e.target.className : '';
                 if (['lm_tab', 'lm_title_wrap', 'lm_tabs', 'lm_header'].includes(targClassName) && docDragData.draggedDocuments.length === 1) {
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 59e093683..671621bbe 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -122,6 +122,7 @@
         }
     }
 }
+.imageBox-regenerateDropTarget,
 .imageBox-alternateDropTarget {
     position: absolute;
     color: white;
@@ -136,6 +137,13 @@
         height: 100%;
     }
 }
+.imageBox-regenerateDropTarget {
+    right: 30;
+    border-radius: 50%;
+    svg {
+        border-radius: 50%;
+    }
+}
 
 .imageBox-fader img {
     position: absolute;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 55474cb7e..d122ca5b0 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -36,7 +36,7 @@ import { OverlayView } from '../OverlayView';
 import { AnchorMenu } from '../pdf/AnchorMenu';
 import { PinDocView, PinProps } from '../PinFuncs';
 import { DrawingFillHandler } from '../smartdraw/DrawingFillHandler';
-import { FireflyImageData, isFireflyImageData } from '../smartdraw/FireflyConstants';
+import { FireflyImageData, FireflyImageDimensions, isFireflyImageData } from '../smartdraw/FireflyConstants';
 import { SmartDrawHandler } from '../smartdraw/SmartDrawHandler';
 import { StickerPalette } from '../smartdraw/StickerPalette';
 import { StyleProp } from '../StyleProp';
@@ -45,6 +45,7 @@ import { FieldView, FieldViewProps } from './FieldView';
 import { FocusViewOptions } from './FocusViewOptions';
 import './ImageBox.scss';
 import { OpenWhere } from './OpenWhere';
+import { RichTextField } from '../../../fields/RichTextField';
 
 export class ImageEditorData {
     // eslint-disable-next-line no-use-before-define
@@ -83,6 +84,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     private _disposers: { [name: string]: IReactionDisposer } = {};
     private _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
     private _overlayIconRef = React.createRef<HTMLDivElement>();
+    private _regenerateIconRef = React.createRef<HTMLDivElement>();
     private _mainCont: HTMLDivElement | null = null;
     private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
     imageRef: HTMLImageElement | null = null; // <video> ref
@@ -196,36 +198,47 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         this._searchInput = selection;
     };
 
-    drop = undoable((e: Event, de: DragManager.DropEvent) => {
-        if (de.complete.docDragData) {
-            let added: boolean | undefined;
-            const targetIsBullseye = (ele: HTMLElement): boolean => {
-                if (!ele) return false;
-                if (ele === this._overlayIconRef.current) return true;
-                return targetIsBullseye(ele.parentElement as HTMLElement);
-            };
-            if (de.metaKey || targetIsBullseye(e.target as HTMLElement)) {
-                added = de.complete.docDragData.droppedDocuments.reduce((last: boolean, drop: Doc) => {
-                    this.layoutDoc[this.fieldKey + '_usePath'] = 'alternate:hover';
-                    return last && Doc.AddDocToList(this.dataDoc, this.fieldKey + '_alternates', drop);
-                }, true);
-            } else if (de.altKey || !this.dataDoc[this.fieldKey]) {
-                const layoutDoc = de.complete.docDragData?.draggedDocuments[0];
-                const targetField = Doc.LayoutFieldKey(layoutDoc);
-                const targetDoc = layoutDoc[DocData];
-                if (targetDoc[targetField] instanceof ImageField) {
-                    added = true;
-                    this.dataDoc[this.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField);
-                    Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(targetDoc), this.fieldKey);
-                    Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(targetDoc), this.fieldKey);
+    drop = undoable(
+        action((e: Event, de: DragManager.DropEvent) => {
+            if (de.complete.docDragData) {
+                let added: boolean | undefined;
+                const hitDropTarget = (ele: HTMLElement, dropTarget: HTMLDivElement | null): boolean => {
+                    if (!ele) return false;
+                    if (ele === dropTarget) return true;
+                    return hitDropTarget(ele.parentElement as HTMLElement, dropTarget);
+                };
+                if (de.metaKey || hitDropTarget(e.target as HTMLElement, this._overlayIconRef.current)) {
+                    added = de.complete.docDragData.droppedDocuments.reduce((last: boolean, drop: Doc) => {
+                        this.layoutDoc[this.fieldKey + '_usePath'] = 'alternate:hover';
+                        return last && Doc.AddDocToList(this.dataDoc, this.fieldKey + '_alternates', drop);
+                    }, true);
+                } else if (hitDropTarget(e.target as HTMLElement, this._regenerateIconRef.current)) {
+                    this._regenerateLoading = true;
+                    const drag = de.complete.docDragData.draggedDocuments.lastElement();
+                    const dragField = drag[Doc.LayoutFieldKey(drag)];
+                    const oldPrompt = StrCast(this.Document.ai_firefly_prompt, StrCast(this.Document.title));
+                    const newPrompt = (text: string) => (oldPrompt ? `${oldPrompt} ~~~ ${text}` : text);
+                    DrawingFillHandler.drawingToImage(this.Document, 100, newPrompt(dragField instanceof RichTextField ? dragField.Text : ''), drag)?.then(action(() => (this._regenerateLoading = false)));
+                    added = false;
+                } else if (de.altKey || !this.dataDoc[this.fieldKey]) {
+                    const layoutDoc = de.complete.docDragData?.draggedDocuments[0];
+                    const targetField = Doc.LayoutFieldKey(layoutDoc);
+                    const targetDoc = layoutDoc[DocData];
+                    if (targetDoc[targetField] instanceof ImageField) {
+                        added = true;
+                        this.dataDoc[this.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField);
+                        Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(targetDoc), this.fieldKey);
+                        Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(targetDoc), this.fieldKey);
+                    }
                 }
+                added === false && e.preventDefault();
+                added !== undefined && e.stopPropagation();
+                return added;
             }
-            added === false && e.preventDefault();
-            added !== undefined && e.stopPropagation();
-            return added;
-        }
-        return false;
-    }, 'image drop');
+            return false;
+        }),
+        'image drop'
+    );
 
     @undoBatch
     resolution = () => {
@@ -485,6 +498,24 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             </Tooltip>
         );
     }
+    @computed get regenerateImageIcon() {
+        return (
+            <div
+                className="imageBox-regenerateDropTarget"
+                ref={this._regenerateIconRef}
+                onClick={() => DocumentView.showDocument(DocCast(this.Document.ai_firefly_generatedDocs), { openLocation: OpenWhere.addRight })}
+                style={{
+                    display: (this._props.isContentActive() && (SnappingManager.CanEmbed || this.Document.ai_firefly_generatedDocs)) || this._regenerateLoading ? 'block' : 'none',
+                    transform: `scale(${this.uiBtnScaling})`,
+                    width: this._sideBtnWidth,
+                    height: this._sideBtnWidth,
+                    background: 'transparent',
+                    // color: SettingsManager.userBackgroundColor,
+                }}>
+                {this._regenerateLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width="100%" height="100%" /> : <FontAwesomeIcon icon="portrait" color={SettingsManager.userColor} size="lg" />}
+            </div>
+        );
+    }
 
     @computed get paths() {
         const field = this.dataDoc[this.fieldKey] instanceof ImageField ? Cast(this.dataDoc[this.fieldKey], ImageField, null) : new ImageField(String(this.dataDoc[this.fieldKey])); // retrieve the primary image URL that is being rendered from the data doc
@@ -807,6 +838,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         <ReactLoading type="spin" height={50} width={50} color={'blue'} />
                     </div>
                 ) : null}
+                {this.regenerateImageIcon}
                 {this.overlayImageIcon}
                 {this.annotationLayer}
                 {!this._mainCont || !this.DocumentView || !this._annotationLayer.current ? null : (
diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx
index 7447f8afb..0a30b14b8 100644
--- a/src/client/views/smartdraw/DrawingFillHandler.tsx
+++ b/src/client/views/smartdraw/DrawingFillHandler.tsx
@@ -28,19 +28,15 @@ export class DrawingFillHandler {
             const hrefParts = ImageCast(styleImg).url.href.split('.');
             return `${hrefParts.slice(0, -1).join('.')}_o.${hrefParts.lastElement()}`;
         });
-        DocumentView.GetDocImage(drawing)?.then(imageField => {
+        return DocumentView.GetDocImage(drawing)?.then(imageField => {
             if (imageField) {
                 const aspectRatio = (drawing.width as number) / (drawing.height as number);
-                let dims: { width: number; height: number };
-                if (aspectRatio > AspectRatioLimits[FireflyImageDimensions.Widescreen]) {
-                    dims = FireflyDimensionsMap[FireflyImageDimensions.Widescreen];
-                } else if (aspectRatio > AspectRatioLimits[FireflyImageDimensions.Landscape]) {
-                    dims = FireflyDimensionsMap[FireflyImageDimensions.Landscape];
-                } else if (aspectRatio < AspectRatioLimits[FireflyImageDimensions.Portrait]) {
-                    dims = FireflyDimensionsMap[FireflyImageDimensions.Portrait];
-                } else {
-                    dims = FireflyDimensionsMap[FireflyImageDimensions.Square];
-                }
+                const dims = (() => {
+                    if (aspectRatio > AspectRatioLimits[FireflyImageDimensions.Widescreen]) return FireflyDimensionsMap[FireflyImageDimensions.Widescreen];
+                    if (aspectRatio > AspectRatioLimits[FireflyImageDimensions.Landscape]) return FireflyDimensionsMap[FireflyImageDimensions.Landscape];
+                    if (aspectRatio < AspectRatioLimits[FireflyImageDimensions.Portrait]) return FireflyDimensionsMap[FireflyImageDimensions.Portrait];
+                    return FireflyDimensionsMap[FireflyImageDimensions.Square];
+                })();
                 const { href } = ImageCast(imageField).url;
                 const hrefParts = href.split('.');
                 const structureUrl = `${hrefParts.slice(0, -1).join('.')}_o.${hrefParts.lastElement()}`;
@@ -62,7 +58,10 @@ export class DrawingFillHandler {
                                             _width: 500,
                                             data_nativeWidth: info.nativeWidth,
                                             data_nativeHeight: info.nativeHeight,
-                                        })
+                                        }),
+                                        undefined,
+                                        undefined,
+                                        true
                                     )
                                 );
                                 if (!DocumentView.getFirstDocumentView(genratedDocs)) DocumentViewInternal.addDocTabFunc(genratedDocs, OpenWhere.addRight);
-- 
cgit v1.2.3-70-g09d2


From db3bdb19ff7bc1c69c544797c05a6db3b72b1464 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 5 Mar 2025 14:54:18 -0500
Subject: added:hover mode for images to make primary image fade in instead of
 alternate.

---
 src/client/documents/Documents.ts                  |  3 ++
 src/client/views/MainView.tsx                      |  2 +-
 src/client/views/TagsView.tsx                      |  3 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 src/client/views/nodes/DocumentView.scss           |  1 +
 src/client/views/nodes/DocumentView.tsx            | 16 +++++----
 src/client/views/nodes/ImageBox.scss               |  6 ++++
 src/client/views/nodes/ImageBox.tsx                | 40 +++++++++++++++-------
 .../views/nodes/chatbot/tools/ImageCreationTool.ts |  3 +-
 src/client/views/pdf/GPTPopup/GPTPopup.tsx         |  3 ++
 src/client/views/smartdraw/DrawingFillHandler.tsx  |  4 +++
 src/client/views/smartdraw/SmartDrawHandler.tsx    |  8 +++--
 12 files changed, 65 insertions(+), 26 deletions(-)

(limited to 'src/client/views/smartdraw/DrawingFillHandler.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 1ce25165c..21d3c978b 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -384,6 +384,9 @@ export class DocumentOptions {
     presentation_duration?: NUMt = new NumInfo('the duration of the slide in presentation view', false);
     presentation_zoomText?: BOOLt = new BoolInfo('whether text anchors should shown in a larger box when following links to make them stand out', false);
 
+    data_annotations?: List<Doc>;
+    _data_usePath?: STRt = new StrInfo("description of field key to display in image box ('alternate','alternate:hover', 'data:hover'). defaults to primary", false);
+    data_alternates?: List<Doc>;
     data?: FieldType;
     data_useCors?: BOOLt = new BoolInfo('whether CORS protocol should be used for web page');
     _face_showImages?: BOOLt = new BoolInfo('whether to show images in uniqe face Doc');
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index afefe3f03..cc7c1a42b 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -686,7 +686,7 @@ export class MainView extends ObservableReactComponent<object> {
         );
     }
     @computed get mainDocView() {
-        const headerBar = null; // this._hideUI || !this.headerBarDocHeight?.() ? null : this.headerBarDocView;
+        const headerBar = this._hideUI || !this.headerBarDocHeight?.() ? null : this.headerBarDocView;
         return (
             <>
                 {headerBar}
diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx
index b70e21918..93d6fb684 100644
--- a/src/client/views/TagsView.tsx
+++ b/src/client/views/TagsView.tsx
@@ -398,8 +398,7 @@ export class TagsView extends ObservableReactComponent<TagViewProps> {
                                         e.stopPropagation();
                                     }}
                                     type="text"
-                                    placeholder="Input tags for document..."
-                                    aria-label="tagsView-input"
+                                    placeholder="Enter #tags or @metadata"
                                     className="tagsView-input"
                                     style={{ width: '100%', borderRadius: '5px' }}
                                 />
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index b3d908da4..43addfc29 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -344,7 +344,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     focusOnPoint = (options: FocusViewOptions) => {
         const { pointFocus, zoomTime, didMove } = options;
         if (!this.Document.isGroup && pointFocus && !didMove) {
-            const dfltScale = this.isAnnotationOverlay ? 1 : 0.5;
+            const dfltScale = this.isAnnotationOverlay ? 1 : 0.25;
             if (this.layoutDoc[this.scaleFieldKey] !== dfltScale) {
                 this.zoomSmoothlyAboutPt(this.screenToFreeformContentsXf.transformPoint(pointFocus.X, pointFocus.Y), dfltScale, zoomTime);
                 options.didMove = true;
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 294af4d96..dd5fd0d0c 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -291,6 +291,7 @@
     justify-items: center;
     background-color: rgb(223, 223, 223);
     transform-origin: top left;
+    background: transparent;
 
     .documentView-editorView-resizer {
         height: 5px;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 5f5dd1210..595abc7f8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -279,16 +279,17 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
         setTimeout(() => this._titleRef.current?.setIsFocused(true)); // use timeout in case title wasn't shown to allow re-render so that titleref will be defined
     };
     onBrowseClick = (e: React.MouseEvent) => {
-        const browseTransitionTime = 500;
+        //const browseTransitionTime = 500;
         DocumentView.DeselectAll();
         DocumentView.showDocument(this.Document, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => {
-            const options: FocusViewOptions = { pointFocus: { X: e.clientX, Y: e.clientY }, zoomTime: browseTransitionTime };
+            // const options: FocusViewOptions = { pointFocus: { X: e.clientX, Y: e.clientY }, zoomTime: browseTransitionTime };
             if (!focused && this._docView) {
-                this._docView
-                    .docViewPath()
-                    .reverse()
-                    .forEach(cont => cont.ComponentView?.focus?.(cont.Document, options));
-                Doc.linkFollowHighlight(this.Document, false);
+                DocumentView.showDocument(this.Document, { zoomScale: 0.3, willZoomCentered: true });
+                // this._docView
+                //     .docViewPath()
+                //     .reverse()
+                //     .forEach(cont => cont.ComponentView?.focus?.(cont.Document, options));
+                // Doc.linkFollowHighlight(this.Document, false);
             }
         });
         e.stopPropagation();
@@ -797,6 +798,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
                         <div
                             className="documentView-editorView"
                             style={{
+                                background: SnappingManager.userVariantColor,
                                 width: `${100 / this.uiBtnScaling}%`, //
                                 transform: `scale(${this.uiBtnScaling})`,
                             }}
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 15581a9e8..3d6942e6f 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -40,6 +40,7 @@
     max-height: 100%;
     pointer-events: inherit;
     background: transparent;
+    z-index: 0;
     // z-index: -10000; // bcz: not sure why this was here.  it broke dropping images on the image box alternate bullseye icon.
 
     img {
@@ -103,6 +104,10 @@
     margin: 0 auto;
     display: flex;
     height: 100%;
+    img {
+        object-fit: contain;
+        height: 100%;
+    }
 
     .imageBox-fadeBlocker,
     .imageBox-fadeBlocker-hover {
@@ -237,5 +242,6 @@
         text-overflow: ellipsis;
         max-width: 65%;
         width: 100%;
+        color: black;
     }
 }
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 4979a4d4d..017ef7191 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -436,6 +436,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     };
     getScrollHeight = () => (this._props.fitWidth?.(this.Document) !== false && NumCast(this.layoutDoc._freeform_scale, 1) === NumCast(this.dataDoc._freeform_scaleMin, 1) ? this.nativeSize.nativeHeight : undefined);
 
+    @computed get usingAlternate() {
+        const usePath = StrCast(this.Document[this.fieldKey + '_usePath']);
+        return 'alternate' === usePath || ('alternate:hover' === usePath && this._isHovering) || (':hover' === usePath && !this._isHovering);
+    }
+
     @computed get nativeSize() {
         TraceMobx();
         if (this.paths.length && this.paths[0].includes('icon-hi')) return { nativeWidth: NumCast(this.layoutDoc._width), nativeHeight: NumCast(this.layoutDoc._height), nativeOrientation: 0 };
@@ -471,10 +476,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         <span style={{ color: usePath === 'alternate' ? 'black' : undefined }}>
                             <em>alternate, </em>
                         </span>
-                        and show
                         <span style={{ color: usePath === 'alternate:hover' ? 'black' : undefined }}>
                             <em> alternate on hover</em>
                         </span>
+                        and show
+                        <span style={{ color: usePath === ':hover' ? 'black' : undefined }}>
+                            <em> primary on hover</em>
+                        </span>
                     </div>
                 }>
                 <div
@@ -482,7 +490,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                     ref={this._overlayIconRef}
                     onPointerDown={e =>
                         setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, () => {
-                            this.layoutDoc[`_${this.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined;
+                            this.layoutDoc[`_${this.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : usePath === 'alternate:hover' ? ':hover' : undefined;
                         })
                     }
                     style={{
@@ -527,7 +535,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 .filter(url => url)
                 .map(url => this.choosePath(url)) ?? []; // acc  ess the primary layout data of the alternate documents
         const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths;
-        return paths.length ? paths : [defaultUrl.href];
+        return paths.length ? paths.reverse() : [defaultUrl.href];
     }
 
     @computed get content() {
@@ -552,7 +560,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             transformOrigin = 'right top';
             transform = `translate(-100%, 0%) rotate(${rotation}deg) scale(${aspect})`;
         }
-        const usePath = this.layoutDoc[`_${this.fieldKey}_usePath`];
 
         return (
             <div
@@ -571,7 +578,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         ref={action((r: HTMLImageElement | null) => (this.imageRef = r))}
                         key="paths"
                         src={srcpath}
-                        style={{ transform, transformOrigin, objectFit: 'fill', height: '100%' }}
+                        style={{ transform, transformOrigin }}
                         onError={action(e => {
                             this._error = e.toString();
                         })}
@@ -579,7 +586,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         width={nativeWidth}
                     />
                     {fadepath === srcpath ? null : (
-                        <div className={`imageBox-fadeBlocker${(this._isHovering && usePath === 'alternate:hover') || usePath === 'alternate' ? '-hover' : ''}`} style={{ transition: StrCast(this.layoutDoc.viewTransition, 'opacity 1000ms') }}>
+                        <div className={`imageBox-fadeBlocker${this.usingAlternate ? '-hover' : ''}`} style={{ transition: StrCast(this.layoutDoc.viewTransition, 'opacity 1000ms') }}>
                             <img alt="" className="imageBox-fadeaway" key="fadeaway" src={fadepath} style={{ transform, transformOrigin }} draggable={false} width={nativeWidth} />
                         </div>
                     )}
@@ -619,8 +626,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         return (
             <div className="imageBox-aiView">
                 <div className="imageBox-aiView-regenerate">
-                    <span className="imageBox-aiView-firefly">Firefly:</span>
+                    <span className="imageBox-aiView-firefly" style={{ color: SnappingManager.userColor }}>
+                        Firefly:
+                    </span>
                     <input
+                        style={{ color: SnappingManager.userColor, background: SnappingManager.userBackgroundColor }}
                         className="imageBox-aiView-input"
                         aria-label="Edit instructions input"
                         type="text"
@@ -631,7 +641,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                     <div className="imageBox-aiView-regenerate-createBtn">
                         <Button
                             text="Create"
-                            type={Type.SEC}
+                            type={Type.TERT}
+                            color={SnappingManager.userColor}
+                            background={SnappingManager.userBackgroundColor}
                             // style={{ alignSelf: 'flex-end' }}
                             icon={this._regenerateLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
                             iconPlacement="right"
@@ -663,13 +675,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                     </div>
                 </div>
                 <div className="imageBox-aiView-strength">
-                    <span className="imageBox-aiView-similarity">Similarity</span>
+                    <span className="imageBox-aiView-similarity" style={{ color: SnappingManager.userColor }}>
+                        Similarity
+                    </span>
                     <Slider
                         className="imageBox-aiView-slider"
                         sx={{
-                            '& .MuiSlider-track': { color: SettingsManager.userVariantColor },
+                            '& .MuiSlider-track': { color: SettingsManager.userColor },
                             '& .MuiSlider-rail': { color: SettingsManager.userBackgroundColor },
-                            '& .MuiSlider-thumb': { color: SettingsManager.userVariantColor, '&.Mui-focusVisible, &:hover, &.Mui-active': { boxShadow: `0px 0px 0px 8px${SettingsManager.userColor.slice(0, 7)}10` } },
+                            '& .MuiSlider-thumb': { color: SettingsManager.userColor, '&.Mui-focusVisible, &:hover, &.Mui-active': { boxShadow: `0px 0px 0px 8px${SettingsManager.userColor.slice(0, 7)}10` } },
                         }}
                         min={0}
                         max={100}
@@ -725,11 +739,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         return { width, height };
     };
     savedAnnotations = () => this._savedAnnotations;
-
     render() {
         TraceMobx();
         const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding) as string;
         const borderRadius = borderRad?.includes('px') ? `${Number(borderRad.split('px')[0]) / (this._props.NativeDimScaling?.() || 1)}px` : borderRad;
+        const alts = DocListCast(this.dataDoc[this.fieldKey + '_alternates']);
+        const doc = this.usingAlternate ? (alts.lastElement() ?? this.Document) : this.Document;
         return (
             <div
                 className="imageBox"
@@ -754,6 +769,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 <CollectionFreeFormView
                     ref={this._ffref}
                     {...this._props}
+                    Document={doc}
                     setContentViewBox={emptyFunction}
                     NativeWidth={returnZero}
                     NativeHeight={returnZero}
diff --git a/src/client/views/nodes/chatbot/tools/ImageCreationTool.ts b/src/client/views/nodes/chatbot/tools/ImageCreationTool.ts
index e92d87dfd..37907fd4f 100644
--- a/src/client/views/nodes/chatbot/tools/ImageCreationTool.ts
+++ b/src/client/views/nodes/chatbot/tools/ImageCreationTool.ts
@@ -5,6 +5,7 @@ import { ParametersType, ToolInfo } from '../types/tool_types';
 import { Observation } from '../types/types';
 import { BaseTool } from './BaseTool';
 import { Upload } from '../../../../../server/SharedMediaTypes';
+import { List } from '../../../../../fields/List';
 
 const imageCreationToolParams = [
     {
@@ -41,7 +42,7 @@ export class ImageCreationTool extends BaseTool<ImageCreationToolParamsType> {
                 image_prompt,
             })) as { result: Upload.FileInformation & Upload.InspectionResults; url: string };
             console.log('Image generation result:', result);
-            this._createImage(result, { text: RTFCast(image_prompt) });
+            this._createImage(result, { text: RTFCast(image_prompt), ai: 'dall-e-3', tags: new List<string>(['@ai']) });
             return url
                 ? [
                       {
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index 79f5121ed..4dc45e6a0 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -30,6 +30,7 @@ import { Upload } from '../../../../server/SharedMediaTypes';
 import { OpenWhere } from '../../nodes/OpenWhere';
 import { DrawingFillHandler } from '../../smartdraw/DrawingFillHandler';
 import { ImageField } from '../../../../fields/URLField';
+import { List } from '../../../../fields/List';
 
 export enum GPTPopupMode {
     SUMMARY, // summary of seleted document text
@@ -352,6 +353,8 @@ export class GPTPopup extends ObservableReactComponent<object> {
                 y: NumCast(textAnchor.y),
                 _height: 200,
                 _width: 200,
+                ai: 'dall-e',
+                tags: new List<string>(['@ai']),
                 data_nativeWidth: 1024,
                 data_nativeHeight: 1024,
             });
diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx
index 0a30b14b8..c672bc718 100644
--- a/src/client/views/smartdraw/DrawingFillHandler.tsx
+++ b/src/client/views/smartdraw/DrawingFillHandler.tsx
@@ -1,6 +1,7 @@
 import { imageUrlToBase64 } from '../../../ClientUtils';
 import { Doc, StrListCast } from '../../../fields/Doc';
 import { DocData } from '../../../fields/DocSymbols';
+import { List } from '../../../fields/List';
 import { DocCast, ImageCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
 import { Upload } from '../../../server/SharedMediaTypes';
@@ -53,7 +54,10 @@ export class DrawingFillHandler {
                                         undefined,
                                         Docs.Create.ImageDocument(info.accessPaths.agnostic.client, {
                                             ai: 'firefly',
+                                            tags: new List<string>(['@ai']),
                                             title: newPrompt,
+                                            _data_usePath: 'alternate:hover',
+                                            data_alternates: new List<Doc>([drawing]),
                                             ai_firefly_prompt: newPrompt,
                                             _width: 500,
                                             data_nativeWidth: info.nativeWidth,
diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx
index ca308015d..1cceabed3 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.tsx
+++ b/src/client/views/smartdraw/SmartDrawHandler.tsx
@@ -28,6 +28,7 @@ import { FireflyDimensionsMap, FireflyImageData, FireflyImageDimensions } from '
 import './SmartDrawHandler.scss';
 import { Upload } from '../../../server/SharedMediaTypes';
 import { PointData } from '../../../pen-gestures/GestureTypes';
+import { List } from '../../../fields/List';
 
 export interface DrawingOptions {
     text?: string;
@@ -293,15 +294,17 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
                     return undefined;
                 }
                 const newseed = img.accessPaths.agnostic.client.match(/\/(\d+)upload/)?.[1];
-                const imgDoc: Doc = Docs.Create.ImageDocument(img.accessPaths.agnostic.client, {
+                return Docs.Create.ImageDocument(img.accessPaths.agnostic.client, {
                     title: input,
                     nativeWidth: dims.width,
                     nativeHeight: dims.height,
+                    tags: new List<string>(['@ai']),
+                    _width: Math.min(400, dims.width),
+                    _height: (Math.min(400, dims.width) * dims.height) / dims.width,
                     ai: 'firefly',
                     ai_firefly_seed: +(newseed ?? 0),
                     ai_firefly_prompt: input,
                 });
-                return imgDoc;
             })
             .catch(e => {
                 alert('create image failed: ' + e.toString());
@@ -568,6 +571,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
                         color={SettingsManager.userColor}
                     />
                     <input
+                        style={{ color: SettingsManager.userColor, background: SettingsManager.userBackgroundColor }}
                         aria-label="Smart Draw Input"
                         className="smartdraw-input"
                         type="text"
-- 
cgit v1.2.3-70-g09d2

