diff options
| author | bobzel <zzzman@gmail.com> | 2021-09-02 10:16:11 -0400 | 
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2021-09-02 10:16:11 -0400 | 
| commit | 4e2e798e0d97858dd03748709d3d55f15a9a1360 (patch) | |
| tree | 4940c2dc2239bcd6b73a567358eebced1394df65 | |
| parent | 01cab1fc7259f1a944fad49403328e70e9d61b97 (diff) | |
| parent | 6a2be14c25313058ff466ed7c2a6631126616263 (diff) | |
Merge branch 'menu_updates_geireann' of https://github.com/brown-dash/Dash-Web into menu_updates_geireann
34 files changed, 502 insertions, 228 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c4a713dc6..bd247bd01 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -59,6 +59,7 @@ import { WebBox } from "../views/nodes/WebBox";  import { SearchBox } from "../views/search/SearchBox";  import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";  import { DocumentType } from "./DocumentTypes"; +import { IconProp } from "@fortawesome/fontawesome-svg-core";  const path = require('path');  const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", "")); @@ -272,7 +273,12 @@ export class DocumentOptions {      treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view      treeViewHideHeader?: boolean; // whether to hide the header for a document in a tree view      treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items. -    treeViewShowClearButton?: boolean; // whether a clear button should be displayed  + +    // Action Button +    buttonMenu?: boolean; // whether a action button should be displayed  +    buttonMenuDoc?: Doc; +    explainer?:string; +      treeViewOpenIsTransient?: boolean; // ignores the treeViewOpen Doc flag, allowing a treeViewItem's expand/collapse state to be independent of other views of the same document in the same or any other tree view      _treeViewOpen?: boolean; // whether this document is expanded in a tree view  (note: need _ and regular versions since this can be specified for both proto and layout docs)      treeViewOpen?: boolean; // whether this document is expanded in a tree view @@ -1165,7 +1171,7 @@ export namespace DocUtils {      export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number, simpleMenu: boolean = false): void {          !simpleMenu && ContextMenu.Instance.addItem({ -            description: "Add Note ...", +            description: "Quick Notes",              subitems: DocListCast((Doc.UserDoc()["template-notes"] as Doc).data).map((note, i) => ({                  description: ":" + StrCast(note.title),                  event: undoBatch((args: { x: number, y: number }) => { @@ -1178,12 +1184,12 @@ export namespace DocUtils {                      textDoc[textDoc.layoutKey] = note;                      docTextAdder(textDoc);                  }), -                icon: "eye" +                icon: StrCast(note.icon) as IconProp              })) as ContextMenuProps[], -            icon: "eye" +            icon: "sticky-note"          }); -        ContextMenu.Instance.addItem({ -            description: ":=math", event: () => { +        const math:ContextMenuProps = ({ +            description: ":Math", event: () => {                  const created = Docs.Create.EquationDocument();                  if (created) {                      created.author = Doc.CurrentUserEmail; @@ -1194,25 +1200,27 @@ export namespace DocUtils {                      EquationBox.SelectOnLoad = created[Id];                      docAdder?.(created);                  } -            }, icon: "compress-arrows-alt" +            }, icon: "calculator"          }); +        const documentList:ContextMenuProps[] = DocListCast(Cast(Doc.UserDoc().myItemCreators, Doc, null)?.data).filter(btnDoc => !btnDoc.hidden).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc && doc !== Doc.UserDoc().emptyPresentation).map((dragDoc, i) => ({ +            description: ":" + StrCast(dragDoc.title), +            event: undoBatch((args: { x: number, y: number }) => { +                const newDoc = Doc.copyDragFactory(dragDoc); +                if (newDoc) { +                    newDoc.author = Doc.CurrentUserEmail; +                    newDoc.x = x; +                    newDoc.y = y; +                    if (newDoc.type === DocumentType.RTF) FormattedTextBox.SelectOnLoad = newDoc[Id]; +                    docAdder?.(newDoc); +                } +            }), +            icon: Doc.toIcon(dragDoc), +        })) as ContextMenuProps[];  +        documentList.push(math)          ContextMenu.Instance.addItem({              description: "Create document", -            subitems: DocListCast(Cast(Doc.UserDoc().myItemCreators, Doc, null)?.data).filter(btnDoc => !btnDoc.hidden).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc && doc !== Doc.UserDoc().emptyPresentation).map((dragDoc, i) => ({ -                description: ":" + StrCast(dragDoc.title), -                event: undoBatch((args: { x: number, y: number }) => { -                    const newDoc = Doc.copyDragFactory(dragDoc); -                    if (newDoc) { -                        newDoc.author = Doc.CurrentUserEmail; -                        newDoc.x = x; -                        newDoc.y = y; -                        if (newDoc.type === DocumentType.RTF) FormattedTextBox.SelectOnLoad = newDoc[Id]; -                        docAdder?.(newDoc); -                    } -                }), -                icon: Doc.toIcon(dragDoc), -            })) as ContextMenuProps[], -            icon: "eye" +            subitems: documentList, +            icon: "file"          });      }// applies a custom template to a document.  the template is identified by it's short name (e.g, slideView not layout_slideView)      export function makeCustomViewClicked(doc: Doc, creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) { diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index afe3940b6..56807c63b 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -55,6 +55,7 @@ interface Button {      width?: number;      list?: string[];      ignoreClick?: boolean; +    buttonText?: string;  }  export let resolvedPorts: { server: number, socket: number }; @@ -84,7 +85,7 @@ export class CurrentUserUtils {                  title: "NEW MOBILE BUTTON",                  onClick: undefined,              }, -                [this.ficon({ +                [this.createToolButton({                      ignoreClick: true,                      icon: "mobile",                      btnType: ButtonType.ToolButton, @@ -92,7 +93,7 @@ export class CurrentUserUtils {                  }),                  this.mobileTextContainer({},                      [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])]); -            doc["template-mobile-button"] = CurrentUserUtils.ficon({ +            doc["template-mobile-button"] = CurrentUserUtils.createToolButton({                  onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),                  dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, title: "mobile button", icon: "mobile", btnType: ButtonType.ToolButton,              }); @@ -107,7 +108,7 @@ export class CurrentUserUtils {                  { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true }              );              slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); -            doc["template-button-slides"] = CurrentUserUtils.ficon({ +            doc["template-button-slides"] = CurrentUserUtils.createToolButton({                  onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),                  dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, title: "presentation slide", icon: "address-card",                  btnType: ButtonType.ToolButton @@ -154,7 +155,7 @@ export class CurrentUserUtils {              };              linkTemplate.header = new RichTextField(JSON.stringify(rtf2), ""); -            doc["template-button-link"] = CurrentUserUtils.ficon({ +            doc["template-button-link"] = CurrentUserUtils.createToolButton({                  onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),                  dragFactory: new PrefetchProxy(linkTemplate) as any as Doc, title: "link view", icon: "window-maximize", system: true,                  btnType: ButtonType.ToolButton @@ -186,7 +187,7 @@ export class CurrentUserUtils {              const box = MulticolumnDocument([/*no, */ yes, name], { title: "value", _width: 120, _height: 35, system: true });              box.isTemplateDoc = makeTemplate(box, true, "switch"); -            doc["template-button-switch"] = CurrentUserUtils.ficon({ +            doc["template-button-switch"] = CurrentUserUtils.createToolButton({                  onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),                  dragFactory: new PrefetchProxy(box) as any as Doc, title: "data switch", icon: "toggle-on", system: true,                  btnType: ButtonType.ToolButton @@ -236,7 +237,7 @@ export class CurrentUserUtils {              short.title = "A Short Description";              long.title = "Long Description"; -            doc["template-button-detail"] = CurrentUserUtils.ficon({ +            doc["template-button-detail"] = CurrentUserUtils.createToolButton({                  onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),                  dragFactory: new PrefetchProxy(detailView) as any as Doc,                  title: "detailView", @@ -275,7 +276,7 @@ export class CurrentUserUtils {      static setupNoteTemplates(doc: Doc) {          if (doc["template-note-Note"] === undefined) {              const noteView = Docs.Create.TextDocument("", { -                title: "text", isTemplateDoc: true, backgroundColor: "yellow", system: true, +                title: "text", isTemplateDoc: true, backgroundColor: "yellow", system: true, icon: "sticky-note",                  _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),              });              noteView.isTemplateDoc = makeTemplate(noteView, true, "Note"); @@ -283,7 +284,7 @@ export class CurrentUserUtils {          }          if (doc["template-note-Idea"] === undefined) {              const noteView = Docs.Create.TextDocument("", { -                title: "text", backgroundColor: "pink", system: true, +                title: "text", backgroundColor: "pink", system: true, icon: "lightbulb",                  _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),              });              noteView.isTemplateDoc = makeTemplate(noteView, true, "Idea"); @@ -291,7 +292,7 @@ export class CurrentUserUtils {          }          if (doc["template-note-Topic"] === undefined) {              const noteView = Docs.Create.TextDocument("", { -                title: "text", backgroundColor: "lightblue", system: true, +                title: "text", backgroundColor: "lightblue", system: true, icon: "book-open",                  _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),              });              noteView.isTemplateDoc = makeTemplate(noteView, true, "Topic"); @@ -467,7 +468,7 @@ export class CurrentUserUtils {              ((doc.emptyHeader as Doc).proto as Doc)["dragFactory-count"] = 0;          }          if (doc.emptyComparison === undefined) { -            doc.emptyComparison = Docs.Create.ComparisonDocument({ title: "compare", _width: 300, _height: 300, system: true, cloneFieldFilter: new List<string>(["system"]) }); +            doc.emptyComparison = Docs.Create.ComparisonDocument({ title: "comparison box", _width: 300, _height: 300, system: true, cloneFieldFilter: new List<string>(["system"]) });          }          if (doc.emptyScript === undefined) {              doc.emptyScript = Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250, title: "script", system: true, cloneFieldFilter: new List<string>(["system"]) }); @@ -512,7 +513,7 @@ export class CurrentUserUtils {              { toolTip: "Tap to create a progressive slide", title: "Slide", icon: "file", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptySlide as Doc },              { toolTip: "Tap to create a cat image in a new pane, drag for a cat image", title: "Image", icon: "cat", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyImage as Doc },              { toolTip: "Tap to create a comparison box in a new pane, drag for a comparison box", title: "Compare", icon: "columns", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyComparison as Doc, noviceMode: true }, -            { toolTip: "Tap to create a screen grabber in a new pane, drag for a screen grabber", title: "Grab", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScreenshot as Doc, noviceMode: true }, +            { toolTip: "Tap to create a screen grabber in a new pane, drag for a screen grabber", title: "Grab", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScreenshot as Doc },              { toolTip: "Tap to create a videoWall", title: "Wall", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWall as Doc },              { toolTip: "Tap to create an audio recorder in a new pane, drag for an audio recorder", title: "Audio", icon: "microphone", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyAudio as Doc, noviceMode: true },              { toolTip: "Tap to create a button in a new pane, drag for a button", title: "Button", icon: "bolt", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyButton as Doc }, @@ -561,7 +562,7 @@ export class CurrentUserUtils {          if (dragCreatorSet === undefined) {              doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, {                  title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, -                _forceActive: true, _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true, +                _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true,                  dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true              }));          } else { @@ -574,31 +575,31 @@ export class CurrentUserUtils {          return [              { title: "Dashboards", target: Cast(doc.myDashboards, Doc, null), icon: "desktop", click: 'selectMainMenu(self)' },              { title: "Search", target: Cast(doc.mySearchPanel, Doc, null), icon: "search", click: 'selectMainMenu(self)' }, -            { title: "My Files", target: Cast(doc.myFilesystem, Doc, null), icon: "file", click: 'selectMainMenu(self)' }, -            { title: "Tools", target: Cast(doc.myTools, Doc, null), icon: "wrench", click: 'selectMainMenu(self)' }, -            { title: "Import", target: Cast(doc.myImportDocs, Doc, null), icon: "upload", click: 'selectMainMenu(self)' }, +            { title: "File Manager", target: Cast(doc.myFilesystem, Doc, null), icon: "folder-open", click: 'selectMainMenu(self)' }, +            { title: "Tools", target: Cast(doc.myTools, Doc, null), icon: "wrench", click: 'selectMainMenu(self)', hidden: "IsNoviceMode()" }, +            { title: "Uploads", target: Cast(doc.myUploadDocs, Doc, null), icon: "upload", click: 'selectMainMenu(self)' },              { title: "Recently Closed", target: Cast(doc.myRecentlyClosedDocs, Doc, null), icon: "archive", click: 'selectMainMenu(self)' },              { title: "Sharing", target: Cast(doc.mySharedDocs, Doc, null), icon: "users", click: 'selectMainMenu(self)', watchedDocuments: doc.mySharedDocs as Doc },              { title: "Trails", target: Cast(doc.myTrails, Doc, null), icon: "pres-trail", click: 'selectMainMenu(self)' }, -            // { title: "Help", target: undefined as any, icon: "question-circle", click: 'selectMainMenu(self)' }, -            // { title: "Settings", target: undefined as any, icon: "cog", click: 'selectMainMenu(self)' }, -            { title: "User Doc", target: Cast(doc.myUserDoc, Doc, null), icon: "address-card", click: 'selectMainMenu(self)' }, +            { title: "User Doc", target: Cast(doc.myUserDoc, Doc, null), icon: "address-card", click: 'selectMainMenu(self)', hidden: "IsNoviceMode()" },          ];      }      static async setupMenuPanel(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) {          if (doc.menuStack === undefined) {              await this.setupSharingSidebar(doc, sharingDocumentId, linkDatabaseId);  // sets up the right sidebar collection for mobile upload documents and sharing -            const menuBtns = (await CurrentUserUtils.menuBtnDescriptions(doc)).map(({ title, target, icon, click, watchedDocuments }) => +            const menuBtns = (await CurrentUserUtils.menuBtnDescriptions(doc)).map(({ title, target, icon, click, watchedDocuments, hidden }) =>                  Docs.Create.FontIconDocument({                      icon,                      btnType: ButtonType.MenuButton,                      _stayInCollection: true,                      _hideContextMenu: true, +                    _chromeHidden: true,                      system: true,                      dontUndo: true,                      title,                      target, +                    hidden: hidden ? ComputedField.MakeFunction("IsNoviceMode()") as any : undefined,                      _dropAction: "alias",                      _removeDropProperties: new List<string>(["dropAction", "_stayInCollection"]),                      _width: 60, @@ -613,8 +614,6 @@ export class CurrentUserUtils {                      this.searchBtn = menuBtn;                  }              }); -            // hack -- last button is assumed to be the userDoc -            menuBtns[menuBtns.length - 1].hidden = ComputedField.MakeFunction("IsNoviceMode()");              menuBtns.forEach(menuBtn => {                  if (menuBtn.title === "Search") { @@ -686,7 +685,7 @@ export class CurrentUserUtils {                  onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,                  backgroundColor: data.backgroundColor, system: true              }, -                [this.ficon({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)", system: true, btnType: ButtonType.ClickButton, }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])]) +                [this.createToolButton({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)", system: true, btnType: ButtonType.ClickButton, }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])])          );      } @@ -822,6 +821,7 @@ export class CurrentUserUtils {              const removeDashboard = ScriptField.MakeScript('removeDashboard(self)');              (doc.myDashboards as any as Doc).childContextMenuScripts = new List<ScriptField>([newDashboard!, shareDashboard!, removeDashboard!]);              (doc.myDashboards as any as Doc).childContextMenuLabels = new List<string>(["Create New Dashboard", "Share Dashboard", "Remove Dashboard"]); +            (doc.myDashboards as any as Doc).childContextMenuIcons = new List<string>(["plus", "share", "times"]);              // (doc.myDashboards as any as Doc).childContextMenuScripts = new List<ScriptField>([newDashboard!, toggleTheme!, toggleComic!, snapshotDashboard!, shareDashboard!, removeDashboard!]);              // (doc.myDashboards as any as Doc).childContextMenuLabels = new List<string>(["Create New Dashboard", "Toggle Theme Colors", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard"]);          } @@ -831,16 +831,17 @@ export class CurrentUserUtils {      static async setupPresentations(doc: Doc) {          await doc.myTrails;          if (doc.myTrails === undefined) { +            const newTrail = ScriptField.MakeScript(`createNewPresentation()`); +            const newTrailButton:Doc = Docs.Create.FontIconDocument({ onClick: newTrail, _forceActive: true, toolTip: "New trail", _stayInCollection: true, _hideContextMenu: true, title: "New trail", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New trail", icon: "plus", system: true });              doc.myTrails = new PrefetchProxy(Docs.Create.TreeDocument([], {                  title: "My Trails", _showTitle: "title", _height: 100, -                treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias", -                treeViewTruncateTitleWidth: 150, ignoreClick: true, -                _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true +                treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _fitWidth: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", +                treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newTrailButton, +                _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true, +                explainer: "All of the trails that you have created will appear here."              })); -            const newPresentations = ScriptField.MakeScript(`createNewPresentation()`); -            (doc.myTrails as any as Doc).contextMenuScripts = new List<ScriptField>([newPresentations!]); +            (doc.myTrails as any as Doc).contextMenuScripts = new List<ScriptField>([newTrail!]);              (doc.myTrails as any as Doc).contextMenuLabels = new List<string>(["Create New Trail"]); -            const presentations = doc.myTrails as any as Doc;          }          return doc.myTrails as any as Doc;      } @@ -849,31 +850,39 @@ export class CurrentUserUtils {          await doc.myFilesystem;          if (doc.myFilesystem === undefined) {              doc.myFileOrphans = Docs.Create.TreeDocument([], { title: "Unfiled", _stayInCollection: true, system: true, isFolder: true }); -            doc.myFileRoot = Docs.Create.TreeDocument([], { title: "file root", _stayInCollection: true, system: true, isFolder: true }); -            doc.myFilesystem = new PrefetchProxy(Docs.Create.TreeDocument([doc.myFileRoot as Doc, doc.myFileOrphans as Doc], { -                title: "My Documents", _showTitle: "title", _height: 100, +            // doc.myFileRoot = Docs.Create.TreeDocument([], { title: "file root", _stayInCollection: true, system: true, isFolder: true }); +            const newFolder = ScriptField.MakeFunction(`doc.makeFolder()`, { doc: doc.myFilesystem })!; +            const newFolderButton:Doc = Docs.Create.FontIconDocument({ onClick: newFolder, _forceActive: true, toolTip: "New folder", _stayInCollection: true, _hideContextMenu: true, title: "New folder", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New folder", icon: "folder-plus", system: true }); +            doc.myFilesystem = new PrefetchProxy(Docs.Create.TreeDocument([doc.myFileOrphans as Doc], { +                title: "My Documents", _showTitle: "title",  buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100,                  treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias",                  treeViewTruncateTitleWidth: 150, ignoreClick: true,                  isFolder: true, treeViewType: "fileSystem", childHideLinkButton: true, -                _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "proto", system: true +                _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "proto", system: true, +                explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."              })); +            (doc.myTrails as any as Doc).contextMenuScripts = new List<ScriptField>([newFolder!]); +            (doc.myTrails as any as Doc).contextMenuLabels = new List<string>(["Create new folder"]);          }          return doc.myFilesystem as any as Doc;      }      static setupRecentlyClosedDocs(doc: Doc) { -        // setup Recently Closed library item          if (doc.myRecentlyClosedDocs === undefined) { -            const clearDocs = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript(`getProto(self).data = new List([])`), toolTip: "Empty", _stayInCollection: true, _hideContextMenu: true, title: "Empty", btnType: ButtonType.TextButton, _width: 200, buttonText: "Empty Recently Closed", icon: "trash", system: true }); -            doc.myRecentlyClosedDocs = new PrefetchProxy(Docs.Create.TreeDocument([clearDocs], { -                title: "My Recently Closed", _showTitle: "title", treeViewShowClearButton: true, childHideLinkButton: true, +            const clearAll = ScriptField.MakeScript(`getProto(self).data = new List([])`); +            const clearDocsButton:Doc = Docs.Create.FontIconDocument({ onClick: clearAll, _forceActive: true, toolTip: "Empty recently closed", _stayInCollection: true, _hideContextMenu: true, title: "Empty", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "Empty", icon: "trash", system: true }); +            doc.myRecentlyClosedDocs = new PrefetchProxy(Docs.Create.TreeDocument([], { +                title: "My Recently Closed", _showTitle: "title", buttonMenu: true, buttonMenuDoc: clearDocsButton, childHideLinkButton: true,                  treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias",                  treeViewTruncateTitleWidth: 150, ignoreClick: true, -                _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true +                _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true, +                explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list." +              })); -            const clearAll = ScriptField.MakeScript(`getProto(self).data = new List([])`);              (doc.myRecentlyClosedDocs as any as Doc).contextMenuScripts = new List<ScriptField>([clearAll!]); -            (doc.myRecentlyClosedDocs as any as Doc).contextMenuLabels = new List<string>(["Clear All"]); +            (doc.myRecentlyClosedDocs as any as Doc).contextMenuLabels = new List<string>(["Empty recently closed"]); +            (doc.myRecentlyClosedDocs as any as Doc).contextMenuIcons = new List<string>(["trash"]); +          }      } @@ -918,7 +927,7 @@ export class CurrentUserUtils {      static async setupSidebarButtons(doc: Doc) {          CurrentUserUtils.setupSidebarContainer(doc);          await CurrentUserUtils.setupToolsBtnPanel(doc); -        CurrentUserUtils.setupImportSidebar(doc); +        CurrentUserUtils.setupUploadSidebar(doc);          CurrentUserUtils.setupDashboards(doc);          CurrentUserUtils.setupPresentations(doc);          CurrentUserUtils.setupFilesystem(doc); @@ -932,17 +941,17 @@ export class CurrentUserUtils {          _lockedPosition: true, system: true, flexDirection: "row"      })) as any as Doc -    static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ -        ...opts, _dropAction: "alias", _removeDropProperties: new List<string>(["_dropAction", "stayInCollection"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true +    static createToolButton = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ +        ...opts, btnType: ButtonType.ToolButton, _forceActive: true, _dropAction: "alias", _removeDropProperties: new List<string>(["_dropAction", "stayInCollection"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true      })) as any as Doc      /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window      static setupDockedButtons(doc: Doc) {          if (doc["dockedBtn-undo"] === undefined) { -            doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), dontUndo: true, _stayInCollection: true, btnType: ButtonType.ToolButton, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "Click to undo", title: "undo", icon: "undo-alt", system: true }); +            doc["dockedBtn-undo"] = CurrentUserUtils.createToolButton({ onClick: ScriptField.MakeScript("undo()"), _width: 30, _height: 30, dontUndo: true, _stayInCollection: true, btnType: ButtonType.ToolButton, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "Click to undo", title: "undo", icon: "undo-alt", system: true });          }          if (doc["dockedBtn-redo"] === undefined) { -            doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), dontUndo: true, _stayInCollection: true, btnType: ButtonType.ToolButton, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "Click to redo", title: "redo", icon: "redo-alt", system: true }); +            doc["dockedBtn-redo"] = CurrentUserUtils.createToolButton({ onClick: ScriptField.MakeScript("redo()"), _width: 30, _height: 30, dontUndo: true, _stayInCollection: true, btnType: ButtonType.ToolButton, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "Click to redo", title: "redo", icon: "redo-alt", system: true });          }          if (doc.dockedBtns === undefined) {              doc.dockedBtns = CurrentUserUtils.linearButtonList({ title: "docked buttons", _height: 40, flexGap: 0, linearViewFloating: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc]); @@ -1002,6 +1011,9 @@ export class CurrentUserUtils {                      title: "Show preview",                      toolTip: "Show preview of selected document",                      btnType: ButtonType.ToggleButton, +                    switchToggle: true, +                    width: 100, +                    buttonText: "Show Preview",                      icon: "eye",                      click: 'toggleSchemaPreview()',                      checkResult: 'toggleSchemaPreview(true)' @@ -1041,7 +1053,7 @@ export class CurrentUserUtils {              // { title: "Alias", btnType: ButtonType.ClickButton, icon: "copy", hidden: 'selectedDocumentType()' }, // Only when a document is selected               { title: "Text", type: "textTools", subMenu: true, expanded: 'selectedDocumentType("rtf")' }, // Always available              { title: "Ink", type: "inkTools", subMenu: true, expanded: 'selectedDocumentType("ink")' }, // Always available -            // { title: "Web", type: "webTools", subMenu: true, hidden: 'selectedDocumentType("web")' }, // Only when Web is selected +            { title: "Web", type: "webTools", subMenu: true, hidden: 'selectedDocumentType("web")' }, // Only when Web is selected              { title: "Schema", type: "schemaTools", subMenu: true, hidden: 'selectedDocumentType(undefined, "schema")' } // Only when Schema is selected          ];      } @@ -1174,13 +1186,15 @@ export class CurrentUserUtils {              }              doc.myLinkDatabase = new PrefetchProxy(linkDocs);          } +        // TODO:glr NOTE: treeViewHideTitle & _showTitle may be confusing, treeViewHideTitle is for the editable title (just for tree view), _showTitle is to show the Document title for any document          if (doc.mySharedDocs === undefined) {              let sharedDocs = Docs.newAccount ? undefined : await DocServer.GetRefField(sharingDocumentId + "outer");              if (!sharedDocs) {                  sharedDocs = Docs.Create.TreeDocument([], {                      title: "My SharedDocs", childDropAction: "alias", system: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 50, _gridGap: 15, -                    _showTitle: "title", ignoreClick: true, _lockedPosition: true, "acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment, +                    _showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, "acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment,                      _chromeHidden: true, boxShadow: "0 0", +                    explainer: "This is where documents or dashboards that other users have shared with you will appear."                  }, sharingDocumentId + "outer", sharingDocumentId);                  (sharedDocs as Doc)["acl-Public"] = (sharedDocs as Doc)[DataSym]["acl-Public"] = SharingPermissions.Augment;              } @@ -1191,18 +1205,21 @@ export class CurrentUserUtils {                  sharedDocs.childContextMenuFilters = new List<ScriptField>([dashboardFilter!,]);                  sharedDocs.childContextMenuScripts = new List<ScriptField>([addToDashboards!,]);                  sharedDocs.childContextMenuLabels = new List<string>(["Add to Dashboards",]); +                sharedDocs.childContextMenuIcons = new List<string>(["user-plus",]); +              }              doc.mySharedDocs = new PrefetchProxy(sharedDocs);          }      }      // Import sidebar is where shared documents are contained -    static setupImportSidebar(doc: Doc) { -        if (doc.myImportDocs === undefined) { -            const newUpload = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("importDocument()"), toolTip: "Import External document", _width: 100, _stayInCollection: true, _hideContextMenu: true, title: "Import", btnType: ButtonType.TextButton, _width: 200, buttonText: "Upload From Computer", icon: "upload", system: true }); -            doc.myImportDocs = new PrefetchProxy(Docs.Create.StackingDocument([newUpload], { -                title: "My ImportDocuments", _forceActive: true, ignoreClick: true, _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0, -                childDropAction: "alias", _autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, system: true, _chromeHidden: true, +    static setupUploadSidebar(doc: Doc) { +        if (doc.myUploadDocs === undefined) { +            const newUploadButton:Doc = Docs.Create.FontIconDocument({ onClick: ScriptField.MakeScript("importDocument()"), _forceActive: true, toolTip: "Upload from computer", _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, title: "Upload", btnType: ButtonType.ClickButton, buttonText: "Upload", icon: "upload", system: true }); +            doc.myUploadDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { +                title: "My Uploads", _forceActive: true, buttonMenu: true, buttonMenuDoc: newUploadButton, ignoreClick: true, _showTitle: "title", _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0, +                childDropAction: "copy", _autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, system: true, _chromeHidden: true, +                explainer: "This is where documents that are uploaded into Dash will go."              }));          }      } @@ -1305,7 +1322,7 @@ export class CurrentUserUtils {          doc.filterDocCount = 0;          this.setupDefaultIconTemplates(doc);  // creates a set of icon templates triggered by the document deoration icon          this.setupDocTemplates(doc); // sets up the template menu of templates -        this.setupImportSidebar(doc); // sets up the import sidebar +        this.setupUploadSidebar(doc); // sets up the import sidebar          this.setupSearchSidebar(doc); // sets up the search sidebar          this.setupActiveMobileMenu(doc); // sets up the current mobile menu for Dash Mobile          this.setupOverlays(doc);  // documents in overlay layer @@ -1432,7 +1449,7 @@ export class CurrentUserUtils {                      }                  }              } else if (input.files && input.files.length !== 0) { -                const importDocs = Cast(Doc.UserDoc().myImportDocs, Doc, null); +                const importDocs = Cast(Doc.UserDoc().myUploadDocs, Doc, null);                  const disposer = OverlayView.ShowSpinner();                  DocListCastAsync(importDocs.data).then(async list => {                      const results = await DocUtils.uploadFilesToDocs(Array.from(input.files || []), {}); diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 41a6dc569..47ae0424b 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -130,7 +130,7 @@  }  .contextMenu-inlineMenu { -    border-top: solid 1px; +    // border-top: solid 1px; //TODO:glr clean  }  .contextMenu-item:hover { diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 168fcb888..c3921d846 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -116,12 +116,12 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select                      style={{ alignItems: where, borderTop: this.props.addDivider ? "solid 1px" : undefined }}                      onMouseLeave={this.onPointerLeave} onMouseEnter={this.onPointerEnter}>                      {this.props.icon ? ( -                        <span className="icon-background" onMouseEnter={this.onPointerLeave} style={{ alignItems: "center" }}> +                        <span className="icon-background" onMouseEnter={this.onPointerLeave} style={{ alignItems: "center", alignSelf: "center" }}>                              <FontAwesomeIcon icon={this.props.icon} size="sm" />                          </span>                      ) : null}                      <div className="contextMenu-description" onMouseEnter={this.onPointerEnter} -                        style={{ alignItems: "center" }} > +                        style={{ alignItems: "center", alignSelf: "center" }} >                          {this.props.description}                          <FontAwesomeIcon icon={"angle-right"} size="lg" style={{ position: "absolute", right: "10px" }} />                      </div> diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 88739fe91..ec30a6a5d 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -16,6 +16,7 @@ import { TabDocView } from './collections/TabDocView';  import "./LightboxView.scss";  import { DocumentView } from './nodes/DocumentView';  import { DefaultStyleProvider, wavyBorderPath } from './StyleProvider'; +import { CollectionMenu } from './collections/CollectionMenu';  interface LightboxViewProps {      PanelWidth: number; @@ -213,6 +214,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {                          LightboxView.SetLightboxDoc(undefined);                      }                  }}  > +                                  <div className="lightboxView-contents" style={{                      left: this.leftBorder,                      top: this.topBorder, @@ -220,6 +222,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {                      height: this.lightboxHeight(),                      clipPath: `path('${Doc.UserDoc().renderStyle === "comic" ? wavyBorderPath(this.lightboxWidth(), this.lightboxHeight()) : undefined}')`                  }}> +                    {/* <CollectionMenu /> TODO:glr This is where it would go*/}                      <DocumentView ref={action((r: DocumentView | null) => {                          LightboxView._docView = r !== null ? r : undefined;                          r && setTimeout(action(() => { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 60016fc3d..dadf5b390 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -173,7 +173,7 @@ export class MainView extends React.Component {              fa.faArrowAltCircleDown, fa.faArrowAltCircleUp, fa.faArrowAltCircleLeft, fa.faArrowAltCircleRight, fa.faStopCircle, fa.faCheckCircle, fa.faGripVertical,              fa.faSortUp, fa.faSortDown, fa.faTable, fa.faTh, fa.faThList, fa.faProjectDiagram, fa.faSignature, fa.faColumns, fa.faChevronCircleUp, fa.faUpload, fa.faBorderAll,              fa.faBraille, fa.faChalkboard, fa.faPencilAlt, fa.faEyeSlash, fa.faSmile, fa.faIndent, fa.faOutdent, fa.faChartBar, fa.faBan, fa.faPhoneSlash, fa.faGripLines, -            fa.faSave, fa.faBookmark, fa.faList, fa.faListOl); +            fa.faSave, fa.faBookmark, fa.faList, fa.faListOl, fa.faFolderPlus, fa.faLightbulb, fa.faBookOpen);          this.initAuthenticationRouters();      } @@ -229,11 +229,11 @@ export class MainView extends React.Component {      createNewPresentation = async () => {          if (!await this.userDoc.myTrails) {              this.userDoc.myTrails = new PrefetchProxy(Docs.Create.TreeDocument([], { -                title: "PRESENTATION TRAILS", childDontRegisterViews: true, _height: 100, _forceActive: true, boxShadow: "0 0", _lockedPosition: true, treeViewOpen: true, system: true +                title: "TRAILS", childDontRegisterViews: true, _height: 100, _forceActive: true, boxShadow: "0 0", _lockedPosition: true, treeViewOpen: true, system: true              }));          }          const pres = Docs.Create.PresDocument(new List<Doc>(), -            { title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0" }); +            { title: "Untitled Trail", _viewType: CollectionViewType.Stacking, _fitWidth: true, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0" });          CollectionDockingView.AddSplit(pres, "right");          this.userDoc.activePresentation = pres;          Doc.AddDocToList(this.userDoc.myTrails as Doc, "data", pres); diff --git a/src/client/views/MainViewModal.scss b/src/client/views/MainViewModal.scss index 03cb5cc84..0648e31c5 100644 --- a/src/client/views/MainViewModal.scss +++ b/src/client/views/MainViewModal.scss @@ -6,6 +6,7 @@      height: 100%;      .dialogue-box { +        padding: 10px;          position: absolute;          z-index: 1000;          text-align: center; @@ -13,7 +14,7 @@          align-self: center;          align-content: center;          background: white; -        border-radius: 10px; +        // border-radius: 10px;          box-shadow: #00000044 5px 5px 10px;          transform: translate(-50%, -50%);          top: 50%; diff --git a/src/client/views/PropertiesButtons.scss b/src/client/views/PropertiesButtons.scss index 484522bc7..36b2df73e 100644 --- a/src/client/views/PropertiesButtons.scss +++ b/src/client/views/PropertiesButtons.scss @@ -44,14 +44,15 @@ $linkGap : 3px;      }  }  .propertiesButtons-linkButton-empty.toggle-on { -    background-color: white; -    color: $dark-gray; +    background-color: $medium-blue; +    color: $white;  }  .propertiesButtons-linkButton-empty.toggle-hover { -    background-color: gray; -    color: $dark-gray; +    background-color: $light-blue; +    color: $black;  }  .propertiesButtons-linkButton-empty.toggle-off { +    background-color: $dark-gray;      color: white;  } @@ -67,10 +68,12 @@ $linkGap : 3px;  }  .onClickFlyout-editScript { +    cursor: pointer;      text-align: center; -    border: 0.5px solid grey; +    margin-top: 5px; +    border: 0.5px solid $medium-gray;      background-color: rgb(230, 230, 230); -    border-radius: 9px; +    border-radius: 5px;      padding: 4px;  } @@ -84,9 +87,32 @@ $linkGap : 3px;      margin-bottom: 8px;  } +.propertiesButton-dropdownList { +    width: 100%; +    height: fit-content; +    top: 100%; +    z-index: 21; + +    .list-item { +        cursor: pointer; +        color: $black; +        width: 100%; +        height: 25px; +        font-weight: 400; +        display: flex; +        justify-content: left; +        align-items: center; +        padding-left: 5px; +    } + +    .list-item:hover { +        background-color: lightgrey; +    } +} +  .propertiesButtons-title { -    background: #121721; -    color: white; +    background: $dark-gray; +    color: $white;      font-size: 6px;      width: 37px;      padding: 3px; @@ -111,17 +137,11 @@ $linkGap : 3px;      margin-left: 4px;      &:hover { -        background: $medium-gray; -        transform: scale(1.05); +        filter:brightness(0.85);          cursor: pointer;      }  } -.propertiesButtons-linker:hover { -    cursor: pointer; -    transform: scale(1.05); -} -  @-moz-keyframes spin {      100% { diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index dcab9bc1e..286365fa6 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -15,6 +15,7 @@ import { InkingStroke } from './InkingStroke';  import { DocumentView } from './nodes/DocumentView';  import './PropertiesButtons.scss';  import React = require("react"); +import { Colors } from "./global/globalEnums";  const higflyout = require("@hig/flyout");  export const { anchorPoints } = higflyout;  export const Flyout = higflyout.default; @@ -65,10 +66,10 @@ export class PropertiesButtons extends React.Component<{}, {}> {          return this.propertyToggleBtn("Lock\xA0View", "_lockedTransform", on => `${on ? "Unlock" : "Lock"} panning of view`, on => "lock");      }      @computed get fitContentButton() { -        return this.propertyToggleBtn("View All", "_fitToBox", on => `${on ? "Don't" : ""} fit content to container visible area`, on => "eye"); +        return this.propertyToggleBtn("View All", "_fitToBox", on => `${on ? "Don't" : "Do"} fit content to container visible area`, on => "eye");      }      @computed get fitWidthButton() { -        return this.propertyToggleBtn("Fit\xA0Width", "_fitWidth", on => `${on ? "Don't" : ""} fit content to width of container`, on => "arrows-alt-h"); +        return this.propertyToggleBtn("Fit\xA0Width", "_fitWidth", on => `${on ? "Don't" : "Do"} fit content to width of container`, on => "arrows-alt-h");      }      @computed get captionButton() {          return this.propertyToggleBtn("Caption", "_showCaption", on => `${on ? "Hide" : "Show"} caption footer`, on => "closed-captioning", (dv, doc) => (dv?.rootDoc || doc)._showCaption = (dv?.rootDoc || doc)._showCaption === undefined ? "caption" : undefined); @@ -128,11 +129,11 @@ export class PropertiesButtons extends React.Component<{}, {}> {      @undoBatch      @action -    handleOptionChange = (e: any) => { -        this.selectedDoc && (this.selectedDoc.onClickBehavior = e.target.value); +    handleOptionChange = (onClick: string) => { +        this.selectedDoc && (this.selectedDoc.onClickBehavior = onClick);          SelectionManager.Views().filter(dv => dv.docView).map(dv => dv.docView!).forEach(docView => {              docView.noOnClick(); -            switch (e.target.value) { +            switch (onClick) {                  case "enterPortal": docView.makeIntoPortal(); break;                  case "toggleDetail": docView.setToggleDetail(); break;                  case "linkInPlace": docView.toggleFollowLink("inPlace", true, false); break; @@ -149,20 +150,34 @@ export class PropertiesButtons extends React.Component<{}, {}> {      @computed      get onClickFlyout() { -        const makeLabel = (value: string, label: string) => <div className="radio"> -            <label> -                <input type="radio" value={value} checked={(this.selectedDoc?.onClickBehavior ?? "nothing") === value} onChange={this.handleOptionChange} /> -                {label} -            </label> -        </div>; +        const buttonList = [ +            ["nothing", "Select Document"], +            ["enterPortal", "Enter Portal"], +            ["toggleDetail", "Toggle Detail"], +            ["linkInPlace", "Follow Link"], +            ["linkOnRight", "Open Link on Right"] +        ] +        const currentSelection = this.selectedDoc.onClickBehavior; +        // Get items to place into the list + +        const list = buttonList.map((value) => { +            const click = () => { +                this.handleOptionChange(value[0]); +            }; +            return <div className="list-item" key={`${value}`} +                style={{ +                    backgroundColor: value[0] === currentSelection ? Colors.LIGHT_BLUE : undefined +                }} +                onClick={click}> +                {value[1]} +            </div>; +        });          return <div> -            <form> -                {makeLabel("nothing", "Select Document")} -                {makeLabel("enterPortal", "Enter Portal")} -                {makeLabel("toggleDetail", "Toggle Detail")} -                {makeLabel("linkInPlace", "Follow Link")} -                {makeLabel("linkOnRight", "Open Link on Right")} -            </form> +            <div> +                <div className="propertiesButton-dropdownList"> +                    {list} +                </div> +            </div>              {Doc.UserDoc().noviceMode ? (null) : <div onPointerDown={this.editOnClickScript} className="onClickFlyout-editScript"> Edit onClick Script</div>}          </div>;      } @@ -190,24 +205,24 @@ export class PropertiesButtons extends React.Component<{}, {}> {          const isFreeForm = this.selectedDoc?._viewType === CollectionViewType.Freeform;          const isTree = this.selectedDoc?._viewType === CollectionViewType.Tree;          const toggle = (ele: JSX.Element | null, style?: React.CSSProperties) => <div className="propertiesButtons-button" style={style}> {ele} </div>; - +        const isNovice = Doc.UserDoc().noviceMode;          return !this.selectedDoc ? (null) :              <div className="propertiesButtons">                  {toggle(this.titleButton)}                  {toggle(this.captionButton)}                  {toggle(this.lockButton)} -                {toggle(this.dictationButton)} +                {toggle(this.dictationButton, { display: isNovice ? "none" : "" })}                  {toggle(this.onClickButton)} -                {toggle(this.fitWidthButton)} +                {toggle(this.fitWidthButton, { display: isNovice ? "none" : "" })}                  {toggle(this.fitContentButton, { display: !isFreeForm ? "none" : "" })}                  {toggle(this.autoHeightButton, { display: !isText && !isStacking && !isTree ? "none" : "" })}                  {toggle(this.maskButton, { display: !isInk ? "none" : "" })} -                {toggle(this.chromeButton, { display: isCollection ? "" : "none" })} +                {toggle(this.chromeButton, { display: !isCollection || isNovice ? "none" : "" })}                  {toggle(this.gridButton, { display: isCollection ? "" : "none" })}                  {toggle(this.snapButton, { display: isCollection ? "" : "none" })}                  {toggle(this.clustersButton, { display: !isFreeForm ? "none" : "" })}                  {toggle(this.panButton, { display: !isFreeForm ? "none" : "" })} -                {toggle(this.perspectiveButton, { display: !isCollection ? "none" : "" })} +                {toggle(this.perspectiveButton, { display: !isCollection || isNovice ? "none" : "" })}              </div>;      }  }
\ No newline at end of file diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 0e3663f65..01b79ffd2 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -106,9 +106,10 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {                  {user}              </div>;          }; +        // TODO: Calculation of the topbar is hardcoded and different for text nodes - it should all be the same and all be part of SidebarAnnos          return !this.props.showSidebar ? (null) :              <div style={{ -                position: "absolute", pointerEvents: this.props.isContentActive() ? "all" : undefined, top: 0, right: 0, +                position: "absolute", pointerEvents: this.props.isContentActive() ? "all" : undefined, top: this.props.rootDoc.type !== DocumentType.RTF && StrCast(this.props.rootDoc._showTitle) === "title" ? 15 : 0, right: 0,                  background: this.props.styleProvider?.(this.props.rootDoc, this.props, StyleProp.WidgetColor),                  width: `${this.panelWidth()}px`,                  height: "100%" diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index fa35081bc..e528e84e3 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -89,7 +89,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps      switch (property.split(":")[0]) {          case StyleProp.TreeViewIcon: return Doc.toIcon(doc, isOpen);          case StyleProp.DocContents: return undefined; -        case StyleProp.WidgetColor: return isAnnotated ? "lightBlue" : darkScheme() ? "lightgrey" : "dimgrey"; +        case StyleProp.WidgetColor: return isAnnotated ? Colors.LIGHT_BLUE : darkScheme() ? "lightgrey" : "dimgrey";          case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null));          case StyleProp.HideLinkButton: return props?.hideLinkButton || (!selected && (doc?.isLinkButton || doc?.hideLinkButton));          case StyleProp.FontSize: return StrCast(doc?.[fieldKey + "fontSize"]); @@ -108,7 +108,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps          case StyleProp.TitleHeight: return 15;          case StyleProp.BorderPath: return comicStyle() && props?.renderDepth ? { path: wavyBorderPath(props?.PanelWidth?.() || 0, props?.PanelHeight?.() || 0), fill: wavyBorderPath(props?.PanelWidth?.() || 0, props?.PanelHeight?.() || 0, .08), width: 3 } : { path: undefined, width: 0 };          case StyleProp.JitterRotation: return comicStyle() ? random(-1, 1, NumCast(doc?.x), NumCast(doc?.y)) * ((props?.PanelWidth() || 0) > (props?.PanelHeight() || 0) ? 5 : 10) : 0; -        case StyleProp.HeaderMargin: return ([CollectionViewType.Stacking, CollectionViewType.Masonry].includes(doc?._viewType as any) || +        case StyleProp.HeaderMargin: return ([CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.Tree].includes(doc?._viewType as any) ||              doc?.type === DocumentType.RTF) && showTitle() && !StrCast(doc?.showTitle).includes(":hover") ? 15 : 0;          case StyleProp.BackgroundColor: {              if (MainView.Instance.LastButton === doc) return Colors.LIGHT_GRAY; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 6bdeaf722..6a22acae8 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -338,7 +338,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {              {this.renderColors(this._col)}              <div className="collectionSchema-headerMenu-group">                  <button onClick={() => { this.deleteColumn(this._col.heading); }} -                >Delete Column</button> +                >Hide Column</button>              </div>          </div>;      } diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 4b123c8b6..2f002736d 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -14,6 +14,30 @@      width: 100%;  } +// TODO:glr Turn this into a seperate class +.documentButtonMenu { +    position: relative; +    height: fit-content; +    border-bottom: $standard-border; +    display: flex; +    justify-content: center; +    flex-direction: column; +    align-items: center; +    align-content: center; +    padding: 5px 0 5px 0; + +    .documentExplanation { +        width: 90%; +        margin: 5px; +        font-size: 11px; +        background-color: $light-blue; +        color: $medium-blue; +        padding: 10px; +        border-radius: 10px; +        border: solid 2px $medium-blue; +    } +} +  .collectionStackingView,  .collectionMasonryView {      height: 100%; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 4fedda1bd..c92b259d0 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";  import { CursorProperty } from "csstype";  import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";  import { observer } from "mobx-react"; -import { DataSym, Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; +import { DataSym, Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../fields/Doc";  import { collectionSchema, documentSchema } from "../../../fields/documentSchemas";  import { Id } from "../../../fields/FieldSymbols";  import { List } from "../../../fields/List"; @@ -11,7 +11,7 @@ import { listSpec, makeInterface } from "../../../fields/Schema";  import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";  import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";  import { TraceMobx } from "../../../fields/util"; -import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils"; +import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, Utils, returnTrue, returnEmptyDoclist, returnEmptyFilter } from "../../../Utils";  import { DocUtils, Docs } from "../../documents/Documents";  import { DragManager, dropActionType } from "../../util/DragManager";  import { SnappingManager } from "../../util/SnappingManager"; @@ -23,12 +23,14 @@ import { EditableView } from "../EditableView";  import { LightboxView } from "../LightboxView";  import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";  import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from "../nodes/DocumentView"; -import { StyleProp } from "../StyleProvider"; +import { StyleProp, DefaultStyleProvider } from "../StyleProvider";  import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow";  import "./CollectionStackingView.scss";  import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";  import { CollectionSubView } from "./CollectionSubView";  import { CollectionViewType } from "./CollectionView"; +import { FontIconBox } from "../nodes/button/FontIconBox"; +import { CurrentUserUtils } from "../../util/CurrentUserUtils";  const _global = (window /* browser */ || global /* node */) as any;  type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>; @@ -514,6 +516,47 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,          return sections.map((section, i) => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1], i === 0));      } +    @computed get buttonMenu() { +        const menuDoc:Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null); +        // TODO:glr Allow support for multiple buttons +        if (menuDoc){ +            const width: number = NumCast(menuDoc._width, 30); +            const height: number = NumCast(menuDoc._height, 30); +            console.log(menuDoc.title, width, height); +            return (<div className="buttonMenu-docBtn" +                style = {{width: width, height: height}}> +                <DocumentView +                    Document={menuDoc} +                    DataDoc={menuDoc} +                    isContentActive={this.props.isContentActive} +                    isDocumentActive={returnTrue} +                    addDocument={this.props.addDocument} +                    moveDocument={this.props.moveDocument} +                    addDocTab={this.props.addDocTab} +                    pinToPres={emptyFunction} +                    rootSelected={this.props.isSelected} +                    removeDocument={this.props.removeDocument} +                    ScreenToLocalTransform={Transform.Identity} +                    PanelWidth={() => 35} +                    PanelHeight={() => 35} +                    renderDepth={this.props.renderDepth} +                    focus={emptyFunction} +                    styleProvider={this.props.styleProvider} +                    layerProvider={this.props.layerProvider} +                    docViewPath={returnEmptyDoclist} +                    whenChildContentsActiveChanged={emptyFunction} +                    bringToFront={emptyFunction} +                    docFilters={this.props.docFilters} +                    docRangeFilters={this.props.docRangeFilters} +                    searchFilterDocs={this.props.searchFilterDocs} +                    ContainingCollectionView={undefined} +                    ContainingCollectionDoc={undefined}  +                /> +            </div> +            ); +        } +    } +      @computed get nativeWidth() { return this.props.NativeWidth?.() ?? Doc.NativeWidth(this.layoutDoc); }      @computed get nativeHeight() { return this.props.NativeHeight?.() ?? Doc.NativeHeight(this.layoutDoc); } @@ -529,34 +572,50 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,              SetValue: this.addGroup,              contents: "+ ADD A GROUP"          }; +        const buttonMenu = this.rootDoc.buttonMenu; +        const noviceExplainer = this.rootDoc.explainer; +        console.log(noviceExplainer);          return ( -            <div className="collectionStackingMasonry-cont" > -                <div className={this.isStackingView ? "collectionStackingView" : "collectionMasonryView"} -                    ref={this.createRef} -                    style={{ -                        overflowY: this.props.isContentActive() ? "auto" : "hidden", -                        background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor), -                        pointerEvents: this.backgroundEvents ? "all" : undefined -                    }} -                    onScroll={action(e => this._scroll = e.currentTarget.scrollTop)} -                    onDrop={this.onExternalDrop.bind(this)} -                    onContextMenu={this.onContextMenu} -                    onWheel={e => this.props.isContentActive(true) && e.stopPropagation()} > -                    {this.renderedSections} -                    {!this.showAddAGroup ? (null) : -                        <div key={`${this.props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton" -                            style={{ width: !this.isStackingView ? "100%" : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}> -                            <EditableView {...editableViewProps} /> -                        </div>} -                    {/* {this.chromeHidden || !this.props.isSelected() ? (null) : -                        <Switch -                            onChange={this.onToggle} -                            onClick={this.onToggle} -                            defaultChecked={true} -                            checkedChildren="edit" -                            unCheckedChildren="view" -                        />} */} -                </div> </div> +            <> +                {buttonMenu || noviceExplainer ? <div className="documentButtonMenu"> +                    {buttonMenu ? this.buttonMenu : null} +                    {Doc.UserDoc().noviceMode && noviceExplainer ?  +                        <div className="documentExplanation"> +                            {noviceExplainer} +                        </div> +                        : null +                    } +                </div> : null} +                <div className="collectionStackingMasonry-cont" > +                    <div className={this.isStackingView ? "collectionStackingView" : "collectionMasonryView"} +                        ref={this.createRef} +                        style={{ +                            overflowY: this.props.isContentActive() ? "auto" : "hidden", +                            background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor), +                            pointerEvents: this.backgroundEvents ? "all" : undefined +                        }} +                        onScroll={action(e => this._scroll = e.currentTarget.scrollTop)} +                        onDrop={this.onExternalDrop.bind(this)} +                        onContextMenu={this.onContextMenu} +                        onWheel={e => this.props.isContentActive(true) && e.stopPropagation()} > +                        {this.renderedSections} +                        {!this.showAddAGroup ? (null) : +                            <div key={`${this.props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton" +                                style={{ width: !this.isStackingView ? "100%" : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}> +                                <EditableView {...editableViewProps} /> +                            </div>} +                        {/* {this.chromeHidden || !this.props.isSelected() ? (null) : +                            <Switch +                                onChange={this.onToggle} +                                onClick={this.onToggle} +                                defaultChecked={true} +                                checkedChildren="edit" +                                unCheckedChildren="view" +                            />} */} +                    </div>  +                </div> +            </> +                      );      }  } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 89d42439e..4d62a1af4 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -8,7 +8,7 @@ import { Document, listSpec } from '../../../fields/Schema';  import { ScriptField } from '../../../fields/ScriptField';  import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';  import { TraceMobx } from '../../../fields/util'; -import { returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils'; +import { returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, emptyFunction } from '../../../Utils';  import { DocUtils } from '../../documents/Documents';  import { CurrentUserUtils } from '../../util/CurrentUserUtils';  import { DocumentManager } from '../../util/DocumentManager'; @@ -26,6 +26,7 @@ import { CollectionSubView } from "./CollectionSubView";  import "./CollectionTreeView.scss";  import { TreeView } from "./TreeView";  import React = require("react"); +import { Transform } from '../../util/Transform';  const _global = (window /* browser */ || global /* node */) as any;  export type collectionTreeViewProps = { @@ -221,8 +222,9 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll      }      childContextMenuItems = () => {          const customScripts = Cast(this.doc.childContextMenuScripts, listSpec(ScriptField), []); -        const filterScripts = Cast(this.doc.childContextMenuFilters, listSpec(ScriptField), []); -        return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: filterScripts[i], label })); +        const customFilters = Cast(this.doc.childContextMenuFilters, listSpec(ScriptField), []); +        const icons = StrListCast(this.doc.childContextMenuIcons); +        return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));      }      @computed get treeViewElements() {          TraceMobx(); @@ -265,13 +267,48 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll          return hideTitle ? (null) : (this.outlineMode ? this.documentTitle : this.editableTitle)(this.treeChildren);      } -    @computed get renderClearButton() { -        return !this.doc.treeViewShowClearButton ? (null) : <div key="toolbar"> -            <button className="toolbar-button round-button" title="Empty" onClick={undoBatch(action(() => Doc.GetProto(this.doc)[this.props.fieldKey] = undefined))}> -                <FontAwesomeIcon icon={"trash"} size="sm" /> -            </button> -        </div >; +    @computed get buttonMenu() { +        const menuDoc:Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null); +        // To create a multibutton menu add a CollectionLinearView +        if (menuDoc){ +             +            const width: number = NumCast(menuDoc._width, 30); +            const height: number = NumCast(menuDoc._height, 30); +            console.log(menuDoc.title, width, height); +            return (<div className="buttonMenu-docBtn" +                style = {{width: width, height: height}}> +                <DocumentView +                    Document={menuDoc} +                    DataDoc={menuDoc} +                    isContentActive={this.props.isContentActive} +                    isDocumentActive={returnTrue} +                    addDocument={this.props.addDocument} +                    moveDocument={this.props.moveDocument} +                    addDocTab={this.props.addDocTab} +                    pinToPres={emptyFunction} +                    rootSelected={this.props.isSelected} +                    removeDocument={this.props.removeDocument} +                    ScreenToLocalTransform={Transform.Identity} +                    PanelWidth={() => 35} +                    PanelHeight={() => 35} +                    renderDepth={this.props.renderDepth + 1} +                    focus={emptyFunction} +                    styleProvider={this.props.styleProvider} +                    layerProvider={this.props.layerProvider} +                    docViewPath={returnEmptyDoclist} +                    whenChildContentsActiveChanged={emptyFunction} +                    bringToFront={emptyFunction} +                    docFilters={this.props.docFilters} +                    docRangeFilters={this.props.docRangeFilters} +                    searchFilterDocs={this.props.searchFilterDocs} +                    ContainingCollectionView={undefined} +                    ContainingCollectionDoc={undefined}  +                /> +            </div>); +        }      } + +          @computed get nativeWidth() { return Doc.NativeWidth(this.Document, undefined, true); }      @computed get nativeHeight() { return Doc.NativeHeight(this.Document, undefined, true); } @@ -295,22 +332,34 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll          TraceMobx();          const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);          const pointerEvents = () => !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined; +        const buttonMenu = this.rootDoc.buttonMenu; +        const noviceExplainer = this.rootDoc.explainer;          return !(this.doc instanceof Doc) || !this.treeChildren ? (null) : -            <div className="collectionTreeView-container" -                style={this.outlineMode ? { transform: `scale(${this.contentScaling})`, width: `calc(${100 / this.contentScaling}%)` } : {}} -                onContextMenu={this.onContextMenu}> -                <div className="collectionTreeView-dropTarget" -                    style={{ background: background(), paddingLeft: `${this.paddingX()}px`, paddingRight: `${this.paddingX()}px`, paddingBottom: `${this.paddingBot()}px`, paddingTop: `${this.paddingTop()}px`, pointerEvents: pointerEvents() }} -                    onWheel={e => e.stopPropagation()} -                    onDrop={this.onTreeDrop} -                    ref={this.createTreeDropTarget}> +               <>                      {this.titleBar} -                    {this.renderClearButton} -                    <ul className={`no-indent${this.outlineMode ? "-outline" : ""}`} > -                        {this.treeViewElements} -                    </ul> -                </div > -            </div>; +                    <div className="collectionTreeView-container" +                        style={this.outlineMode ? { transform: `scale(${this.contentScaling})`, width: `calc(${100 / this.contentScaling}%)` } : {}} +                        onContextMenu={this.onContextMenu}> +                        {buttonMenu || noviceExplainer ? <div className="documentButtonMenu"> +                            {buttonMenu ? this.buttonMenu : null} +                            {Doc.UserDoc().noviceMode && noviceExplainer ?  +                                <div className="documentExplanation"> +                                    {noviceExplainer} +                                </div> +                                : null +                            } +                        </div> : null} +                        <div className="collectionTreeView-dropTarget" +                            style={{ background: background(), paddingLeft: `${this.paddingX()}px`, paddingRight: `${this.paddingX()}px`, paddingBottom: `${this.paddingBot()}px`, paddingTop: `${this.paddingTop()}px`, pointerEvents: pointerEvents() }} +                            onWheel={e => e.stopPropagation()} +                            onDrop={this.onTreeDrop} +                            ref={this.createTreeDropTarget}> +                            <ul className={`no-indent${this.outlineMode ? "-outline" : ""}`} > +                                {this.treeViewElements} +                            </ul> +                        </div > +                    </div> +               </>;      }  }
\ No newline at end of file diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 889db1ef6..34cb6ec55 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -387,9 +387,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {                      background={this.miniMapColor}                      document={this._document}                      tabView={this.tabView} /> -                <Tooltip style={{ display: this.disableMinimap() ? "none" : undefined }} key="ttip" title={<div className="dash-tooltip">{this._document.hideMinimap ? "Open minimap" : "Close minimap"}</div>}> +                <Tooltip key="ttip" title={<div className="dash-tooltip">{this._document.hideMinimap ? "Open minimap" : "Close minimap"}</div>}>                      <div className="miniMap-hidden"                          style={{ +                            display: this.disableMinimap() || this._document._viewType !== "freeform" ? "none" : undefined,                              color: this._document.hideMinimap ? Colors.BLACK : Colors.WHITE,                              backgroundColor: this._document.hideMinimap ? Colors.LIGHT_GRAY : Colors.MEDIUM_BLUE,                              boxShadow: this._document.hideMinimap ? Shadows.STANDARD_SHADOW : undefined diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index b9487054b..8cf34ddcc 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -525,7 +525,8 @@ export class TreeView extends React.Component<TreeViewProps> {      childContextMenuItems = () => {          const customScripts = Cast(this.doc.childContextMenuScripts, listSpec(ScriptField), []);          const customFilters = Cast(this.doc.childContextMenuFilters, listSpec(ScriptField), []); -        return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], label })); +        const icons = StrListCast(this.doc.childContextMenuIcons); +        return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));      }      onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick)); @@ -835,7 +836,7 @@ export class TreeView extends React.Component<TreeViewProps> {          dontRegisterView: boolean | undefined,          observerHeight: (ref: any) => void,          unobserveHeight: (ref: any) => void, -        contextMenuItems: ({ script: ScriptField, filter: ScriptField, label: string }[]) +        contextMenuItems: ({ script: ScriptField, filter: ScriptField, label: string, icon: string }[])      ) {          const viewSpecScript = Cast(conainerCollection.viewSpecScript, ScriptField);          if (viewSpecScript) { diff --git a/src/client/views/collections/collectionLinearView/CollectionLinearView.scss b/src/client/views/collections/collectionLinearView/CollectionLinearView.scss index f249eb1f5..8fe804466 100644 --- a/src/client/views/collections/collectionLinearView/CollectionLinearView.scss +++ b/src/client/views/collections/collectionLinearView/CollectionLinearView.scss @@ -98,7 +98,11 @@              transition: transform 0.2s;              align-items: center;              justify-content: center; -            transition: 0.15s; +            transition: 0.2s; + +            &:hover{ +                filter: brightness(0.85); +            }          }          >input { diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx index b28c32e0e..a25f962df 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx @@ -191,7 +191,7 @@ export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps>                          {this.renderSorting()}                          {this.renderColors()}                          <div className="collectionSchema-headerMenu-group"> -                            <button onClick={() => this.props.deleteColumn(this.props.columnField.heading)}>Delete Column</button> +                            <button onClick={() => this.props.deleteColumn(this.props.columnField.heading)}>Hide Column</button>                          </div>                      </>                  } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index fed64b620..dfe99ffc8 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -338,7 +338,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {              {this.renderColors(this._col)}              <div className="collectionSchema-headerMenu-group">                  <button onClick={() => { this.deleteColumn(this._col.heading); }} -                >Delete Column</button> +                >Hide Column</button>              </div>          </div>;      } diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index f5a7e61aa..8962d29f0 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -638,12 +638,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent<                                  </div>                              </div>                          ) : ( -                                <button +                                <div                                      className={`audiobox-record${interactive}`}                                      style={{ backgroundColor: Colors.DARK_GRAY }}                                  >                                      RECORD -                                </button> +                                </div>                              )}                      </div>                  ) : ( diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c9482c770..501665f3f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -635,7 +635,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps      makeIntoPortal = async () => {          const portalLink = this.allLinks.find(d => d.anchor1 === this.props.Document);          if (!portalLink) { -            const portal = Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), _fitWidth: true, title: StrCast(this.props.Document.title) + ".portal" }); +            const portal = Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), _fitWidth: true, title: StrCast(this.props.Document.title) + " [Portal]" });              DocUtils.MakeLink({ doc: this.props.Document }, { doc: portal }, "portal to");          }          this.Document.followLinkLocation = "inPlace"; @@ -679,7 +679,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps              const appearance = cm.findByDescription("UI Controls...");              const appearanceItems: ContextMenuProps[] = appearance && "subitems" in appearance ? appearance.subitems : [];              !Doc.UserDoc().noviceMode && templateDoc && appearanceItems.push({ description: "Open Template   ", event: () => this.props.addDocTab(templateDoc, "add:right"), icon: "eye" }); -            appearanceItems.push({ +            !Doc.UserDoc().noviceMode && appearanceItems.push({                  description: "Add a Field", event: () => {                      const alias = Doc.MakeAlias(this.rootDoc);                      alias.layout = FormattedTextBox.LayoutString("newfield"); diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index 72dec6e4c..f44355929 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -1,3 +1,5 @@ +@import "../global/globalCssVariables.scss"; +  .pdfBox,  .pdfBox-interactive {      display: inline-block; @@ -18,12 +20,13 @@          top: 0;          left: 0; +        // glr: This should really be the same component as text and PDFs          .pdfBox-sidebarBtn { -            background: #121721; +            background: $black;              height: 25px;              width: 25px; -            right: 0; -            color: white; +            right: 5px; +            color: $white;              display: flex;              position: absolute;              align-items: center; @@ -31,6 +34,13 @@              border-radius: 3px;              pointer-events: all;              z-index: 1; // so it appears on top of the document's title, if shown + +            box-shadow: $standard-box-shadow; +            transition: 0.2s; + +            &:hover{ +                filter: brightness(0.85); +            }          }          .pdfBox-pageNums { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 5e07229c1..3a399bfdb 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -24,6 +24,7 @@ import { pageSchema } from "./ImageBox";  import "./PDFBox.scss";  import React = require("react");  import { AnchorMenu } from '../pdf/AnchorMenu'; +import { Colors } from '../global/globalEnums';  type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>;  const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema); @@ -208,11 +209,15 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps                          onClick={action(() => this._pageControls = !this._pageControls)} />                      {this._pageControls ? pageBtns : (null)}                  </div> -                <button className="pdfBox-sidebarBtn" title="Toggle Sidebar" -                    style={{ display: !this.props.isContentActive() ? "none" : undefined }} +                <div className="pdfBox-sidebarBtn" key="sidebar" title="Toggle Sidebar" +                    style={{  +                        display: !this.props.isContentActive() ? "none" : undefined,  +                        top: StrCast(this.rootDoc._showTitle) === "title" ? 20 : 5, +                        backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK +                    }}                      onPointerDown={this.sidebarBtnDown} > -                    <FontAwesomeIcon icon={"chevron-left"} size="sm" /> -                </button> +                        <FontAwesomeIcon style={{ color: Colors.WHITE }} icon={"comment-alt"} size="sm" /> +                </div>              </div>;      }      sidebarWidth = () => !this.SidebarShown ? 0 : diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index 19b69ff5a..417a17d96 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -10,7 +10,7 @@          background: #121721;          height: 25px;          width: 25px; -        right: 0; +        right: 5px;          display: flex;          position: absolute;          align-items: center; @@ -18,6 +18,13 @@          border-radius: 3px;          pointer-events: all;          z-index: 1; // so it appears on top of the document's title, if shown + +        box-shadow: $standard-box-shadow; +        transition: 0.2s; + +        &:hover{ +            filter: brightness(0.85); +        }      }      .pdfViewerDash-dragAnnotationBox { diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 719e5a796..1f85219d6 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -33,6 +33,7 @@ import { FieldView, FieldViewProps } from './FieldView';  import { LinkDocPreview } from "./LinkDocPreview";  import "./WebBox.scss";  import React = require("react"); +import { Colors } from "../global/globalEnums";  const _global = (window /* browser */ || global /* node */) as any;  const htmlToText = require("html-to-text"); @@ -590,11 +591,15 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps                      moveDocument={this.moveDocument}                      removeDocument={this.removeDocument}                  /> -                <button className="webBox-overlayButton-sidebar" key="sidebar" title="Toggle Sidebar" -                    style={{ display: !this.props.isContentActive() ? "none" : undefined }} +                <div className="webBox-overlayButton-sidebar" key="sidebar" title="Toggle Sidebar" +                    style={{  +                        display: !this.props.isContentActive() ? "none" : undefined,  +                        top: StrCast(this.rootDoc._showTitle) === "title" ? 20 : 5, +                        backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK +                    }}                      onPointerDown={this.sidebarBtnDown} > -                    <FontAwesomeIcon style={{ color: "white" }} icon={"chevron-left"} size="sm" /> -                </button> +                        <FontAwesomeIcon style={{ color: Colors.WHITE }} icon={"comment-alt"} size="sm" /> +                </div>              </div>);      }  } diff --git a/src/client/views/nodes/button/FontIconBox.scss b/src/client/views/nodes/button/FontIconBox.scss index 48fb2c8dc..a2da35fe1 100644 --- a/src/client/views/nodes/button/FontIconBox.scss +++ b/src/client/views/nodes/button/FontIconBox.scss @@ -7,6 +7,7 @@      align-items: center;      font-size: 80%;      border-radius: $standard-border-radius; +    transition: 0.15s;      .menuButton-wrap {          grid-column: 1; @@ -29,6 +30,9 @@          font-family: 'ROBOTO';          text-transform: uppercase;          font-weight: bold; +        transition: 0.15s; + +      }      .fontIconBox-icon { @@ -50,7 +54,18 @@      }      &.textBtn { +        display: grid; +        /* grid-row: auto; */ +        grid-auto-flow: column; +        cursor: pointer;          width: 100%; +        justify-content: center; +        align-items: center; +        justify-items: center; + +        &:hover { +            filter:brightness(0.85) !important; +        }      }      &.tglBtn { @@ -127,13 +142,13 @@          }          &:hover { -            background-color: rgba(0, 0, 0, 0.3) !important; +            background-color: rgba(0, 0, 0, 0.3);          }      }      &.toolBtn {          cursor: pointer; -        width: 40px; +        width: 100%;          border-radius: 100%;          svg { @@ -143,7 +158,7 @@      }      &.menuBtn { -        cursor: pointer; +        cursor: pointer !important;          border-radius: 0px;          flex-direction: column; @@ -151,6 +166,10 @@              width: 45% !important;              height: 45%;          } +         +        &:hover{ +            filter: brightness(0.85); +        }      } @@ -163,8 +182,8 @@          .colorButton-color {              margin-top: 3px; -            width: 90%; -            height: 6px; +            width: 80%; +            height: 3px;          }          .menuButton-dropdownBox { diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index fbb336445..b72f31ef8 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -253,11 +253,12 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon              } else if (selected) {                  dropdown = false;                  text = StrCast(selected.Document.type); +                if (text === DocumentType.RTF) text = "Text";                  icon = Doc.toIcon(selected.Document);              } else {                  dropdown = false; -                noneSelected = true; -                text = "None selected"; +                icon = "globe-asia"; +                text = "User Default";              }              noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking];          } else if (script === 'setFont') { @@ -302,7 +303,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon              <div className={`menuButton ${this.type} ${active}`}                  style={{ backgroundColor: this.rootDoc.dropDownOpen ? Colors.MEDIUM_BLUE : backgroundColor, color: color, display: dropdown ? undefined : "flex" }}                  onClick={dropdown ? () => this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen : undefined}> -                {dropdown || noneSelected ? (null) : <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />} +                {dropdown || noneSelected ? (null) : <FontAwesomeIcon style={{marginLeft: 5}} className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />}                  <div className="menuButton-dropdown-header">                      {text && text[0].toUpperCase() + text.slice(1)}                  </div> @@ -399,7 +400,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon      @computed get toggleButton() {          // Determine the type of toggle button          const switchToggle: boolean = BoolCast(this.rootDoc.switchToggle); - +        const buttonText: string = StrCast(this.rootDoc.buttonText);          // Colors          const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);          const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); @@ -413,6 +414,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon          if (switchToggle) {              return (                  <div className={`menuButton ${this.type} ${'switch'}`}> +                    {buttonText ? buttonText : null}                      <label className="switch">                          <input type="checkbox"                              checked={backgroundColor === Colors.MEDIUM_BLUE} @@ -487,7 +489,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon              </div>;          const menuLabel = !this.label || !Doc.UserDoc()._showMenuLabel ? (null) : -            <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor }}> +            <div className="fontIconBox-label" style={{ color: color, backgroundColor: "transparent" }}>                  {this.label}              </div>; @@ -508,7 +510,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon          switch (this.type) {              case ButtonType.TextButton:                  button = ( -                    <div className={`menuButton ${this.type}`} style={{ color: color, backgroundColor: backgroundColor, opacity: 1 }}> +                    <div className={`menuButton ${this.type}`} style={{ color: color, backgroundColor: backgroundColor, opacity: 1, gridAutoColumns: `${NumCast(this.rootDoc._height)} auto` }}>                          <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} />                          {buttonText ?                               <div className="button-text"> @@ -557,9 +559,11 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon                  );                  break;              case ButtonType.MenuButton: +                const trailsIcon = <img src={`/assets/${"presTrails.png"}`} +                    style={{ width: 30, height: 30, filter: `invert(${color === Colors.DARK_GRAY ? "0%" : "100%"})` }} />;                  button = (                      <div className={`menuButton ${this.type}`} style={{ color: color, backgroundColor: backgroundColor }}> -                        <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} /> +                        {this.icon === "pres-trail" ? trailsIcon : <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} />}                          {menuLabel}                          <FontIconBadge collection={Cast(this.rootDoc.watchedDocuments, Doc, null)} />                      </div > @@ -603,7 +607,7 @@ Scripting.addGlobal(function setBackgroundColor(color?: string, checkResult?: bo  Scripting.addGlobal(function toggleOverlay(checkResult?: boolean) {      const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;      if (checkResult && selected) { -        if (NumCast(selected.Document.z) === 1) return Colors.MEDIUM_BLUE; +        if (NumCast(selected.Document.z) >= 1) return Colors.MEDIUM_BLUE;          else return "transparent";      }      selected ? selected.props.CollectionFreeFormDocumentView?.().float() : console.log("[FontIconBox.tsx] toggleOverlay failed"); @@ -877,6 +881,7 @@ Scripting.addGlobal(function webSetURL(url: string, checkResult?: boolean) {   **/  Scripting.addGlobal(function toggleSchemaPreview(checkResult?: boolean) {      const selected = SelectionManager.Views().length ? SelectionManager.Views()[0].rootDoc : undefined; +    console.log(selected && selected.title);      if (checkResult && selected) {          const result: boolean = NumCast(selected.schemaPreviewWidth) > 0;          if (result) return Colors.MEDIUM_BLUE; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss index 3cedab1a4..56f5c5631 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.scss +++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss @@ -66,14 +66,25 @@ audiotag:hover {  .formattedTextBox-sidebar-handle {      position: absolute; -    top: 0; +    top: 5px;      //top: calc(50% - 17.5px);  // use this to center vertically -- make sure it looks okay for slide views -    width: 10px; +    width: 25px;      height: 100%; -    max-height: 35px; -    background: lightgray; -    border-radius: 20px; +    max-height: 25px; +    color: white; +    background: $medium-gray; +    border-radius: 5px; +    display: flex; +    justify-content: center; +    align-items: center;      cursor:grabbing; +    box-shadow: $standard-box-shadow; +    // transition: 0.2s; + +    &:hover{ +        filter: brightness(0.85); +    } +  }  .formattedTextBox-sidebar, diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index f45b9de7a..468edf6cc 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -63,6 +63,8 @@ import { SummaryView } from "./SummaryView";  import applyDevTools = require("prosemirror-dev-tools");  import React = require("react");  import { SidebarAnnos } from '../../SidebarAnnos'; +import { Colors } from '../../global/globalEnums'; +import { IconProp } from '@fortawesome/fontawesome-svg-core';  const translateGoogleApi = require("translate-google-api");  export interface FormattedTextBoxProps { @@ -574,11 +576,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp          changeItems.push({ description: "plain", event: undoBatch(() => Doc.setNativeView(this.rootDoc)), icon: "eye" });          const noteTypesDoc = Cast(Doc.UserDoc()["template-notes"], Doc, null);          DocListCast(noteTypesDoc?.data).forEach(note => { +            const icon: IconProp = StrCast(note.icon) as IconProp;              changeItems.push({                  description: StrCast(note.title), event: undoBatch(() => {                      Doc.setNativeView(this.rootDoc);                      DocUtils.makeCustomViewClicked(this.rootDoc, Docs.Create.TreeDocument, StrCast(note.title), note); -                }), icon: "eye" +                }), icon: icon              });          });          !Doc.UserDoc().noviceMode && changeItems.push({ description: "FreeForm", event: () => DocUtils.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), icon: "eye" }); @@ -1481,11 +1484,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp      @computed get sidebarHandle() {          TraceMobx();          const annotated = DocListCast(this.dataDoc[this.SidebarKey]).filter(d => d?.author).length; +        const color = !annotated ? Colors.WHITE : Colors.BLACK; +        const backgroundColor = !annotated ? this.sidebarWidth() ? Colors.MEDIUM_BLUE : Colors.BLACK : this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.WidgetColor + (annotated ? ":annotated" : ""));          return (!annotated && !this.props.isContentActive()) ? (null) : <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown}              style={{ -                left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`, -                background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.WidgetColor + (annotated ? ":annotated" : "")) -            }} />; +                left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${"- 30px"}))`, +                backgroundColor: backgroundColor, +                color: color +            }} > +                <FontAwesomeIcon icon={"comment-alt"}/> +            </div>;      }      @computed get sidebarCollection() {          const renderComponent = (tag: string) => { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index b805aa6ae..1abe26c20 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -167,7 +167,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>          this.layoutDoc._yMargin = 0;          this.turnOffEdit(true);          DocListCastAsync((Doc.UserDoc().myTrails as Doc).data).then(pres => -            !pres?.includes(this.rootDoc) && Doc.AddDocToList(Doc.UserDoc().myPresentations as Doc, "data", this.rootDoc)); +            !pres?.includes(this.rootDoc) && Doc.AddDocToList(Doc.UserDoc().myTrails as Doc, "data", this.rootDoc));          this._disposers.selection = reaction(() => SelectionManager.Views(),              views => views.some(view => view.props.Document === this.rootDoc) && this.updateCurrentPresentation());      } @@ -2229,7 +2229,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>          const isMini: boolean = this.toolbarWidth <= 100;          return (              <div className="presBox-buttons" style={{ display: !this.rootDoc._chromeHidden ? "none" : undefined }}> -                {isMini ? (null) : <select className="presBox-viewPicker" +                {isMini || Doc.UserDoc().noviceMode ? (null) : <select className="presBox-viewPicker"                      style={{ display: this.layoutDoc.presStatus === "edit" ? "block" : "none" }}                      onPointerDown={e => e.stopPropagation()}                      onChange={this.viewChanged} diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 260ddfc90..e70b2bc19 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -114,7 +114,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc              const linkFrom = this.props.linkFrom();              if (linkFrom) {                  console.log(linkFrom.title); -                DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo }); +                DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo }, "Link");              }          }      }); diff --git a/src/client/views/topbar/TopBar.scss b/src/client/views/topbar/TopBar.scss index 05aeb177c..923f1892e 100644 --- a/src/client/views/topbar/TopBar.scss +++ b/src/client/views/topbar/TopBar.scss @@ -33,12 +33,12 @@              align-self: center;              border-radius: $standard-border-radius;              padding: 5px; -            transition: linear 0.1s; +            transition: linear 0.2s;              color: $black;              background-color: $light-gray;              &:hover { -                background-color: $light-blue; +                background-color: darken($color: $light-gray, $amount: 20);              }          } diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 4dbd5e22c..d5254e315 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -51,7 +51,8 @@ export class TopBar extends React.Component {                          </div>                      </div>                      <div className="topbar-right" > -                        <div className="topbar-icon"> +                        <div className="topbar-icon" onClick={() => window.open( +                            "https://brown-dash.github.io/Dash-Documentation/", "_blank")}>                              {"Help"}<FontAwesomeIcon icon="question-circle"></FontAwesomeIcon>                          </div>                          <div className="topbar-icon" onClick={() => SettingsManager.Instance.open()}>  | 
