From 520405deac3a1efa65ed10541d6bfe3c2921aa23 Mon Sep 17 00:00:00 2001
From: Eric <ericmabr@gmail.com>
Date: Mon, 21 Aug 2023 17:01:30 -0400
Subject: MapAnchorMenu created; tons of compiler errors idk why

---
 src/client/views/nodes/MapBox/MapAnchorMenu.tsx | 393 ++++++++++++++++++++++++
 1 file changed, 393 insertions(+)
 create mode 100644 src/client/views/nodes/MapBox/MapAnchorMenu.tsx

(limited to 'src/client/views/nodes/MapBox/MapAnchorMenu.tsx')

diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
new file mode 100644
index 000000000..798905bcd
--- /dev/null
+++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
@@ -0,0 +1,393 @@
+import React = require('react');
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction } from 'mobx';
+import { observer } from 'mobx-react';
+import { ColorState } from 'react-color';
+import { Doc, Opt } from '../../../fields/Doc';
+import { returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from '../../../Utils';
+import { SelectionManager } from '../../util/SelectionManager';
+import { AntimodeMenu, AntimodeMenuProps } from "../AntimodeMenu"
+import { LinkPopup } from '../linking/LinkPopup';
+import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT';
+import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup';
+import { EditorView } from 'prosemirror-view';
+import './MapAnchorMenu.scss';
+import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
+import { StrCast } from '../../../fields/Types';
+import { DocumentType } from '../../documents/DocumentTypes';
+
+@observer
+export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
+    static Instance: MapAnchorMenu;
+
+    private _disposer: IReactionDisposer | undefined;
+    private _disposer2: IReactionDisposer | undefined;
+    private _commentCont = React.createRef<HTMLButtonElement>();
+
+    @observable private highlightColor: string = 'rgba(245, 230, 95, 0.616)';
+
+    @observable public Status: 'marquee' | 'annotation' | '' = '';
+
+    // GPT additions
+    @observable private GPTpopupText: string = '';
+    @observable private loadingGPT: boolean = false;
+    @observable private showGPTPopup: boolean = false;
+    @observable private GPTMode: GPTPopupMode = GPTPopupMode.SUMMARY;
+    @observable private selectedText: string = '';
+    @observable private editorView?: EditorView;
+    @observable private textDoc?: Doc;
+    @observable private highlightRange: number[] | undefined;
+    private selectionRange: number[] | undefined;
+
+    @action
+    setGPTPopupVis = (vis: boolean) => {
+        this.showGPTPopup = vis;
+    };
+    @action
+    setGPTMode = (mode: GPTPopupMode) => {
+        this.GPTMode = mode;
+    };
+
+    @action
+    setGPTPopupText = (txt: string) => {
+        this.GPTpopupText = txt;
+    };
+
+    @action
+    setLoading = (loading: boolean) => {
+        this.loadingGPT = loading;
+    };
+
+    @action
+    setHighlightRange(r: number[] | undefined) {
+        this.highlightRange = r;
+    }
+
+    @action
+    public setSelectedText = (txt: string) => {
+        this.selectedText = txt;
+    };
+
+    @action
+    public setEditorView = (editor: EditorView) => {
+        this.editorView = editor;
+    };
+
+    @action
+    public setTextDoc = (textDoc: Doc) => {
+        this.textDoc = textDoc;
+    };
+
+    public onMakeAnchor: () => Opt<Doc> = () => undefined; // Method to get anchor from text search
+
+    public OnCrop: (e: PointerEvent) => void = unimplementedFunction;
+    public OnClick: (e: PointerEvent) => void = unimplementedFunction;
+    public OnAudio: (e: PointerEvent) => void = unimplementedFunction;
+    public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
+    public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
+    public Highlight: (color: string, isTargetToggler: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>, addAsAnnotation?: boolean) => Opt<Doc> = (color: string, isTargetToggler: boolean) => undefined;
+    public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => undefined;
+    public Delete: () => void = unimplementedFunction;
+    public PinToPres: () => void = unimplementedFunction;
+    public MakeTargetToggle: () => void = unimplementedFunction;
+    public ShowTargetTrail: () => void = unimplementedFunction;
+    public IsTargetToggler: () => boolean = returnFalse;
+    public get Active() {
+        return this._left > 0;
+    }
+
+    constructor(props: Readonly<{}>) {
+        super(props);
+
+        MapAnchorMenu.Instance = this;
+        MapAnchorMenu.Instance._canFade = false;
+    }
+
+    componentWillUnmount() {
+        this._disposer?.();
+        this._disposer2?.();
+    }
+
+    componentDidMount() {
+        this._disposer2 = reaction(
+            () => this._opacity,
+            opacity => {
+                if (!opacity) {
+                    this.setGPTPopupVis(false);
+                    this.setGPTPopupText('');
+                }
+            },
+            { fireImmediately: true }
+        );
+        this._disposer = reaction(
+            () => SelectionManager.Views().slice(),
+            selected => {
+                this.setGPTPopupVis(false);
+                this.setGPTPopupText('');
+                MapAnchorMenu.Instance.fadeOut(true);
+            }
+        );
+    }
+
+    /**
+     * Invokes the API with the selected text and stores it in the summarized text.
+     * @param e pointer down event
+     */
+    gptSummarize = async (e: React.PointerEvent) => {
+        this.setHighlightRange(undefined);
+        this.setGPTPopupVis(true);
+        this.setGPTMode(GPTPopupMode.SUMMARY);
+        this.setLoading(true);
+
+        try {
+            const res = await gptAPICall(this.selectedText, GPTCallType.SUMMARY);
+            if (res) {
+                this.setGPTPopupText(res);
+            } else {
+                this.setGPTPopupText('Something went wrong.');
+            }
+        } catch (err) {
+            console.error(err);
+        }
+
+        this.setLoading(false);
+    };
+
+    /**
+     * Makes a GPT call to edit selected text.
+     * @returns nothing
+     */
+    gptEdit = async () => {
+        if (!this.editorView) return;
+        this.setHighlightRange(undefined);
+        const state = this.editorView.state;
+        const sel = state.selection;
+        const fullText = state.doc.textBetween(0, this.editorView.state.doc.content.size, ' \n');
+        const selectedText = state.doc.textBetween(sel.from, sel.to);
+
+        this.setGPTPopupVis(true);
+        this.setGPTMode(GPTPopupMode.EDIT);
+        this.setLoading(true);
+
+        try {
+            let res = await gptAPICall(selectedText, GPTCallType.EDIT);
+            // let res = await this.mockGPTCall();
+            if (!res) return;
+            res = res.trim();
+            const resultText = fullText.slice(0, sel.from - 1) + res + fullText.slice(sel.to - 1);
+
+            if (res) {
+                this.setGPTPopupText(resultText);
+                this.setHighlightRange([sel.from - 1, sel.from - 1 + res.length]);
+            } else {
+                this.setGPTPopupText('Something went wrong.');
+            }
+        } catch (err) {
+            console.error(err);
+        }
+
+        this.setLoading(false);
+    };
+
+    /**
+     * Replaces text suggestions from GPT.
+     */
+    replaceText = (replacement: string) => {
+        if (!this.editorView || !this.textDoc) return;
+        this.textDoc.text = replacement;
+    };
+
+    pointerDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(
+            this,
+            e,
+            (e: PointerEvent) => {
+                this.StartDrag(e, this._commentCont.current!);
+                return true;
+            },
+            returnFalse,
+            e => this.OnClick?.(e)
+        );
+    };
+
+    audioDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, returnFalse, returnFalse, e => this.OnAudio?.(e));
+    };
+
+    cropDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(
+            this,
+            e,
+            (e: PointerEvent) => {
+                this.StartCropDrag(e, this._commentCont.current!);
+                return true;
+            },
+            returnFalse,
+            e => this.OnCrop?.(e)
+        );
+    };
+
+    @action
+    highlightClicked = (e: React.MouseEvent) => {
+        this.Highlight(this.highlightColor, false, undefined, true);
+        MapAnchorMenu.Instance.fadeOut(true);
+    };
+
+    @computed get highlighter() {
+        return (
+            <Group>
+                <IconButton
+                    icon={<FontAwesomeIcon icon="highlighter" style={{ transition: 'transform 0.1s', transform: 'rotate(-45deg)' }} />}
+                    tooltip={'Click to Highlight'}
+                    onClick={this.highlightClicked}
+                    colorPicker={this.highlightColor}
+                    color={StrCast(Doc.UserDoc().userColor)}
+                />
+                <ColorPicker selectedColor={this.highlightColor} setFinalColor={this.changeHighlightColor} setSelectedColor={this.changeHighlightColor} size={Size.XSMALL} />
+            </Group>
+        );
+    }
+
+    @action changeHighlightColor = (color: string) => {
+        const col: ColorState = {
+            hex: color,
+            hsl: { a: 0, h: 0, s: 0, l: 0, source: '' },
+            hsv: { a: 0, h: 0, s: 0, v: 0, source: '' },
+            rgb: { a: 0, r: 0, b: 0, g: 0, source: '' },
+            oldHue: 0,
+            source: '',
+        };
+        this.highlightColor = Utils.colorString(col);
+    };
+
+    /**
+     * Returns whether the selected text can be summarized. The goal is to have
+     * all selected text available to summarize but its only supported for pdf and web ATM.
+     * @returns Whether the GPT icon for summarization should appear
+     */
+    canSummarize = (): boolean => {
+        const docs = SelectionManager.Docs();
+        if (docs.length > 0) {
+            return docs.some(doc => doc.type === DocumentType.PDF || doc.type === DocumentType.WEB);
+        }
+        return false;
+    };
+
+    /**
+     * Returns whether the selected text can be edited.
+     * @returns Whether the GPT icon for summarization should appear
+     */
+    canEdit = (): boolean => {
+        const docs = SelectionManager.Docs();
+        if (docs.length > 0) {
+            return docs.some(doc => doc.type === 'rtf');
+        }
+        return false;
+    };
+
+    render() {
+        const buttons =
+            this.Status === 'marquee' ? (
+                <>
+                    {this.highlighter}
+                    <IconButton
+                        tooltip="Drag to Place Annotation" //
+                        onPointerDown={this.pointerDown}
+                        icon={<FontAwesomeIcon icon="comment-alt" />}
+                        color={StrCast(Doc.UserDoc().userColor)}
+                    />
+                    {/* GPT Summarize icon only shows up when text is highlighted, not on marquee selection*/}
+                    {MapAnchorMenu.Instance.StartCropDrag === unimplementedFunction && this.canSummarize() && (
+                        <IconButton
+                            tooltip="Summarize with AI" //
+                            onPointerDown={this.gptSummarize}
+                            icon={<FontAwesomeIcon icon="comment-dots" size="lg" />}
+                            color={StrCast(Doc.UserDoc().userColor)}
+                        />
+                    )}
+                    <GPTPopup
+                        key="gptpopup"
+                        visible={this.showGPTPopup}
+                        text={this.GPTpopupText}
+                        highlightRange={this.highlightRange}
+                        loading={this.loadingGPT}
+                        callSummaryApi={this.gptSummarize}
+                        callEditApi={this.gptEdit}
+                        replaceText={this.replaceText}
+                        mode={this.GPTMode}
+                    />
+                    {MapAnchorMenu.Instance.OnAudio === unimplementedFunction ? null : (
+                        <IconButton
+                            tooltip="Click to Record Annotation" //
+                            onPointerDown={this.audioDown}
+                            icon={<FontAwesomeIcon icon="microphone" />}
+                            color={StrCast(Doc.UserDoc().userColor)}
+                        />
+                    )}
+                    {this.canEdit() && (
+                        <IconButton
+                            tooltip="AI edit suggestions" //
+                            onPointerDown={this.gptEdit}
+                            icon={<FontAwesomeIcon icon="pencil-alt" />}
+                            color={StrCast(Doc.UserDoc().userColor)}
+                        />
+                    )}
+                    <Popup
+                        tooltip="Find document to link to selected text" //
+                        type={Type.PRIM}
+                        icon={<FontAwesomeIcon icon={'search'} />}
+                        popup={<LinkPopup key="popup" linkCreateAnchor={this.onMakeAnchor} />}
+                        color={StrCast(Doc.UserDoc().userColor)}
+                    />
+                    {MapAnchorMenu.Instance.StartCropDrag === unimplementedFunction ? null : (
+                        <IconButton
+                            tooltip="Click/Drag to create cropped image" //
+                            onPointerDown={this.cropDown}
+                            icon={<FontAwesomeIcon icon="image" />}
+                            color={StrCast(Doc.UserDoc().userColor)}
+                        />
+                    )}
+                </>
+            ) : (
+                <>
+                    {this.Delete !== returnFalse && (
+                        <IconButton
+                            tooltip="Remove Link Anchor" //
+                            onPointerDown={this.Delete}
+                            icon={<FontAwesomeIcon icon="trash-alt" />}
+                            color={StrCast(Doc.UserDoc().userColor)}
+                        />
+                    )}
+                    {this.PinToPres !== returnFalse && (
+                        <IconButton
+                            tooltip="Pin to Presentation" //
+                            onPointerDown={this.PinToPres}
+                            icon={<FontAwesomeIcon icon="map-pin" />}
+                            color={StrCast(Doc.UserDoc().userColor)}
+                        />
+                    )}
+                    {this.ShowTargetTrail !== returnFalse && (
+                        <IconButton
+                            tooltip="Show Linked Trail" //
+                            onPointerDown={this.ShowTargetTrail}
+                            icon={<FontAwesomeIcon icon="taxi" />}
+                            color={StrCast(Doc.UserDoc().userColor)}
+                        />
+                    )}
+                    {this.IsTargetToggler !== returnFalse && (
+                        <Toggle
+                            tooltip={'Make target visibility toggle on click'}
+                            type={Type.PRIM}
+                            toggleType={ToggleType.BUTTON}
+                            toggleStatus={this.IsTargetToggler()}
+                            onClick={this.MakeTargetToggle}
+                            icon={<FontAwesomeIcon icon="thumbtack" />}
+                            color={StrCast(Doc.UserDoc().userColor)}
+                        />
+                    )}
+                </>
+            );
+
+        return this.getElement(buttons);
+    }
+}
-- 
cgit v1.2.3-70-g09d2


From e724cf830b773d22bada7c319f5c2527b2ffeae7 Mon Sep 17 00:00:00 2001
From: Eric <ericmabr@gmail.com>
Date: Tue, 22 Aug 2023 16:31:00 -0400
Subject: Everything working, except for offset of placing pins and
 mapanchormenu when sidebar is open

---
 src/client/util/CurrentUserUtils.ts             |   2 +-
 src/client/views/MainView.tsx                   |   2 +
 src/client/views/nodes/MapBox/MapAnchorMenu.tsx | 355 ++++--------------------
 src/client/views/nodes/MapBox/MapBox.tsx        | 162 +++++++----
 src/client/views/nodes/MapBox/MapPushpinBox.tsx |   2 +-
 5 files changed, 168 insertions(+), 355 deletions(-)

(limited to 'src/client/views/nodes/MapBox/MapAnchorMenu.tsx')

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 25c8f511b..b63d501de 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -272,7 +272,7 @@ export class CurrentUserUtils {
             {key: "Webpage",    creator: opts => Docs.Create.WebDocument("",opts),          opts: { _width: 400, _height: 512, _nativeWidth: 850, data_useCors: true, }},
             {key: "Comparison", creator: Docs.Create.ComparisonDocument,                    opts: { _width: 300, _height: 300 }},
             {key: "Audio",      creator: opts => Docs.Create.AudioDocument(nullAudio, opts),opts: { _width: 200, _height: 100, }},
-            {key: "Map",        creator: opts => Docs.Create.MapDocument([], opts),         opts: { _width: 800, _height: 600, _layout_fitWidth: true, _layout_showSidebar: true,  }},
+            {key: "Map",        creator: opts => Docs.Create.MapDocument([], opts),         opts: { _width: 800, _height: 600, _layout_fitWidth: true, }},
             {key: "Screengrab", creator: Docs.Create.ScreenshotDocument,                    opts: { _width: 400, _height: 200 }},
             {key: "WebCam",     creator: opts => Docs.Create.WebCamDocument("", opts),      opts: { _width: 400, _height: 200, recording:true, isSystem: true, cloneFieldFilter: new List<string>(["isSystem"]) }},
             {key: "Button",     creator: Docs.Create.ButtonDocument,                        opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}},
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index e376c4fdf..b088157e5 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -57,6 +57,7 @@ import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 import { RichTextMenu } from './nodes/formattedText/RichTextMenu';
 import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup';
 import { LinkDocPreview } from './nodes/LinkDocPreview';
+import { MapAnchorMenu } from './nodes/MapBox/MapAnchorMenu';
 import { RadialMenu } from './nodes/RadialMenu';
 import { TaskCompletionBox } from './nodes/TaskCompletedBox';
 import { OverlayView } from './OverlayView';
@@ -1004,6 +1005,7 @@ export class MainView extends React.Component {
                 <ContextMenu />
                 <RadialMenu />
                 <AnchorMenu />
+                <MapAnchorMenu/>
                 <DashFieldViewMenu />
                 <MarqueeOptionsMenu />
                 <OverlayView />
diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
index 798905bcd..439c1f14f 100644
--- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
+++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
@@ -3,18 +3,18 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import { ColorState } from 'react-color';
-import { Doc, Opt } from '../../../fields/Doc';
-import { returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from '../../../Utils';
-import { SelectionManager } from '../../util/SelectionManager';
-import { AntimodeMenu, AntimodeMenuProps } from "../AntimodeMenu"
-import { LinkPopup } from '../linking/LinkPopup';
-import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT';
-import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup';
+import { Doc, Opt } from '../../../../fields/Doc';
+import { returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from '../../../../Utils';
+import { SelectionManager } from '../../../util/SelectionManager';
+import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu"
+import { LinkPopup } from '../../linking/LinkPopup';
+import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT';
+// import { GPTPopup, GPTPopupMode } from './../../GPTPopup/GPTPopup';
 import { EditorView } from 'prosemirror-view';
 import './MapAnchorMenu.scss';
 import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
-import { StrCast } from '../../../fields/Types';
-import { DocumentType } from '../../documents/DocumentTypes';
+import { StrCast } from '../../../../fields/Types';
+import { DocumentType } from '../../../documents/DocumentTypes';
 
 @observer
 export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -24,73 +24,22 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     private _disposer2: IReactionDisposer | undefined;
     private _commentCont = React.createRef<HTMLButtonElement>();
 
-    @observable private highlightColor: string = 'rgba(245, 230, 95, 0.616)';
 
-    @observable public Status: 'marquee' | 'annotation' | '' = '';
 
-    // GPT additions
-    @observable private GPTpopupText: string = '';
-    @observable private loadingGPT: boolean = false;
-    @observable private showGPTPopup: boolean = false;
-    @observable private GPTMode: GPTPopupMode = GPTPopupMode.SUMMARY;
-    @observable private selectedText: string = '';
-    @observable private editorView?: EditorView;
-    @observable private textDoc?: Doc;
-    @observable private highlightRange: number[] | undefined;
-    private selectionRange: number[] | undefined;
-
-    @action
-    setGPTPopupVis = (vis: boolean) => {
-        this.showGPTPopup = vis;
-    };
-    @action
-    setGPTMode = (mode: GPTPopupMode) => {
-        this.GPTMode = mode;
-    };
-
-    @action
-    setGPTPopupText = (txt: string) => {
-        this.GPTpopupText = txt;
-    };
-
-    @action
-    setLoading = (loading: boolean) => {
-        this.loadingGPT = loading;
-    };
-
-    @action
-    setHighlightRange(r: number[] | undefined) {
-        this.highlightRange = r;
-    }
-
-    @action
-    public setSelectedText = (txt: string) => {
-        this.selectedText = txt;
-    };
-
-    @action
-    public setEditorView = (editor: EditorView) => {
-        this.editorView = editor;
-    };
-
-    @action
-    public setTextDoc = (textDoc: Doc) => {
-        this.textDoc = textDoc;
-    };
 
     public onMakeAnchor: () => Opt<Doc> = () => undefined; // Method to get anchor from text search
 
-    public OnCrop: (e: PointerEvent) => void = unimplementedFunction;
-    public OnClick: (e: PointerEvent) => void = unimplementedFunction;
-    public OnAudio: (e: PointerEvent) => void = unimplementedFunction;
-    public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
-    public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
+    public Center: () => void = unimplementedFunction;
+    // public OnClick: (e: PointerEvent) => void = unimplementedFunction;
+    // public OnAudio: (e: PointerEvent) => void = unimplementedFunction;
+    // public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
+    // public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
     public Highlight: (color: string, isTargetToggler: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>, addAsAnnotation?: boolean) => Opt<Doc> = (color: string, isTargetToggler: boolean) => undefined;
     public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => undefined;
     public Delete: () => void = unimplementedFunction;
-    public PinToPres: () => void = unimplementedFunction;
-    public MakeTargetToggle: () => void = unimplementedFunction;
-    public ShowTargetTrail: () => void = unimplementedFunction;
+    public LinkNote: () => void = unimplementedFunction;
+    // public MakeTargetToggle: () => void = unimplementedFunction;
+    // public ShowTargetTrail: () => void = unimplementedFunction;
     public IsTargetToggler: () => boolean = returnFalse;
     public get Active() {
         return this._left > 0;
@@ -113,8 +62,6 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
             () => this._opacity,
             opacity => {
                 if (!opacity) {
-                    this.setGPTPopupVis(false);
-                    this.setGPTPopupText('');
                 }
             },
             { fireImmediately: true }
@@ -122,259 +69,62 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
         this._disposer = reaction(
             () => SelectionManager.Views().slice(),
             selected => {
-                this.setGPTPopupVis(false);
-                this.setGPTPopupText('');
                 MapAnchorMenu.Instance.fadeOut(true);
             }
         );
     }
+    // audioDown = (e: React.PointerEvent) => {
+    //     setupMoveUpEvents(this, e, returnFalse, returnFalse, e => this.OnAudio?.(e));
+    // };
+
+    // cropDown = (e: React.PointerEvent) => {
+    //     setupMoveUpEvents(
+    //         this,
+    //         e,
+    //         (e: PointerEvent) => {
+    //             this.StartCropDrag(e, this._commentCont.current!);
+    //             return true;
+    //         },
+    //         returnFalse,
+    //         e => this.OnCrop?.(e)
+    //     );
+    // };
+
+
+    static top = React.createRef<HTMLDivElement>();
+    // public get Top(){
+    //     return this.top
+    // }
 
-    /**
-     * Invokes the API with the selected text and stores it in the summarized text.
-     * @param e pointer down event
-     */
-    gptSummarize = async (e: React.PointerEvent) => {
-        this.setHighlightRange(undefined);
-        this.setGPTPopupVis(true);
-        this.setGPTMode(GPTPopupMode.SUMMARY);
-        this.setLoading(true);
-
-        try {
-            const res = await gptAPICall(this.selectedText, GPTCallType.SUMMARY);
-            if (res) {
-                this.setGPTPopupText(res);
-            } else {
-                this.setGPTPopupText('Something went wrong.');
-            }
-        } catch (err) {
-            console.error(err);
-        }
-
-        this.setLoading(false);
-    };
-
-    /**
-     * Makes a GPT call to edit selected text.
-     * @returns nothing
-     */
-    gptEdit = async () => {
-        if (!this.editorView) return;
-        this.setHighlightRange(undefined);
-        const state = this.editorView.state;
-        const sel = state.selection;
-        const fullText = state.doc.textBetween(0, this.editorView.state.doc.content.size, ' \n');
-        const selectedText = state.doc.textBetween(sel.from, sel.to);
-
-        this.setGPTPopupVis(true);
-        this.setGPTMode(GPTPopupMode.EDIT);
-        this.setLoading(true);
-
-        try {
-            let res = await gptAPICall(selectedText, GPTCallType.EDIT);
-            // let res = await this.mockGPTCall();
-            if (!res) return;
-            res = res.trim();
-            const resultText = fullText.slice(0, sel.from - 1) + res + fullText.slice(sel.to - 1);
-
-            if (res) {
-                this.setGPTPopupText(resultText);
-                this.setHighlightRange([sel.from - 1, sel.from - 1 + res.length]);
-            } else {
-                this.setGPTPopupText('Something went wrong.');
-            }
-        } catch (err) {
-            console.error(err);
-        }
-
-        this.setLoading(false);
-    };
-
-    /**
-     * Replaces text suggestions from GPT.
-     */
-    replaceText = (replacement: string) => {
-        if (!this.editorView || !this.textDoc) return;
-        this.textDoc.text = replacement;
-    };
-
-    pointerDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(
-            this,
-            e,
-            (e: PointerEvent) => {
-                this.StartDrag(e, this._commentCont.current!);
-                return true;
-            },
-            returnFalse,
-            e => this.OnClick?.(e)
-        );
-    };
-
-    audioDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(this, e, returnFalse, returnFalse, e => this.OnAudio?.(e));
-    };
-
-    cropDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(
-            this,
-            e,
-            (e: PointerEvent) => {
-                this.StartCropDrag(e, this._commentCont.current!);
-                return true;
-            },
-            returnFalse,
-            e => this.OnCrop?.(e)
-        );
-    };
-
-    @action
-    highlightClicked = (e: React.MouseEvent) => {
-        this.Highlight(this.highlightColor, false, undefined, true);
-        MapAnchorMenu.Instance.fadeOut(true);
-    };
-
-    @computed get highlighter() {
-        return (
-            <Group>
-                <IconButton
-                    icon={<FontAwesomeIcon icon="highlighter" style={{ transition: 'transform 0.1s', transform: 'rotate(-45deg)' }} />}
-                    tooltip={'Click to Highlight'}
-                    onClick={this.highlightClicked}
-                    colorPicker={this.highlightColor}
-                    color={StrCast(Doc.UserDoc().userColor)}
-                />
-                <ColorPicker selectedColor={this.highlightColor} setFinalColor={this.changeHighlightColor} setSelectedColor={this.changeHighlightColor} size={Size.XSMALL} />
-            </Group>
-        );
-    }
-
-    @action changeHighlightColor = (color: string) => {
-        const col: ColorState = {
-            hex: color,
-            hsl: { a: 0, h: 0, s: 0, l: 0, source: '' },
-            hsv: { a: 0, h: 0, s: 0, v: 0, source: '' },
-            rgb: { a: 0, r: 0, b: 0, g: 0, source: '' },
-            oldHue: 0,
-            source: '',
-        };
-        this.highlightColor = Utils.colorString(col);
-    };
-
-    /**
-     * Returns whether the selected text can be summarized. The goal is to have
-     * all selected text available to summarize but its only supported for pdf and web ATM.
-     * @returns Whether the GPT icon for summarization should appear
-     */
-    canSummarize = (): boolean => {
-        const docs = SelectionManager.Docs();
-        if (docs.length > 0) {
-            return docs.some(doc => doc.type === DocumentType.PDF || doc.type === DocumentType.WEB);
-        }
-        return false;
-    };
-
-    /**
-     * Returns whether the selected text can be edited.
-     * @returns Whether the GPT icon for summarization should appear
-     */
-    canEdit = (): boolean => {
-        const docs = SelectionManager.Docs();
-        if (docs.length > 0) {
-            return docs.some(doc => doc.type === 'rtf');
-        }
-        return false;
-    };
 
     render() {
-        const buttons =
-            this.Status === 'marquee' ? (
-                <>
-                    {this.highlighter}
-                    <IconButton
-                        tooltip="Drag to Place Annotation" //
-                        onPointerDown={this.pointerDown}
-                        icon={<FontAwesomeIcon icon="comment-alt" />}
-                        color={StrCast(Doc.UserDoc().userColor)}
-                    />
-                    {/* GPT Summarize icon only shows up when text is highlighted, not on marquee selection*/}
-                    {MapAnchorMenu.Instance.StartCropDrag === unimplementedFunction && this.canSummarize() && (
-                        <IconButton
-                            tooltip="Summarize with AI" //
-                            onPointerDown={this.gptSummarize}
-                            icon={<FontAwesomeIcon icon="comment-dots" size="lg" />}
-                            color={StrCast(Doc.UserDoc().userColor)}
-                        />
-                    )}
-                    <GPTPopup
-                        key="gptpopup"
-                        visible={this.showGPTPopup}
-                        text={this.GPTpopupText}
-                        highlightRange={this.highlightRange}
-                        loading={this.loadingGPT}
-                        callSummaryApi={this.gptSummarize}
-                        callEditApi={this.gptEdit}
-                        replaceText={this.replaceText}
-                        mode={this.GPTMode}
-                    />
-                    {MapAnchorMenu.Instance.OnAudio === unimplementedFunction ? null : (
-                        <IconButton
-                            tooltip="Click to Record Annotation" //
-                            onPointerDown={this.audioDown}
-                            icon={<FontAwesomeIcon icon="microphone" />}
-                            color={StrCast(Doc.UserDoc().userColor)}
-                        />
-                    )}
-                    {this.canEdit() && (
-                        <IconButton
-                            tooltip="AI edit suggestions" //
-                            onPointerDown={this.gptEdit}
-                            icon={<FontAwesomeIcon icon="pencil-alt" />}
-                            color={StrCast(Doc.UserDoc().userColor)}
-                        />
-                    )}
-                    <Popup
-                        tooltip="Find document to link to selected text" //
-                        type={Type.PRIM}
-                        icon={<FontAwesomeIcon icon={'search'} />}
-                        popup={<LinkPopup key="popup" linkCreateAnchor={this.onMakeAnchor} />}
-                        color={StrCast(Doc.UserDoc().userColor)}
-                    />
-                    {MapAnchorMenu.Instance.StartCropDrag === unimplementedFunction ? null : (
-                        <IconButton
-                            tooltip="Click/Drag to create cropped image" //
-                            onPointerDown={this.cropDown}
-                            icon={<FontAwesomeIcon icon="image" />}
-                            color={StrCast(Doc.UserDoc().userColor)}
-                        />
-                    )}
-                </>
-            ) : (
+        const buttons =(
                 <>
-                    {this.Delete !== returnFalse && (
+                    {(
                         <IconButton
-                            tooltip="Remove Link Anchor" //
+                            tooltip="Delete Pin" //
                             onPointerDown={this.Delete}
                             icon={<FontAwesomeIcon icon="trash-alt" />}
                             color={StrCast(Doc.UserDoc().userColor)}
                         />
                     )}
-                    {this.PinToPres !== returnFalse && (
+                    {(
                         <IconButton
-                            tooltip="Pin to Presentation" //
-                            onPointerDown={this.PinToPres}
+                            tooltip="Link Note to Pin" //
+                            onPointerDown={this.LinkNote}
                             icon={<FontAwesomeIcon icon="map-pin" />}
                             color={StrCast(Doc.UserDoc().userColor)}
                         />
                     )}
-                    {this.ShowTargetTrail !== returnFalse && (
+                    {(
                         <IconButton
-                            tooltip="Show Linked Trail" //
-                            onPointerDown={this.ShowTargetTrail}
+                            tooltip="Center on pin" //
+                            onPointerDown={this.Center}
                             icon={<FontAwesomeIcon icon="taxi" />}
                             color={StrCast(Doc.UserDoc().userColor)}
                         />
                     )}
-                    {this.IsTargetToggler !== returnFalse && (
+                    {/* {this.IsTargetToggler !== returnFalse && (
                         <Toggle
                             tooltip={'Make target visibility toggle on click'}
                             type={Type.PRIM}
@@ -384,10 +134,13 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                             icon={<FontAwesomeIcon icon="thumbtack" />}
                             color={StrCast(Doc.UserDoc().userColor)}
                         />
-                    )}
+                    )} */}
                 </>
             );
 
-        return this.getElement(buttons);
+        return this.getElement(<div ref={MapAnchorMenu.top} style={{width:"100%", display:"flex"}}>
+        {buttons}
+        </div>
+        );
     }
 }
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index be2defa9b..14ecc910e 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -5,6 +5,7 @@ import { Button, EditableText, IconButton, Type } from 'browndash-components';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
+import { TbHeartMinus } from 'react-icons/tb';
 import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
 import { Width } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
@@ -26,6 +27,7 @@ import { SidebarAnnos } from '../../SidebarAnnos';
 import { DocumentView, OpenWhere } from '../DocumentView';
 import { FieldView, FieldViewProps } from '../FieldView';
 import { PinProps, PresBox } from '../trails';
+import { MapAnchorMenu } from './MapAnchorMenu';
 import './MapBox.scss';
 // amongus
 /**
@@ -116,9 +118,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @observable private toggleAddMarker = false;
     private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
 
-    @observable _showSidebar = false;
     @computed get SidebarShown() {
-        return this._showSidebar || this.layoutDoc._layout_showSidebar ? true : false;
+        return this.layoutDoc._layout_showSidebar ? true : false;
     }
 
     static _canAnnotate = true;
@@ -299,11 +300,11 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     const fullWidth = this.layoutDoc[Width]();
                     const mapWidth = fullWidth - this.sidebarWidth();
                     if (this.sidebarWidth() + localDelta[0] > 0) {
-                        this._showSidebar = true;
+                        this.layoutDoc._layout_showSidebar = true;
                         this.layoutDoc._width = fullWidth + localDelta[0];
                         this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%';
                     } else {
-                        this._showSidebar = false;
+                        this.layoutDoc._layout_showSidebar = false;
                         this.layoutDoc._width = mapWidth;
                         this.layoutDoc._layout_sidebarWidthPercent = '0%';
                     }
@@ -505,13 +506,14 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     /*
      * Pushpin dblclick
      */
-    @action
-    pushpinDblClicked = (pin: any, pinDoc?: Doc) => {
-        if (pinDoc) this.removePushpin(pinDoc, pin);
-        else this._bingMap.current.entities.remove(pin);
-    };
+    // @action
+    // pushpinDblClicked = (pin: any, pinDoc?: Doc) => {
+    //     if (pinDoc) this.removePushpin(pinDoc);
+    //     else this._bingMap.current.entities.remove(pin);
+    // };
 
     // The pin that is selected
+    @observable
     selectedPin:Doc | undefined;
 
     /*
@@ -519,18 +521,37 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      */
     @action
     pushpinClicked = (pinDoc: Doc) => {
-        // TODO:
-        // if (sidebarannos is not open) open sidebarannos
-        // creates button onclick removes the doc from annotations
+        if (this.selectedPin) {
+            const temp = this.selectedPin;
+            this._bingMap.current.entities.remove(this.map_docToPinMap.get(temp));
+            const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(temp.latitude,temp.longitude));
+            this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(temp as Doc));
+            this._bingMap.current.entities.push(newpin);
+            this.map_docToPinMap.set(temp, newpin);
+        }
+
+        this.selectedPin = pinDoc;
 
-        // pan to pushpin location
-        // this.dataDoc.latitude = pinDoc.latitude;
-        // this.dataDoc.longitude = pinDoc.longitude;
-        this.selectedPin = pinDoc
+        this._bingMap.current.entities.remove(this.map_docToPinMap.get(this.selectedPin));
+        const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(this.selectedPin.latitude,this.selectedPin.longitude), {
+            color: 'green',
+        })
+        this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(this.selectedPin as Doc));
+        this._bingMap.current.entities.push(newpin);
+        this.map_docToPinMap.set(this.selectedPin, newpin);
 
-        /// this should SELECT, not center
+        MapAnchorMenu.Instance.Delete = this.deleteSelectedPin
+        MapAnchorMenu.Instance.Center = this.centerOnSelectedPin;
+        MapAnchorMenu.Instance.LinkNote = this.createNoteAnnotation;
+
+        const point = this._bingMap.current.tryLocationToPixel(new this.MicrosoftMaps.Location(this.selectedPin.latitude,this.selectedPin.longitude))
+        const x = point.x + this.props.PanelWidth() / 2;
+        const y = point.y + this.props.PanelHeight() / 2 +32
+        const cpt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y);
+        MapAnchorMenu.Instance.jumpTo(cpt[0] - this.sidebarWidth()/this.panelWidth()*200, cpt[1], true);
+        document.addEventListener('pointerdown', this.tryHideMapAnchorMenu, true)
+        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', this.mapOnClick);
 
-        this.createNoteAnnotation();
     };
 
     /**
@@ -545,10 +566,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      */
     @action
     mapOnClick = (e: { location: { latitude: any; longitude: any } }) => {
-        if (this.placePinOn) {
-            this.createPushpin(e.location.latitude, e.location.longitude);
-            // this.addAllPins();
-            // this.placePinOn = false;
+        if (this.selectedPin) {
+            const temp = this.selectedPin;
+            this._bingMap.current.entities.remove(this.map_docToPinMap.get(temp));
+            const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(temp.latitude,temp.longitude));
+            this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(temp as Doc));
+            this._bingMap.current.entities.push(newpin);
+            this.map_docToPinMap.set(temp, newpin);
+
+            this.selectedPin=undefined;
+            this.MicrosoftMaps.Events.removeEventListener(this._bingMap.current, 'click', this.mapOnClick);
         }
     };
 
@@ -585,26 +612,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.dataDoc.latitude = location.latitude;
         this.dataDoc.longitude = location.longitude;
         this.dataDoc.mapZoom = this._bingMap.current.getZoom();
-        // this.dataDoc.mapType = this._bingMap.current.getMapTypeId();
-        // this.bingSearchBarContents=location.name;
-
-        // Centers on the searched location
-        // this._bingMap.current.panTo(new this.MicrosoftMaps.Location(this.dataDoc.latitude, this.dataDoc.longitude));
-
-        // this._bingMap.current.setView({
-        //     center: new this.MicrosoftMaps.Location(this.dataDoc.latitude, this.dataDoc.longitude),
-        // });
-
         // Creates a temporary pin but does not add it to the dataDoc
-        var temp = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(location.latitude, location.longitude), {
-            color: 'blue',
-        });
-
-        this.MicrosoftMaps.Events.addHandler(temp, 'dblclick', (e: any) => this.pushpinDblClicked(temp));
-        if (temp != this.searched_pin || this.searched_pin == null) {
-            this._bingMap.current.entities.push(temp);
-            this.searched_pin = temp;
-        }
+        this.createPushpin(this.dataDoc.latitude, this.dataDoc.longitude)
     };
 
     /**
@@ -624,8 +633,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         /// this should use SELECTED pushpin for lat/long  if there is a selection, otherwise CENTER
         const anchor = Docs.Create.MapanchorDocument({
             title: 'MapAnchor:' + this.rootDoc.title,
-            config_latitude: NumCast(this.selectedPin ? this.selectedPin.latitude : this.dataDoc.latitude),
-            config_longitude: NumCast(this.selectedPin ? this.selectedPin.longitude : this.dataDoc.longitude),
+            config_latitude: NumCast(this.selectedPin?.latitude ??  this.dataDoc.latitude),
+            config_longitude: NumCast(this.selectedPin?.longitude ?? this.dataDoc.longitude),
             config_mapZoom: NumCast(this.dataDoc.mapZoom),
             config_mapType: StrCast(this.dataDoc.mapType),
             // preslocationToLookAt:this.dataDoc.locationToLookAt,
@@ -642,6 +651,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return this.rootDoc;
     };
 
+    map_docToPinMap  = new Map<Doc, any>();
     /*
      *   Input: pin doc
      *   Adds MicrosoftMaps Pushpin to the map (render)
@@ -658,7 +668,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this._bingMap.current.entities.push(pushPin);
 
         this.MicrosoftMaps.Events.addHandler(pushPin, 'click', (e: any) => this.pushpinClicked(pin));
-        this.MicrosoftMaps.Events.addHandler(pushPin, 'dblclick', (e: any) => this.pushpinDblClicked(pushPin, pin));
+        // this.MicrosoftMaps.Events.addHandler(pushPin, 'dblclick', (e: any) => this.pushpinDblClicked(pushPin, pin));
+        this.map_docToPinMap.set(pin,pushPin);
     };
 
     @observable
@@ -666,24 +677,72 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     /*
      *   Input: pin doc
-     *   Removes MicrosoftMaps Pushpin to the map (render)
+     *   Removes pin from annotations
      */
     @action
-    removePushpin = (pinDoc: Doc, pin: any) => {
+    removePushpin = (pinDoc: Doc) => {
         // this.allMapPushpins
         // this.allMapPushpins.map(pin => this.addPushpin(pin));
         // this._bingMap.current.entities.clear();
-        this._bingMap.current.entities.remove(pin);
+        
         this.removeDocument(pinDoc, this.annotationKey);
 
         // this.dataDoc[this.annotationKey]
     };
+    /*
+     * Removes pushpin from map render
+    */
+    deletePushpin = (pinDoc:Doc)=>{
+        this._bingMap.current.entities.remove(this.map_docToPinMap.get(pinDoc));
+        this.map_docToPinMap.delete(pinDoc);
+        this.selectedPin=undefined;
+    }
+
+    @action
+    deleteSelectedPin = undoable(()=>{
+        if (this.selectedPin){
+            this.removePushpin(this.selectedPin)
+            
+        }
+        MapAnchorMenu.Instance.fadeOut(true);
+       document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true)
+    }, "delete pin");
+
+    tryHideMapAnchorMenu = (e:PointerEvent) =>{
+        let target = document.elementFromPoint(e.x, e.y);
+
+        while (target != null) {
+            if (target === MapAnchorMenu.top.current) {
+                return;
+            }
+            target = target.parentElement;
+        }
+        e.stopPropagation();
+        e.preventDefault();
+        MapAnchorMenu.Instance.fadeOut(true);
+        document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true)
+
+    }
+
+    // tryhidemenu = e => if( e.parent... == mapanchormenu.top.currrent) do nothing; else hide menu
+
+    @action
+    centerOnSelectedPin = () =>{
+        if (this.selectedPin){
+            this.dataDoc.latitude = this.selectedPin.latitude;
+            this.dataDoc.longitude = this.selectedPin.longitude;
+            
+            
+        }
+        MapAnchorMenu.Instance.fadeOut(true);
+        document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu)
+    }
 
     /**
      * View options for bing maps
      */
     bingViewOptions = {
-        center: { latitude: this.dataDoc.latitude ?? defaultCenter.lat, longitude: this.dataDoc.longitude ?? defaultCenter.lng },
+        // center: { latitude: this.dataDoc.latitude ?? defaultCenter.lat, longitude: this.dataDoc.longitude ?? defaultCenter.lng },
         zoom: this.dataDoc.latitude ?? 10,
         mapTypeId: 'grayscale',
     };
@@ -734,10 +793,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         if (!this._bingMap.current) {
             alert('NO Map!?');
         }
-        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', undoable(this.mapOnClick, 'Added Pin to Map'));
         this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', undoable(this.updateLayout, 'Map Layout Change'));
         this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', undoable(this.updateMapType, 'Map ViewType Change'));
-        //this.updateLayout();
+        // this.updateLayout();
         // this.updateMapType();
         this._disposer.location = reaction(
             () => ({ lat: this.rootDoc.latitude, lng: this.rootDoc.longitude, zoom: this.rootDoc.mapZoom, mapType: this.rootDoc.mapType }),
@@ -756,13 +814,13 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     // Keeps track of when dragging a pin onto map
     draggingPin = false;
     dragToggle = (e: React.PointerEvent) => {
-        console.log('DRAGGING TOGGLE');
+        // console.log('DRAGGING TOGGLE');
         document.addEventListener('drop', this.dropPin, true);
         document.addEventListener('pointermove', this.pinMove, true);
         e.stopPropagation();
     };
     pinMove = (e: PointerEvent) => {
-        console.log('MOVING');
+        // console.log('MOVING');
         e.stopPropagation();
     };
     dropPin = (e: DragEvent) => {
diff --git a/src/client/views/nodes/MapBox/MapPushpinBox.tsx b/src/client/views/nodes/MapBox/MapPushpinBox.tsx
index d28209ea1..66fe1ce53 100644
--- a/src/client/views/nodes/MapBox/MapPushpinBox.tsx
+++ b/src/client/views/nodes/MapBox/MapPushpinBox.tsx
@@ -19,7 +19,7 @@ export class MapPushpinBox extends ViewBoxBaseComponent<FieldViewProps>() {
         this.mapBoxView.addPushpin(this.rootDoc);
     }
     componentWillUnmount() {
-        // this.mapBoxView.removePushpin(this.rootDoc);
+        this.mapBoxView.deletePushpin(this.rootDoc);
     }
 
     @computed get mapBoxView() {
-- 
cgit v1.2.3-70-g09d2


From 6a85c8d4115a968f563369516d38549745e76303 Mon Sep 17 00:00:00 2001
From: Eric <ericmabr@gmail.com>
Date: Thu, 24 Aug 2023 12:47:57 -0400
Subject: All working except createnote undo, and center on selected pin
 getAnchor

---
 src/client/views/SidebarAnnos.tsx               |  5 ++-
 src/client/views/nodes/MapBox/MapAnchorMenu.tsx |  2 +-
 src/client/views/nodes/MapBox/MapBox.tsx        | 47 ++++++++++++++++++-------
 src/fields/Doc.ts                               |  4 +--
 4 files changed, 40 insertions(+), 18 deletions(-)

(limited to 'src/client/views/nodes/MapBox/MapAnchorMenu.tsx')

diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index cd50865fb..7635d719e 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -225,10 +225,9 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                 <div className="sidebarAnnos-tagList" style={{ height: this.filtersHeight() }} onWheel={e => e.stopPropagation()}>
                     {this.allUsers.map(renderUsers)}
                     {this.allHashtags.map(renderTag)}
-                    {Array.from(this.allMetadata.keys())
+                    {/* {Array.from(this.allMetadata.keys())
                         .sort()
-                        .map(key => renderMeta(key, this.allMetadata.get(key)))}
-                    Hello
+                        .map(key => renderMeta(key, this.allMetadata.get(key)))} */}
                 </div>
 
 
diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
index 439c1f14f..897bb90a6 100644
--- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
+++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
@@ -120,7 +120,7 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                         <IconButton
                             tooltip="Center on pin" //
                             onPointerDown={this.Center}
-                            icon={<FontAwesomeIcon icon="taxi" />}
+                            icon={<FontAwesomeIcon icon="compress-arrows-alt" />}
                             color={StrCast(Doc.UserDoc().userColor)}
                         />
                     )}
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 654d446a2..dbb38e763 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -14,6 +14,7 @@ import { ScriptField } from '../../../../fields/ScriptField';
 import { NumCast, StrCast } from '../../../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils';
 import { Docs } from '../../../documents/Documents';
+import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from '../../../util/DragManager';
 import { SnappingManager } from '../../../util/SnappingManager';
 import { Transform } from '../../../util/Transform';
@@ -352,10 +353,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
     };
 
-    createNoteAnnotation = () => {
+    createNoteAnnotation = undoable(() => {
         !this.layoutDoc.layout_showSidebar && this.toggleSidebar();
-        setTimeout(() => this._sidebarRef.current?.anchorMenuClick(this.getAnchor(false))); // give time for sidebarRef to be created
-    };
+        setTimeout(() =>{
+          const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(false));
+          if (note && this.selectedPin) {
+            note.latitude = this.selectedPin.latitude;
+            note.longitude = this.selectedPin.latitude;
+          }
+        }); // give time for sidebarRef to be created
+    }, "create linked note");
 
     sidebarDown = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, () => setTimeout(this.toggleSidebar), true);
@@ -488,7 +495,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      * Creates Pushpin doc and adds it to the list of annotations
      */
     @action
-    createPushpin = (latitude: number, longitude: number) => {
+    createPushpin = undoable((latitude: number, longitude: number) => {
         // Stores the pushpin as a MapMarkerDocument
         const mapMarker = Docs.Create.PushpinDocument(
             NumCast(latitude),
@@ -501,7 +508,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.addDocument(mapMarker, this.annotationKey);
 
         // mapMarker.infoWindowOpen = true;
-    };
+    },"createpin");
 
     /*
      * Pushpin dblclick
@@ -519,6 +526,10 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @action
     deselectPin = () => {
         if (this.selectedPin) {
+            // Removes filter
+            Doc.setDocFilter(this.rootDoc, "latitude", this.selectedPin.latitude, "remove");
+            Doc.setDocFilter(this.rootDoc, "longitude", this.selectedPin.longitude, "remove");
+
             const temp = this.selectedPin;
             this._bingMap.current.entities.remove(this.map_docToPinMap.get(temp));
             const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(temp.latitude, temp.longitude));
@@ -527,10 +538,15 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             this.map_docToPinMap.set(temp, newpin);
             this.selectedPin = undefined;
 
-            // setTimeout(() => this._sidebarRef.current?.makeDocUnfiltered(this._sidebarRef.current.));
+            
         }
+        
     };
 
+    getView = async (doc: Doc) => {
+        if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar();
+        return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
+    };
     /*
      * Pushpin onclick
      */
@@ -539,6 +555,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.deselectPin();
         this.selectedPin = pinDoc;
 
+        Doc.setDocFilter(this.rootDoc, "latitude", this.selectedPin.latitude, "match");
+        Doc.setDocFilter(this.rootDoc, "longitude", this.selectedPin.latitude, "match");
+
         this._bingMap.current.entities.remove(this.map_docToPinMap.get(this.selectedPin));
         const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(this.selectedPin.latitude, this.selectedPin.longitude), {
             color: 'green',
@@ -552,17 +571,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         MapAnchorMenu.Instance.LinkNote = this.createNoteAnnotation;
 
         const point = this._bingMap.current.tryLocationToPixel(new this.MicrosoftMaps.Location(this.selectedPin.latitude, this.selectedPin.longitude));
-        const x = point.x + this.props.PanelWidth() / 2;
+        const x = point.x + (this.props.PanelWidth() - this.sidebarWidth()) / 2;
         const y = point.y + this.props.PanelHeight() / 2 + 32;
         const cpt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y);
-        MapAnchorMenu.Instance.jumpTo(cpt[0] - (this.sidebarWidth() / this.panelWidth()) * 200, cpt[1], true);
+        MapAnchorMenu.Instance.jumpTo(cpt[0], cpt[1], true);
+
         document.addEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
         this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', this.mapOnClick);
 
         // Filter sidebar:
-        // if sidebar is open, filter.
-        if (this.layoutDoc._layout_showSidebar) {
-        }
+
     };
 
     /**
@@ -573,7 +591,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     }
 
     /**
-     * Map OnClick ~> creates a pushpin
+     * Map OnClick
      */
     @action
     mapOnClick = (e: { location: { latitude: any; longitude: any } }) => {
@@ -700,11 +718,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this._bingMap.current.entities.remove(this.map_docToPinMap.get(pinDoc));
         this.map_docToPinMap.delete(pinDoc);
         this.selectedPin = undefined;
+
     };
 
     @action
     deleteSelectedPin = undoable(() => {
         if (this.selectedPin) {
+            // Removes filter
+            Doc.setDocFilter(this.rootDoc, "latitude", this.selectedPin.latitude, "remove");
+            Doc.setDocFilter(this.rootDoc, "longitude", this.selectedPin.longitude, "remove");
+
             this.removePushpin(this.selectedPin);
         }
         MapAnchorMenu.Instance.fadeOut(true);
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 6d4f4180d..7ba4f0e6f 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1490,8 +1490,8 @@ export namespace Doc {
         runInAction(() => {
             for (let i = 0; i < childFilters.length; i++) {
                 const fields = childFilters[i].split(FilterSep); // split key:value:modifier
-                if (fields[0] === key && (fields[1] === value || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) {
-                    if (fields[2] === modifiers && modifiers && fields[1] === value) {
+                if (fields[0] === key && (fields[1] === value.toString() || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) {
+                    if (fields[2] === modifiers && modifiers && fields[1] === value.toString()) {
                         if (toggle) modifiers = 'remove';
                         else return;
                     }
-- 
cgit v1.2.3-70-g09d2


From 10bb2ae3171c2035163c611de966c5aee4769ac3 Mon Sep 17 00:00:00 2001
From: Eric <ericmabr@gmail.com>
Date: Thu, 24 Aug 2023 12:57:22 -0400
Subject: note icon for mapanchormenu changed

---
 src/client/views/nodes/MapBox/MapAnchorMenu.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/nodes/MapBox/MapAnchorMenu.tsx')

diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
index 897bb90a6..f731763af 100644
--- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
+++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
@@ -112,7 +112,7 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                         <IconButton
                             tooltip="Link Note to Pin" //
                             onPointerDown={this.LinkNote}
-                            icon={<FontAwesomeIcon icon="map-pin" />}
+                            icon={<FontAwesomeIcon icon="sticky-note" />}
                             color={StrCast(Doc.UserDoc().userColor)}
                         />
                     )}
-- 
cgit v1.2.3-70-g09d2

