aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/InkingStroke.tsx4
-rw-r--r--src/client/views/MainView.tsx2
-rw-r--r--src/client/views/MarqueeAnnotator.tsx1
-rw-r--r--src/client/views/ObservableReactComponent.tsx8
-rw-r--r--src/client/views/PropertiesButtons.tsx2
-rw-r--r--src/client/views/ViewBoxInterface.ts1
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx2
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx2
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx6
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx6
-rw-r--r--src/client/views/collections/CollectionSubView.tsx32
-rw-r--r--src/client/views/collections/TabDocView.tsx4
-rw-r--r--src/client/views/collections/TreeView.tsx8
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx60
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx4
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx16
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx2
-rw-r--r--src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx7
-rw-r--r--src/client/views/global/globalScripts.ts5
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx14
-rw-r--r--src/client/views/nodes/DocumentView.scss3
-rw-r--r--src/client/views/nodes/DocumentView.tsx107
-rw-r--r--src/client/views/nodes/FieldView.tsx4
-rw-r--r--src/client/views/nodes/IconTagBox.tsx24
-rw-r--r--src/client/views/nodes/ImageBox.scss2
-rw-r--r--src/client/views/nodes/ImageBox.tsx107
-rw-r--r--src/client/views/nodes/LabelBox.tsx35
-rw-r--r--src/client/views/nodes/PDFBox.tsx4
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx4
-rw-r--r--src/client/views/nodes/WebBox.tsx22
-rw-r--r--src/client/views/nodes/WebBoxRenderer.js2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx22
-rw-r--r--src/client/views/nodes/imageEditor/ImageEditor.tsx5
-rw-r--r--src/client/views/nodes/imageEditor/imageEditorUtils/ImageHandler.ts6
-rw-r--r--src/client/views/nodes/trails/PresSlideBox.tsx8
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.scss7
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx153
-rw-r--r--src/client/views/smartdraw/DrawingFillHandler.tsx6
-rw-r--r--src/client/views/smartdraw/SmartDrawHandler.scss1
-rw-r--r--src/client/views/smartdraw/SmartDrawHandler.tsx65
-rw-r--r--src/client/views/smartdraw/StickerPalette.tsx12
41 files changed, 374 insertions, 411 deletions
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 0136f6abe..253db08de 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -497,8 +497,8 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>()
{...this._props}
setHeight={undefined}
setContentViewBox={this.setSubContentView} // this makes the inkingStroke the "dominant" component - ie, it will show the inking UI when selected (not text)
- yPadding={10}
- xPadding={10}
+ yMargin={10}
+ xMargin={10}
fieldKey="text"
// dontRegisterView={true}
noSidebar
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index ad6bb09c7..c49b7e6de 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -173,7 +173,7 @@ export class MainView extends ObservableReactComponent<object> {
views => views.length > 1 && document.activeElement instanceof HTMLElement && document.activeElement?.blur()
);
reaction(
- () => Doc.MyDockedBtns?.linearView_IsOpen,
+ () => Doc.MyDockedBtns?.linearView_isOpen,
open => SnappingManager.SetPrintToConsole(!!open)
);
const scriptTag = document.createElement('script');
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index e4811a902..b2e42652d 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -198,6 +198,7 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
const targetCreator = (annotationOn: Doc | undefined) => {
const target = DocUtils.GetNewTextDoc('Note linked to ' + this.props.Document.title, 0, 0, 100, 100, annotationOn, 'yellow');
+ target.layout_fitWidth = true;
DocumentView.SetSelectOnLoad(target);
return target;
};
diff --git a/src/client/views/ObservableReactComponent.tsx b/src/client/views/ObservableReactComponent.tsx
index 2290516dc..cf4bf991e 100644
--- a/src/client/views/ObservableReactComponent.tsx
+++ b/src/client/views/ObservableReactComponent.tsx
@@ -16,15 +16,13 @@ export abstract class ObservableReactComponent<T> extends React.Component<T, obj
makeObservable(this);
}
__passiveWheel: HTMLElement | null = null;
- _isContentActive: () => boolean | undefined = () => false;
+ __isContentActive: () => boolean | undefined = () => false;
/**
* default method to stop wheel events from bubbling up to parent components.
* @param e
*/
- onPassiveWheel = (e: WheelEvent) => {
- if (this._isContentActive?.()) e.stopPropagation();
- };
+ onPassiveWheel = (e: WheelEvent) => this.__isContentActive?.() && e.stopPropagation();
/**
* This fixes the problem where a component uses wheel events to scroll, but is nested inside another component that
@@ -36,7 +34,7 @@ export abstract class ObservableReactComponent<T> extends React.Component<T, obj
* @param onPassiveWheel an optional function to call to handle the wheel event (and block its propagation. If omitted, the event won't propagate.
*/
fixWheelEvents = (ele: HTMLElement | null, isContentActive: () => boolean | undefined, onPassiveWheel?: (e: WheelEvent) => void) => {
- this._isContentActive = isContentActive;
+ this.__isContentActive = isContentActive;
this.__passiveWheel?.removeEventListener('wheel', onPassiveWheel ?? this.onPassiveWheel);
this.__passiveWheel = ele;
ele?.addEventListener('wheel', onPassiveWheel ?? this.onPassiveWheel, { passive: false });
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 28566ba1d..ded342df0 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -165,7 +165,7 @@ export class PropertiesButtons extends React.Component {
// // containerDoc._forceActive =
// //containerDoc._freeform_fitContentsToBox =
// containerDoc._isLightbox = !containerDoc._isLightbox;
- // //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined;
+ // //containerDoc._xMargin = containerDoc._yMargin = containerDoc._isLightbox ? 10 : undefined;
// const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]);
// //dv.Document.onClick = ScriptField.MakeScript('{this.data = undefined; documentView.select(false)}', { documentView: 'any' });
// containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.layout_linkDisplay = false)));
diff --git a/src/client/views/ViewBoxInterface.ts b/src/client/views/ViewBoxInterface.ts
index 0ddac8914..d8dab8e89 100644
--- a/src/client/views/ViewBoxInterface.ts
+++ b/src/client/views/ViewBoxInterface.ts
@@ -64,5 +64,4 @@ export abstract class ViewBoxInterface<P> extends ObservableReactComponent<React
dontRegisterView?: () => boolean; // KeyValueBox's don't want to register their views
isUnstyledView?: () => boolean; // SchemaView and KeyValue are unstyled -- not titles, no opacity, no animations
componentAIView?: () => JSX.Element;
- componentAIViewHistory?: () => JSX.Element;
}
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index d5edc3e0b..3dc7bc515 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -133,7 +133,7 @@ export class CollectionCardView extends CollectionSubView() {
}
@computed get yMargin() {
- return this._props.yPadding || NumCast(this.layoutDoc._yMargin, Math.min(5, 0.05 * this._props.PanelWidth()));
+ return this._props.yMargin || NumCast(this.layoutDoc._yMargin, Math.min(5, 0.05 * this._props.PanelWidth()));
}
@computed get cardDeckWidth() {
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index ac1981012..3c5bc10de 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -206,7 +206,7 @@ export class CollectionCarouselView extends CollectionSubView() {
marginLeft: this.captionMarginX,
width: `calc(100% - ${this.captionMarginX * 2}px)`,
}}>
- <FormattedTextBox xPadding={10} yPadding={10} {...captionProps} fieldKey={carouselShowsCaptions} styleProvider={this.captionStyleProvider} Document={this.curDoc()} TemplateDataDocument={undefined} />
+ <FormattedTextBox xMargin={10} yMargin={10} {...captionProps} fieldKey={carouselShowsCaptions} styleProvider={this.captionStyleProvider} Document={this.curDoc()} TemplateDataDocument={undefined} />
</div>
)}
</>
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index be570564b..25a222cbb 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -89,7 +89,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return NumCast(this.layoutDoc._xMargin, Math.max(3, 0.05 * this._props.PanelWidth()));
}
@computed get yMargin() {
- return this._props.yPadding || NumCast(this.layoutDoc._yMargin, Math.min(5, 0.05 * this._props.PanelWidth()));
+ return this._props.yMargin || NumCast(this.layoutDoc._yMargin, Math.min(5, 0.05 * this._props.PanelWidth()));
}
@computed get gridGap() {
@@ -381,8 +381,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
hideDecorations={this._props.childHideDecorations}
childFiltersByRanges={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
- xPadding={NumCast(this.layoutDoc._childXPadding, this._props.childXPadding)}
- yPadding={NumCast(this.layoutDoc._childYPadding, this._props.childYPadding)}
+ xMargin={NumCast(this.layoutDoc._childXPadding, this._props.childXPadding)}
+ yMargin={NumCast(this.layoutDoc._childYPadding, this._props.childYPadding)}
rejectDrop={this._props.childRejectDrop}
addDocument={this._props.addDocument}
moveDocument={this._props.moveDocument}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 994669734..345f60e75 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -71,6 +71,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
}
_ele: HTMLElement | null = null;
+ _eleMasonrySingle = React.createRef<HTMLDivElement>();
protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, targetDropAction: dropActionType) => {
const dragData = de.complete.docDragData;
@@ -92,13 +93,13 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
createColumnDropRef = (ele: HTMLDivElement | null) => {
this.dropDisposer?.();
if (ele) this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Doc, this.onInternalPreDrop.bind(this));
- else if (this._ele) this.props.refList.splice(this.props.refList.indexOf(this._ele), 1);
+ else if (this._eleMasonrySingle.current) this.props.refList.splice(this.props.refList.indexOf(this._eleMasonrySingle.current), 1);
this._ele = ele;
};
@action
componentDidMount() {
- this._ele && this.props.refList.push(this._ele);
+ this._eleMasonrySingle.current && this.props.refList.push(this._eleMasonrySingle.current);
this._disposers.collapser = reaction(
() => this._props.headingObject?.collapsed,
collapsed => { this.collapsed = collapsed !== undefined ? BoolCast(collapsed) : false; }, // prettier-ignore
@@ -363,6 +364,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
}}>
<div
key={`${heading}-stack`}
+ ref={this._eleMasonrySingle}
className="collectionStackingView-masonrySingle"
style={{
padding: `${columnYMargin}px ${0}px ${this._props.yMargin}px ${0}px`,
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index e79d0a76d..01a8da313 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -9,7 +9,7 @@ import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, DateCast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types';
+import { BoolCast, Cast, DateCast, DocCast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types';
import { WebField } from '../../../fields/URLField';
import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
import { GestureUtils } from '../../../pen-gestures/GestureUtils';
@@ -356,12 +356,16 @@ export function CollectionSubView<X>() {
return !!added;
}
if (de.complete.annoDragData) {
- const dropCreator = de.complete.annoDragData.dropDocCreator;
- de.complete.annoDragData.dropDocCreator = () => {
- const dropped = dropCreator(this._props.isAnnotationOverlay ? this.Document : undefined);
- this.addDocument(dropped);
- return dropped;
- };
+ if (![de.complete.annoDragData.dragDocument.embedContainer, de.complete.annoDragData.dragDocument].includes(this.Document)) {
+ de.complete.annoDragData.dropDocCreator = () => this.getAnchor?.(true) || this.Document;
+ } else {
+ const dropCreator = de.complete.annoDragData.dropDocCreator;
+ de.complete.annoDragData.dropDocCreator = () => {
+ const dropped = dropCreator(this._props.isAnnotationOverlay ? this.Document : undefined);
+ this.addDocument(dropped);
+ return dropped;
+ };
+ }
return true;
}
return false;
@@ -415,7 +419,7 @@ export function CollectionSubView<X>() {
const tags = html.split('<');
if (tags[0] === '') tags.splice(0, 1);
let img = tags[0].startsWith('img') ? tags[0] : tags.length > 1 && tags[1].startsWith('img') ? tags[1] : '';
- const cors = img.includes('corsProxy') ? img.match(/http.*corsProxy\//)![0] : '';
+ const cors = img.includes('corsproxy') ? img.match(/http.*corsproxy\//)![0] : '';
img = cors ? img.replace(cors, '') : img;
if (img) {
const imgSrc = img.split('src="')[1].split('"')[0];
@@ -561,7 +565,17 @@ export function CollectionSubView<X>() {
}
const loading = Docs.Create.LoadingDocument(file, options);
Doc.addCurrentlyLoading(loading);
- DocUtils.uploadFileToDoc(file, {}, loading);
+ DocUtils.uploadFileToDoc(file, {}, loading).then(d => {
+ if (d && d?.type === DocumentType.IMG) {
+ const imgTemplate = DocCast(Doc.UserDoc().defaultImageLayout);
+ if (imgTemplate) {
+ const templateFieldKey = StrCast(imgTemplate.title);
+ d.layout_fieldKey = templateFieldKey;
+ d[templateFieldKey] = imgTemplate;
+ }
+ }
+ });
+
return loading;
})
))
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 4348bc7dc..c4373aaa7 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -163,8 +163,8 @@ export class TabMinimapView extends ObservableReactComponent<TabMinimapViewProps
childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyFilter}
searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
fitContentsToBox={returnTrue}
- xPadding={this.xPadding}
- yPadding={this.yPadding}
+ xMargin={this.xPadding}
+ yMargin={this.yPadding}
/>
<div className="miniOverlay" onPointerDown={this.miniDown}>
<TabMiniThumb miniLeft={miniLeft} miniTop={miniTop} miniWidth={miniWidth} miniHeight={miniHeight} />
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index fb2d0955f..5b2f1ff81 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1042,8 +1042,8 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
disableBrushing={this.treeView._props.disableBrushing}
hideLinkButton={BoolCast(this.treeView.Document.childHideLinkButton)}
dontRegisterView={BoolCast(this.treeView.Document.childDontRegisterViews, this._props.dontRegisterView)}
- xPadding={NumCast(this.treeView.Document.childXPadding, this.treeView._props.childXPadding)}
- yPadding={NumCast(this.treeView.Document.childYPadding, this.treeView._props.childYPadding)}
+ xMargin={NumCast(this.treeView.Document.childXPadding, this.treeView._props.childXPadding)}
+ yMargin={NumCast(this.treeView.Document.childYPadding, this.treeView._props.childYPadding)}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
@@ -1148,8 +1148,8 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
moveDocument={this.move}
removeDocument={this._props.removeDoc}
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
- xPadding={NumCast(this.treeView.Document.childXPadding, this.treeView._props.childXPadding)}
- yPadding={NumCast(this.treeView.Document.childYPadding, this.treeView._props.childYPadding)}
+ xMargin={NumCast(this.treeView.Document.childXPadding, this.treeView._props.childXPadding)}
+ yMargin={NumCast(this.treeView.Document.childYPadding, this.treeView._props.childYPadding)}
addDocTab={this._props.addDocTab}
pinToPres={this.treeView._props.pinToPres}
disableBrushing={this.treeView._props.disableBrushing}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 93314e383..5bbe93a90 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -258,8 +258,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
override contentBounds = () => {
const { x, y, r, b } = aggregateBounds(
this._layoutElements.filter(e => e.bounds?.width && !e.bounds.z).map(e => e.bounds!),
- NumCast(this.layoutDoc._xPadding, NumCast(this.layoutDoc._xMargin, this._props.xPadding ?? 0)),
- NumCast(this.layoutDoc._yPadding, NumCast(this.layoutDoc._yMargin, this._props.yPadding ?? 0))
+ NumCast(this.layoutDoc._xMargin, this._props.xMargin ?? 0),
+ NumCast(this.layoutDoc._yMargin, this._props.yMargin ?? 0)
);
const [width, height] = [r - x, b - y];
return {
@@ -1261,15 +1261,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
/**
* Adds the created drawing to the freeform canvas and sets the metadata.
*/
- addDrawing = (doc: Doc, opts: DrawingOptions, gptRes: string, x?: number, y?: number) => {
- doc.$title = opts.text;
- doc.$width = opts.size;
- doc.$ai_drawing_input = opts.text;
- doc.$ai_drawing_complexity = opts.complexity;
- doc.$ai_drawing_colored = opts.autoColor;
- doc.$ai_drawing_size = opts.size;
- doc.$ai_drawing_data = gptRes;
- doc.$ai = 'gpt';
+ addDrawing = (doc: Doc, opts: DrawingOptions, x?: number, y?: number) => {
+ doc.$ai_prompt = opts.text;
this._drawingContainer = doc;
if (x !== undefined && y !== undefined) {
[doc.x, doc.y] = this.screenToFreeformContentsXf.transformPoint(x, y);
@@ -1815,7 +1808,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
() => {
if (this.Document.isGroup && this.childDocs.length === this.childDocList?.length) {
const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: NumCast(cd._width), height: NumCast(cd._height) }));
- return aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding));
+ return aggregateBounds(clist, NumCast(this.layoutDoc._xMargin), NumCast(this.layoutDoc._yMargin));
}
return undefined;
},
@@ -2017,7 +2010,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
event: action(() => {
SmartDrawHandler.Instance.AddDrawing = this.addDrawing;
SmartDrawHandler.Instance.RemoveDrawing = this.removeDrawing;
- !SmartDrawHandler.Instance.ShowRegenerate ? SmartDrawHandler.Instance.displayRegenerate(this._downX, this._downY - 10) : SmartDrawHandler.Instance.hideRegenerate();
+ !SmartDrawHandler.Instance.ShowRegenerate ? SmartDrawHandler.Instance.displayRegenerate(this._downX, this._downY - 10, NumCast(this.layoutDoc[this.scaleFieldKey])) : SmartDrawHandler.Instance.hideRegenerate();
}),
icon: 'pen-to-square',
});
@@ -2222,9 +2215,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
placeholder={this._drawingFillInput || StrCast(this.Document.title) || 'Describe image'}
type="text"
value={this._drawingFillInput}
- onChange={action(e => {
- this._drawingFillInput = e.target.value;
- })}
+ onChange={action(e => (this._drawingFillInput = e.target.value))}
/>
<div className="collectionFreeFormView-aiView-strength">
<span className="collectionFreeFormView-aiView-similarity">Similarity</span>
@@ -2253,11 +2244,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
onClick={undoable(
action(() => {
this._drawingFillLoading = true;
- DrawingFillHandler.drawingToImage(this.props.Document, this._fireflyRefStrength, this._drawingFillInput || StrCast(this.Document.title))?.then(
- action(() => {
- this._drawingFillLoading = false;
- })
- );
+ DrawingFillHandler.drawingToImage(this.props.Document, this._fireflyRefStrength, this._drawingFillInput || StrCast(this.Document.title))?.then(action(() => (this._drawingFillLoading = false)));
}),
'create image'
)}
@@ -2265,37 +2252,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
</div>
</div>
</div>
- <div className="collectionfreeformview-aiView-regenerate-container">
- <span className="collectionfreeformview-aiView-subtitle">Regenerate</span>
- <div className="collectionfreeformview-aiView-regenerate">
- <input
- className="collectionfreeformview-aiView-input"
- aria-label="Edit instructions input"
- type="text"
- value={this._regenInput}
- onChange={action(e => {
- this._regenInput = e.target.value;
- })}
- placeholder="..under development.."
- />
- <div className="collectionFreeFormView-aiView-regenBtn">
- <Button
- text="Regenerate"
- type={Type.SEC}
- icon={this._regenLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
- iconPlacement="right"
- // onClick={action(async () => {
- // this._regenLoading = true;
- // SmartDrawHandler.Instance.CreateDrawingDoc = this.createDrawingDoc;
- // SmartDrawHandler.Instance.AddDrawing = this.addDrawing;
- // SmartDrawHandler.Instance.RemoveDrawing = this.removeDrawing;
- // await SmartDrawHandler.Instance.regenerate([this.Document], undefined, undefined, this._regenInput, true);
- // this._regenLoading = false;
- // })}
- />
- </div>
- </div>
- </div>
</div>
);
};
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 1d5e70be7..b837b3a86 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -58,7 +58,7 @@ export class CollectionGridView extends CollectionSubView() {
return NumCast(this.layoutDoc._xMargin, Math.max(3, 0.05 * this._props.PanelWidth()));
}
@computed get yMargin() {
- return this._props.yPadding || NumCast(this.layoutDoc._yMargin, Math.min(5, 0.05 * this._props.PanelWidth()));
+ return this._props.yMargin || NumCast(this.layoutDoc._yMargin, Math.min(5, 0.05 * this._props.PanelWidth()));
}
@computed get gridGap() {
return NumCast(this.Document._gridGap, 10);
@@ -206,7 +206,7 @@ export class CollectionGridView extends CollectionSubView() {
setContentViewBox={emptyFunction}
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
onClickScript={this.onChildClickHandler}
- dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'x' | 'y' | 'xy'}
+ dontCenter={StrCast(this.layoutDoc.layout_dontCenter, StrCast(childLayout.layout_dontCenter)) as 'x' | 'y' | 'xy'}
showTags={BoolCast(this.layoutDoc.showChildTags) || BoolCast(this.Document._layout_showTags)}
/>
);
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 3c2a99b1e..d0a1e6f0d 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -27,7 +27,7 @@ import './CollectionLinearView.scss';
/**
* CollectionLinearView is the class for rendering the horizontal collection
* of documents, it useful for horizontal menus. It can either be expandable
- * or not using the linearView_Expandable field.
+ * or not using the linearView_expandable field.
* It is used in the following locations:
* - It is used in the popup menu on the bottom left (see docButtons() in MainView.tsx)
* - It is used for the context sensitive toolbar at the top (see contMenuButtons() in CollectionMenu.tsx)
@@ -52,7 +52,7 @@ export class CollectionLinearView extends CollectionSubView() {
componentDidMount() {
this._widthDisposer = reaction(
- () => 5 + NumCast(this.dataDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearView_IsOpen ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (NumCast(doc._width) || this.dimension()) + tot + 4, 0) : 0),
+ () => 5 + NumCast(this.dataDoc.linearView_btnWidth, this.dimension()) + (this.layoutDoc.linearView_isOpen ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (NumCast(doc._width) || this.dimension()) + tot + 4, 0) : 0),
width => {
this.childDocs.length && (this.layoutDoc._width = width);
},
@@ -208,7 +208,7 @@ export class CollectionLinearView extends CollectionSubView() {
render() {
const flexDir = StrCast(this.Document.flexDirection); // Specify direction of linear view content
const flexGap = NumCast(this.Document.flexGap); // Specify the gap between linear view content
- const isExpanded = BoolCast(this.layoutDoc.linearView_IsOpen);
+ const isExpanded = BoolCast(this.layoutDoc.linearView_isOpen);
const menuOpener = (
<Toggle
@@ -219,9 +219,9 @@ export class CollectionLinearView extends CollectionSubView() {
type={Type.TERT}
onPointerDown={e => e.stopPropagation()}
toggleType={ToggleType.BUTTON}
- toggleStatus={BoolCast(this.layoutDoc.linearView_IsOpen)}
+ toggleStatus={BoolCast(this.layoutDoc.linearView_isOpen)}
onClick={() => {
- this.layoutDoc.linearView_IsOpen = !isExpanded;
+ this.layoutDoc.linearView_isOpen = !isExpanded;
ScriptCast(this.Document.onClick)?.script.run({ this: this.Document }, console.log);
}}
tooltip={isExpanded ? 'Close' : 'Open'}
@@ -231,10 +231,10 @@ export class CollectionLinearView extends CollectionSubView() {
);
return (
- <div className={`collectionLinearView-outer ${this.layoutDoc.linearView_SubMenu}`} style={{ backgroundColor: this.layoutDoc.linearView_IsOpen ? undefined : 'transparent' }}>
+ <div className="collectionLinearView-outer" style={{ backgroundColor: this.layoutDoc.linearView_isOpen ? undefined : 'transparent' }}>
<div className="collectionLinearView" ref={this.createDashEventsTarget} onContextMenu={this.myContextMenu} style={{ minHeight: this.dimension(), pointerEvents: 'all' }}>
- {!this.layoutDoc.linearView_Expandable ? null : menuOpener}
- {!this.layoutDoc.linearView_IsOpen ? null : (
+ {!this.layoutDoc.linearView_expandable ? null : menuOpener}
+ {!this.layoutDoc.linearView_isOpen && this.layoutDoc.linearView_expandable ? null : (
<div
className="collectionLinearView-content"
style={{
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index c06391f35..6442385c0 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -359,7 +359,7 @@ export class CollectionSchemaView extends CollectionSubView() {
@action
addNewKey = (key: string, defaultVal: FieldType | undefined) => {
this.childDocs.forEach(doc => {
- doc[DocData][key] = defaultVal;
+ if (doc[DocData][key] === undefined) doc[DocData][key] = defaultVal;
});
};
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 16d33eb93..134f2ed31 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -115,12 +115,11 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
};
const readOnly = this.getFinfo(fieldKey)?.readOnly ?? false;
const cursor = !readOnly ? 'text' : 'default';
- const pointerEvents: 'all' | 'none' = 'all';
- return { color, fieldProps, cursor, pointerEvents };
+ return { color, fieldProps, cursor };
};
@computed get editableView() {
- const { color, fieldProps, pointerEvents } = this.renderProps(this._props);
+ const { color, fieldProps } = this.renderProps(this._props);
return (
<div
@@ -132,7 +131,6 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
style={{
color,
width: '100%',
- pointerEvents,
}}>
<EditableView
ref={r => {
@@ -232,6 +230,7 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
className="schema-column-header"
style={{
width: this._props.columnWidths[this._props.columnIndex],
+ pointerEvents: this.props.isContentActive() ? undefined : 'none',
}}
onPointerEnter={() => {
this.handlePointerEnter();
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index f4beb1004..cb3adae10 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -156,6 +156,11 @@ ScriptingGlobals.add(function setDefaultTemplate(checkResult?: boolean) {
});
// toggle: Set overlay status of selected document
// eslint-disable-next-line prefer-arrow-callback
+ScriptingGlobals.add(function setDefaultImageTemplate(checkResult?: boolean) {
+ return DocumentView.setDefaultImageTemplate(checkResult);
+});
+// toggle: Set overlay status of selected document
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function setHeaderColor(color?: string, checkResult?: boolean) {
if (checkResult) {
return DocumentView.Selected().length ? StrCast(DocumentView.SelectedDocs().lastElement().layout_headingColor) : Doc.SharingDoc()?.headingColor;
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 940c4cb99..3805b0dca 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -148,7 +148,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
public static getValues(doc: Doc, time: number, fillIn: boolean = true) {
return CollectionFreeFormDocumentView.animFields.reduce(
(p, val) => {
- p[val.key] = Cast(doc[`${val.key}_indexed`], listSpec('number'), fillIn ? [NumCast(doc[val.key], val.val)] : []).reduce(
+ p[val.key] = Cast(doc[`${val.key}_indexed`], listSpec('number'), fillIn ? [NumCast(doc[val.key], val.val)] : [])!.reduce(
(prev, v, i) => ((i <= Math.round(time) && v !== undefined) || prev === undefined ? v : prev),
undefined as unknown as number
);
@@ -161,7 +161,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
public static getStringValues(doc: Doc, time: number) {
return CollectionFreeFormDocumentView.animStringFields.reduce(
(p, val) => {
- p[val] = Cast(doc[`${val}_indexed`], listSpec('string'), [StrCast(doc[val])]).reduce((prev, v, i) => ((i <= Math.round(time) && v !== undefined) || prev === undefined ? v : prev), undefined as unknown as string);
+ p[val] = Cast(doc[`${val}_indexed`], listSpec('string'), [StrCast(doc[val])])!.reduce((prev, v, i) => ((i <= Math.round(time) && v !== undefined) || prev === undefined ? v : prev), undefined as unknown as string);
return p;
},
{} as { [val: string]: Opt<string> }
@@ -171,7 +171,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
public static setStringValues(time: number, d: Doc, vals: { [val: string]: Opt<string> }) {
const timecode = Math.round(time);
Object.keys(vals).forEach(val => {
- const findexed = Cast(d[`${val}_indexed`], listSpec('string'), []).slice();
+ const findexed = Cast(d[`${val}_indexed`], listSpec('string'), [])!.slice();
findexed[timecode] = vals[val] || '';
d[`${val}_indexed`] = new List<string>(findexed);
});
@@ -180,7 +180,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
public static setValues(time: number, d: Doc, vals: { [val: string]: Opt<number> }) {
const timecode = Math.round(time);
Object.keys(vals).forEach(val => {
- const findexed = Cast(d[`${val}_indexed`], listSpec('number'), []).slice();
+ const findexed = Cast(d[`${val}_indexed`], listSpec('number'), [])!.slice();
findexed[timecode] = vals[val] as unknown as number;
d[`${val}_indexed`] = new List<number>(findexed);
});
@@ -204,15 +204,15 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
docs.forEach(doc => {
this.animFields.forEach(val => {
const findexed = Cast(doc[`${val.key}_indexed`], listSpec('number'), null);
- findexed?.length <= timecode + 1 && findexed.push(undefined as unknown as number);
+ (findexed?.length ?? 0) <= timecode + 1 && findexed?.push(undefined as unknown as number);
});
this.animStringFields.forEach(val => {
const findexed = Cast(doc[`${val}_indexed`], listSpec('string'), null);
- findexed?.length <= timecode + 1 && findexed.push(undefined as unknown as string);
+ (findexed?.length ?? 0) <= timecode + 1 && findexed?.push(undefined as unknown as string);
});
this.animDataFields(doc).forEach(val => {
const findexed = Cast(doc[`${val}_indexed`], listSpec(InkField), null);
- findexed?.length <= timecode + 1 && findexed.push(undefined as unknown as InkField);
+ (findexed?.length ?? 0) <= timecode + 1 && findexed?.push(undefined as unknown as InkField);
});
});
return newTimer;
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 5ac66f2cd..c4351a200 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -119,6 +119,7 @@
display: flex;
justify-content: center;
align-items: center;
+ margin: auto;
position: relative; // allows contents to be positioned relative/below title
> .formattedTextBox {
position: absolute; // position a child text box
@@ -302,6 +303,6 @@
background: transparent;
.documentView-editorView-resizer {
- height: 5px;
+ height: 2px;
}
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 284014e54..05706fe6b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -648,11 +648,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewProps & Field
rootSelected = () => this._rootSelected;
panelHeight = () => this._props.PanelHeight() - this.headerMargin - 2 * NumCast(this.Document.borderWidth);
- screenToLocalContent = () =>
- this._props
- .ScreenToLocalTransform()
- .translate(-NumCast(this.Document.borderWidth), -this.headerMargin - NumCast(this.Document.borderWidth))
- .scale(this.viewingAiEditor() ? (this._props.PanelHeight() || 1) / this.aiContentsHeight() : 1);
+ aiShift = () => (!this.viewingAiEditor() ? 0 : (this._props.PanelWidth() - this.aiContentsWidth()) / 2);
+ aiScale = () => (this.viewingAiEditor() ? (this._props.PanelHeight() || 1) / this.aiContentsHeight() : 1);
onClickFunc = () => (this.disableClickScriptFunc ? undefined : this.onClickHdlr);
setHeight = (height: number) => { !this._props.suppressSetHeight && (this.layoutDoc._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), height + 2 * NumCast(this.Document.borderWidth))); } // prettier-ignore
setContentView = action((view: ViewBoxInterface<FieldViewProps>) => (this._componentView = view));
@@ -678,7 +675,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewProps & Field
return this._props.styleProvider?.(doc, props, property);
};
- @observable _aiWinHeight = 88;
+ @observable _aiWinHeight = 32;
TagsBtnHeight = 22;
@computed get currentScale() {
@@ -703,33 +700,21 @@ export class DocumentViewInternal extends DocComponent<DocumentViewProps & Field
@computed get uiBtnScaling() { return Math.max(this.maxWidgetSize / this.TagsBtnHeight, 1) * Math.min(1, this.viewScaling); } // prettier-ignore
aiContentsWidth = () => (this.aiContentsHeight() * (this._props.NativeWidth?.() || 1)) / (this._props.NativeHeight?.() || 1);
- aiContentsHeight = () => Math.max(10, this._props.PanelHeight() - this._aiWinHeight * this.uiBtnScaling);
+ aiContentsHeight = () => Math.max(10, this._props.PanelHeight() - (this._aiWinHeight + (this.tagsOverlayFunc() ? 22 : 0)) * this.uiBtnScaling);
@computed get aiEditor() {
return (
- <>
- <div
- className="documentView-editorView-history"
- ref={r => this.historyRef(this._oldAiWheel, (this._oldAiWheel = r))}
- style={{
- transform: `scale(${this.uiBtnScaling})`,
- height: this.aiContentsHeight() / this.uiBtnScaling,
- width: ((this._props.PanelWidth() - this.aiContentsWidth()) * 0.95) / this.uiBtnScaling,
- }}>
- {this._componentView?.componentAIViewHistory?.() ?? null}
- </div>
- <div
- className="documentView-editorView"
- style={{
- background: SnappingManager.userVariantColor,
- width: `${100 / this.uiBtnScaling}%`, //
- transform: `scale(${this.uiBtnScaling})`,
- }}
- ref={r => this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}>
- <div className="documentView-editorView-resizer" />
- {this._componentView?.componentAIView?.() ?? null}
- {this._props.DocumentView?.() ? <TagsView background={this.backgroundBoxColor} Views={[this._props.DocumentView?.()]} /> : null}
- </div>
- </>
+ <div
+ className="documentView-editorView"
+ style={{
+ background: SnappingManager.userVariantColor,
+ width: `${100 / this.uiBtnScaling}%`, //
+ transform: `scale(${this.uiBtnScaling})`,
+ }}
+ ref={r => this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}>
+ <div className="documentView-editorView-resizer" />
+ {this._componentView?.componentAIView?.() ?? null}
+ {this._props.DocumentView?.() ? <TagsView background={this.backgroundBoxColor} Views={[this._props.DocumentView?.()]} /> : null}
+ </div>
);
}
@computed get tagsOverlay() {
@@ -755,7 +740,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewProps & Field
}
widgetOverlayFunc = () => (this.widgetDecorations ? this.widgetOverlay : null);
viewingAiEditor = () => (this._props.showAIEditor && this._componentView?.componentAIView?.() !== undefined ? this.aiEditor : null);
- _contentsRef = React.createRef<DocumentContentsView>();
+ @observable _contentsRef: DocumentContentsView | undefined = undefined;
@computed get viewBoxContents() {
TraceMobx();
const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString;
@@ -771,7 +756,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewProps & Field
}}>
<DocumentContentsView
{...this._props}
- ref={this._contentsRef}
+ ref={action((r: DocumentContentsView) => (this._contentsRef = r))}
layoutFieldKey={StrCast(this.Document.layout_fieldKey, 'layout')}
pointerEvents={this.contentPointerEvents}
setContentViewBox={this.setContentView}
@@ -780,7 +765,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewProps & Field
PanelHeight={this.viewingAiEditor() ? this.aiContentsHeight : this.panelHeight}
setHeight={this.setHeight}
isContentActive={this.isContentActive}
- ScreenToLocalTransform={this.screenToLocalContent}
rootSelected={this.rootSelected}
onClickScript={this.onClickFunc}
setTitleFocus={this.setTitleFocus}
@@ -913,8 +897,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewProps & Field
}}>
<FormattedTextBox
{...this._props}
- yPadding={10}
- xPadding={10}
+ yMargin={10}
+ xMargin={10}
fieldKey={this.showCaption}
styleProvider={this.captionStyleProvider}
dontRegisterView
@@ -1184,7 +1168,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
* @returns boolean whether sub-component Doc is in synch with the layoutDoc that this view thinks its rendering
*/
IsInvalid = (renderDoc?: Doc): boolean => {
- const docContents = this._docViewInternal?._contentsRef.current;
+ const docContents = this._docViewInternal?._contentsRef;
return !(
(!renderDoc ||
(docContents?.layoutDoc === renderDoc && //
@@ -1291,7 +1275,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
if (this.ComponentView?.screenBounds?.()) {
return this.ComponentView.screenBounds();
}
- const xf = this.screenToContentsTransform().scale(this.nativeScaling).inverse();
+ const xf = this.screenToContentBoundsTransform().inverse();
const [[left, top], [right, bottom]] = [xf.transformPoint(0, 0), xf.transformPoint(this.panelWidth, this.panelHeight)];
// transition is returned so that the bounds will 'update' at the end of an animated transition. This is needed by xAnchor in LinkBox
@@ -1405,28 +1389,36 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
custom && DocUtils.makeCustomViewClicked(this.Document, Docs.Create.StackingDocument, layout, undefined);
}, 'set custom view');
- public static setDefaultTemplate(checkResult?: boolean) {
- if (checkResult) {
- return Doc.UserDoc().defaultTextLayout;
+ private static getTemplate(view: DocumentView | undefined) {
+ if (view) {
+ if (!view.layoutDoc.isTemplateDoc) {
+ MakeTemplate(view.Document);
+ Doc.AddDocToList(Doc.UserDoc(), 'template_user', view.Document);
+ Doc.AddDocToList(DocListCast(Doc.MyTools?.data)[1], 'data', makeUserTemplateButtonOrImage(view.Document));
+ DocCast(Doc.UserDoc().template_user) && view.Document && Doc.AddDocToList(DocCast(Doc.UserDoc().template_user)!, 'data', view.Document);
+ return view.Document;
+ }
+ return DocCast(Doc.LayoutField(view.Document)) ?? view.Document;
}
+ }
+ public static setDefaultTemplate(checkResult?: boolean) {
+ if (checkResult) return Doc.UserDoc().defaultTextLayout;
const view = DocumentView.Selected()[0]?._props.renderDepth > 0 ? DocumentView.Selected()[0] : undefined;
undoable(() => {
- let tempDoc: Opt<Doc>;
- if (view) {
- if (!view.layoutDoc.isTemplateDoc) {
- tempDoc = view.Document;
- MakeTemplate(tempDoc);
- Doc.AddDocToList(Doc.UserDoc(), 'template_user', tempDoc);
- Doc.AddDocToList(DocListCast(Doc.MyTools?.data)[1], 'data', makeUserTemplateButtonOrImage(tempDoc));
- DocCast(Doc.UserDoc().template_user) && tempDoc && Doc.AddDocToList(DocCast(Doc.UserDoc().template_user)!, 'data', tempDoc);
- } else {
- tempDoc = DocCast(Doc.LayoutField(view.Document));
- }
- }
+ const tempDoc = DocumentView.getTemplate(view);
Doc.UserDoc().defaultTextLayout = tempDoc ? new PrefetchProxy(tempDoc) : undefined;
}, 'set default template')();
return undefined;
}
+ public static setDefaultImageTemplate(checkResult?: boolean) {
+ if (checkResult) return Doc.UserDoc().defaultImageLayout;
+ const view = DocumentView.Selected()[0]?._props.renderDepth > 0 ? DocumentView.Selected()[0] : undefined;
+ undoable(() => {
+ const tempDoc = DocumentView.getTemplate(view);
+ Doc.UserDoc().defaultImageLayout = tempDoc ? new PrefetchProxy(tempDoc) : undefined;
+ }, 'set default image template')();
+ return undefined;
+ }
/**
* This switches between the current view of a Doc and a specified alternate layout view.
@@ -1498,17 +1490,22 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
isHovering = () => this._isHovering;
selfView = () => this;
/**
- * @returns Transform to the document view (in the coordinate system of whatever contains the DocumentView)
+ * @returns Transform to the document view's available panel space (in the coordinate system of whatever contains the DocumentView)
*/
screenToViewTransform = () => this._props.ScreenToLocalTransform();
/**
+ * @returns Transform to the document view after centering in available panel space(in the coordinate system of whatever contains the DocumentView)
+ */
+ private screenToContentBoundsTransform = () => this.screenToViewTransform().translate(-this.centeringX, -this.centeringY);
+ /**
* @returns Transform to the coordinate system of the contents of the document view (includes native dimension scaling and centering)
*/
screenToContentsTransform = () =>
this._props
.ScreenToLocalTransform()
.translate(-this.centeringX, -this.centeringY)
- .scale(1 / this.nativeScaling);
+ .translate(-(this._docViewInternal?.aiShift() ?? 0), 0)
+ .scale((this._docViewInternal?.aiScale() ?? 1) / this.nativeScaling);
htmlOverlay = () => {
const effect = StrCast(this._htmlOverlayEffect?.presentation_effect, StrCast(this._htmlOverlayEffect?.followLinkAnimEffect));
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index a6872f8dc..f6b405a43 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -52,8 +52,8 @@ export interface FieldViewSharedProps {
renderDepth: number;
scriptContext?: unknown; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document
screenXPadding?: (view: DocumentView | undefined) => number; // padding in screen space coordinates (used by text box to reflow around UI buttons in carouselView)
- xPadding?: number;
- yPadding?: number;
+ xMargin?: number;
+ yMargin?: number;
dontRegisterView?: boolean;
dropAction?: dropActionType;
dragAction?: dropActionType;
diff --git a/src/client/views/nodes/IconTagBox.tsx b/src/client/views/nodes/IconTagBox.tsx
index 0bbd6a0d3..d04ec3a10 100644
--- a/src/client/views/nodes/IconTagBox.tsx
+++ b/src/client/views/nodes/IconTagBox.tsx
@@ -58,16 +58,20 @@ export class IconTagBox extends ObservableReactComponent<IconTagProps> {
const tag = StrCast(key.toolType);
const color = dv._props.styleProvider?.(dv.layoutDoc, dv.ComponentView?._props, StyleProp.FontColor) as string;
return (
- <Toggle
- tooltip={`Click to add/remove the tag ${tag}`}
- toggleStatus={TagItem.docHasTag(dv.Document, tag)}
- toggleType={ToggleType.BUTTON}
- icon={<FontAwesomeIcon className={`fontIconBox-icon-${ToggleType.BUTTON}`} icon={icon} color={color} />}
- size={Size.XSMALL}
- type={Type.PRIM}
- onClick={() => this.setIconTag(tag, !TagItem.docHasTag(this.View.Document, tag))}
- color={color}
- />
+ <div>
+ {' '}
+ {/* tooltips require the wrapped item to be an element ref */}
+ <Toggle
+ tooltip={`Click to add/remove the tag ${tag}`}
+ toggleStatus={TagItem.docHasTag(dv.Document, tag)}
+ toggleType={ToggleType.BUTTON}
+ icon={<FontAwesomeIcon className={`fontIconBox-icon-${ToggleType.BUTTON}`} icon={icon} color={color} />}
+ size={Size.XSMALL}
+ type={Type.PRIM}
+ onClick={() => this.setIconTag(tag, !TagItem.docHasTag(this.View.Document, tag))}
+ color={color}
+ />
+ </div>
);
};
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 9f7a5d03f..5a6292fab 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -236,7 +236,7 @@
.imageBox-aiView-input {
overflow: hidden;
text-overflow: ellipsis;
- max-width: 65%;
+ max-width: 80%;
width: 100%;
color: black;
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index d16baada6..f7ad5c7e2 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,6 +1,6 @@
-import { Button, Colors, EditableText, IconButton, Size, Toggle, ToggleType, Type } from '@dash/components';
+import { Button, Colors, EditableText, IconButton, NumberDropdown, Size, Toggle, ToggleType, Type } from '@dash/components';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Slider, Tooltip } from '@mui/material';
+import { Tooltip } from '@mui/material';
import axios from 'axios';
import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
@@ -37,7 +37,6 @@ 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 { SmartDrawHandler } from '../smartdraw/SmartDrawHandler';
import { StickerPalette } from '../smartdraw/StickerPalette';
import { StyleProp } from '../StyleProp';
@@ -102,7 +101,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@observable private _regenInput = '';
@observable private _canInteract = true;
@observable private _regenerateLoading = false;
- @observable private _prevImgs: FireflyImageData[] = StrCast(this.Document.ai_firefly_history) ? JSON.parse(StrCast(this.Document.ai_firefly_history)) : [];
// Add these observable properties to the ImageBox class
@observable private _outpaintingInProgress = false;
@@ -154,7 +152,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._disposers.path = reaction(
() => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width), height: this.layoutDoc._height }),
({ nativeSize, width, height }) => {
- if (!this.layoutDoc._layout_nativeDimEditable || !height) {
+ if (!this.layoutDoc._layout_nativeDimEditable || !height || this.layoutDoc.layout_resetNativeDim) {
+ this.layoutDoc.layout_resetNativeDim = undefined; // template images need to reset their dimensions when they are rendered with content. afterwards, remove this flag.
this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
}
},
@@ -227,7 +226,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const drag = de.complete.docDragData.draggedDocuments.lastElement();
const dragField = drag[Doc.LayoutDataKey(drag)];
const descText = RTFCast(dragField)?.Text || StrCast(dragField) || RTFCast(drag.text)?.Text || StrCast(drag.text) || StrCast(this.Document.title);
- const oldPrompt = StrCast(this.Document.ai_firefly_prompt, StrCast(this.Document.title));
+ const oldPrompt = StrCast(this.Document.ai_prompt, StrCast(this.Document.title));
const newPrompt = (text: string) => (oldPrompt ? `${oldPrompt} ~~~ ${text}` : text);
DrawingFillHandler.drawingToImage(this.Document, 90, newPrompt(descText), drag)?.then(action(() => (this._regenerateLoading = false)));
added = false;
@@ -737,9 +736,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
<div
className="imageBox-regenerateDropTarget"
ref={this._regenerateIconRef}
- onClick={() => DocCast(this.Document.ai_firefly_generatedDocs) && DocumentView.showDocument(DocCast(this.Document.ai_firefly_generatedDocs)!, { openLocation: OpenWhere.addRight })}
+ onClick={() => DocCast(this.Document.ai_generatedDocs) && DocumentView.showDocument(DocCast(this.Document.ai_generatedDocs)!, { openLocation: OpenWhere.addRight })}
style={{
- display: (this._props.isContentActive() && (SnappingManager.CanEmbed || this.Document.ai_firefly_generatedDocs)) || this._regenerateLoading ? 'block' : 'none',
+ display: (this._props.isContentActive() && (SnappingManager.CanEmbed || this.Document.ai_generatedDocs)) || this._regenerateLoading ? 'block' : 'none',
transform: `scale(${this.uiBtnScaling})`,
width: this._sideBtnWidth,
height: this._sideBtnWidth,
@@ -845,34 +844,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@observable _filterFunc: ((doc: Doc) => boolean) | undefined = undefined;
@observable private _fireflyRefStrength = 0;
- componentAIViewHistory = () => (
- <div className="imageBox-aiView-history">
- <Button text="Clear History" type={Type.SEC} size={Size.XSMALL} />
- {this._prevImgs.map(img => (
- <div key={img.pathname}>
- <img
- className="imageBox-aiView-img"
- src={ClientUtils.prepend(img.pathname.replace(extname(img.pathname), '_s' + extname(img.pathname)))}
- onClick={() => {
- this.dataDoc[this.fieldKey] = new ImageField(img.pathname);
- this.dataDoc.ai_firefly_prompt = img.prompt;
- this.dataDoc.ai_firefly_seed = img.seed;
- }}
- />
- <span>{img.prompt}</span>
- </div>
- ))}
- </div>
- );
-
componentAIView = () => {
- const field = this.dataDoc[this.fieldKey] instanceof ImageField ? Cast(this.dataDoc[this.fieldKey], ImageField, null) : new ImageField(String(this.dataDoc[this.fieldKey]));
return (
<div className="imageBox-aiView">
<div className="imageBox-aiView-regenerate">
- <span className="imageBox-aiView-firefly" style={{ color: SnappingManager.userColor }}>
- Firefly:
- </span>
<input
style={{ color: SnappingManager.userColor, background: SnappingManager.userBackgroundColor }}
className="imageBox-aiView-input"
@@ -886,57 +861,39 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
<Button
text="Create"
type={Type.TERT}
+ size={Size.XSMALL}
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"
- onClick={action(async () => {
+ onClick={action(() => {
this._regenerateLoading = true;
- if (this._fireflyRefStrength) {
- DrawingFillHandler.drawingToImage(this.Document, this._fireflyRefStrength, this._regenInput || StrCast(this.Document.title))?.then(action(() => (this._regenerateLoading = false)));
- } else {
- SmartDrawHandler.Instance.regenerate([this.Document], undefined, undefined, this._regenInput || StrCast(this.Document.title), true).then(
- action(newImgs => {
- const firstImg = newImgs[0];
- if (isFireflyImageData(firstImg)) {
- const url = firstImg.pathname;
- const imgField = new ImageField(url);
- this._prevImgs.length === 0 &&
- this._prevImgs.push({ prompt: StrCast(this.dataDoc.ai_firefly_prompt), seed: this.dataDoc.ai_firefly_seed as number, href: this.paths.lastElement(), pathname: field?.url.pathname ?? '' });
- this._prevImgs.unshift({ prompt: firstImg.prompt, seed: firstImg.seed, pathname: url });
- this.dataDoc.ai_firefly_history = JSON.stringify(this._prevImgs);
- this.dataDoc.ai_firefly_prompt = firstImg.prompt;
- this.dataDoc[this.fieldKey] = imgField;
- this._regenerateLoading = false;
- this._regenInput = '';
- }
- })
- );
- }
+ DrawingFillHandler.drawingToImage(this.Document, this._fireflyRefStrength, this._regenInput || StrCast(this.Document.title))?.then(action(() => (this._regenerateLoading = false)));
})}
/>
</div>
- </div>
- <div className="imageBox-aiView-strength">
- <span className="imageBox-aiView-similarity" style={{ color: SnappingManager.userColor }}>
- Similarity
- </span>
- <Slider
- className="imageBox-aiView-slider"
- sx={{
- '& .MuiSlider-track': { color: SettingsManager.userColor },
- '& .MuiSlider-rail': { color: SettingsManager.userBackgroundColor },
- '& .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}
- step={1}
- size="small"
- value={this._fireflyRefStrength}
- onChange={action((e, val) => this._canInteract && (this._fireflyRefStrength = val as number))}
- valueLabelDisplay="auto"
- />
+ <div>
+ <NumberDropdown
+ color={SnappingManager.userColor}
+ background={SnappingManager.userBackgroundColor}
+ numberDropdownType="slider"
+ showPlusMinus={false}
+ formLabel="similarity"
+ tooltip="structure similarity of created images to current image"
+ type={Type.PRIM}
+ width={75}
+ min={0}
+ max={100}
+ number={this._fireflyRefStrength}
+ size={Size.XXSMALL}
+ setNumber={undoable(
+ action(val => this._canInteract && (this._fireflyRefStrength = val as number)),
+ `${this.Document.title} button set from list`
+ )}
+ fillWidth
+ />
+ </div>
</div>
</div>
);
@@ -1092,7 +1049,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
alert('Error uploading files - possibly due to unsupported file types');
} else {
this.dataDoc[this.fieldKey] = new ImageField(result.accessPaths.agnostic.client);
- !(result instanceof Error) && DocUtils.assignImageInfo(result, this.dataDoc);
+ !(result instanceof Error) && DocUtils.assignUploadInfo(result, this.dataDoc);
}
disposer();
} else {
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index b08ed84b7..4cbe01b82 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -27,7 +27,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
private dropDisposer?: DragManager.DragDropDisposer;
private _timeout: NodeJS.Timeout | undefined;
private _divRef: HTMLDivElement | null = null;
- private _reaction: IReactionDisposer | undefined;
+ private _disposers: { [key: string]: IReactionDisposer } = {};
constructor(props: FieldViewProps) {
super(props);
@@ -43,7 +43,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
componentDidMount() {
this._props.setContentViewBox?.(this);
- this._reaction = reaction(
+ this._disposers.active = reaction(
() => this.Title,
() => document.activeElement !== this._divRef && this._forceRerender++
);
@@ -51,7 +51,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
componentWillUnMount() {
this._timeout && clearTimeout(this._timeout);
this.setText(this._divRef?.innerText ?? '');
- this._reaction?.();
+ Object.values(this._disposers).forEach(disposer => disposer());
}
@observable _forceRerender = 0;
@@ -171,20 +171,21 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
render() {
TraceMobx();
const boxParams = this.fitTextToBox(undefined); // this causes mobx to trigger re-render when data changes
+ const [xmargin, ymargin] = [NumCast(this.layoutDoc._xMargin), NumCast(this.layoutDoc._uMargin)];
return (
<div className="labelBox-outerDiv" ref={this.createDropTarget} style={{ boxShadow: this.boxShadow }}>
<div
className="labelBox-mainButton"
style={{
backgroundColor: this.backgroundColor,
- color: StrCast(this.layoutDoc._text_fontColor, StrCast(this.layoutDoc._color)),
- fontFamily: StrCast(this.layoutDoc._text_fontFamily, StrCast(Doc.UserDoc().fontFamily)) || 'inherit',
+ color: StrCast(this.layoutDoc[`${this.fieldKey}_fontColor`], StrCast(this.layoutDoc._color)),
+ fontFamily: StrCast(this.layoutDoc[`${this.fieldKey}_fontFamily`], StrCast(Doc.UserDoc().fontFamily)) || 'inherit',
letterSpacing: StrCast(this.layoutDoc.letterSpacing),
- textTransform: StrCast(this.layoutDoc[this.fieldKey + '_transform']) as Property.TextTransform,
- paddingLeft: NumCast(this.layoutDoc._xPadding),
- paddingRight: NumCast(this.layoutDoc._xPadding),
- paddingTop: NumCast(this.layoutDoc._yPadding),
- paddingBottom: NumCast(this.layoutDoc._yPadding),
+ textTransform: StrCast(this.layoutDoc[`${this.fieldKey}_transform`]) as Property.TextTransform,
+ paddingLeft: xmargin,
+ paddingRight: xmargin,
+ paddingTop: ymargin,
+ paddingBottom: ymargin,
width: this._props.PanelWidth(),
height: this._props.PanelHeight(),
whiteSpace: boxParams.multiLine ? 'pre-wrap' : 'pre',
@@ -192,8 +193,8 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div
key={this._forceRerender}
style={{
- width: this._props.PanelWidth() - 2 * NumCast(this.layoutDoc._xPadding),
- height: this._props.PanelHeight() - 2 * NumCast(this.layoutDoc._yPadding),
+ width: this._props.PanelWidth() - 2 * xmargin,
+ height: this._props.PanelHeight() - 2 * ymargin,
outline: 'unset !important',
}}
onKeyDown={e => {
@@ -214,12 +215,14 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
this._divRef?.removeEventListener('focusout', this.keepFocus);
this._divRef?.addEventListener('focusout', this.keepFocus);
}}
- onBlur={() => {
+ onBlur={e => {
this._divRef?.removeEventListener('focusout', this.keepFocus);
this.setText(this._divRef?.innerText ?? '');
- RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined, undefined);
- FormattedTextBox.LiveTextUndo?.end();
- FormattedTextBox.LiveTextUndo = undefined;
+ if (!FormattedTextBox.tryKeepingFocus(e.relatedTarget, () => this._divRef?.focus())) {
+ RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined, undefined);
+ FormattedTextBox.LiveTextUndo?.end();
+ FormattedTextBox.LiveTextUndo = undefined;
+ }
}}
dangerouslySetInnerHTML={{
__html: `<span class="textFitted textFitAlignVert" style="display: inline-block; text-align: center; font-size: 100px; height: 0px;">${this.Title?.startsWith('#') ? '' : (this.Title ?? '')}</span>`,
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 83c44c80f..55e6d5596 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -557,8 +557,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
NativeHeight={this.sidebarNativeHeightFunc}
PanelHeight={this._props.PanelHeight}
PanelWidth={this.sidebarWidth}
- xPadding={0}
- yPadding={0}
+ xMargin={0}
+ yMargin={0}
viewField={this.SidebarKey}
isAnnotationOverlay={false}
originTopLeft
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 4f02d68d6..603dcad5c 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -335,8 +335,8 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
select={emptyFunction}
isContentActive={emptyFunction}
NativeDimScaling={returnOne}
- xPadding={25}
- yPadding={10}
+ xMargin={25}
+ yMargin={10}
whenChildContentsActiveChanged={emptyFunction}
removeDocument={returnFalse}
moveDocument={returnFalse}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 5603786f0..838dbea9d 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -454,7 +454,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
iframeDown = (e: PointerEvent) => {
this._textAnnotationCreator = undefined;
const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection();
- if (sel?.empty)
+ if (sel?.empty && !(e.target as any).textContent)
sel.empty(); // Chrome
else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox
@@ -509,10 +509,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
try {
href = iframe?.contentWindow?.location.href;
} catch {
- runInAction(() => this._warning++);
+ // runInAction(() => this._warning++);
href = undefined;
}
- let requrlraw = decodeURIComponent(href?.replace(ClientUtils.prepend('') + '/corsProxy/', '') ?? this._url.toString());
+ let requrlraw = decodeURIComponent(href?.replace(ClientUtils.prepend('') + '/corsproxy/', '') ?? this._url.toString());
if (requrlraw !== this._url.toString()) {
if (requrlraw.match(/q=.*&/)?.length && this._url.toString().match(/q=.*&/)?.length) {
const matches = requrlraw.match(/[^a-zA-z]q=[^&]*/g);
@@ -565,9 +565,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
'click',
undoable(
action((e: MouseEvent) => {
- let eleHref = '';
+ let eleHref = (e.target as any)?.outerHTML?.split('"="')[1]?.split('"')[0];
for (let ele = e.target as HTMLElement | Element | null; ele; ele = ele.parentElement) {
- if (ele instanceof HTMLAnchorElement) {
+ if ('href' in ele) {
eleHref = (typeof ele.href === 'string' ? ele.href : eleHref) || (ele.parentElement && 'href' in ele.parentElement ? (ele.parentElement.href as string) : eleHref);
}
}
@@ -576,7 +576,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const batch = UndoManager.StartBatch('webclick');
e.stopPropagation();
setTimeout(() => {
- this.setData(eleHref.replace(ClientUtils.prepend(''), origin));
+ const url = eleHref.replace(ClientUtils.prepend(''), origin);
+ this.setData(url);
batch.end();
});
if (this._outerRef.current) {
@@ -858,7 +859,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
);
}
if (field instanceof WebField) {
- const url = this.layoutDoc[this.fieldKey + '_useCors'] ? ClientUtils.CorsProxy(this._webUrl) : this._webUrl;
+ const url = this.layoutDoc[this.fieldKey + '_useCors'] ? '/corsproxy/' + this._webUrl : this._webUrl;
const scripts = this.dataDoc[this.fieldKey + '_allowScripts'] || this._webUrl.includes('wikipedia.org') || this._webUrl.includes('google.com') || this._webUrl.startsWith('https://bing');
// if (!scripts) console.log('No scripts for: ' + url);
return (
@@ -1074,15 +1075,15 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
childPointerEvents = () => (this._props.isContentActive() ? 'all' : undefined);
@computed get webpage() {
TraceMobx();
- const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
+ // const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as Property.PointerEvents | undefined);
- const scale = previewScale * (this._props.NativeDimScaling?.() || 1);
+ // const scale = previewScale * (this._props.NativeDimScaling?.() || 1);
return (
<div
className="webBox-outerContent"
ref={this._outerRef}
style={{
- height: `${100 / scale}%`,
+ height: '100%', //`${100 / scale}%`,
pointerEvents,
}}
// when active, block wheel events from propagating since they're handled by the iframe
@@ -1175,6 +1176,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
className="webBox-container"
style={{
width: `calc(${100 / scale}% - ${!this.SidebarShown ? 0 : ((this.sidebarWidth() - WebBox.sidebarResizerWidth) / scale) * (this._previewWidth ? scale : 1)}px)`,
+ height: `${100 / scale}%`,
transform: `scale(${scale})`,
pointerEvents,
}}
diff --git a/src/client/views/nodes/WebBoxRenderer.js b/src/client/views/nodes/WebBoxRenderer.js
index b727107a9..ef465c453 100644
--- a/src/client/views/nodes/WebBoxRenderer.js
+++ b/src/client/views/nodes/WebBoxRenderer.js
@@ -21,7 +21,7 @@ const ForeignHtmlRenderer = function (styleSheets) {
return window.location.origin + extension;
}
function CorsProxy(url) {
- return prepend('/corsProxy/') + encodeURIComponent(url);
+ return prepend('/corsproxy/') + encodeURIComponent(url);
}
/**
*
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index c51f6c38b..57720baae 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1164,7 +1164,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
};
@computed get tagsHeight() {
- return this.DocumentView?.().showTags ? Math.max(0, 20 - Math.max(this._props.yPadding ?? 0, NumCast(this.layoutDoc._yMargin))) * this.ScreenToLocalBoxXf().Scale : 0;
+ return this.DocumentView?.().showTags ? Math.max(0, 20 - Math.max(this._props.yMargin ?? 0, NumCast(this.layoutDoc._yMargin))) * this.ScreenToLocalBoxXf().Scale : 0;
}
@computed get contentScaling() {
@@ -1224,13 +1224,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
incomingValue => {
if (this.EditorView && this.ApplyingChange !== this.fieldKey) {
if (incomingValue?.data) {
- const updatedState = JSON.parse(incomingValue.data.Data);
+ const updatedState = JSON.parse(incomingValue.data.Data.replace(/\n/g, ''));
if (JSON.stringify(this.EditorView.state.toJSON()) !== JSON.stringify(updatedState)) {
this.EditorView.updateState(EditorState.fromJSON(this.config, updatedState));
this.tryUpdateScrollHeight();
}
} else if (this.EditorView.state.doc.textContent !== (incomingValue?.str ?? '')) {
selectAll(this.EditorView.state, tx => this.EditorView?.dispatch(tx.insertText(incomingValue?.str ?? '')));
+ this.tryUpdateScrollHeight();
}
}
},
@@ -1750,19 +1751,22 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
* When a text box loses focus, it might be because a text button was clicked (eg, bold, italics) or color picker.
* In these cases, force focus back onto the text box.
* @param target
+ * @returns true if focus was kept on the text box, false otherwise
*/
- tryKeepingFocus = (target: Element | null) => {
+ public static tryKeepingFocus(target: Element | null, refocusFunc?: () => void) {
for (let newFocusEle = target instanceof HTMLElement ? target : null; newFocusEle; newFocusEle = newFocusEle?.parentElement) {
// bcz: HACK!! test if parent of new focused element is a UI button (should be more specific than testing className)
if (['fonticonbox', 'antimodeMenu-cont', 'popup-container'].includes(newFocusEle?.className ?? '')) {
- return this.EditorView?.focus(); // keep focus on text box
+ refocusFunc?.(); // keep focus on text box
+ return true;
}
}
- };
+ return false;
+ }
@action
onBlur = (e: React.FocusEvent) => {
- this.tryKeepingFocus(e.relatedTarget);
+ FormattedTextBox.tryKeepingFocus(e.relatedTarget, () => this.EditorView?.focus());
if (this.ProseRef?.children[0] !== e.nativeEvent.target) return;
if (!(this.EditorView?.state.selection instanceof NodeSelection) || this.EditorView.state.selection.node.type !== this.EditorView.state.schema.nodes.footnote) {
const stordMarks = this.EditorView?.state.storedMarks?.slice();
@@ -1880,7 +1884,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
};
tryUpdateScrollHeight = () => {
- const margins = 2 * NumCast(this.layoutDoc._yMargin, this._props.yPadding || 0);
+ const margins = 2 * NumCast(this.layoutDoc._yMargin, this._props.yMargin || 0);
const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined;
if (this.EditorView && children && !SnappingManager.IsDragging) {
const getChildrenHeights = (kids: Element[] | undefined) => kids?.reduce((p, child) => p + toHgt(child), margins) ?? 0;
@@ -2112,8 +2116,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const rounded = StrCast(this.layoutDoc._layout_borderRounding) === '100%' ? '-rounded' : '';
setTimeout(() => !this._props.isContentActive() && FormattedTextBoxComment.textBox === this && FormattedTextBoxComment.Hide);
- const paddingX = Math.max(NumCast(this.layoutDoc._xMargin), 0, this._props.xPadding ?? 0, this._props.screenXPadding?.(this._props.DocumentView?.()) ?? 0);
- const paddingY = Math.max(NumCast(this.layoutDoc._yMargin), 0, this._props.yPadding ?? 0); // prettier-ignore
+ const paddingX = Math.max(NumCast(this.layoutDoc._xMargin), 0, this._props.xMargin ?? 0, this._props.screenXPadding?.(this._props.DocumentView?.()) ?? 0);
+ const paddingY = Math.max(NumCast(this.layoutDoc._yMargin), 0, this._props.yMargin ?? 0); // prettier-ignore
const styleFromLayout = styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props. e.g., <FormattedTextBox height='{this._header_height}px' >
return this.isLabel ? (
<LabelBox {...this._props} />
diff --git a/src/client/views/nodes/imageEditor/ImageEditor.tsx b/src/client/views/nodes/imageEditor/ImageEditor.tsx
index 85bd95d15..198b8e713 100644
--- a/src/client/views/nodes/imageEditor/ImageEditor.tsx
+++ b/src/client/views/nodes/imageEditor/ImageEditor.tsx
@@ -281,11 +281,14 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
try {
const canvasOriginalImg = ImageUtility.getCanvasImg(img);
if (!canvasOriginalImg) return;
- const canvasMask = ImageUtility.getCanvasMask(canvas, canvasOriginalImg);
+ const canvasMask = ImageUtility.getCanvasMask(canvas, canvas);
if (!canvasMask) return;
const maskBlob = await ImageUtility.canvasToBlob(canvasMask);
const imgBlob = await ImageUtility.canvasToBlob(canvasOriginalImg);
const res = await ImageUtility.getEdit(imgBlob, maskBlob, input || 'Fill in the image in the same style', 2);
+ if ((res as any).status == 'error') {
+ alert((res as any).message);
+ }
// create first image
if (!newCollectionRef.current) {
diff --git a/src/client/views/nodes/imageEditor/imageEditorUtils/ImageHandler.ts b/src/client/views/nodes/imageEditor/imageEditorUtils/ImageHandler.ts
index 1c6a38a24..d6093c6eb 100644
--- a/src/client/views/nodes/imageEditor/imageEditorUtils/ImageHandler.ts
+++ b/src/client/views/nodes/imageEditor/imageEditorUtils/ImageHandler.ts
@@ -75,7 +75,7 @@ export class ImageUtility {
fd.append('mask', maskBlob, 'mask.png');
fd.append('prompt', prompt);
fd.append('size', '1024x1024');
- fd.append('n', n ? JSON.stringify(n) : '1');
+ fd.append('n', n ? n + '' : '1');
fd.append('response_format', 'b64_json');
try {
@@ -268,14 +268,14 @@ export class ImageUtility {
ctx.drawImage(img, xOffset, 0, width, height);
// draw reflected image padding
- this.drawHorizontalReflection(ctx, canvas, xOffset);
+ // this.drawHorizontalReflection(ctx, canvas, xOffset);
} else {
// vertical padding, y offset
const yOffset = Math.floor((canvasSize - height) / 2);
ctx.drawImage(img, 0, yOffset, width, height);
// draw reflected image padding
- this.drawVerticalReflection(ctx, canvas, yOffset);
+ // this.drawVerticalReflection(ctx, canvas, yOffset);
}
return canvas;
};
diff --git a/src/client/views/nodes/trails/PresSlideBox.tsx b/src/client/views/nodes/trails/PresSlideBox.tsx
index 3dbb3da88..55a655c7a 100644
--- a/src/client/views/nodes/trails/PresSlideBox.tsx
+++ b/src/client/views/nodes/trails/PresSlideBox.tsx
@@ -559,10 +559,10 @@ export class PresSlideBox extends ViewBoxBaseComponent<FieldViewProps>() {
style={{
backgroundColor: presColorBool ? (isSelected ? 'rgba(250,250,250,0.3)' : 'transparent') : isSelected ? Colors.LIGHT_BLUE : 'transparent',
opacity: this._dragging ? 0.3 : 1,
- paddingLeft: NumCast(this.layoutDoc._xPadding, this._props.xPadding),
- paddingRight: NumCast(this.layoutDoc._xPadding, this._props.xPadding),
- paddingTop: NumCast(this.layoutDoc._yPadding, this._props.yPadding),
- paddingBottom: NumCast(this.layoutDoc._yPadding, this._props.yPadding),
+ paddingLeft: NumCast(this.layoutDoc._xMargin, this._props.xMargin),
+ paddingRight: NumCast(this.layoutDoc._xMargin, this._props.xMargin),
+ paddingTop: NumCast(this.layoutDoc._yPadding, this._props.yMargin),
+ paddingBottom: NumCast(this.layoutDoc._yPadding, this._props.yMargin),
}}
onDoubleClick={action(() => {
this.toggleProperties();
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.scss b/src/client/views/pdf/GPTPopup/GPTPopup.scss
index bb43291ee..f6fa45221 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.scss
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.scss
@@ -7,6 +7,11 @@ $highlightedText: #82e0ff;
$inputHeight: 60px;
$headingHeight: 32px;
+.gptPopup-sortBox {
+ display: block;
+ max-height: calc(100% - 45px); // leave room for input
+}
+
.gptPopup-summary-box {
position: fixed;
padding-left: 10px;
@@ -87,6 +92,7 @@ $headingHeight: 32px;
}
.btns-wrapper-gpt {
height: 100%;
+ width: 100%;
display: flex;
justify-content: center;
align-items: center;
@@ -97,7 +103,6 @@ $headingHeight: 32px;
flex-direction: column;
width: 100%;
height: 100%;
- overflow-y: auto;
padding-right: 5px;
}
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index c45d8e052..568e48edf 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -93,7 +93,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
this.onGptResponse = (sortResult: string, questionType: GPTDocCommand, args?: string) => this.processGptResponse(selDoc, this._textToDocMap, sortResult, questionType, args);
this.onQuizRandom = () => this.randomlyChooseDoc(selDoc.Document, hasChildDocs());
this._documentDescriptions = Promise.all(hasChildDocs().map(doc =>
- Doc.getDescription(doc).then(text => this._textToDocMap.set(text.trim(), doc) && `${DescriptionSeperator}${text}${DescriptionSeperator}`)
+ Doc.getDescription(doc).then(text => this._textToDocMap.set(text.replace(/\n/g, ' ').trim(), doc) && `${DescriptionSeperator}${text}${DescriptionSeperator}`)
)).then(docDescriptions => docDescriptions.join()); // prettier-ignore
}
},
@@ -211,7 +211,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
const selView = DocumentView.Selected().lastElement();
const selDoc = selView?.Document;
if (selDoc && (selView._props.renderDepth > 1 || selDoc[Doc.LayoutDataKey(selDoc)] instanceof ImageField)) {
- const oldPrompt = StrCast(selDoc.ai_firefly_prompt, StrCast(selDoc.title));
+ const oldPrompt = StrCast(selDoc.ai_prompt, StrCast(selDoc.title));
const newPrompt = oldPrompt ? `${oldPrompt} ~~~ ${imgDesc}` : imgDesc;
return DrawingFillHandler.drawingToImage(selDoc, 100, newPrompt, selDoc)
.then(action(() => (this._userPrompt = '')))
@@ -406,73 +406,80 @@ export class GPTPopup extends ObservableReactComponent<object> {
scrollToBottom = () => setTimeout(() => this._messagesEndRef.current?.scrollIntoView({ behavior: 'smooth', block: 'end' }), 50);
gptMenu = () => (
- <div className="btns-wrapper-gpt">
- <Button
- tooltip="Ask Firefly to create images"
- text="Ask Firefly"
- onClick={() => this.setMode(GPTPopupMode.FIREFLY)}
- color={SettingsManager.userColor}
- background={SettingsManager.userVariantColor}
- type={Type.TERT}
- style={{
- width: '100%',
- height: '40%',
- textAlign: 'center',
- color: '#ffffff',
- fontSize: '16px',
- marginBottom: '10px',
- }}
- />
- <Button
- tooltip="Ask GPT to sort, tag, define, or filter your Docs!"
- text="Ask GPT"
- onClick={() => this.setMode(GPTPopupMode.USER_PROMPT)}
- color={SettingsManager.userColor}
- background={SettingsManager.userVariantColor}
- type={Type.TERT}
- style={{
- width: '100%',
- height: '40%',
- textAlign: 'center',
- color: '#ffffff',
- fontSize: '16px',
- marginBottom: '10px',
- }}
- />
- <Button
- tooltip="Test your knowledge by verifying answers with ChatGPT"
- text="Take Quiz"
- onClick={() => {
- this._conversationArray = ['Define the selected card!'];
- this.setMode(GPTPopupMode.QUIZ_RESPONSE);
- this.onQuizRandom?.();
- }}
- color={SettingsManager.userColor}
- background={SettingsManager.userVariantColor}
- type={Type.TERT}
- style={{
- width: '100%',
- height: '40%',
- textAlign: 'center',
- color: '#ffffff',
- fontSize: '16px',
- }}
- />
+ <div style={{ display: 'flex', maxHeight: 'calc(100% - 32px)', overflow: 'auto' }}>
+ <div className="btns-wrapper-gpt">
+ <Button
+ tooltip="Ask Firefly to create images"
+ text="Ask Firefly"
+ onClick={() => this.setMode(GPTPopupMode.FIREFLY)}
+ color={SettingsManager.userColor}
+ background={SettingsManager.userVariantColor}
+ type={Type.TERT}
+ style={{
+ width: '100%',
+ height: '40%',
+ textAlign: 'center',
+ color: '#ffffff',
+ fontSize: '16px',
+ marginBottom: '10px',
+ }}
+ />
+ <Button
+ tooltip="Ask GPT to sort, tag, define, or filter your Docs!"
+ text="Ask GPT"
+ onClick={() => this.setMode(GPTPopupMode.USER_PROMPT)}
+ color={SettingsManager.userColor}
+ background={SettingsManager.userVariantColor}
+ type={Type.TERT}
+ style={{
+ width: '100%',
+ height: '40%',
+ textAlign: 'center',
+ color: '#ffffff',
+ fontSize: '16px',
+ marginBottom: '10px',
+ }}
+ />
+ <Button
+ tooltip="Test your knowledge by verifying answers with ChatGPT"
+ text="Take Quiz"
+ onClick={() => {
+ this._conversationArray = ['Define the selected card!'];
+ this.setMode(GPTPopupMode.QUIZ_RESPONSE);
+ this.onQuizRandom?.();
+ }}
+ color={SettingsManager.userColor}
+ background={SettingsManager.userVariantColor}
+ type={Type.TERT}
+ style={{
+ width: '100%',
+ height: '40%',
+ textAlign: 'center',
+ color: '#ffffff',
+ fontSize: '16px',
+ }}
+ />
+ </div>
</div>
);
callGpt = action((mode: GPTPopupMode) => {
this.setGptProcessing(true);
+ const reset = action(() => {
+ this.setGptProcessing(false);
+ this._userPrompt = '';
+ this._quizAnswer = '';
+ });
switch (mode) {
case GPTPopupMode.FIREFLY:
this._fireflyArray.push(this._userPrompt);
- return this.generateFireflyImage(this._userPrompt).then(action(() => (this._userPrompt = '')));
+ return this.generateFireflyImage(this._userPrompt).then(reset);
case GPTPopupMode.USER_PROMPT:
this._conversationArray.push(this._userPrompt);
- return this.generateUserPromptResponse(this._userPrompt).then(action(() => (this._userPrompt = '')));
+ return this.generateUserPromptResponse(this._userPrompt).then(reset);
case GPTPopupMode.QUIZ_RESPONSE:
this._conversationArray.push(this._quizAnswer);
- return this.generateQuizAnswerAnalysis(DocumentView.SelectedDocs().lastElement(), this._quizAnswer).then(action(() => (this._quizAnswer = '')));
+ return this.generateQuizAnswerAnalysis(DocumentView.SelectedDocs().lastElement(), this._quizAnswer).then(reset);
}
});
@@ -490,18 +497,20 @@ export class GPTPopup extends ObservableReactComponent<object> {
};
gptUserInput = () => (
- <div className="btns-wrapper-gpt">
- <div className="chat-wrapper">
- <div className="chat-bubbles">
- {(this._mode === GPTPopupMode.FIREFLY ? this._fireflyArray : this._conversationArray).map((message, index) => (
- <div key={index} className={`chat-bubble ${index % 2 === 1 ? 'user-message' : 'chat-message'}`}>
- {message}
- </div>
- ))}
- {this._gptProcessing && <div className="chat-bubble chat-message">...</div>}
- </div>
+ <div style={{ display: 'flex', maxHeight: 'calc(100% - 32px)', overflow: 'auto' }}>
+ <div className="btns-wrapper-gpt">
+ <div className="chat-wrapper">
+ <div className="chat-bubbles">
+ {(this._mode === GPTPopupMode.FIREFLY ? this._fireflyArray : this._conversationArray).map((message, index) => (
+ <div key={index} className={`chat-bubble ${index % 2 === 1 ? 'user-message' : 'chat-message'}`}>
+ {message}
+ </div>
+ ))}
+ {this._gptProcessing && <div className="chat-bubble chat-message">...</div>}
+ </div>
- <div ref={this._messagesEndRef} style={{ height: '100px' }} />
+ <div ref={this._messagesEndRef} style={{ height: '40px' }} />
+ </div>
</div>
</div>
);
@@ -520,7 +529,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
onChange={e => onChange(e.target.value)}
onKeyDown={e => this.handleKeyPress(e, this._mode)}
type="text"
- style={{ color: SnappingManager.userColor }}
+ style={{ color: 'black' }}
placeholder={placeholder}
/>
<Button //
@@ -744,7 +753,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
onClick={() => this._collectionContext && Doc.setDocFilter(this._collectionContext, 'tags', GPTPopup.ChatTag, 'remove')}
/>
{[GPTPopupMode.USER_PROMPT, GPTPopupMode.QUIZ_RESPONSE, GPTPopupMode.FIREFLY].includes(this._mode) && (
- <IconButton color={SettingsManager.userVariantColor} background={SettingsManager.userColor} tooltip="back" icon={<CgCornerUpLeft size="16px" />} onClick={() => (this._mode = GPTPopupMode.GPT_MENU)} />
+ <IconButton color={SettingsManager.userVariantColor} background={SettingsManager.userColor} tooltip="back" icon={<CgCornerUpLeft size="16px" />} onClick={action(() => (this._mode = GPTPopupMode.GPT_MENU))} />
)}
</>
)}
@@ -753,12 +762,12 @@ export class GPTPopup extends ObservableReactComponent<object> {
render() {
return (
- <div className="gptPopup-summary-box" style={{ background: SnappingManager.userColor, color: SnappingManager.userBackgroundColor, display: SnappingManager.ChatVisible ? 'flex' : 'none', overflow: 'auto' }}>
+ <div className="gptPopup-summary-box" style={{ background: SnappingManager.userColor, color: SnappingManager.userBackgroundColor, display: SnappingManager.ChatVisible ? 'flex' : 'none' }}>
{(() => {
//prettier-ignore
switch (this._mode) {
case GPTPopupMode.USER_PROMPT: return this.promptBox("ASK", this._userPrompt, this.setUserPrompt, 'Ask GPT to sort, tag, define, or filter your documents for you!');
- case GPTPopupMode.FIREFLY: return this.promptBox("CREATE", this._userPrompt, this.setUserPrompt, StrCast(DocumentView.Selected().lastElement()?.Document.ai_firefly_prompt, 'Ask Firefly to generate images'));
+ case GPTPopupMode.FIREFLY: return this.promptBox("CREATE", this._userPrompt, this.setUserPrompt, StrCast(DocumentView.Selected().lastElement()?.Document.ai_prompt, 'Ask Firefly to generate images'));
case GPTPopupMode.QUIZ_RESPONSE: return this.promptBox("QUIZ", this._quizAnswer, this.setQuizAnswer, 'Describe/answer the selected document!');
case GPTPopupMode.GPT_MENU: return this.menuBox();
case GPTPopupMode.SUMMARY: return this.summaryBox();
diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx
index 2c69284db..f773957e7 100644
--- a/src/client/views/smartdraw/DrawingFillHandler.tsx
+++ b/src/client/views/smartdraw/DrawingFillHandler.tsx
@@ -51,19 +51,19 @@ export class DrawingFillHandler {
if (error.includes('Dropbox') && confirm('Create image failed. Try authorizing DropBox?\r\n' + error.replace(/^[^"]*/, ''))) {
return DrawingFillHandler.authorizeDropbox();
}
- const genratedDocs = DocCast(drawing.ai_firefly_generatedDocs) ?? Docs.Create.MasonryDocument([], { title: StrCast(drawing.title) + ' AI Images', _width: 400, _height: 400 });
- drawing.$ai_firefly_generatedDocs = genratedDocs;
+ const genratedDocs = DocCast(drawing.ai_generatedDocs) ?? Docs.Create.MasonryDocument([], { title: StrCast(drawing.title) + ' AI Images', _width: 400, _height: 400 });
+ drawing.$ai_generatedDocs = genratedDocs;
(res as Upload.ImageInformation[]).map(info =>
Doc.AddDocToList(
genratedDocs,
undefined,
Docs.Create.ImageDocument(info.accessPaths.agnostic.client, {
ai: 'firefly',
+ ai_prompt: newPrompt,
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,
data_nativeHeight: info.nativeHeight,
diff --git a/src/client/views/smartdraw/SmartDrawHandler.scss b/src/client/views/smartdraw/SmartDrawHandler.scss
index cca7d77c7..e80f1122b 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.scss
+++ b/src/client/views/smartdraw/SmartDrawHandler.scss
@@ -73,5 +73,6 @@
.edit-box {
display: flex;
flex-direction: row;
+ color: black;
}
}
diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx
index 4f0cd3978..3976ec39e 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.tsx
+++ b/src/client/views/smartdraw/SmartDrawHandler.tsx
@@ -61,7 +61,6 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
static Instance: SmartDrawHandler;
private _lastInput: DrawingOptions = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 };
- private _lastResponse: string = '';
private _selectedDocs: Doc[] = [];
@observable private _display: boolean = false;
@@ -97,7 +96,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
CollectionFreeForm, FormattedTextBox, StickerPalette) to define how a drawing document should be added
or removed in their respective locations (to the freeform canvas, to the sticker palette's preview, etc.)
*/
- public AddDrawing: (doc: Doc, opts: DrawingOptions, gptRes: string, x?: number, y?: number) => void = unimplementedFunction;
+ public AddDrawing: (doc: Doc, opts: DrawingOptions, x?: number, y?: number) => void = unimplementedFunction;
public RemoveDrawing: (useLastContainer: boolean, doc?: Doc) => void = unimplementedFunction;
/**
* This creates the ink document that represents a drawing, so it goes through the strokes that make up the drawing,
@@ -105,7 +104,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
* classes to customize the way the drawing docs get created. For example, the freeform canvas has a different way of
* defining document bounds, so CreateDrawingDoc is redefined when that class calls gpt draw functions.
*/
- public static CreateDrawingDoc: (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => Doc | undefined = (strokeList: [InkData, string, string][], opts: DrawingOptions) => {
+ public static CreateDrawingDoc: (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => Doc | undefined = (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string) => {
const drawing: Doc[] = [];
strokeList.forEach((stroke: [InkData, string, string]) => {
const bounds = InkField.getBounds(stroke[0]);
@@ -130,7 +129,14 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
drawing.push(inkDoc);
});
- return MarqueeView.getCollection(drawing, undefined, true, { left: 1, top: 1, width: 1, height: 1 });
+ const drawn = MarqueeView.getCollection(drawing, undefined, true, { left: 1, top: 1, width: 1, height: 1 });
+
+ drawn.$ai_drawing = true;
+ drawn.$ai_drawing_complexity = opts.complexity;
+ drawn.$ai_drawing_colored = opts.autoColor;
+ drawn.$ai_drawing_size = opts.size;
+ drawn.$ai_drawing_data = gptRes;
+ return drawn;
};
@action
@@ -146,15 +152,16 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
* the regenerate popup show by user command.
*/
@action
- displayRegenerate = (x: number, y: number) => {
+ displayRegenerate = (x: number, y: number, scale: number) => {
this._selectedDocs = [DocumentView.SelectedDocs()?.lastElement()];
[this._pageX, this._pageY] = [x, y];
+ this._scale = scale;
this._display = false;
this.ShowRegenerate = true;
this._showEditBox = false;
const docData = this._selectedDocs[0];
- this._lastResponse = StrCast(docData.$drawingData);
- this._lastInput = { text: StrCast(docData.$ai_drawing_input), complexity: NumCast(docData.$ai_drawing_complexity), size: NumCast(docData.$ai_drawing_size), autoColor: BoolCast(docData.$ai_drawing_colored), x: this._pageX, y: this._pageY };
+ this._regenInput = StrCast(docData.$ai_prompt, StrCast(docData.title));
+ this._lastInput = { text: StrCast(docData.$ai_prompt), complexity: NumCast(docData.$ai_drawing_complexity), size: NumCast(docData.$ai_drawing_size), autoColor: BoolCast(docData.$ai_drawing_colored), x: this._pageX, y: this._pageY };
};
/**
@@ -168,9 +175,6 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
this._isLoading = false;
this._showOptions = false;
this._userInput = '';
- this._complexity = 5;
- this._size = 350;
- this._autoColor = true;
Doc.ActiveTool = InkTool.None;
}
};
@@ -184,7 +188,6 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
this.ShowRegenerate = false;
this._isLoading = false;
this._regenInput = '';
- this._lastInput = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 };
}
};
@@ -208,7 +211,9 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
this._isLoading = true;
this._canInteract = false;
if (this.ShowRegenerate) {
- await this.regenerate(this._selectedDocs, undefined, undefined, this._regenInput).then(action(() => (this._showEditBox = false)));
+ this._lastInput.x = X;
+ this._lastInput.y = Y;
+ await this.regenerate(this._selectedDocs).then(action(() => (this._showEditBox = false)));
} else {
this._showOptions = false;
try {
@@ -234,13 +239,15 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
*/
drawWithGPT = async (screenPt: { X: number; Y: number }, input: string, complexity: number, size: number, autoColor: boolean) => {
if (input) {
- this._lastInput = { text: input, complexity: complexity, size: size, autoColor: autoColor, x: screenPt.X, y: screenPt.Y };
+ this._lastInput = { text: input, complexity, size, autoColor, x: screenPt.X, y: screenPt.Y };
const res = await gptAPICall(`"${input}", "${complexity}", "${size}"`, GPTCallType.DRAW, undefined, true);
if (res) {
const strokeData = await this.parseSvg(res, { X: 0, Y: 0 }, false, autoColor);
const drawingDoc = strokeData && SmartDrawHandler.CreateDrawingDoc(strokeData.data, strokeData.lastInput, strokeData.lastRes);
- drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res, screenPt.X, screenPt.Y);
- drawingDoc && this._selectedDocs.push(drawingDoc);
+ if (drawingDoc) {
+ this.AddDrawing(drawingDoc, this._lastInput, screenPt.X, screenPt.Y);
+ this._selectedDocs.push(drawingDoc);
+ }
return strokeData;
} else {
console.error('GPT call failed');
@@ -255,7 +262,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
createImageWithFirefly = (input: string, seed?: number): Promise<FireflyImageData | Doc | undefined> => {
this._lastInput.text = input;
return SmartDrawHandler.CreateWithFirefly(input, this._imgDims, seed).then(doc => {
- doc instanceof Doc && this.AddDrawing(doc, this._lastInput, input, this._pageX, this._pageY);
+ doc instanceof Doc && this.AddDrawing(doc, this._lastInput, this._pageX, this._pageY);
return doc;
});
}; /**
@@ -301,8 +308,8 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
_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,
+ ai_prompt_seed: +(newseed ?? 0),
+ ai_prompt: input,
});
})
.catch(e => {
@@ -316,33 +323,30 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
* @param doc the drawing Docs to regenerate
*/
@action
- regenerate = (drawingDocs: Doc[], lastInput?: DrawingOptions, lastResponse?: string, regenInput?: string, changeInPlace?: boolean) => {
- if (lastInput) this._lastInput = lastInput;
- if (lastResponse) this._lastResponse = lastResponse;
+ regenerate = (drawingDocs: Doc[], regenInput?: string, changeInPlace?: boolean) => {
if (regenInput) this._regenInput = regenInput;
return Promise.all(
drawingDocs.map(async doc => {
switch (doc.type) {
case DocumentType.IMG: {
const func = changeInPlace ? this.recreateImageWithFirefly : this.createImageWithFirefly;
- const newPrompt = doc.ai_firefly_prompt ? `${doc.ai_firefly_prompt} ~~~ ${this._regenInput}` : this._regenInput;
- return this._regenInput ? func(newPrompt, NumCast(doc?.ai_firefly_seed)) : func(this._lastInput.text || StrCast(doc.ai_firefly_prompt));
+ const newPrompt = doc.ai_prompt && doc.ai_prompt !== this._regenInput ? `${doc.ai_prompt} ~~~ ${this._regenInput}` : this._regenInput;
+ return this._regenInput ? func(newPrompt, NumCast(doc?.ai_prompt_seed)) : func(this._lastInput.text || StrCast(doc.ai_prompt));
}
case DocumentType.COL: {
try {
const res = await (async () => {
if (this._regenInput) {
- const prompt = `This is your previously generated svg code: ${this._lastResponse} for the user input "${this._lastInput.text}". Please regenerate it with the provided specifications.`;
+ const prompt = `This is your previously generated svg code: ${doc.$ai_drawing_data} for the user input "${doc.ai_prompt}". Please regenerate it with the provided specifications.`;
this._lastInput.text = `${this._lastInput.text} ~~~ ${this._regenInput}`;
return gptAPICall(`"${this._regenInput}"`, GPTCallType.DRAW, prompt, true);
}
- return gptAPICall(`"${this._lastInput.text}", "${this._lastInput.complexity}", "${this._lastInput.size}"`, GPTCallType.DRAW, undefined, true);
+ return gptAPICall(`"${doc.$ai_prompt}", "${doc.$ai_drawing_complexity}", "${doc.$ai_drawing_size}"`, GPTCallType.DRAW, undefined, true);
})();
if (res) {
- const strokeData = await this.parseSvg(res, { X: this._lastInput.x ?? 0, Y: this._lastInput.y ?? 0 }, true, lastInput?.autoColor || this._autoColor);
- this.RemoveDrawing !== unimplementedFunction && this.RemoveDrawing(true, doc);
+ const strokeData = await this.parseSvg(res, { X: 0, Y: 0 }, true, this._autoColor);
const drawingDoc = strokeData && SmartDrawHandler.CreateDrawingDoc(strokeData.data, strokeData.lastInput, strokeData.lastRes);
- drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res);
+ drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, this._lastInput.x, this._lastInput.y);
} else {
console.error('GPT call failed');
}
@@ -363,7 +367,6 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
const svg = res.match(/<svg[^>]*>([\s\S]*?)<\/svg>/g);
if (svg) {
- this._lastResponse = svg[0];
const svgObject = await parse(svg[0]);
console.log(res, svgObject);
const svgStrokes: INode[] = svgObject.children;
@@ -398,7 +401,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
*/
colorWithGPT = async (drawing: Doc) => {
const img = await DocumentView.GetDocImage(drawing);
- const { href } = ImageCast(img).url;
+ const { href } = ImageCast(img)?.url ?? { href: '' };
const hrefParts = href.split('.');
const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`;
try {
@@ -664,7 +667,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
<div className="regenerate-box">
<IconButton
tooltip="Regenerate"
- icon={this._isLoading && this._regenInput === '' ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <FontAwesomeIcon icon={'rotate'} />}
+ icon={this._isLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <FontAwesomeIcon icon={'rotate'} />}
color={SettingsManager.userColor}
onClick={() => this.handleSendClick(this._pageX, this._pageY)}
/>
diff --git a/src/client/views/smartdraw/StickerPalette.tsx b/src/client/views/smartdraw/StickerPalette.tsx
index 0e234e966..6ef3d26ad 100644
--- a/src/client/views/smartdraw/StickerPalette.tsx
+++ b/src/client/views/smartdraw/StickerPalette.tsx
@@ -9,7 +9,7 @@ import ReactLoading from 'react-loading';
import { returnEmptyFilter, returnFalse, returnTrue } from '../../../ClientUtils';
import { emptyFunction, numberRange } from '../../../Utils';
import { Doc, DocListCast, returnEmptyDoclist } from '../../../fields/Doc';
-import { ImageCast, NumCast } from '../../../fields/Types';
+import { ImageCast, NumCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { DocumentType } from '../../documents/DocumentTypes';
import { Docs } from '../../documents/Documents';
@@ -147,9 +147,9 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
SmartDrawHandler.Instance.AddDrawing = this.addDrawing;
this._canInteract = false;
Promise.all(
- numberRange(3).map(i => {
+ numberRange(3).map(() => {
return this._showRegenerate
- ? SmartDrawHandler.Instance.regenerate(prevDrawings, this._opts, this._gptRes[i], this._userInput)
+ ? SmartDrawHandler.Instance.regenerate(prevDrawings, this._userInput)
: SmartDrawHandler.Instance.drawWithGPT({ X: 0, Y: 0 }, this._userInput, this._opts.complexity || 0, this._opts.size || 0, !!this._opts.autoColor);
})
).then(() => {
@@ -161,8 +161,8 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
});
@action
- addDrawing = (drawing: Doc, opts: DrawingOptions, gptRes: string) => {
- this._gptRes.push(gptRes);
+ addDrawing = (drawing: Doc) => {
+ this._gptRes.push(StrCast(drawing.$ai_drawing_data));
drawing.$freeform_fitContentsToBox = true;
Doc.AddDocToList(this._props.Doc, 'data', drawing);
};
@@ -176,7 +176,7 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
const cIndex = NumCast(this._props.Doc.carousel_index);
const focusedDrawing = DocListCast(this._props.Doc.data)[cIndex];
focusedDrawing.$title = this._opts.text?.match(/^(.*?)~~~.*$/)?.[1] || this._opts.text;
- focusedDrawing.$ai_drawing_input = this._opts.text;
+ focusedDrawing.$ai_prompt = this._opts.text;
focusedDrawing.$ai_drawing_complexity = this._opts.complexity;
focusedDrawing.$ai_drawing_colored = this._opts.autoColor;
focusedDrawing.$ai_drawing_size = this._opts.size;