aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-04-19 13:01:37 -0400
committerbobzel <zzzman@gmail.com>2023-04-19 13:01:37 -0400
commit0a66b0f369a13d5f399bf125727aff73cd6fd1b4 (patch)
tree1214f42703f07a4cc1b6e88bae02795f65c9b9ff
parent615bd643f6afc95f6548bcbec468177582d4ffc3 (diff)
fixed image importing metadata for gpt. fixed showTitle UI to be able to turn off titles on templates (like icon views). added ui for choosing primary/alternate image and a drop target for setting alternate.
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/views/MainView.tsx2
-rw-r--r--src/client/views/PropertiesButtons.tsx6
-rw-r--r--src/client/views/nodes/ImageBox.scss8
-rw-r--r--src/client/views/nodes/ImageBox.tsx58
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx6
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx4
7 files changed, 73 insertions, 13 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 09b45a481..a0149eadf 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -147,6 +147,8 @@ export class DocumentOptions {
_panY?: NUMt = new NumInfo('vertical pan location of a freeform view');
_width?: NUMt = new NumInfo('displayed width of a document');
_height?: NUMt = new NumInfo('displayed height of document');
+ 'data-nativeWidth'?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)');
+ 'data-nativeHeight'?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)');
_nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)');
_nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)');
_nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers');
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index acbe0cbc3..4cbf8a811 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -314,6 +314,8 @@ export class MainView extends React.Component {
fa.faArrowUp,
fa.faBolt,
fa.faBullseye,
+ fa.faTurnUp,
+ fa.faTurnDown,
fa.faCaretUp,
fa.faCat,
fa.faCheck,
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 031d501ad..98dcf4f21 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -177,7 +177,11 @@ export class PropertiesButtons extends React.Component<{}, {}> {
'_showTitle',
on => 'Switch between title styles',
on => 'text-width',
- (dv, doc) => ((dv?.rootDoc || doc)._showTitle = !(dv?.rootDoc || doc)._showTitle ? 'title' : (dv?.rootDoc || doc)._showTitle === 'title' ? 'title:hover' : undefined)
+ (dv, doc) => {
+ const tdoc = dv?.rootDoc || doc;
+ const newtitle = !tdoc._showTitle ? 'title' : tdoc._showTitle === 'title' ? 'title:hover' : '';
+ tdoc._showTitle = newtitle;
+ }
);
}
@computed get autoHeightButton() {
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 6359a9491..22dbc1e80 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -119,6 +119,14 @@
}
}
}
+.imageBox-alternateDropTarget {
+ position: absolute;
+ color: white;
+ background: black;
+ right: 0;
+ bottom: 0;
+ z-index: 2;
+}
.imageBox-fader img {
position: absolute;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index e8d4be1fd..98df777cb 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,3 +1,5 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@material-ui/core';
import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { extname } from 'path';
@@ -8,7 +10,7 @@ import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
import { createSchema } from '../../../fields/Schema';
import { ComputedField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
+import { Cast, NumCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { TraceMobx } from '../../../fields/util';
import { DashColor, emptyFunction, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
@@ -19,6 +21,7 @@ import { DocumentType } from '../../documents/DocumentTypes';
import { Networking } from '../../Network';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager } from '../../util/DragManager';
+import { SnappingManager } from '../../util/SnappingManager';
import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from '../../views/ContextMenu';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
@@ -57,6 +60,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
private _dropDisposer?: DragManager.DragDropDisposer;
private _disposers: { [name: string]: IReactionDisposer } = {};
private _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
+ private _overlayIconRef = React.createRef<HTMLDivElement>();
@observable _curSuffix = '';
@observable _uploadIcon = uploadIcons.idle;
@@ -131,10 +135,16 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
@action
drop = (e: Event, de: DragManager.DropEvent) => {
if (de.complete.docDragData) {
- if (de.metaKey) {
+ const targetIsBullseye = (ele: HTMLElement): boolean => {
+ if (!ele) return false;
+ if (ele === this._overlayIconRef.current) return true;
+ return targetIsBullseye(ele.parentElement as HTMLElement);
+ };
+ if (de.metaKey || targetIsBullseye(e.target as HTMLElement)) {
de.complete.docDragData.droppedDocuments.forEach(
action((drop: Doc) => {
Doc.AddDocToList(this.dataDoc, this.fieldKey + '-alternates', drop);
+ this.rootDoc[this.fieldKey + '-usePath'] = 'alternate:hover';
e.stopPropagation();
})
);
@@ -154,8 +164,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
@undoBatch
resolution = () => (this.layoutDoc._showFullRes = !this.layoutDoc._showFullRes);
- @undoBatch
- setUseAlt = () => (this.layoutDoc[this.fieldKey + '-useAlt'] = !this.layoutDoc[this.fieldKey + '-useAlt']);
@undoBatch
setNativeSize = action(() => {
@@ -239,7 +247,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
funcs.push({ description: 'Rotate Clockwise 90', event: this.rotate, icon: 'redo-alt' });
funcs.push({ description: `Show ${this.layoutDoc._showFullRes ? 'Dynamic Res' : 'Full Res'}`, event: this.resolution, icon: 'expand' });
funcs.push({ description: 'Set Native Pixel Size', event: this.setNativeSize, icon: 'expand-arrows-alt' });
- funcs.push({ description: `${this.layoutDoc[this.fieldKey + '-useAlt'] ? 'Show Alternate' : 'Show Primary'}`, event: this.setUseAlt, icon: 'image' });
funcs.push({ description: 'Copy path', event: () => Utils.CopyText(this.choosePath(field.url)), icon: 'copy' });
if (!Doc.noviceMode) {
funcs.push({ description: 'Export to Google Photos', event: () => GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: 'caret-square-right' });
@@ -356,6 +363,41 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
const nativeOrientation = NumCast(this.dataDoc[this.fieldKey + '-nativeOrientation'], 1);
return { nativeWidth, nativeHeight, nativeOrientation };
}
+ @computed get overlayImageIcon() {
+ const usePath = this.rootDoc[`_${this.fieldKey}-usePath`];
+ return (
+ <Tooltip
+ title={
+ <div className="dash-tooltip">
+ toggle between
+ <span style={{ color: usePath === undefined ? 'black' : undefined }}>
+ <em> primary, </em>
+ </span>
+ <span style={{ color: usePath === 'alternate' ? 'black' : undefined }}>
+ <em>alternate, </em>
+ </span>
+ and show
+ <span style={{ color: usePath === 'alternate:hover' ? 'black' : undefined }}>
+ <em> alternate on hover</em>
+ </span>
+ </div>
+ }>
+ <div
+ className="imageBox-alternateDropTarget"
+ ref={this._overlayIconRef}
+ onPointerDown={e => setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, e => (this.rootDoc[`_${this.fieldKey}-usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined))}
+ style={{
+ display: (SnappingManager.GetIsDragging() && DragManager.DocDragData?.canEmbed) || DocListCast(this.dataDoc[this.fieldKey + '-alternates']).length ? 'block' : 'none',
+ width: 'min(10%, 25px)',
+ height: 'min(10%, 25px)',
+ background: usePath === undefined ? 'white' : usePath === 'alternate' ? 'black' : 'gray',
+ color: usePath === undefined ? 'black' : 'white',
+ }}>
+ <FontAwesomeIcon icon="turn-up" size="lg" />
+ </div>
+ </Tooltip>
+ );
+ }
@computed get paths() {
const field = Cast(this.dataDoc[this.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
@@ -389,15 +431,14 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
transformOrigin = 'right top';
transform = `translate(-100%, 0%) rotate(${rotation}deg) scale(${aspect})`;
}
+ const usePath = this.rootDoc[`_${this.fieldKey}-usePath`];
return (
<div className="imageBox-cont" onPointerEnter={action(() => (this._isHovering = true))} onPointerLeave={action(() => (this._isHovering = false))} key={this.layoutDoc[Id]} ref={this.createDropTarget} onPointerDown={this.marqueeDown}>
<div className="imageBox-fader" style={{ opacity: backAlpha }}>
<img key="paths" src={srcpath} style={{ transform, transformOrigin }} draggable={false} width={nativeWidth} />
{fadepath === srcpath ? null : (
- <div
- className={`imageBox-fadeBlocker${(this._isHovering && this.layoutDoc[this.fieldKey + '-useAlt'] === undefined) || BoolCast(this.layoutDoc[this.fieldKey + '-useAlt']) ? '-hover' : ''}`}
- style={{ transition: StrCast(this.layoutDoc.viewTransition, 'opacity 1000ms') }}>
+ <div className={`imageBox-fadeBlocker${(this._isHovering && usePath === 'alternate:hover') || usePath === 'alternate' ? '-hover' : ''}`} style={{ transition: StrCast(this.layoutDoc.viewTransition, 'opacity 1000ms') }}>
<img className="imageBox-fadeaway" key="fadeaway" src={fadepath} style={{ transform, transformOrigin }} draggable={false} width={nativeWidth} />
</div>
)}
@@ -405,6 +446,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
{!Doc.noviceMode && this.considerDownloadIcon}
{this.considerGooglePhotosLink()}
<FaceRectangles document={this.dataDoc} color={'#0000FF'} backgroundColor={'#0000FF'} />
+ {this.overlayImageIcon}
</div>
);
}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 3e60441aa..bbe38cf99 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -885,13 +885,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
try {
let image_url = await gptImageCall((this.dataDoc.text as RichTextField)?.Text);
if (image_url) {
- const [{ accessPaths }] = await Networking.PostToServer('/uploadRemoteImage', { sources: [image_url] });
- const source = Utils.prepend(accessPaths.agnostic.client);
+ const [result] = await Networking.PostToServer('/uploadRemoteImage', { sources: [image_url] });
+ const source = Utils.prepend(result.accessPaths.agnostic.client);
const newDoc = Docs.Create.ImageDocument(source, {
x: NumCast(this.rootDoc.x) + NumCast(this.layoutDoc._width) + 10,
y: NumCast(this.rootDoc.y),
_height: 200,
_width: 200,
+ 'data-nativeWidth': result.nativeWidth,
+ 'data-nativeHeight': result.nativeHeight,
});
if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.rootDoc)) {
newDoc.overlayX = this.rootDoc.x;
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 807a19771..f8c47aafe 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -527,7 +527,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
bestTarget._dataTransition = `all ${transTime}ms`;
const fkey = Doc.LayoutFieldKey(bestTarget);
Doc.GetProto(bestTarget)[fkey] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
- bestTarget[fkey + '-useAlt'] = activeItem.presUseAlt;
+ bestTarget[fkey + '-usePath'] = activeItem.presUsePath;
setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10);
}
if ((pinDataTypes?.textview && activeItem.presData !== undefined) || (!pinDataTypes && activeItem.presData !== undefined)) {
@@ -613,7 +613,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
pinProps?.activeFrame !== undefined;
const fkey = Doc.LayoutFieldKey(targetDoc);
if (pinProps.pinData.dataview) {
- pinDoc.presUseAlt = targetDoc[fkey + '-useAlt'];
+ pinDoc.presUsePath = targetDoc[fkey + '-usePath'];
pinDoc.presData = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data;
}
if (pinProps.pinData.dataannos) {